4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
104 cfg.id = this.id || Roo.id();
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
129 this.el = ct.createChild(cfg, position);
132 this.tooltipEl().attr('tooltip', this.tooltip);
135 if(this.tabIndex !== undefined){
136 this.el.dom.setAttribute('tabIndex', this.tabIndex);
143 * Fetch the element to add children to
144 * @return {Roo.Element} defaults to this.el
146 getChildContainer : function()
151 * Fetch the element to display the tooltip on.
152 * @return {Roo.Element} defaults to this.el
154 tooltipEl : function()
159 addxtype : function(tree,cntr)
163 cn = Roo.factory(tree);
165 cn.parentType = this.xtype; //??
166 cn.parentId = this.id;
168 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
169 if (typeof(cn.container_method) == 'string') {
170 cntr = cn.container_method;
174 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
176 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
178 var build_from_html = Roo.XComponent.build_from_html;
180 var is_body = (tree.xtype == 'Body') ;
182 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
184 var self_cntr_el = Roo.get(this[cntr](false));
186 // do not try and build conditional elements
187 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
192 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
193 return this.addxtypeChild(tree,cntr);
196 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202 Roo.log('skipping render');
208 if (!build_from_html) {
212 // this i think handles overlaying multiple children of the same type
213 // with the sam eelement.. - which might be buggy..
215 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
221 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
230 addxtypeChild : function (tree, cntr)
232 Roo.debug && Roo.log('addxtypeChild:' + cntr);
234 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
237 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
238 (typeof(tree['flexy:foreach']) != 'undefined');
242 skip_children = false;
243 // render the element if it's not BODY.
244 if (tree.xtype != 'Body') {
246 cn = Roo.factory(tree);
248 cn.parentType = this.xtype; //??
249 cn.parentId = this.id;
251 var build_from_html = Roo.XComponent.build_from_html;
254 // does the container contain child eleemnts with 'xtype' attributes.
255 // that match this xtype..
256 // note - when we render we create these as well..
257 // so we should check to see if body has xtype set.
258 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
260 var self_cntr_el = Roo.get(this[cntr](false));
261 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
263 //Roo.log(Roo.XComponent.build_from_html);
264 //Roo.log("got echild:");
267 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
268 // and are not displayed -this causes this to use up the wrong element when matching.
269 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
272 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
273 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
279 //echild.dom.removeAttribute('xtype');
281 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
282 Roo.debug && Roo.log(self_cntr_el);
283 Roo.debug && Roo.log(echild);
284 Roo.debug && Roo.log(cn);
290 // if object has flexy:if - then it may or may not be rendered.
291 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
292 // skip a flexy if element.
293 Roo.debug && Roo.log('skipping render');
294 Roo.debug && Roo.log(tree);
296 Roo.debug && Roo.log('skipping all children');
297 skip_children = true;
302 // actually if flexy:foreach is found, we really want to create
303 // multiple copies here...
305 //Roo.log(this[cntr]());
306 cn.render(this[cntr](true));
308 // then add the element..
316 if (typeof (tree.menu) != 'undefined') {
317 tree.menu.parentType = cn.xtype;
318 tree.menu.triggerEl = cn.el;
319 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
323 if (!tree.items || !tree.items.length) {
327 var items = tree.items;
330 //Roo.log(items.length);
332 if (!skip_children) {
333 for(var i =0;i < items.length;i++) {
334 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
340 this.fireEvent('childrenrendered', this);
345 * Show a component - removes 'hidden' class
350 this.el.removeClass('hidden');
354 * Hide a component - adds 'hidden' class
358 if (this.el && !this.el.hasClass('hidden')) {
359 this.el.addClass('hidden');
373 * @class Roo.bootstrap.Body
374 * @extends Roo.bootstrap.Component
375 * Bootstrap Body class
379 * @param {Object} config The config object
382 Roo.bootstrap.Body = function(config){
383 Roo.bootstrap.Body.superclass.constructor.call(this, config);
384 this.el = Roo.get(document.body);
385 if (this.cls && this.cls.length) {
386 Roo.get(document.body).addClass(this.cls);
390 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
395 onRender : function(ct, position)
397 /* Roo.log("Roo.bootstrap.Body - onRender");
398 if (this.cls && this.cls.length) {
399 Roo.get(document.body).addClass(this.cls);
419 * @class Roo.bootstrap.ButtonGroup
420 * @extends Roo.bootstrap.Component
421 * Bootstrap ButtonGroup class
422 * @cfg {String} size lg | sm | xs (default empty normal)
423 * @cfg {String} align vertical | justified (default none)
424 * @cfg {String} direction up | down (default down)
425 * @cfg {Boolean} toolbar false | true
426 * @cfg {Boolean} btn true | false
431 * @param {Object} config The config object
434 Roo.bootstrap.ButtonGroup = function(config){
435 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
438 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
446 getAutoCreate : function(){
452 cfg.html = this.html || cfg.html;
463 if (['vertical','justified'].indexOf(this.align)!==-1) {
464 cfg.cls = 'btn-group-' + this.align;
466 if (this.align == 'justified') {
467 console.log(this.items);
471 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
472 cfg.cls += ' btn-group-' + this.size;
475 if (this.direction == 'up') {
476 cfg.cls += ' dropup' ;
492 * @class Roo.bootstrap.Button
493 * @extends Roo.bootstrap.Component
494 * Bootstrap Button class
495 * @cfg {String} html The button content
496 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
497 * @cfg {String} size ( lg | sm | xs)
498 * @cfg {String} tag ( a | input | submit)
499 * @cfg {String} href empty or href
500 * @cfg {Boolean} disabled default false;
501 * @cfg {Boolean} isClose default false;
502 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
503 * @cfg {String} badge text for badge
504 * @cfg {String} theme default
505 * @cfg {Boolean} inverse
506 * @cfg {Boolean} toggle
507 * @cfg {String} ontext text for on toggle state
508 * @cfg {String} offtext text for off toggle state
509 * @cfg {Boolean} defaulton
510 * @cfg {Boolean} preventDefault default true
511 * @cfg {Boolean} removeClass remove the standard class..
512 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
515 * Create a new button
516 * @param {Object} config The config object
520 Roo.bootstrap.Button = function(config){
521 Roo.bootstrap.Button.superclass.constructor.call(this, config);
526 * When a butotn is pressed
527 * @param {Roo.bootstrap.Button} this
528 * @param {Roo.EventObject} e
533 * After the button has been toggles
534 * @param {Roo.EventObject} e
535 * @param {boolean} pressed (also available as button.pressed)
541 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
559 preventDefault: true,
568 getAutoCreate : function(){
576 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
577 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
582 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
584 if (this.toggle == true) {
587 cls: 'slider-frame roo-button',
592 'data-off-text':'OFF',
593 cls: 'slider-button',
599 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
600 cfg.cls += ' '+this.weight;
609 cfg["aria-hidden"] = true;
611 cfg.html = "×";
617 if (this.theme==='default') {
618 cfg.cls = 'btn roo-button';
620 //if (this.parentType != 'Navbar') {
621 this.weight = this.weight.length ? this.weight : 'default';
623 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
625 cfg.cls += ' btn-' + this.weight;
627 } else if (this.theme==='glow') {
630 cfg.cls = 'btn-glow roo-button';
632 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
634 cfg.cls += ' ' + this.weight;
640 this.cls += ' inverse';
645 cfg.cls += ' active';
649 cfg.disabled = 'disabled';
653 Roo.log('changing to ul' );
655 this.glyphicon = 'caret';
658 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
660 //gsRoo.log(this.parentType);
661 if (this.parentType === 'Navbar' && !this.parent().bar) {
662 Roo.log('changing to li?');
671 href : this.href || '#'
674 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
675 cfg.cls += ' dropdown';
682 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
684 if (this.glyphicon) {
685 cfg.html = ' ' + cfg.html;
690 cls: 'glyphicon glyphicon-' + this.glyphicon
700 // cfg.cls='btn roo-button';
704 var value = cfg.html;
709 cls: 'glyphicon glyphicon-' + this.glyphicon,
728 cfg.cls += ' dropdown';
729 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
732 if (cfg.tag !== 'a' && this.href !== '') {
733 throw "Tag must be a to set href.";
734 } else if (this.href.length > 0) {
735 cfg.href = this.href;
738 if(this.removeClass){
743 cfg.target = this.target;
748 initEvents: function() {
749 // Roo.log('init events?');
750 // Roo.log(this.el.dom);
753 if (typeof (this.menu) != 'undefined') {
754 this.menu.parentType = this.xtype;
755 this.menu.triggerEl = this.el;
756 this.addxtype(Roo.apply({}, this.menu));
760 if (this.el.hasClass('roo-button')) {
761 this.el.on('click', this.onClick, this);
763 this.el.select('.roo-button').on('click', this.onClick, this);
766 if(this.removeClass){
767 this.el.on('click', this.onClick, this);
770 this.el.enableDisplayMode();
773 onClick : function(e)
780 Roo.log('button on click ');
781 if(this.preventDefault){
784 if (this.pressed === true || this.pressed === false) {
785 this.pressed = !this.pressed;
786 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
787 this.fireEvent('toggle', this, e, this.pressed);
791 this.fireEvent('click', this, e);
795 * Enables this button
799 this.disabled = false;
800 this.el.removeClass('disabled');
804 * Disable this button
808 this.disabled = true;
809 this.el.addClass('disabled');
812 * sets the active state on/off,
813 * @param {Boolean} state (optional) Force a particular state
815 setActive : function(v) {
817 this.el[v ? 'addClass' : 'removeClass']('active');
820 * toggles the current active state
822 toggleActive : function()
824 var active = this.el.hasClass('active');
825 this.setActive(!active);
829 setText : function(str)
831 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
835 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
858 * @class Roo.bootstrap.Column
859 * @extends Roo.bootstrap.Component
860 * Bootstrap Column class
861 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
862 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
863 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
864 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
865 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
866 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
867 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
868 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
871 * @cfg {Boolean} hidden (true|false) hide the element
872 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
873 * @cfg {String} fa (ban|check|...) font awesome icon
874 * @cfg {Number} fasize (1|2|....) font awsome size
876 * @cfg {String} icon (info-sign|check|...) glyphicon name
878 * @cfg {String} html content of column.
881 * Create a new Column
882 * @param {Object} config The config object
885 Roo.bootstrap.Column = function(config){
886 Roo.bootstrap.Column.superclass.constructor.call(this, config);
889 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
907 getAutoCreate : function(){
908 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
916 ['xs','sm','md','lg'].map(function(size){
917 //Roo.log( size + ':' + settings[size]);
919 if (settings[size+'off'] !== false) {
920 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
923 if (settings[size] === false) {
926 Roo.log(settings[size]);
927 if (!settings[size]) { // 0 = hidden
928 cfg.cls += ' hidden-' + size;
931 cfg.cls += ' col-' + size + '-' + settings[size];
936 cfg.cls += ' hidden';
939 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
940 cfg.cls +=' alert alert-' + this.alert;
944 if (this.html.length) {
945 cfg.html = this.html;
949 if (this.fasize > 1) {
950 fasize = ' fa-' + this.fasize + 'x';
952 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
957 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
976 * @class Roo.bootstrap.Container
977 * @extends Roo.bootstrap.Component
978 * Bootstrap Container class
979 * @cfg {Boolean} jumbotron is it a jumbotron element
980 * @cfg {String} html content of element
981 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
982 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
983 * @cfg {String} header content of header (for panel)
984 * @cfg {String} footer content of footer (for panel)
985 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
986 * @cfg {String} tag (header|aside|section) type of HTML tag.
987 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
988 * @cfg {String} fa (ban|check|...) font awesome icon
989 * @cfg {String} icon (info-sign|check|...) glyphicon name
990 * @cfg {Boolean} hidden (true|false) hide the element
991 * @cfg {Boolean} expandable (true|false) default false
992 * @cfg {String} rheader contet on the right of header
996 * Create a new Container
997 * @param {Object} config The config object
1000 Roo.bootstrap.Container = function(config){
1001 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1007 * After the panel has been expand
1009 * @param {Roo.bootstrap.Container} this
1014 * After the panel has been collapsed
1016 * @param {Roo.bootstrap.Container} this
1022 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1039 getChildContainer : function() {
1045 if (this.panel.length) {
1046 return this.el.select('.panel-body',true).first();
1053 getAutoCreate : function(){
1056 tag : this.tag || 'div',
1060 if (this.jumbotron) {
1061 cfg.cls = 'jumbotron';
1066 // - this is applied by the parent..
1068 // cfg.cls = this.cls + '';
1071 if (this.sticky.length) {
1073 var bd = Roo.get(document.body);
1074 if (!bd.hasClass('bootstrap-sticky')) {
1075 bd.addClass('bootstrap-sticky');
1076 Roo.select('html',true).setStyle('height', '100%');
1079 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1083 if (this.well.length) {
1084 switch (this.well) {
1087 cfg.cls +=' well well-' +this.well;
1096 cfg.cls += ' hidden';
1100 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1101 cfg.cls +=' alert alert-' + this.alert;
1106 if (this.panel.length) {
1107 cfg.cls += ' panel panel-' + this.panel;
1109 if (this.header.length) {
1113 if(this.expandable){
1115 cfg.cls = cfg.cls + ' expandable';
1126 cls : 'panel-title',
1131 cls: 'panel-header-right',
1137 cls : 'panel-heading',
1150 if (this.footer.length) {
1152 cls : 'panel-footer',
1161 body.html = this.html || cfg.html;
1162 // prefix with the icons..
1164 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1167 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1172 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1173 cfg.cls = 'container';
1179 initEvents: function()
1181 if(!this.expandable){
1185 var headerEl = this.headerEl();
1191 headerEl.on('click', this.onToggleClick, this);
1195 onToggleClick : function()
1197 var headerEl = this.headerEl();
1213 if(this.fireEvent('expand', this)) {
1215 this.expanded = true;
1217 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1219 var toggleEl = this.toggleEl();
1225 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1230 collapse : function()
1232 if(this.fireEvent('collapse', this)) {
1234 this.expanded = false;
1236 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1238 var toggleEl = this.toggleEl();
1244 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1248 toggleEl : function()
1250 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1254 return this.el.select('.panel-heading .fa',true).first();
1257 headerEl : function()
1259 if(!this.el || !this.panel.length || !this.header.length){
1263 return this.el.select('.panel-heading',true).first()
1266 titleEl : function()
1268 if(!this.el || !this.panel.length || !this.header.length){
1272 return this.el.select('.panel-title',true).first();
1275 setTitle : function(v)
1277 var titleEl = this.titleEl();
1283 titleEl.dom.innerHTML = v;
1286 getTitle : function()
1289 var titleEl = this.titleEl();
1295 return titleEl.dom.innerHTML;
1298 setRightTitle : function(v)
1300 var t = this.el.select('.panel-header-right',true).first();
1306 t.dom.innerHTML = v;
1320 * @class Roo.bootstrap.Img
1321 * @extends Roo.bootstrap.Component
1322 * Bootstrap Img class
1323 * @cfg {Boolean} imgResponsive false | true
1324 * @cfg {String} border rounded | circle | thumbnail
1325 * @cfg {String} src image source
1326 * @cfg {String} alt image alternative text
1327 * @cfg {String} href a tag href
1328 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1329 * @cfg {String} xsUrl xs image source
1330 * @cfg {String} smUrl sm image source
1331 * @cfg {String} mdUrl md image source
1332 * @cfg {String} lgUrl lg image source
1335 * Create a new Input
1336 * @param {Object} config The config object
1339 Roo.bootstrap.Img = function(config){
1340 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1346 * The img click event for the img.
1347 * @param {Roo.EventObject} e
1353 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1355 imgResponsive: true,
1365 getAutoCreate : function()
1367 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1368 return this.createSingleImg();
1373 cls: 'roo-image-responsive-group',
1378 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1380 if(!_this[size + 'Url']){
1386 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1387 html: _this.html || cfg.html,
1388 src: _this[size + 'Url']
1391 img.cls += ' roo-image-responsive-' + size;
1393 var s = ['xs', 'sm', 'md', 'lg'];
1395 s.splice(s.indexOf(size), 1);
1397 Roo.each(s, function(ss){
1398 img.cls += ' hidden-' + ss;
1401 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1402 cfg.cls += ' img-' + _this.border;
1406 cfg.alt = _this.alt;
1419 a.target = _this.target;
1423 cfg.cn.push((_this.href) ? a : img);
1430 createSingleImg : function()
1434 cls: (this.imgResponsive) ? 'img-responsive' : '',
1438 cfg.html = this.html || cfg.html;
1440 cfg.src = this.src || cfg.src;
1442 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1443 cfg.cls += ' img-' + this.border;
1460 a.target = this.target;
1465 return (this.href) ? a : cfg;
1468 initEvents: function()
1471 this.el.on('click', this.onClick, this);
1476 onClick : function(e)
1478 Roo.log('img onclick');
1479 this.fireEvent('click', this, e);
1493 * @class Roo.bootstrap.Link
1494 * @extends Roo.bootstrap.Component
1495 * Bootstrap Link Class
1496 * @cfg {String} alt image alternative text
1497 * @cfg {String} href a tag href
1498 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1499 * @cfg {String} html the content of the link.
1500 * @cfg {String} anchor name for the anchor link
1502 * @cfg {Boolean} preventDefault (true | false) default false
1506 * Create a new Input
1507 * @param {Object} config The config object
1510 Roo.bootstrap.Link = function(config){
1511 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1517 * The img click event for the img.
1518 * @param {Roo.EventObject} e
1524 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1528 preventDefault: false,
1532 getAutoCreate : function()
1538 // anchor's do not require html/href...
1539 if (this.anchor === false) {
1540 cfg.html = this.html || '';
1541 cfg.href = this.href || '#';
1543 cfg.name = this.anchor;
1544 if (this.html !== false) {
1545 cfg.html = this.html;
1547 if (this.href !== false) {
1548 cfg.href = this.href;
1552 if(this.alt !== false){
1557 if(this.target !== false) {
1558 cfg.target = this.target;
1564 initEvents: function() {
1566 if(!this.href || this.preventDefault){
1567 this.el.on('click', this.onClick, this);
1571 onClick : function(e)
1573 if(this.preventDefault){
1576 //Roo.log('img onclick');
1577 this.fireEvent('click', this, e);
1590 * @class Roo.bootstrap.Header
1591 * @extends Roo.bootstrap.Component
1592 * Bootstrap Header class
1593 * @cfg {String} html content of header
1594 * @cfg {Number} level (1|2|3|4|5|6) default 1
1597 * Create a new Header
1598 * @param {Object} config The config object
1602 Roo.bootstrap.Header = function(config){
1603 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1606 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1614 getAutoCreate : function(){
1619 tag: 'h' + (1 *this.level),
1620 html: this.html || ''
1632 * Ext JS Library 1.1.1
1633 * Copyright(c) 2006-2007, Ext JS, LLC.
1635 * Originally Released Under LGPL - original licence link has changed is not relivant.
1638 * <script type="text/javascript">
1642 * @class Roo.bootstrap.MenuMgr
1643 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1646 Roo.bootstrap.MenuMgr = function(){
1647 var menus, active, groups = {}, attached = false, lastShow = new Date();
1649 // private - called when first menu is created
1652 active = new Roo.util.MixedCollection();
1653 Roo.get(document).addKeyListener(27, function(){
1654 if(active.length > 0){
1662 if(active && active.length > 0){
1663 var c = active.clone();
1673 if(active.length < 1){
1674 Roo.get(document).un("mouseup", onMouseDown);
1682 var last = active.last();
1683 lastShow = new Date();
1686 Roo.get(document).on("mouseup", onMouseDown);
1691 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1692 m.parentMenu.activeChild = m;
1693 }else if(last && last.isVisible()){
1694 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1699 function onBeforeHide(m){
1701 m.activeChild.hide();
1703 if(m.autoHideTimer){
1704 clearTimeout(m.autoHideTimer);
1705 delete m.autoHideTimer;
1710 function onBeforeShow(m){
1711 var pm = m.parentMenu;
1712 if(!pm && !m.allowOtherMenus){
1714 }else if(pm && pm.activeChild && active != m){
1715 pm.activeChild.hide();
1719 // private this should really trigger on mouseup..
1720 function onMouseDown(e){
1721 Roo.log("on Mouse Up");
1722 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1732 function onBeforeCheck(mi, state){
1734 var g = groups[mi.group];
1735 for(var i = 0, l = g.length; i < l; i++){
1737 g[i].setChecked(false);
1746 * Hides all menus that are currently visible
1748 hideAll : function(){
1753 register : function(menu){
1757 menus[menu.id] = menu;
1758 menu.on("beforehide", onBeforeHide);
1759 menu.on("hide", onHide);
1760 menu.on("beforeshow", onBeforeShow);
1761 menu.on("show", onShow);
1763 if(g && menu.events["checkchange"]){
1767 groups[g].push(menu);
1768 menu.on("checkchange", onCheck);
1773 * Returns a {@link Roo.menu.Menu} object
1774 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1775 * be used to generate and return a new Menu instance.
1777 get : function(menu){
1778 if(typeof menu == "string"){ // menu id
1780 }else if(menu.events){ // menu instance
1783 /*else if(typeof menu.length == 'number'){ // array of menu items?
1784 return new Roo.bootstrap.Menu({items:menu});
1785 }else{ // otherwise, must be a config
1786 return new Roo.bootstrap.Menu(menu);
1793 unregister : function(menu){
1794 delete menus[menu.id];
1795 menu.un("beforehide", onBeforeHide);
1796 menu.un("hide", onHide);
1797 menu.un("beforeshow", onBeforeShow);
1798 menu.un("show", onShow);
1800 if(g && menu.events["checkchange"]){
1801 groups[g].remove(menu);
1802 menu.un("checkchange", onCheck);
1807 registerCheckable : function(menuItem){
1808 var g = menuItem.group;
1813 groups[g].push(menuItem);
1814 menuItem.on("beforecheckchange", onBeforeCheck);
1819 unregisterCheckable : function(menuItem){
1820 var g = menuItem.group;
1822 groups[g].remove(menuItem);
1823 menuItem.un("beforecheckchange", onBeforeCheck);
1835 * @class Roo.bootstrap.Menu
1836 * @extends Roo.bootstrap.Component
1837 * Bootstrap Menu class - container for MenuItems
1838 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1842 * @param {Object} config The config object
1846 Roo.bootstrap.Menu = function(config){
1847 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1848 if (this.registerMenu) {
1849 Roo.bootstrap.MenuMgr.register(this);
1854 * Fires before this menu is displayed
1855 * @param {Roo.menu.Menu} this
1860 * Fires before this menu is hidden
1861 * @param {Roo.menu.Menu} this
1866 * Fires after this menu is displayed
1867 * @param {Roo.menu.Menu} this
1872 * Fires after this menu is hidden
1873 * @param {Roo.menu.Menu} this
1878 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1879 * @param {Roo.menu.Menu} this
1880 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1881 * @param {Roo.EventObject} e
1886 * Fires when the mouse is hovering over this menu
1887 * @param {Roo.menu.Menu} this
1888 * @param {Roo.EventObject} e
1889 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1894 * Fires when the mouse exits this menu
1895 * @param {Roo.menu.Menu} this
1896 * @param {Roo.EventObject} e
1897 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1902 * Fires when a menu item contained in this menu is clicked
1903 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1904 * @param {Roo.EventObject} e
1908 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1911 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1915 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1918 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1920 registerMenu : true,
1922 menuItems :false, // stores the menu items..
1928 getChildContainer : function() {
1932 getAutoCreate : function(){
1934 //if (['right'].indexOf(this.align)!==-1) {
1935 // cfg.cn[1].cls += ' pull-right'
1941 cls : 'dropdown-menu' ,
1942 style : 'z-index:1000'
1946 if (this.type === 'submenu') {
1947 cfg.cls = 'submenu active';
1949 if (this.type === 'treeview') {
1950 cfg.cls = 'treeview-menu';
1955 initEvents : function() {
1957 // Roo.log("ADD event");
1958 // Roo.log(this.triggerEl.dom);
1959 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1961 this.triggerEl.addClass('dropdown-toggle');
1962 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1964 this.el.on("mouseover", this.onMouseOver, this);
1965 this.el.on("mouseout", this.onMouseOut, this);
1969 findTargetItem : function(e){
1970 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1974 //Roo.log(t); Roo.log(t.id);
1976 //Roo.log(this.menuitems);
1977 return this.menuitems.get(t.id);
1979 //return this.items.get(t.menuItemId);
1984 onClick : function(e){
1985 Roo.log("menu.onClick");
1986 var t = this.findTargetItem(e);
1987 if(!t || t.isContainer){
1992 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1993 if(t == this.activeItem && t.shouldDeactivate(e)){
1994 this.activeItem.deactivate();
1995 delete this.activeItem;
1999 this.setActiveItem(t, true);
2007 Roo.log('pass click event');
2011 this.fireEvent("click", this, t, e);
2015 onMouseOver : function(e){
2016 var t = this.findTargetItem(e);
2019 // if(t.canActivate && !t.disabled){
2020 // this.setActiveItem(t, true);
2024 this.fireEvent("mouseover", this, e, t);
2026 isVisible : function(){
2027 return !this.hidden;
2029 onMouseOut : function(e){
2030 var t = this.findTargetItem(e);
2033 // if(t == this.activeItem && t.shouldDeactivate(e)){
2034 // this.activeItem.deactivate();
2035 // delete this.activeItem;
2038 this.fireEvent("mouseout", this, e, t);
2043 * Displays this menu relative to another element
2044 * @param {String/HTMLElement/Roo.Element} element The element to align to
2045 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2046 * the element (defaults to this.defaultAlign)
2047 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2049 show : function(el, pos, parentMenu){
2050 this.parentMenu = parentMenu;
2054 this.fireEvent("beforeshow", this);
2055 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2058 * Displays this menu at a specific xy position
2059 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2060 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2062 showAt : function(xy, parentMenu, /* private: */_e){
2063 this.parentMenu = parentMenu;
2068 this.fireEvent("beforeshow", this);
2069 //xy = this.el.adjustForConstraints(xy);
2073 this.hideMenuItems();
2074 this.hidden = false;
2075 this.triggerEl.addClass('open');
2077 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2078 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2083 this.fireEvent("show", this);
2089 this.doFocus.defer(50, this);
2093 doFocus : function(){
2095 this.focusEl.focus();
2100 * Hides this menu and optionally all parent menus
2101 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2103 hide : function(deep){
2105 this.hideMenuItems();
2106 if(this.el && this.isVisible()){
2107 this.fireEvent("beforehide", this);
2108 if(this.activeItem){
2109 this.activeItem.deactivate();
2110 this.activeItem = null;
2112 this.triggerEl.removeClass('open');;
2114 this.fireEvent("hide", this);
2116 if(deep === true && this.parentMenu){
2117 this.parentMenu.hide(true);
2121 onTriggerPress : function(e)
2124 Roo.log('trigger press');
2125 //Roo.log(e.getTarget());
2126 // Roo.log(this.triggerEl.dom);
2127 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2131 if (this.isVisible()) {
2136 this.show(this.triggerEl, false, false);
2145 hideMenuItems : function()
2147 //$(backdrop).remove()
2148 Roo.select('.open',true).each(function(aa) {
2150 aa.removeClass('open');
2151 //var parent = getParent($(this))
2152 //var relatedTarget = { relatedTarget: this }
2154 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2155 //if (e.isDefaultPrevented()) return
2156 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2159 addxtypeChild : function (tree, cntr) {
2160 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2162 this.menuitems.add(comp);
2183 * @class Roo.bootstrap.MenuItem
2184 * @extends Roo.bootstrap.Component
2185 * Bootstrap MenuItem class
2186 * @cfg {String} html the menu label
2187 * @cfg {String} href the link
2188 * @cfg {Boolean} preventDefault (true | false) default true
2189 * @cfg {Boolean} isContainer (true | false) default false
2193 * Create a new MenuItem
2194 * @param {Object} config The config object
2198 Roo.bootstrap.MenuItem = function(config){
2199 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2204 * The raw click event for the entire grid.
2205 * @param {Roo.bootstrap.MenuItem} this
2206 * @param {Roo.EventObject} e
2212 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2216 preventDefault: true,
2217 isContainer : false,
2219 getAutoCreate : function(){
2221 if(this.isContainer){
2224 cls: 'dropdown-menu-item'
2230 cls: 'dropdown-menu-item',
2239 if (this.parent().type == 'treeview') {
2240 cfg.cls = 'treeview-menu';
2243 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2244 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2248 initEvents: function() {
2250 //this.el.select('a').on('click', this.onClick, this);
2253 onClick : function(e)
2255 Roo.log('item on click ');
2256 //if(this.preventDefault){
2257 // e.preventDefault();
2259 //this.parent().hideMenuItems();
2261 this.fireEvent('click', this, e);
2280 * @class Roo.bootstrap.MenuSeparator
2281 * @extends Roo.bootstrap.Component
2282 * Bootstrap MenuSeparator class
2285 * Create a new MenuItem
2286 * @param {Object} config The config object
2290 Roo.bootstrap.MenuSeparator = function(config){
2291 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2294 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2296 getAutoCreate : function(){
2315 * @class Roo.bootstrap.Modal
2316 * @extends Roo.bootstrap.Component
2317 * Bootstrap Modal class
2318 * @cfg {String} title Title of dialog
2319 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2320 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2321 * @cfg {Boolean} specificTitle default false
2322 * @cfg {Array} buttons Array of buttons or standard button set..
2323 * @cfg {String} buttonPosition (left|right|center) default right
2324 * @cfg {Boolean} animate default true
2325 * @cfg {Boolean} allow_close default true
2328 * Create a new Modal Dialog
2329 * @param {Object} config The config object
2332 Roo.bootstrap.Modal = function(config){
2333 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2338 * The raw btnclick event for the button
2339 * @param {Roo.EventObject} e
2343 this.buttons = this.buttons || [];
2346 this.tmpl = Roo.factory(this.tmpl);
2351 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2353 title : 'test dialog',
2363 specificTitle: false,
2365 buttonPosition: 'right',
2379 onRender : function(ct, position)
2381 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2384 var cfg = Roo.apply({}, this.getAutoCreate());
2387 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2389 //if (!cfg.name.length) {
2393 cfg.cls += ' ' + this.cls;
2396 cfg.style = this.style;
2398 this.el = Roo.get(document.body).createChild(cfg, position);
2400 //var type = this.el.dom.type;
2405 if(this.tabIndex !== undefined){
2406 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2410 this.bodyEl = this.el.select('.modal-body',true).first();
2411 this.closeEl = this.el.select('.modal-header .close', true).first();
2412 this.footerEl = this.el.select('.modal-footer',true).first();
2413 this.titleEl = this.el.select('.modal-title',true).first();
2417 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2418 this.maskEl.enableDisplayMode("block");
2420 //this.el.addClass("x-dlg-modal");
2422 if (this.buttons.length) {
2423 Roo.each(this.buttons, function(bb) {
2424 b = Roo.apply({}, bb);
2425 b.xns = b.xns || Roo.bootstrap;
2426 b.xtype = b.xtype || 'Button';
2427 if (typeof(b.listeners) == 'undefined') {
2428 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2431 var btn = Roo.factory(b);
2433 btn.onRender(this.el.select('.modal-footer div').first());
2437 // render the children.
2440 if(typeof(this.items) != 'undefined'){
2441 var items = this.items;
2444 for(var i =0;i < items.length;i++) {
2445 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2449 this.items = nitems;
2451 // where are these used - they used to be body/close/footer
2455 //this.el.addClass([this.fieldClass, this.cls]);
2458 getAutoCreate : function(){
2463 html : this.html || ''
2468 cls : 'modal-title',
2472 if(this.specificTitle){
2478 if (this.allow_close) {
2489 style : 'display: none',
2492 cls: "modal-dialog",
2495 cls : "modal-content",
2498 cls : 'modal-header',
2503 cls : 'modal-footer',
2507 cls: 'btn-' + this.buttonPosition
2524 modal.cls += ' fade';
2530 getChildContainer : function() {
2535 getButtonContainer : function() {
2536 return this.el.select('.modal-footer div',true).first();
2539 initEvents : function()
2541 if (this.allow_close) {
2542 this.closeEl.on('click', this.hide, this);
2548 if (!this.rendered) {
2552 this.el.setStyle('display', 'block');
2556 (function(){ _this.el.addClass('in'); }).defer(50);
2558 this.el.addClass('in');
2561 // not sure how we can show data in here..
2563 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2566 Roo.get(document.body).addClass("x-body-masked");
2567 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2569 this.el.setStyle('zIndex', '10001');
2571 this.fireEvent('show', this);
2578 Roo.get(document.body).removeClass("x-body-masked");
2579 this.el.removeClass('in');
2583 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2585 this.el.setStyle('display', 'none');
2588 this.fireEvent('hide', this);
2591 addButton : function(str, cb)
2595 var b = Roo.apply({}, { html : str } );
2596 b.xns = b.xns || Roo.bootstrap;
2597 b.xtype = b.xtype || 'Button';
2598 if (typeof(b.listeners) == 'undefined') {
2599 b.listeners = { click : cb.createDelegate(this) };
2602 var btn = Roo.factory(b);
2604 btn.onRender(this.el.select('.modal-footer div').first());
2610 setDefaultButton : function(btn)
2612 //this.el.select('.modal-footer').()
2614 resizeTo: function(w,h)
2618 setContentSize : function(w, h)
2622 onButtonClick: function(btn,e)
2625 this.fireEvent('btnclick', btn.name, e);
2628 * Set the title of the Dialog
2629 * @param {String} str new Title
2631 setTitle: function(str) {
2632 this.titleEl.dom.innerHTML = str;
2635 * Set the body of the Dialog
2636 * @param {String} str new Title
2638 setBody: function(str) {
2639 this.bodyEl.dom.innerHTML = str;
2642 * Set the body of the Dialog using the template
2643 * @param {Obj} data - apply this data to the template and replace the body contents.
2645 applyBody: function(obj)
2648 Roo.log("Error - using apply Body without a template");
2651 this.tmpl.overwrite(this.bodyEl, obj);
2657 Roo.apply(Roo.bootstrap.Modal, {
2659 * Button config that displays a single OK button
2668 * Button config that displays Yes and No buttons
2684 * Button config that displays OK and Cancel buttons
2699 * Button config that displays Yes, No and Cancel buttons
2722 * messagebox - can be used as a replace
2726 * @class Roo.MessageBox
2727 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2731 Roo.Msg.alert('Status', 'Changes saved successfully.');
2733 // Prompt for user data:
2734 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2736 // process text value...
2740 // Show a dialog using config options:
2742 title:'Save Changes?',
2743 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2744 buttons: Roo.Msg.YESNOCANCEL,
2751 Roo.bootstrap.MessageBox = function(){
2752 var dlg, opt, mask, waitTimer;
2753 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2754 var buttons, activeTextEl, bwidth;
2758 var handleButton = function(button){
2760 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2764 var handleHide = function(){
2766 dlg.el.removeClass(opt.cls);
2769 // Roo.TaskMgr.stop(waitTimer);
2770 // waitTimer = null;
2775 var updateButtons = function(b){
2778 buttons["ok"].hide();
2779 buttons["cancel"].hide();
2780 buttons["yes"].hide();
2781 buttons["no"].hide();
2782 //dlg.footer.dom.style.display = 'none';
2785 dlg.footerEl.dom.style.display = '';
2786 for(var k in buttons){
2787 if(typeof buttons[k] != "function"){
2790 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2791 width += buttons[k].el.getWidth()+15;
2801 var handleEsc = function(d, k, e){
2802 if(opt && opt.closable !== false){
2812 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2813 * @return {Roo.BasicDialog} The BasicDialog element
2815 getDialog : function(){
2817 dlg = new Roo.bootstrap.Modal( {
2820 //constraintoviewport:false,
2822 //collapsible : false,
2827 //buttonAlign:"center",
2828 closeClick : function(){
2829 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2832 handleButton("cancel");
2837 dlg.on("hide", handleHide);
2839 //dlg.addKeyListener(27, handleEsc);
2841 this.buttons = buttons;
2842 var bt = this.buttonText;
2843 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2844 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2845 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2846 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2848 bodyEl = dlg.bodyEl.createChild({
2850 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2851 '<textarea class="roo-mb-textarea"></textarea>' +
2852 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2854 msgEl = bodyEl.dom.firstChild;
2855 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2856 textboxEl.enableDisplayMode();
2857 textboxEl.addKeyListener([10,13], function(){
2858 if(dlg.isVisible() && opt && opt.buttons){
2861 }else if(opt.buttons.yes){
2862 handleButton("yes");
2866 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2867 textareaEl.enableDisplayMode();
2868 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2869 progressEl.enableDisplayMode();
2870 var pf = progressEl.dom.firstChild;
2872 pp = Roo.get(pf.firstChild);
2873 pp.setHeight(pf.offsetHeight);
2881 * Updates the message box body text
2882 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2883 * the XHTML-compliant non-breaking space character '&#160;')
2884 * @return {Roo.MessageBox} This message box
2886 updateText : function(text){
2887 if(!dlg.isVisible() && !opt.width){
2888 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2890 msgEl.innerHTML = text || ' ';
2892 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2893 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2895 Math.min(opt.width || cw , this.maxWidth),
2896 Math.max(opt.minWidth || this.minWidth, bwidth)
2899 activeTextEl.setWidth(w);
2901 if(dlg.isVisible()){
2902 dlg.fixedcenter = false;
2904 // to big, make it scroll. = But as usual stupid IE does not support
2907 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2908 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2909 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2911 bodyEl.dom.style.height = '';
2912 bodyEl.dom.style.overflowY = '';
2915 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2917 bodyEl.dom.style.overflowX = '';
2920 dlg.setContentSize(w, bodyEl.getHeight());
2921 if(dlg.isVisible()){
2922 dlg.fixedcenter = true;
2928 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2929 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2930 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2931 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2932 * @return {Roo.MessageBox} This message box
2934 updateProgress : function(value, text){
2936 this.updateText(text);
2938 if (pp) { // weird bug on my firefox - for some reason this is not defined
2939 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2945 * Returns true if the message box is currently displayed
2946 * @return {Boolean} True if the message box is visible, else false
2948 isVisible : function(){
2949 return dlg && dlg.isVisible();
2953 * Hides the message box if it is displayed
2956 if(this.isVisible()){
2962 * Displays a new message box, or reinitializes an existing message box, based on the config options
2963 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2964 * The following config object properties are supported:
2966 Property Type Description
2967 ---------- --------------- ------------------------------------------------------------------------------------
2968 animEl String/Element An id or Element from which the message box should animate as it opens and
2969 closes (defaults to undefined)
2970 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2971 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2972 closable Boolean False to hide the top-right close button (defaults to true). Note that
2973 progress and wait dialogs will ignore this property and always hide the
2974 close button as they can only be closed programmatically.
2975 cls String A custom CSS class to apply to the message box element
2976 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2977 displayed (defaults to 75)
2978 fn Function A callback function to execute after closing the dialog. The arguments to the
2979 function will be btn (the name of the button that was clicked, if applicable,
2980 e.g. "ok"), and text (the value of the active text field, if applicable).
2981 Progress and wait dialogs will ignore this option since they do not respond to
2982 user actions and can only be closed programmatically, so any required function
2983 should be called by the same code after it closes the dialog.
2984 icon String A CSS class that provides a background image to be used as an icon for
2985 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2986 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2987 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2988 modal Boolean False to allow user interaction with the page while the message box is
2989 displayed (defaults to true)
2990 msg String A string that will replace the existing message box body text (defaults
2991 to the XHTML-compliant non-breaking space character ' ')
2992 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2993 progress Boolean True to display a progress bar (defaults to false)
2994 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2995 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2996 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2997 title String The title text
2998 value String The string value to set into the active textbox element if displayed
2999 wait Boolean True to display a progress bar (defaults to false)
3000 width Number The width of the dialog in pixels
3007 msg: 'Please enter your address:',
3009 buttons: Roo.MessageBox.OKCANCEL,
3012 animEl: 'addAddressBtn'
3015 * @param {Object} config Configuration options
3016 * @return {Roo.MessageBox} This message box
3018 show : function(options)
3021 // this causes nightmares if you show one dialog after another
3022 // especially on callbacks..
3024 if(this.isVisible()){
3027 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3028 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3029 Roo.log("New Dialog Message:" + options.msg )
3030 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3031 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3034 var d = this.getDialog();
3036 d.setTitle(opt.title || " ");
3037 d.closeEl.setDisplayed(opt.closable !== false);
3038 activeTextEl = textboxEl;
3039 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3044 textareaEl.setHeight(typeof opt.multiline == "number" ?
3045 opt.multiline : this.defaultTextHeight);
3046 activeTextEl = textareaEl;
3055 progressEl.setDisplayed(opt.progress === true);
3056 this.updateProgress(0);
3057 activeTextEl.dom.value = opt.value || "";
3059 dlg.setDefaultButton(activeTextEl);
3061 var bs = opt.buttons;
3065 }else if(bs && bs.yes){
3066 db = buttons["yes"];
3068 dlg.setDefaultButton(db);
3070 bwidth = updateButtons(opt.buttons);
3071 this.updateText(opt.msg);
3073 d.el.addClass(opt.cls);
3075 d.proxyDrag = opt.proxyDrag === true;
3076 d.modal = opt.modal !== false;
3077 d.mask = opt.modal !== false ? mask : false;
3079 // force it to the end of the z-index stack so it gets a cursor in FF
3080 document.body.appendChild(dlg.el.dom);
3081 d.animateTarget = null;
3082 d.show(options.animEl);
3088 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3089 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3090 * and closing the message box when the process is complete.
3091 * @param {String} title The title bar text
3092 * @param {String} msg The message box body text
3093 * @return {Roo.MessageBox} This message box
3095 progress : function(title, msg){
3102 minWidth: this.minProgressWidth,
3109 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3110 * If a callback function is passed it will be called after the user clicks the button, and the
3111 * id of the button that was clicked will be passed as the only parameter to the callback
3112 * (could also be the top-right close button).
3113 * @param {String} title The title bar text
3114 * @param {String} msg The message box body text
3115 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3116 * @param {Object} scope (optional) The scope of the callback function
3117 * @return {Roo.MessageBox} This message box
3119 alert : function(title, msg, fn, scope){
3132 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3133 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3134 * You are responsible for closing the message box when the process is complete.
3135 * @param {String} msg The message box body text
3136 * @param {String} title (optional) The title bar text
3137 * @return {Roo.MessageBox} This message box
3139 wait : function(msg, title){
3150 waitTimer = Roo.TaskMgr.start({
3152 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3160 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3161 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3162 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3163 * @param {String} title The title bar text
3164 * @param {String} msg The message box body text
3165 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3166 * @param {Object} scope (optional) The scope of the callback function
3167 * @return {Roo.MessageBox} This message box
3169 confirm : function(title, msg, fn, scope){
3173 buttons: this.YESNO,
3182 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3183 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3184 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3185 * (could also be the top-right close button) and the text that was entered will be passed as the two
3186 * parameters to the callback.
3187 * @param {String} title The title bar text
3188 * @param {String} msg The message box body text
3189 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3190 * @param {Object} scope (optional) The scope of the callback function
3191 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3192 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3193 * @return {Roo.MessageBox} This message box
3195 prompt : function(title, msg, fn, scope, multiline){
3199 buttons: this.OKCANCEL,
3204 multiline: multiline,
3211 * Button config that displays a single OK button
3216 * Button config that displays Yes and No buttons
3219 YESNO : {yes:true, no:true},
3221 * Button config that displays OK and Cancel buttons
3224 OKCANCEL : {ok:true, cancel:true},
3226 * Button config that displays Yes, No and Cancel buttons
3229 YESNOCANCEL : {yes:true, no:true, cancel:true},
3232 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3235 defaultTextHeight : 75,
3237 * The maximum width in pixels of the message box (defaults to 600)
3242 * The minimum width in pixels of the message box (defaults to 100)
3247 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3248 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3251 minProgressWidth : 250,
3253 * An object containing the default button text strings that can be overriden for localized language support.
3254 * Supported properties are: ok, cancel, yes and no.
3255 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3268 * Shorthand for {@link Roo.MessageBox}
3270 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3271 Roo.Msg = Roo.Msg || Roo.MessageBox;
3280 * @class Roo.bootstrap.Navbar
3281 * @extends Roo.bootstrap.Component
3282 * Bootstrap Navbar class
3285 * Create a new Navbar
3286 * @param {Object} config The config object
3290 Roo.bootstrap.Navbar = function(config){
3291 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3295 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3304 getAutoCreate : function(){
3307 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3311 initEvents :function ()
3313 //Roo.log(this.el.select('.navbar-toggle',true));
3314 this.el.select('.navbar-toggle',true).on('click', function() {
3315 // Roo.log('click');
3316 this.el.select('.navbar-collapse',true).toggleClass('in');
3324 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3326 var size = this.el.getSize();
3327 this.maskEl.setSize(size.width, size.height);
3328 this.maskEl.enableDisplayMode("block");
3337 getChildContainer : function()
3339 if (this.el.select('.collapse').getCount()) {
3340 return this.el.select('.collapse',true).first();
3373 * @class Roo.bootstrap.NavSimplebar
3374 * @extends Roo.bootstrap.Navbar
3375 * Bootstrap Sidebar class
3377 * @cfg {Boolean} inverse is inverted color
3379 * @cfg {String} type (nav | pills | tabs)
3380 * @cfg {Boolean} arrangement stacked | justified
3381 * @cfg {String} align (left | right) alignment
3383 * @cfg {Boolean} main (true|false) main nav bar? default false
3384 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3386 * @cfg {String} tag (header|footer|nav|div) default is nav
3392 * Create a new Sidebar
3393 * @param {Object} config The config object
3397 Roo.bootstrap.NavSimplebar = function(config){
3398 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3401 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3417 getAutoCreate : function(){
3421 tag : this.tag || 'div',
3434 this.type = this.type || 'nav';
3435 if (['tabs','pills'].indexOf(this.type)!==-1) {
3436 cfg.cn[0].cls += ' nav-' + this.type
3440 if (this.type!=='nav') {
3441 Roo.log('nav type must be nav/tabs/pills')
3443 cfg.cn[0].cls += ' navbar-nav'
3449 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3450 cfg.cn[0].cls += ' nav-' + this.arrangement;
3454 if (this.align === 'right') {
3455 cfg.cn[0].cls += ' navbar-right';
3459 cfg.cls += ' navbar-inverse';
3486 * @class Roo.bootstrap.NavHeaderbar
3487 * @extends Roo.bootstrap.NavSimplebar
3488 * Bootstrap Sidebar class
3490 * @cfg {String} brand what is brand
3491 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3492 * @cfg {String} brand_href href of the brand
3493 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3494 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3495 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3496 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3499 * Create a new Sidebar
3500 * @param {Object} config The config object
3504 Roo.bootstrap.NavHeaderbar = function(config){
3505 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3509 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3516 desktopCenter : false,
3519 getAutoCreate : function(){
3522 tag: this.nav || 'nav',
3529 if (this.desktopCenter) {
3530 cn.push({cls : 'container', cn : []});
3537 cls: 'navbar-header',
3542 cls: 'navbar-toggle',
3543 'data-toggle': 'collapse',
3548 html: 'Toggle navigation'
3570 cls: 'collapse navbar-collapse',
3574 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3576 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3577 cfg.cls += ' navbar-' + this.position;
3579 // tag can override this..
3581 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3584 if (this.brand !== '') {
3587 href: this.brand_href ? this.brand_href : '#',
3588 cls: 'navbar-brand',
3596 cfg.cls += ' main-nav';
3604 getHeaderChildContainer : function()
3606 if (this.el.select('.navbar-header').getCount()) {
3607 return this.el.select('.navbar-header',true).first();
3610 return this.getChildContainer();
3614 initEvents : function()
3616 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3618 if (this.autohide) {
3623 Roo.get(document).on('scroll',function(e) {
3624 var ns = Roo.get(document).getScroll().top;
3625 var os = prevScroll;
3629 ft.removeClass('slideDown');
3630 ft.addClass('slideUp');
3633 ft.removeClass('slideUp');
3634 ft.addClass('slideDown');
3655 * @class Roo.bootstrap.NavSidebar
3656 * @extends Roo.bootstrap.Navbar
3657 * Bootstrap Sidebar class
3660 * Create a new Sidebar
3661 * @param {Object} config The config object
3665 Roo.bootstrap.NavSidebar = function(config){
3666 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3669 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3671 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3673 getAutoCreate : function(){
3678 cls: 'sidebar sidebar-nav'
3700 * @class Roo.bootstrap.NavGroup
3701 * @extends Roo.bootstrap.Component
3702 * Bootstrap NavGroup class
3703 * @cfg {String} align (left|right)
3704 * @cfg {Boolean} inverse
3705 * @cfg {String} type (nav|pills|tab) default nav
3706 * @cfg {String} navId - reference Id for navbar.
3710 * Create a new nav group
3711 * @param {Object} config The config object
3714 Roo.bootstrap.NavGroup = function(config){
3715 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3718 Roo.bootstrap.NavGroup.register(this);
3722 * Fires when the active item changes
3723 * @param {Roo.bootstrap.NavGroup} this
3724 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3725 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3732 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3743 getAutoCreate : function()
3745 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3752 if (['tabs','pills'].indexOf(this.type)!==-1) {
3753 cfg.cls += ' nav-' + this.type
3755 if (this.type!=='nav') {
3756 Roo.log('nav type must be nav/tabs/pills')
3758 cfg.cls += ' navbar-nav'
3761 if (this.parent().sidebar) {
3764 cls: 'dashboard-menu sidebar-menu'
3770 if (this.form === true) {
3776 if (this.align === 'right') {
3777 cfg.cls += ' navbar-right';
3779 cfg.cls += ' navbar-left';
3783 if (this.align === 'right') {
3784 cfg.cls += ' navbar-right';
3788 cfg.cls += ' navbar-inverse';
3796 * sets the active Navigation item
3797 * @param {Roo.bootstrap.NavItem} the new current navitem
3799 setActiveItem : function(item)
3802 Roo.each(this.navItems, function(v){
3807 v.setActive(false, true);
3814 item.setActive(true, true);
3815 this.fireEvent('changed', this, item, prev);
3820 * gets the active Navigation item
3821 * @return {Roo.bootstrap.NavItem} the current navitem
3823 getActive : function()
3827 Roo.each(this.navItems, function(v){
3838 indexOfNav : function()
3842 Roo.each(this.navItems, function(v,i){
3853 * adds a Navigation item
3854 * @param {Roo.bootstrap.NavItem} the navitem to add
3856 addItem : function(cfg)
3858 var cn = new Roo.bootstrap.NavItem(cfg);
3860 cn.parentId = this.id;
3861 cn.onRender(this.el, null);
3865 * register a Navigation item
3866 * @param {Roo.bootstrap.NavItem} the navitem to add
3868 register : function(item)
3870 this.navItems.push( item);
3871 item.navId = this.navId;
3876 * clear all the Navigation item
3879 clearAll : function()
3882 this.el.dom.innerHTML = '';
3885 getNavItem: function(tabId)
3888 Roo.each(this.navItems, function(e) {
3889 if (e.tabId == tabId) {
3899 setActiveNext : function()
3901 var i = this.indexOfNav(this.getActive());
3902 if (i > this.navItems.length) {
3905 this.setActiveItem(this.navItems[i+1]);
3907 setActivePrev : function()
3909 var i = this.indexOfNav(this.getActive());
3913 this.setActiveItem(this.navItems[i-1]);
3915 clearWasActive : function(except) {
3916 Roo.each(this.navItems, function(e) {
3917 if (e.tabId != except.tabId && e.was_active) {
3918 e.was_active = false;
3925 getWasActive : function ()
3928 Roo.each(this.navItems, function(e) {
3943 Roo.apply(Roo.bootstrap.NavGroup, {
3947 * register a Navigation Group
3948 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3950 register : function(navgrp)
3952 this.groups[navgrp.navId] = navgrp;
3956 * fetch a Navigation Group based on the navigation ID
3957 * @param {string} the navgroup to add
3958 * @returns {Roo.bootstrap.NavGroup} the navgroup
3960 get: function(navId) {
3961 if (typeof(this.groups[navId]) == 'undefined') {
3963 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3965 return this.groups[navId] ;
3980 * @class Roo.bootstrap.NavItem
3981 * @extends Roo.bootstrap.Component
3982 * Bootstrap Navbar.NavItem class
3983 * @cfg {String} href link to
3984 * @cfg {String} html content of button
3985 * @cfg {String} badge text inside badge
3986 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3987 * @cfg {String} glyphicon name of glyphicon
3988 * @cfg {String} icon name of font awesome icon
3989 * @cfg {Boolean} active Is item active
3990 * @cfg {Boolean} disabled Is item disabled
3992 * @cfg {Boolean} preventDefault (true | false) default false
3993 * @cfg {String} tabId the tab that this item activates.
3994 * @cfg {String} tagtype (a|span) render as a href or span?
3995 * @cfg {Boolean} animateRef (true|false) link to element default false
3998 * Create a new Navbar Item
3999 * @param {Object} config The config object
4001 Roo.bootstrap.NavItem = function(config){
4002 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4007 * The raw click event for the entire grid.
4008 * @param {Roo.EventObject} e
4013 * Fires when the active item active state changes
4014 * @param {Roo.bootstrap.NavItem} this
4015 * @param {boolean} state the new state
4021 * Fires when scroll to element
4022 * @param {Roo.bootstrap.NavItem} this
4023 * @param {Object} options
4024 * @param {Roo.EventObject} e
4032 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4040 preventDefault : false,
4047 getAutoCreate : function(){
4055 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4057 if (this.disabled) {
4058 cfg.cls += ' disabled';
4061 if (this.href || this.html || this.glyphicon || this.icon) {
4065 href : this.href || "#",
4066 html: this.html || ''
4071 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4074 if(this.glyphicon) {
4075 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4080 cfg.cn[0].html += " <span class='caret'></span>";
4084 if (this.badge !== '') {
4086 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4094 initEvents: function()
4096 if (typeof (this.menu) != 'undefined') {
4097 this.menu.parentType = this.xtype;
4098 this.menu.triggerEl = this.el;
4099 this.menu = this.addxtype(Roo.apply({}, this.menu));
4102 this.el.select('a',true).on('click', this.onClick, this);
4104 if(this.tagtype == 'span'){
4105 this.el.select('span',true).on('click', this.onClick, this);
4108 // at this point parent should be available..
4109 this.parent().register(this);
4112 onClick : function(e)
4115 this.preventDefault ||
4122 if (this.disabled) {
4126 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4127 if (tg && tg.transition) {
4128 Roo.log("waiting for the transitionend");
4134 //Roo.log("fire event clicked");
4135 if(this.fireEvent('click', this, e) === false){
4139 if(this.tagtype == 'span'){
4143 //Roo.log(this.href);
4144 var ael = this.el.select('a',true).first();
4147 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4148 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4149 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4150 return; // ignore... - it's a 'hash' to another page.
4154 this.scrollToElement(e);
4158 var p = this.parent();
4160 if (['tabs','pills'].indexOf(p.type)!==-1) {
4161 if (typeof(p.setActiveItem) !== 'undefined') {
4162 p.setActiveItem(this);
4166 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4167 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4168 // remove the collapsed menu expand...
4169 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4173 isActive: function () {
4176 setActive : function(state, fire, is_was_active)
4178 if (this.active && !state & this.navId) {
4179 this.was_active = true;
4180 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4182 nv.clearWasActive(this);
4186 this.active = state;
4189 this.el.removeClass('active');
4190 } else if (!this.el.hasClass('active')) {
4191 this.el.addClass('active');
4194 this.fireEvent('changed', this, state);
4197 // show a panel if it's registered and related..
4199 if (!this.navId || !this.tabId || !state || is_was_active) {
4203 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4207 var pan = tg.getPanelByName(this.tabId);
4211 // if we can not flip to new panel - go back to old nav highlight..
4212 if (false == tg.showPanel(pan)) {
4213 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4215 var onav = nv.getWasActive();
4217 onav.setActive(true, false, true);
4226 // this should not be here...
4227 setDisabled : function(state)
4229 this.disabled = state;
4231 this.el.removeClass('disabled');
4232 } else if (!this.el.hasClass('disabled')) {
4233 this.el.addClass('disabled');
4239 * Fetch the element to display the tooltip on.
4240 * @return {Roo.Element} defaults to this.el
4242 tooltipEl : function()
4244 return this.el.select('' + this.tagtype + '', true).first();
4247 scrollToElement : function(e)
4249 var c = document.body;
4252 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4254 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4255 c = document.documentElement;
4258 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4264 var o = target.calcOffsetsTo(c);
4271 this.fireEvent('scrollto', this, options, e);
4273 Roo.get(c).scrollTo('top', options.value, true);
4286 * <span> icon </span>
4287 * <span> text </span>
4288 * <span>badge </span>
4292 * @class Roo.bootstrap.NavSidebarItem
4293 * @extends Roo.bootstrap.NavItem
4294 * Bootstrap Navbar.NavSidebarItem class
4296 * Create a new Navbar Button
4297 * @param {Object} config The config object
4299 Roo.bootstrap.NavSidebarItem = function(config){
4300 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4305 * The raw click event for the entire grid.
4306 * @param {Roo.EventObject} e
4311 * Fires when the active item active state changes
4312 * @param {Roo.bootstrap.NavSidebarItem} this
4313 * @param {boolean} state the new state
4321 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4324 getAutoCreate : function(){
4329 href : this.href || '#',
4341 html : this.html || ''
4346 cfg.cls += ' active';
4350 if (this.glyphicon || this.icon) {
4351 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4352 a.cn.push({ tag : 'i', cls : c }) ;
4357 if (this.badge !== '') {
4358 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4362 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4363 a.cls += 'dropdown-toggle treeview' ;
4387 * @class Roo.bootstrap.Row
4388 * @extends Roo.bootstrap.Component
4389 * Bootstrap Row class (contains columns...)
4393 * @param {Object} config The config object
4396 Roo.bootstrap.Row = function(config){
4397 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4400 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4402 getAutoCreate : function(){
4421 * @class Roo.bootstrap.Element
4422 * @extends Roo.bootstrap.Component
4423 * Bootstrap Element class
4424 * @cfg {String} html contents of the element
4425 * @cfg {String} tag tag of the element
4426 * @cfg {String} cls class of the element
4427 * @cfg {Boolean} preventDefault (true|false) default false
4428 * @cfg {Boolean} clickable (true|false) default false
4431 * Create a new Element
4432 * @param {Object} config The config object
4435 Roo.bootstrap.Element = function(config){
4436 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4442 * When a element is chick
4443 * @param {Roo.bootstrap.Element} this
4444 * @param {Roo.EventObject} e
4450 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4455 preventDefault: false,
4458 getAutoCreate : function(){
4469 initEvents: function()
4471 Roo.bootstrap.Element.superclass.initEvents.call(this);
4474 this.el.on('click', this.onClick, this);
4479 onClick : function(e)
4481 if(this.preventDefault){
4485 this.fireEvent('click', this, e);
4488 getValue : function()
4490 return this.el.dom.innerHTML;
4493 setValue : function(value)
4495 this.el.dom.innerHTML = value;
4510 * @class Roo.bootstrap.Pagination
4511 * @extends Roo.bootstrap.Component
4512 * Bootstrap Pagination class
4513 * @cfg {String} size xs | sm | md | lg
4514 * @cfg {Boolean} inverse false | true
4517 * Create a new Pagination
4518 * @param {Object} config The config object
4521 Roo.bootstrap.Pagination = function(config){
4522 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4525 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4531 getAutoCreate : function(){
4537 cfg.cls += ' inverse';
4543 cfg.cls += " " + this.cls;
4561 * @class Roo.bootstrap.PaginationItem
4562 * @extends Roo.bootstrap.Component
4563 * Bootstrap PaginationItem class
4564 * @cfg {String} html text
4565 * @cfg {String} href the link
4566 * @cfg {Boolean} preventDefault (true | false) default true
4567 * @cfg {Boolean} active (true | false) default false
4568 * @cfg {Boolean} disabled default false
4572 * Create a new PaginationItem
4573 * @param {Object} config The config object
4577 Roo.bootstrap.PaginationItem = function(config){
4578 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4583 * The raw click event for the entire grid.
4584 * @param {Roo.EventObject} e
4590 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4594 preventDefault: true,
4599 getAutoCreate : function(){
4605 href : this.href ? this.href : '#',
4606 html : this.html ? this.html : ''
4616 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4620 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4626 initEvents: function() {
4628 this.el.on('click', this.onClick, this);
4631 onClick : function(e)
4633 Roo.log('PaginationItem on click ');
4634 if(this.preventDefault){
4642 this.fireEvent('click', this, e);
4658 * @class Roo.bootstrap.Slider
4659 * @extends Roo.bootstrap.Component
4660 * Bootstrap Slider class
4663 * Create a new Slider
4664 * @param {Object} config The config object
4667 Roo.bootstrap.Slider = function(config){
4668 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4671 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4673 getAutoCreate : function(){
4677 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4681 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4693 * Ext JS Library 1.1.1
4694 * Copyright(c) 2006-2007, Ext JS, LLC.
4696 * Originally Released Under LGPL - original licence link has changed is not relivant.
4699 * <script type="text/javascript">
4704 * @class Roo.grid.ColumnModel
4705 * @extends Roo.util.Observable
4706 * This is the default implementation of a ColumnModel used by the Grid. It defines
4707 * the columns in the grid.
4710 var colModel = new Roo.grid.ColumnModel([
4711 {header: "Ticker", width: 60, sortable: true, locked: true},
4712 {header: "Company Name", width: 150, sortable: true},
4713 {header: "Market Cap.", width: 100, sortable: true},
4714 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4715 {header: "Employees", width: 100, sortable: true, resizable: false}
4720 * The config options listed for this class are options which may appear in each
4721 * individual column definition.
4722 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4724 * @param {Object} config An Array of column config objects. See this class's
4725 * config objects for details.
4727 Roo.grid.ColumnModel = function(config){
4729 * The config passed into the constructor
4731 this.config = config;
4734 // if no id, create one
4735 // if the column does not have a dataIndex mapping,
4736 // map it to the order it is in the config
4737 for(var i = 0, len = config.length; i < len; i++){
4739 if(typeof c.dataIndex == "undefined"){
4742 if(typeof c.renderer == "string"){
4743 c.renderer = Roo.util.Format[c.renderer];
4745 if(typeof c.id == "undefined"){
4748 if(c.editor && c.editor.xtype){
4749 c.editor = Roo.factory(c.editor, Roo.grid);
4751 if(c.editor && c.editor.isFormField){
4752 c.editor = new Roo.grid.GridEditor(c.editor);
4754 this.lookup[c.id] = c;
4758 * The width of columns which have no width specified (defaults to 100)
4761 this.defaultWidth = 100;
4764 * Default sortable of columns which have no sortable specified (defaults to false)
4767 this.defaultSortable = false;
4771 * @event widthchange
4772 * Fires when the width of a column changes.
4773 * @param {ColumnModel} this
4774 * @param {Number} columnIndex The column index
4775 * @param {Number} newWidth The new width
4777 "widthchange": true,
4779 * @event headerchange
4780 * Fires when the text of a header changes.
4781 * @param {ColumnModel} this
4782 * @param {Number} columnIndex The column index
4783 * @param {Number} newText The new header text
4785 "headerchange": true,
4787 * @event hiddenchange
4788 * Fires when a column is hidden or "unhidden".
4789 * @param {ColumnModel} this
4790 * @param {Number} columnIndex The column index
4791 * @param {Boolean} hidden true if hidden, false otherwise
4793 "hiddenchange": true,
4795 * @event columnmoved
4796 * Fires when a column is moved.
4797 * @param {ColumnModel} this
4798 * @param {Number} oldIndex
4799 * @param {Number} newIndex
4801 "columnmoved" : true,
4803 * @event columlockchange
4804 * Fires when a column's locked state is changed
4805 * @param {ColumnModel} this
4806 * @param {Number} colIndex
4807 * @param {Boolean} locked true if locked
4809 "columnlockchange" : true
4811 Roo.grid.ColumnModel.superclass.constructor.call(this);
4813 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4815 * @cfg {String} header The header text to display in the Grid view.
4818 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4819 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4820 * specified, the column's index is used as an index into the Record's data Array.
4823 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4824 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4827 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4828 * Defaults to the value of the {@link #defaultSortable} property.
4829 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4832 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4835 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4838 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4841 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4844 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4845 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4846 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4847 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4850 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4853 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4856 * @cfg {String} cursor (Optional)
4859 * @cfg {String} tooltip (Optional)
4862 * Returns the id of the column at the specified index.
4863 * @param {Number} index The column index
4864 * @return {String} the id
4866 getColumnId : function(index){
4867 return this.config[index].id;
4871 * Returns the column for a specified id.
4872 * @param {String} id The column id
4873 * @return {Object} the column
4875 getColumnById : function(id){
4876 return this.lookup[id];
4881 * Returns the column for a specified dataIndex.
4882 * @param {String} dataIndex The column dataIndex
4883 * @return {Object|Boolean} the column or false if not found
4885 getColumnByDataIndex: function(dataIndex){
4886 var index = this.findColumnIndex(dataIndex);
4887 return index > -1 ? this.config[index] : false;
4891 * Returns the index for a specified column id.
4892 * @param {String} id The column id
4893 * @return {Number} the index, or -1 if not found
4895 getIndexById : function(id){
4896 for(var i = 0, len = this.config.length; i < len; i++){
4897 if(this.config[i].id == id){
4905 * Returns the index for a specified column dataIndex.
4906 * @param {String} dataIndex The column dataIndex
4907 * @return {Number} the index, or -1 if not found
4910 findColumnIndex : function(dataIndex){
4911 for(var i = 0, len = this.config.length; i < len; i++){
4912 if(this.config[i].dataIndex == dataIndex){
4920 moveColumn : function(oldIndex, newIndex){
4921 var c = this.config[oldIndex];
4922 this.config.splice(oldIndex, 1);
4923 this.config.splice(newIndex, 0, c);
4924 this.dataMap = null;
4925 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4928 isLocked : function(colIndex){
4929 return this.config[colIndex].locked === true;
4932 setLocked : function(colIndex, value, suppressEvent){
4933 if(this.isLocked(colIndex) == value){
4936 this.config[colIndex].locked = value;
4938 this.fireEvent("columnlockchange", this, colIndex, value);
4942 getTotalLockedWidth : function(){
4944 for(var i = 0; i < this.config.length; i++){
4945 if(this.isLocked(i) && !this.isHidden(i)){
4946 this.totalWidth += this.getColumnWidth(i);
4952 getLockedCount : function(){
4953 for(var i = 0, len = this.config.length; i < len; i++){
4954 if(!this.isLocked(i)){
4961 * Returns the number of columns.
4964 getColumnCount : function(visibleOnly){
4965 if(visibleOnly === true){
4967 for(var i = 0, len = this.config.length; i < len; i++){
4968 if(!this.isHidden(i)){
4974 return this.config.length;
4978 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4979 * @param {Function} fn
4980 * @param {Object} scope (optional)
4981 * @return {Array} result
4983 getColumnsBy : function(fn, scope){
4985 for(var i = 0, len = this.config.length; i < len; i++){
4986 var c = this.config[i];
4987 if(fn.call(scope||this, c, i) === true){
4995 * Returns true if the specified column is sortable.
4996 * @param {Number} col The column index
4999 isSortable : function(col){
5000 if(typeof this.config[col].sortable == "undefined"){
5001 return this.defaultSortable;
5003 return this.config[col].sortable;
5007 * Returns the rendering (formatting) function defined for the column.
5008 * @param {Number} col The column index.
5009 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5011 getRenderer : function(col){
5012 if(!this.config[col].renderer){
5013 return Roo.grid.ColumnModel.defaultRenderer;
5015 return this.config[col].renderer;
5019 * Sets the rendering (formatting) function for a column.
5020 * @param {Number} col The column index
5021 * @param {Function} fn The function to use to process the cell's raw data
5022 * to return HTML markup for the grid view. The render function is called with
5023 * the following parameters:<ul>
5024 * <li>Data value.</li>
5025 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5026 * <li>css A CSS style string to apply to the table cell.</li>
5027 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5028 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5029 * <li>Row index</li>
5030 * <li>Column index</li>
5031 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5033 setRenderer : function(col, fn){
5034 this.config[col].renderer = fn;
5038 * Returns the width for the specified column.
5039 * @param {Number} col The column index
5042 getColumnWidth : function(col){
5043 return this.config[col].width * 1 || this.defaultWidth;
5047 * Sets the width for a column.
5048 * @param {Number} col The column index
5049 * @param {Number} width The new width
5051 setColumnWidth : function(col, width, suppressEvent){
5052 this.config[col].width = width;
5053 this.totalWidth = null;
5055 this.fireEvent("widthchange", this, col, width);
5060 * Returns the total width of all columns.
5061 * @param {Boolean} includeHidden True to include hidden column widths
5064 getTotalWidth : function(includeHidden){
5065 if(!this.totalWidth){
5066 this.totalWidth = 0;
5067 for(var i = 0, len = this.config.length; i < len; i++){
5068 if(includeHidden || !this.isHidden(i)){
5069 this.totalWidth += this.getColumnWidth(i);
5073 return this.totalWidth;
5077 * Returns the header for the specified column.
5078 * @param {Number} col The column index
5081 getColumnHeader : function(col){
5082 return this.config[col].header;
5086 * Sets the header for a column.
5087 * @param {Number} col The column index
5088 * @param {String} header The new header
5090 setColumnHeader : function(col, header){
5091 this.config[col].header = header;
5092 this.fireEvent("headerchange", this, col, header);
5096 * Returns the tooltip for the specified column.
5097 * @param {Number} col The column index
5100 getColumnTooltip : function(col){
5101 return this.config[col].tooltip;
5104 * Sets the tooltip for a column.
5105 * @param {Number} col The column index
5106 * @param {String} tooltip The new tooltip
5108 setColumnTooltip : function(col, tooltip){
5109 this.config[col].tooltip = tooltip;
5113 * Returns the dataIndex for the specified column.
5114 * @param {Number} col The column index
5117 getDataIndex : function(col){
5118 return this.config[col].dataIndex;
5122 * Sets the dataIndex for a column.
5123 * @param {Number} col The column index
5124 * @param {Number} dataIndex The new dataIndex
5126 setDataIndex : function(col, dataIndex){
5127 this.config[col].dataIndex = dataIndex;
5133 * Returns true if the cell is editable.
5134 * @param {Number} colIndex The column index
5135 * @param {Number} rowIndex The row index
5138 isCellEditable : function(colIndex, rowIndex){
5139 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5143 * Returns the editor defined for the cell/column.
5144 * return false or null to disable editing.
5145 * @param {Number} colIndex The column index
5146 * @param {Number} rowIndex The row index
5149 getCellEditor : function(colIndex, rowIndex){
5150 return this.config[colIndex].editor;
5154 * Sets if a column is editable.
5155 * @param {Number} col The column index
5156 * @param {Boolean} editable True if the column is editable
5158 setEditable : function(col, editable){
5159 this.config[col].editable = editable;
5164 * Returns true if the column is hidden.
5165 * @param {Number} colIndex The column index
5168 isHidden : function(colIndex){
5169 return this.config[colIndex].hidden;
5174 * Returns true if the column width cannot be changed
5176 isFixed : function(colIndex){
5177 return this.config[colIndex].fixed;
5181 * Returns true if the column can be resized
5184 isResizable : function(colIndex){
5185 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5188 * Sets if a column is hidden.
5189 * @param {Number} colIndex The column index
5190 * @param {Boolean} hidden True if the column is hidden
5192 setHidden : function(colIndex, hidden){
5193 this.config[colIndex].hidden = hidden;
5194 this.totalWidth = null;
5195 this.fireEvent("hiddenchange", this, colIndex, hidden);
5199 * Sets the editor for a column.
5200 * @param {Number} col The column index
5201 * @param {Object} editor The editor object
5203 setEditor : function(col, editor){
5204 this.config[col].editor = editor;
5208 Roo.grid.ColumnModel.defaultRenderer = function(value){
5209 if(typeof value == "string" && value.length < 1){
5215 // Alias for backwards compatibility
5216 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5219 * Ext JS Library 1.1.1
5220 * Copyright(c) 2006-2007, Ext JS, LLC.
5222 * Originally Released Under LGPL - original licence link has changed is not relivant.
5225 * <script type="text/javascript">
5229 * @class Roo.LoadMask
5230 * A simple utility class for generically masking elements while loading data. If the element being masked has
5231 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5232 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5233 * element's UpdateManager load indicator and will be destroyed after the initial load.
5235 * Create a new LoadMask
5236 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5237 * @param {Object} config The config object
5239 Roo.LoadMask = function(el, config){
5240 this.el = Roo.get(el);
5241 Roo.apply(this, config);
5243 this.store.on('beforeload', this.onBeforeLoad, this);
5244 this.store.on('load', this.onLoad, this);
5245 this.store.on('loadexception', this.onLoadException, this);
5246 this.removeMask = false;
5248 var um = this.el.getUpdateManager();
5249 um.showLoadIndicator = false; // disable the default indicator
5250 um.on('beforeupdate', this.onBeforeLoad, this);
5251 um.on('update', this.onLoad, this);
5252 um.on('failure', this.onLoad, this);
5253 this.removeMask = true;
5257 Roo.LoadMask.prototype = {
5259 * @cfg {Boolean} removeMask
5260 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5261 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5265 * The text to display in a centered loading message box (defaults to 'Loading...')
5269 * @cfg {String} msgCls
5270 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5272 msgCls : 'x-mask-loading',
5275 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5281 * Disables the mask to prevent it from being displayed
5283 disable : function(){
5284 this.disabled = true;
5288 * Enables the mask so that it can be displayed
5290 enable : function(){
5291 this.disabled = false;
5294 onLoadException : function()
5298 if (typeof(arguments[3]) != 'undefined') {
5299 Roo.MessageBox.alert("Error loading",arguments[3]);
5303 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5304 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5313 this.el.unmask(this.removeMask);
5318 this.el.unmask(this.removeMask);
5322 onBeforeLoad : function(){
5324 this.el.mask(this.msg, this.msgCls);
5329 destroy : function(){
5331 this.store.un('beforeload', this.onBeforeLoad, this);
5332 this.store.un('load', this.onLoad, this);
5333 this.store.un('loadexception', this.onLoadException, this);
5335 var um = this.el.getUpdateManager();
5336 um.un('beforeupdate', this.onBeforeLoad, this);
5337 um.un('update', this.onLoad, this);
5338 um.un('failure', this.onLoad, this);
5349 * @class Roo.bootstrap.Table
5350 * @extends Roo.bootstrap.Component
5351 * Bootstrap Table class
5352 * @cfg {String} cls table class
5353 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5354 * @cfg {String} bgcolor Specifies the background color for a table
5355 * @cfg {Number} border Specifies whether the table cells should have borders or not
5356 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5357 * @cfg {Number} cellspacing Specifies the space between cells
5358 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5359 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5360 * @cfg {String} sortable Specifies that the table should be sortable
5361 * @cfg {String} summary Specifies a summary of the content of a table
5362 * @cfg {Number} width Specifies the width of a table
5363 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5365 * @cfg {boolean} striped Should the rows be alternative striped
5366 * @cfg {boolean} bordered Add borders to the table
5367 * @cfg {boolean} hover Add hover highlighting
5368 * @cfg {boolean} condensed Format condensed
5369 * @cfg {boolean} responsive Format condensed
5370 * @cfg {Boolean} loadMask (true|false) default false
5371 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5372 * @cfg {Boolean} thead (true|false) generate thead, default true
5373 * @cfg {Boolean} RowSelection (true|false) default false
5374 * @cfg {Boolean} CellSelection (true|false) default false
5375 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5379 * Create a new Table
5380 * @param {Object} config The config object
5383 Roo.bootstrap.Table = function(config){
5384 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5387 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5388 this.sm = this.selModel;
5389 this.sm.xmodule = this.xmodule || false;
5391 if (this.cm && typeof(this.cm.config) == 'undefined') {
5392 this.colModel = new Roo.grid.ColumnModel(this.cm);
5393 this.cm = this.colModel;
5394 this.cm.xmodule = this.xmodule || false;
5397 this.store= Roo.factory(this.store, Roo.data);
5398 this.ds = this.store;
5399 this.ds.xmodule = this.xmodule || false;
5402 if (this.footer && this.store) {
5403 this.footer.dataSource = this.ds;
5404 this.footer = Roo.factory(this.footer);
5411 * Fires when a cell is clicked
5412 * @param {Roo.bootstrap.Table} this
5413 * @param {Roo.Element} el
5414 * @param {Number} rowIndex
5415 * @param {Number} columnIndex
5416 * @param {Roo.EventObject} e
5420 * @event celldblclick
5421 * Fires when a cell is double clicked
5422 * @param {Roo.bootstrap.Table} this
5423 * @param {Roo.Element} el
5424 * @param {Number} rowIndex
5425 * @param {Number} columnIndex
5426 * @param {Roo.EventObject} e
5428 "celldblclick" : true,
5431 * Fires when a row is clicked
5432 * @param {Roo.bootstrap.Table} this
5433 * @param {Roo.Element} el
5434 * @param {Number} rowIndex
5435 * @param {Roo.EventObject} e
5439 * @event rowdblclick
5440 * Fires when a row is double clicked
5441 * @param {Roo.bootstrap.Table} this
5442 * @param {Roo.Element} el
5443 * @param {Number} rowIndex
5444 * @param {Roo.EventObject} e
5446 "rowdblclick" : true,
5449 * Fires when a mouseover occur
5450 * @param {Roo.bootstrap.Table} this
5451 * @param {Roo.Element} el
5452 * @param {Number} rowIndex
5453 * @param {Number} columnIndex
5454 * @param {Roo.EventObject} e
5459 * Fires when a mouseout occur
5460 * @param {Roo.bootstrap.Table} this
5461 * @param {Roo.Element} el
5462 * @param {Number} rowIndex
5463 * @param {Number} columnIndex
5464 * @param {Roo.EventObject} e
5469 * Fires when a row is rendered, so you can change add a style to it.
5470 * @param {Roo.bootstrap.Table} this
5471 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5475 * @event rowsrendered
5476 * Fires when all the rows have been rendered
5477 * @param {Roo.bootstrap.Table} this
5479 'rowsrendered' : true
5484 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5508 RowSelection : false,
5509 CellSelection : false,
5512 // Roo.Element - the tbody
5515 getAutoCreate : function(){
5516 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5525 cfg.cls += ' table-striped';
5529 cfg.cls += ' table-hover';
5531 if (this.bordered) {
5532 cfg.cls += ' table-bordered';
5534 if (this.condensed) {
5535 cfg.cls += ' table-condensed';
5537 if (this.responsive) {
5538 cfg.cls += ' table-responsive';
5542 cfg.cls+= ' ' +this.cls;
5545 // this lot should be simplifed...
5548 cfg.align=this.align;
5551 cfg.bgcolor=this.bgcolor;
5554 cfg.border=this.border;
5556 if (this.cellpadding) {
5557 cfg.cellpadding=this.cellpadding;
5559 if (this.cellspacing) {
5560 cfg.cellspacing=this.cellspacing;
5563 cfg.frame=this.frame;
5566 cfg.rules=this.rules;
5568 if (this.sortable) {
5569 cfg.sortable=this.sortable;
5572 cfg.summary=this.summary;
5575 cfg.width=this.width;
5578 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5581 if(this.store || this.cm){
5583 cfg.cn.push(this.renderHeader());
5586 cfg.cn.push(this.renderBody());
5589 cfg.cn.push(this.renderFooter());
5592 cfg.cls+= ' TableGrid';
5595 return { cn : [ cfg ] };
5598 initEvents : function()
5600 if(!this.store || !this.cm){
5604 //Roo.log('initEvents with ds!!!!');
5606 this.mainBody = this.el.select('tbody', true).first();
5611 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5612 e.on('click', _this.sort, _this);
5615 this.el.on("click", this.onClick, this);
5616 this.el.on("dblclick", this.onDblClick, this);
5618 // why is this done????? = it breaks dialogs??
5619 //this.parent().el.setStyle('position', 'relative');
5623 this.footer.parentId = this.id;
5624 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5627 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5629 this.store.on('load', this.onLoad, this);
5630 this.store.on('beforeload', this.onBeforeLoad, this);
5631 this.store.on('update', this.onUpdate, this);
5632 this.store.on('add', this.onAdd, this);
5636 onMouseover : function(e, el)
5638 var cell = Roo.get(el);
5644 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5645 cell = cell.findParent('td', false, true);
5648 var row = cell.findParent('tr', false, true);
5649 var cellIndex = cell.dom.cellIndex;
5650 var rowIndex = row.dom.rowIndex - 1; // start from 0
5652 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5656 onMouseout : function(e, el)
5658 var cell = Roo.get(el);
5664 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5665 cell = cell.findParent('td', false, true);
5668 var row = cell.findParent('tr', false, true);
5669 var cellIndex = cell.dom.cellIndex;
5670 var rowIndex = row.dom.rowIndex - 1; // start from 0
5672 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5676 onClick : function(e, el)
5678 var cell = Roo.get(el);
5680 if(!cell || (!this.CellSelection && !this.RowSelection)){
5684 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5685 cell = cell.findParent('td', false, true);
5688 if(!cell || typeof(cell) == 'undefined'){
5692 var row = cell.findParent('tr', false, true);
5694 if(!row || typeof(row) == 'undefined'){
5698 var cellIndex = cell.dom.cellIndex;
5699 var rowIndex = this.getRowIndex(row);
5701 if(this.CellSelection){
5702 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5705 if(this.RowSelection){
5706 this.fireEvent('rowclick', this, row, rowIndex, e);
5712 onDblClick : function(e,el)
5714 var cell = Roo.get(el);
5716 if(!cell || (!this.CellSelection && !this.RowSelection)){
5720 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5721 cell = cell.findParent('td', false, true);
5724 if(!cell || typeof(cell) == 'undefined'){
5728 var row = cell.findParent('tr', false, true);
5730 if(!row || typeof(row) == 'undefined'){
5734 var cellIndex = cell.dom.cellIndex;
5735 var rowIndex = this.getRowIndex(row);
5737 if(this.CellSelection){
5738 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5741 if(this.RowSelection){
5742 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5746 sort : function(e,el)
5748 var col = Roo.get(el);
5750 if(!col.hasClass('sortable')){
5754 var sort = col.attr('sort');
5757 if(col.hasClass('glyphicon-arrow-up')){
5761 this.store.sortInfo = {field : sort, direction : dir};
5764 Roo.log("calling footer first");
5765 this.footer.onClick('first');
5768 this.store.load({ params : { start : 0 } });
5772 renderHeader : function()
5781 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5783 var config = cm.config[i];
5788 html: cm.getColumnHeader(i)
5791 if(typeof(config.tooltip) != 'undefined'){
5792 c.tooltip = config.tooltip;
5795 if(typeof(config.colspan) != 'undefined'){
5796 c.colspan = config.colspan;
5799 if(typeof(config.hidden) != 'undefined' && config.hidden){
5800 c.style += ' display:none;';
5803 if(typeof(config.dataIndex) != 'undefined'){
5804 c.sort = config.dataIndex;
5807 if(typeof(config.sortable) != 'undefined' && config.sortable){
5811 if(typeof(config.align) != 'undefined' && config.align.length){
5812 c.style += ' text-align:' + config.align + ';';
5815 if(typeof(config.width) != 'undefined'){
5816 c.style += ' width:' + config.width + 'px;';
5819 if(typeof(config.cls) != 'undefined'){
5820 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5829 renderBody : function()
5839 colspan : this.cm.getColumnCount()
5849 renderFooter : function()
5859 colspan : this.cm.getColumnCount()
5873 Roo.log('ds onload');
5878 var ds = this.store;
5880 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5881 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5883 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5884 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5887 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5888 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5892 var tbody = this.mainBody;
5894 if(ds.getCount() > 0){
5895 ds.data.each(function(d,rowIndex){
5896 var row = this.renderRow(cm, ds, rowIndex);
5898 tbody.createChild(row);
5902 if(row.cellObjects.length){
5903 Roo.each(row.cellObjects, function(r){
5904 _this.renderCellObject(r);
5911 Roo.each(this.el.select('tbody td', true).elements, function(e){
5912 e.on('mouseover', _this.onMouseover, _this);
5915 Roo.each(this.el.select('tbody td', true).elements, function(e){
5916 e.on('mouseout', _this.onMouseout, _this);
5918 this.fireEvent('rowsrendered', this);
5919 //if(this.loadMask){
5920 // this.maskEl.hide();
5925 onUpdate : function(ds,record)
5927 this.refreshRow(record);
5930 onRemove : function(ds, record, index, isUpdate){
5931 if(isUpdate !== true){
5932 this.fireEvent("beforerowremoved", this, index, record);
5934 var bt = this.mainBody.dom;
5936 var rows = this.el.select('tbody > tr', true).elements;
5938 if(typeof(rows[index]) != 'undefined'){
5939 bt.removeChild(rows[index].dom);
5942 // if(bt.rows[index]){
5943 // bt.removeChild(bt.rows[index]);
5946 if(isUpdate !== true){
5947 //this.stripeRows(index);
5948 //this.syncRowHeights(index, index);
5950 this.fireEvent("rowremoved", this, index, record);
5954 onAdd : function(ds, records, rowIndex)
5956 //Roo.log('on Add called');
5957 // - note this does not handle multiple adding very well..
5958 var bt = this.mainBody.dom;
5959 for (var i =0 ; i < records.length;i++) {
5960 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5961 //Roo.log(records[i]);
5962 //Roo.log(this.store.getAt(rowIndex+i));
5963 this.insertRow(this.store, rowIndex + i, false);
5970 refreshRow : function(record){
5971 var ds = this.store, index;
5972 if(typeof record == 'number'){
5974 record = ds.getAt(index);
5976 index = ds.indexOf(record);
5978 this.insertRow(ds, index, true);
5979 this.onRemove(ds, record, index+1, true);
5980 //this.syncRowHeights(index, index);
5982 this.fireEvent("rowupdated", this, index, record);
5985 insertRow : function(dm, rowIndex, isUpdate){
5988 this.fireEvent("beforerowsinserted", this, rowIndex);
5990 //var s = this.getScrollState();
5991 var row = this.renderRow(this.cm, this.store, rowIndex);
5992 // insert before rowIndex..
5993 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5997 if(row.cellObjects.length){
5998 Roo.each(row.cellObjects, function(r){
5999 _this.renderCellObject(r);
6004 this.fireEvent("rowsinserted", this, rowIndex);
6005 //this.syncRowHeights(firstRow, lastRow);
6006 //this.stripeRows(firstRow);
6013 getRowDom : function(rowIndex)
6015 var rows = this.el.select('tbody > tr', true).elements;
6017 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6020 // returns the object tree for a tr..
6023 renderRow : function(cm, ds, rowIndex)
6026 var d = ds.getAt(rowIndex);
6033 var cellObjects = [];
6035 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6036 var config = cm.config[i];
6038 var renderer = cm.getRenderer(i);
6042 if(typeof(renderer) !== 'undefined'){
6043 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6045 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6046 // and are rendered into the cells after the row is rendered - using the id for the element.
6048 if(typeof(value) === 'object'){
6058 rowIndex : rowIndex,
6063 this.fireEvent('rowclass', this, rowcfg);
6067 cls : rowcfg.rowClass,
6069 html: (typeof(value) === 'object') ? '' : value
6076 if(typeof(config.colspan) != 'undefined'){
6077 td.colspan = config.colspan;
6080 if(typeof(config.hidden) != 'undefined' && config.hidden){
6081 td.style += ' display:none;';
6084 if(typeof(config.align) != 'undefined' && config.align.length){
6085 td.style += ' text-align:' + config.align + ';';
6088 if(typeof(config.width) != 'undefined'){
6089 td.style += ' width:' + config.width + 'px;';
6092 if(typeof(config.cursor) != 'undefined'){
6093 td.style += ' cursor:' + config.cursor + ';';
6096 if(typeof(config.cls) != 'undefined'){
6097 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6104 row.cellObjects = cellObjects;
6112 onBeforeLoad : function()
6114 //Roo.log('ds onBeforeLoad');
6118 //if(this.loadMask){
6119 // this.maskEl.show();
6127 this.el.select('tbody', true).first().dom.innerHTML = '';
6130 * Show or hide a row.
6131 * @param {Number} rowIndex to show or hide
6132 * @param {Boolean} state hide
6134 setRowVisibility : function(rowIndex, state)
6136 var bt = this.mainBody.dom;
6138 var rows = this.el.select('tbody > tr', true).elements;
6140 if(typeof(rows[rowIndex]) == 'undefined'){
6143 rows[rowIndex].dom.style.display = state ? '' : 'none';
6147 getSelectionModel : function(){
6149 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6151 return this.selModel;
6154 * Render the Roo.bootstrap object from renderder
6156 renderCellObject : function(r)
6160 var t = r.cfg.render(r.container);
6163 Roo.each(r.cfg.cn, function(c){
6165 container: t.getChildContainer(),
6168 _this.renderCellObject(child);
6173 getRowIndex : function(row)
6177 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6200 * @class Roo.bootstrap.TableCell
6201 * @extends Roo.bootstrap.Component
6202 * Bootstrap TableCell class
6203 * @cfg {String} html cell contain text
6204 * @cfg {String} cls cell class
6205 * @cfg {String} tag cell tag (td|th) default td
6206 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6207 * @cfg {String} align Aligns the content in a cell
6208 * @cfg {String} axis Categorizes cells
6209 * @cfg {String} bgcolor Specifies the background color of a cell
6210 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6211 * @cfg {Number} colspan Specifies the number of columns a cell should span
6212 * @cfg {String} headers Specifies one or more header cells a cell is related to
6213 * @cfg {Number} height Sets the height of a cell
6214 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6215 * @cfg {Number} rowspan Sets the number of rows a cell should span
6216 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6217 * @cfg {String} valign Vertical aligns the content in a cell
6218 * @cfg {Number} width Specifies the width of a cell
6221 * Create a new TableCell
6222 * @param {Object} config The config object
6225 Roo.bootstrap.TableCell = function(config){
6226 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6229 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6249 getAutoCreate : function(){
6250 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6270 cfg.align=this.align
6276 cfg.bgcolor=this.bgcolor
6279 cfg.charoff=this.charoff
6282 cfg.colspan=this.colspan
6285 cfg.headers=this.headers
6288 cfg.height=this.height
6291 cfg.nowrap=this.nowrap
6294 cfg.rowspan=this.rowspan
6297 cfg.scope=this.scope
6300 cfg.valign=this.valign
6303 cfg.width=this.width
6322 * @class Roo.bootstrap.TableRow
6323 * @extends Roo.bootstrap.Component
6324 * Bootstrap TableRow class
6325 * @cfg {String} cls row class
6326 * @cfg {String} align Aligns the content in a table row
6327 * @cfg {String} bgcolor Specifies a background color for a table row
6328 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6329 * @cfg {String} valign Vertical aligns the content in a table row
6332 * Create a new TableRow
6333 * @param {Object} config The config object
6336 Roo.bootstrap.TableRow = function(config){
6337 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6340 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6348 getAutoCreate : function(){
6349 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6359 cfg.align = this.align;
6362 cfg.bgcolor = this.bgcolor;
6365 cfg.charoff = this.charoff;
6368 cfg.valign = this.valign;
6386 * @class Roo.bootstrap.TableBody
6387 * @extends Roo.bootstrap.Component
6388 * Bootstrap TableBody class
6389 * @cfg {String} cls element class
6390 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6391 * @cfg {String} align Aligns the content inside the element
6392 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6393 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6396 * Create a new TableBody
6397 * @param {Object} config The config object
6400 Roo.bootstrap.TableBody = function(config){
6401 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6404 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6412 getAutoCreate : function(){
6413 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6427 cfg.align = this.align;
6430 cfg.charoff = this.charoff;
6433 cfg.valign = this.valign;
6440 // initEvents : function()
6447 // this.store = Roo.factory(this.store, Roo.data);
6448 // this.store.on('load', this.onLoad, this);
6450 // this.store.load();
6454 // onLoad: function ()
6456 // this.fireEvent('load', this);
6466 * Ext JS Library 1.1.1
6467 * Copyright(c) 2006-2007, Ext JS, LLC.
6469 * Originally Released Under LGPL - original licence link has changed is not relivant.
6472 * <script type="text/javascript">
6475 // as we use this in bootstrap.
6476 Roo.namespace('Roo.form');
6478 * @class Roo.form.Action
6479 * Internal Class used to handle form actions
6481 * @param {Roo.form.BasicForm} el The form element or its id
6482 * @param {Object} config Configuration options
6487 // define the action interface
6488 Roo.form.Action = function(form, options){
6490 this.options = options || {};
6493 * Client Validation Failed
6496 Roo.form.Action.CLIENT_INVALID = 'client';
6498 * Server Validation Failed
6501 Roo.form.Action.SERVER_INVALID = 'server';
6503 * Connect to Server Failed
6506 Roo.form.Action.CONNECT_FAILURE = 'connect';
6508 * Reading Data from Server Failed
6511 Roo.form.Action.LOAD_FAILURE = 'load';
6513 Roo.form.Action.prototype = {
6515 failureType : undefined,
6516 response : undefined,
6520 run : function(options){
6525 success : function(response){
6530 handleResponse : function(response){
6534 // default connection failure
6535 failure : function(response){
6537 this.response = response;
6538 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6539 this.form.afterAction(this, false);
6542 processResponse : function(response){
6543 this.response = response;
6544 if(!response.responseText){
6547 this.result = this.handleResponse(response);
6551 // utility functions used internally
6552 getUrl : function(appendParams){
6553 var url = this.options.url || this.form.url || this.form.el.dom.action;
6555 var p = this.getParams();
6557 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6563 getMethod : function(){
6564 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6567 getParams : function(){
6568 var bp = this.form.baseParams;
6569 var p = this.options.params;
6571 if(typeof p == "object"){
6572 p = Roo.urlEncode(Roo.applyIf(p, bp));
6573 }else if(typeof p == 'string' && bp){
6574 p += '&' + Roo.urlEncode(bp);
6577 p = Roo.urlEncode(bp);
6582 createCallback : function(){
6584 success: this.success,
6585 failure: this.failure,
6587 timeout: (this.form.timeout*1000),
6588 upload: this.form.fileUpload ? this.success : undefined
6593 Roo.form.Action.Submit = function(form, options){
6594 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6597 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6600 haveProgress : false,
6601 uploadComplete : false,
6603 // uploadProgress indicator.
6604 uploadProgress : function()
6606 if (!this.form.progressUrl) {
6610 if (!this.haveProgress) {
6611 Roo.MessageBox.progress("Uploading", "Uploading");
6613 if (this.uploadComplete) {
6614 Roo.MessageBox.hide();
6618 this.haveProgress = true;
6620 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6622 var c = new Roo.data.Connection();
6624 url : this.form.progressUrl,
6629 success : function(req){
6630 //console.log(data);
6634 rdata = Roo.decode(req.responseText)
6636 Roo.log("Invalid data from server..");
6640 if (!rdata || !rdata.success) {
6642 Roo.MessageBox.alert(Roo.encode(rdata));
6645 var data = rdata.data;
6647 if (this.uploadComplete) {
6648 Roo.MessageBox.hide();
6653 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6654 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6657 this.uploadProgress.defer(2000,this);
6660 failure: function(data) {
6661 Roo.log('progress url failed ');
6672 // run get Values on the form, so it syncs any secondary forms.
6673 this.form.getValues();
6675 var o = this.options;
6676 var method = this.getMethod();
6677 var isPost = method == 'POST';
6678 if(o.clientValidation === false || this.form.isValid()){
6680 if (this.form.progressUrl) {
6681 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6682 (new Date() * 1) + '' + Math.random());
6687 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6688 form:this.form.el.dom,
6689 url:this.getUrl(!isPost),
6691 params:isPost ? this.getParams() : null,
6692 isUpload: this.form.fileUpload
6695 this.uploadProgress();
6697 }else if (o.clientValidation !== false){ // client validation failed
6698 this.failureType = Roo.form.Action.CLIENT_INVALID;
6699 this.form.afterAction(this, false);
6703 success : function(response)
6705 this.uploadComplete= true;
6706 if (this.haveProgress) {
6707 Roo.MessageBox.hide();
6711 var result = this.processResponse(response);
6712 if(result === true || result.success){
6713 this.form.afterAction(this, true);
6717 this.form.markInvalid(result.errors);
6718 this.failureType = Roo.form.Action.SERVER_INVALID;
6720 this.form.afterAction(this, false);
6722 failure : function(response)
6724 this.uploadComplete= true;
6725 if (this.haveProgress) {
6726 Roo.MessageBox.hide();
6729 this.response = response;
6730 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6731 this.form.afterAction(this, false);
6734 handleResponse : function(response){
6735 if(this.form.errorReader){
6736 var rs = this.form.errorReader.read(response);
6739 for(var i = 0, len = rs.records.length; i < len; i++) {
6740 var r = rs.records[i];
6744 if(errors.length < 1){
6748 success : rs.success,
6754 ret = Roo.decode(response.responseText);
6758 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6768 Roo.form.Action.Load = function(form, options){
6769 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6770 this.reader = this.form.reader;
6773 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6778 Roo.Ajax.request(Roo.apply(
6779 this.createCallback(), {
6780 method:this.getMethod(),
6781 url:this.getUrl(false),
6782 params:this.getParams()
6786 success : function(response){
6788 var result = this.processResponse(response);
6789 if(result === true || !result.success || !result.data){
6790 this.failureType = Roo.form.Action.LOAD_FAILURE;
6791 this.form.afterAction(this, false);
6794 this.form.clearInvalid();
6795 this.form.setValues(result.data);
6796 this.form.afterAction(this, true);
6799 handleResponse : function(response){
6800 if(this.form.reader){
6801 var rs = this.form.reader.read(response);
6802 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6804 success : rs.success,
6808 return Roo.decode(response.responseText);
6812 Roo.form.Action.ACTION_TYPES = {
6813 'load' : Roo.form.Action.Load,
6814 'submit' : Roo.form.Action.Submit
6823 * @class Roo.bootstrap.Form
6824 * @extends Roo.bootstrap.Component
6825 * Bootstrap Form class
6826 * @cfg {String} method GET | POST (default POST)
6827 * @cfg {String} labelAlign top | left (default top)
6828 * @cfg {String} align left | right - for navbars
6829 * @cfg {Boolean} loadMask load mask when submit (default true)
6834 * @param {Object} config The config object
6838 Roo.bootstrap.Form = function(config){
6839 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6842 * @event clientvalidation
6843 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6844 * @param {Form} this
6845 * @param {Boolean} valid true if the form has passed client-side validation
6847 clientvalidation: true,
6849 * @event beforeaction
6850 * Fires before any action is performed. Return false to cancel the action.
6851 * @param {Form} this
6852 * @param {Action} action The action to be performed
6856 * @event actionfailed
6857 * Fires when an action fails.
6858 * @param {Form} this
6859 * @param {Action} action The action that failed
6861 actionfailed : true,
6863 * @event actioncomplete
6864 * Fires when an action is completed.
6865 * @param {Form} this
6866 * @param {Action} action The action that completed
6868 actioncomplete : true
6873 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6876 * @cfg {String} method
6877 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6882 * The URL to use for form actions if one isn't supplied in the action options.
6885 * @cfg {Boolean} fileUpload
6886 * Set to true if this form is a file upload.
6890 * @cfg {Object} baseParams
6891 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6895 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6899 * @cfg {Sting} align (left|right) for navbar forms
6904 activeAction : null,
6907 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6908 * element by passing it or its id or mask the form itself by passing in true.
6911 waitMsgTarget : false,
6915 getAutoCreate : function(){
6919 method : this.method || 'POST',
6920 id : this.id || Roo.id(),
6923 if (this.parent().xtype.match(/^Nav/)) {
6924 cfg.cls = 'navbar-form navbar-' + this.align;
6928 if (this.labelAlign == 'left' ) {
6929 cfg.cls += ' form-horizontal';
6935 initEvents : function()
6937 this.el.on('submit', this.onSubmit, this);
6938 // this was added as random key presses on the form where triggering form submit.
6939 this.el.on('keypress', function(e) {
6940 if (e.getCharCode() != 13) {
6943 // we might need to allow it for textareas.. and some other items.
6944 // check e.getTarget().
6946 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6950 Roo.log("keypress blocked");
6958 onSubmit : function(e){
6963 * Returns true if client-side validation on the form is successful.
6966 isValid : function(){
6967 var items = this.getItems();
6969 items.each(function(f){
6978 * Returns true if any fields in this form have changed since their original load.
6981 isDirty : function(){
6983 var items = this.getItems();
6984 items.each(function(f){
6994 * Performs a predefined action (submit or load) or custom actions you define on this form.
6995 * @param {String} actionName The name of the action type
6996 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6997 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6998 * accept other config options):
7000 Property Type Description
7001 ---------------- --------------- ----------------------------------------------------------------------------------
7002 url String The url for the action (defaults to the form's url)
7003 method String The form method to use (defaults to the form's method, or POST if not defined)
7004 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7005 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7006 validate the form on the client (defaults to false)
7008 * @return {BasicForm} this
7010 doAction : function(action, options){
7011 if(typeof action == 'string'){
7012 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7014 if(this.fireEvent('beforeaction', this, action) !== false){
7015 this.beforeAction(action);
7016 action.run.defer(100, action);
7022 beforeAction : function(action){
7023 var o = action.options;
7026 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7028 // not really supported yet.. ??
7030 //if(this.waitMsgTarget === true){
7031 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7032 //}else if(this.waitMsgTarget){
7033 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7034 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7036 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7042 afterAction : function(action, success){
7043 this.activeAction = null;
7044 var o = action.options;
7046 //if(this.waitMsgTarget === true){
7048 //}else if(this.waitMsgTarget){
7049 // this.waitMsgTarget.unmask();
7051 // Roo.MessageBox.updateProgress(1);
7052 // Roo.MessageBox.hide();
7059 Roo.callback(o.success, o.scope, [this, action]);
7060 this.fireEvent('actioncomplete', this, action);
7064 // failure condition..
7065 // we have a scenario where updates need confirming.
7066 // eg. if a locking scenario exists..
7067 // we look for { errors : { needs_confirm : true }} in the response.
7069 (typeof(action.result) != 'undefined') &&
7070 (typeof(action.result.errors) != 'undefined') &&
7071 (typeof(action.result.errors.needs_confirm) != 'undefined')
7074 Roo.log("not supported yet");
7077 Roo.MessageBox.confirm(
7078 "Change requires confirmation",
7079 action.result.errorMsg,
7084 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7094 Roo.callback(o.failure, o.scope, [this, action]);
7095 // show an error message if no failed handler is set..
7096 if (!this.hasListener('actionfailed')) {
7097 Roo.log("need to add dialog support");
7099 Roo.MessageBox.alert("Error",
7100 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7101 action.result.errorMsg :
7102 "Saving Failed, please check your entries or try again"
7107 this.fireEvent('actionfailed', this, action);
7112 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7113 * @param {String} id The value to search for
7116 findField : function(id){
7117 var items = this.getItems();
7118 var field = items.get(id);
7120 items.each(function(f){
7121 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7128 return field || null;
7131 * Mark fields in this form invalid in bulk.
7132 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7133 * @return {BasicForm} this
7135 markInvalid : function(errors){
7136 if(errors instanceof Array){
7137 for(var i = 0, len = errors.length; i < len; i++){
7138 var fieldError = errors[i];
7139 var f = this.findField(fieldError.id);
7141 f.markInvalid(fieldError.msg);
7147 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7148 field.markInvalid(errors[id]);
7152 //Roo.each(this.childForms || [], function (f) {
7153 // f.markInvalid(errors);
7160 * Set values for fields in this form in bulk.
7161 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7162 * @return {BasicForm} this
7164 setValues : function(values){
7165 if(values instanceof Array){ // array of objects
7166 for(var i = 0, len = values.length; i < len; i++){
7168 var f = this.findField(v.id);
7170 f.setValue(v.value);
7171 if(this.trackResetOnLoad){
7172 f.originalValue = f.getValue();
7176 }else{ // object hash
7179 if(typeof values[id] != 'function' && (field = this.findField(id))){
7181 if (field.setFromData &&
7183 field.displayField &&
7184 // combos' with local stores can
7185 // be queried via setValue()
7186 // to set their value..
7187 (field.store && !field.store.isLocal)
7191 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7192 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7193 field.setFromData(sd);
7196 field.setValue(values[id]);
7200 if(this.trackResetOnLoad){
7201 field.originalValue = field.getValue();
7207 //Roo.each(this.childForms || [], function (f) {
7208 // f.setValues(values);
7215 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7216 * they are returned as an array.
7217 * @param {Boolean} asString
7220 getValues : function(asString){
7221 //if (this.childForms) {
7222 // copy values from the child forms
7223 // Roo.each(this.childForms, function (f) {
7224 // this.setValues(f.getValues());
7230 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7231 if(asString === true){
7234 return Roo.urlDecode(fs);
7238 * Returns the fields in this form as an object with key/value pairs.
7239 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7242 getFieldValues : function(with_hidden)
7244 var items = this.getItems();
7246 items.each(function(f){
7250 var v = f.getValue();
7251 if (f.inputType =='radio') {
7252 if (typeof(ret[f.getName()]) == 'undefined') {
7253 ret[f.getName()] = ''; // empty..
7256 if (!f.el.dom.checked) {
7264 // not sure if this supported any more..
7265 if ((typeof(v) == 'object') && f.getRawValue) {
7266 v = f.getRawValue() ; // dates..
7268 // combo boxes where name != hiddenName...
7269 if (f.name != f.getName()) {
7270 ret[f.name] = f.getRawValue();
7272 ret[f.getName()] = v;
7279 * Clears all invalid messages in this form.
7280 * @return {BasicForm} this
7282 clearInvalid : function(){
7283 var items = this.getItems();
7285 items.each(function(f){
7296 * @return {BasicForm} this
7299 var items = this.getItems();
7300 items.each(function(f){
7304 Roo.each(this.childForms || [], function (f) {
7311 getItems : function()
7313 var r=new Roo.util.MixedCollection(false, function(o){
7314 return o.id || (o.id = Roo.id());
7316 var iter = function(el) {
7323 Roo.each(el.items,function(e) {
7343 * Ext JS Library 1.1.1
7344 * Copyright(c) 2006-2007, Ext JS, LLC.
7346 * Originally Released Under LGPL - original licence link has changed is not relivant.
7349 * <script type="text/javascript">
7352 * @class Roo.form.VTypes
7353 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7356 Roo.form.VTypes = function(){
7357 // closure these in so they are only created once.
7358 var alpha = /^[a-zA-Z_]+$/;
7359 var alphanum = /^[a-zA-Z0-9_]+$/;
7360 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7361 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7363 // All these messages and functions are configurable
7366 * The function used to validate email addresses
7367 * @param {String} value The email address
7369 'email' : function(v){
7370 return email.test(v);
7373 * The error text to display when the email validation function returns false
7376 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7378 * The keystroke filter mask to be applied on email input
7381 'emailMask' : /[a-z0-9_\.\-@]/i,
7384 * The function used to validate URLs
7385 * @param {String} value The URL
7387 'url' : function(v){
7391 * The error text to display when the url validation function returns false
7394 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7397 * The function used to validate alpha values
7398 * @param {String} value The value
7400 'alpha' : function(v){
7401 return alpha.test(v);
7404 * The error text to display when the alpha validation function returns false
7407 'alphaText' : 'This field should only contain letters and _',
7409 * The keystroke filter mask to be applied on alpha input
7412 'alphaMask' : /[a-z_]/i,
7415 * The function used to validate alphanumeric values
7416 * @param {String} value The value
7418 'alphanum' : function(v){
7419 return alphanum.test(v);
7422 * The error text to display when the alphanumeric validation function returns false
7425 'alphanumText' : 'This field should only contain letters, numbers and _',
7427 * The keystroke filter mask to be applied on alphanumeric input
7430 'alphanumMask' : /[a-z0-9_]/i
7440 * @class Roo.bootstrap.Input
7441 * @extends Roo.bootstrap.Component
7442 * Bootstrap Input class
7443 * @cfg {Boolean} disabled is it disabled
7444 * @cfg {String} fieldLabel - the label associated
7445 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7446 * @cfg {String} name name of the input
7447 * @cfg {string} fieldLabel - the label associated
7448 * @cfg {string} inputType - input / file submit ...
7449 * @cfg {string} placeholder - placeholder to put in text.
7450 * @cfg {string} before - input group add on before
7451 * @cfg {string} after - input group add on after
7452 * @cfg {string} size - (lg|sm) or leave empty..
7453 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7454 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7455 * @cfg {Number} md colspan out of 12 for computer-sized screens
7456 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7457 * @cfg {string} value default value of the input
7458 * @cfg {Number} labelWidth set the width of label (0-12)
7459 * @cfg {String} labelAlign (top|left)
7460 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7461 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7463 * @cfg {String} align (left|center|right) Default left
7468 * Create a new Input
7469 * @param {Object} config The config object
7472 Roo.bootstrap.Input = function(config){
7473 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7478 * Fires when this field receives input focus.
7479 * @param {Roo.form.Field} this
7484 * Fires when this field loses input focus.
7485 * @param {Roo.form.Field} this
7490 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7491 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7492 * @param {Roo.form.Field} this
7493 * @param {Roo.EventObject} e The event object
7498 * Fires just before the field blurs if the field value has changed.
7499 * @param {Roo.form.Field} this
7500 * @param {Mixed} newValue The new value
7501 * @param {Mixed} oldValue The original value
7506 * Fires after the field has been marked as invalid.
7507 * @param {Roo.form.Field} this
7508 * @param {String} msg The validation message
7513 * Fires after the field has been validated with no errors.
7514 * @param {Roo.form.Field} this
7519 * Fires after the key up
7520 * @param {Roo.form.Field} this
7521 * @param {Roo.EventObject} e The event Object
7527 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7529 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7530 automatic validation (defaults to "keyup").
7532 validationEvent : "keyup",
7534 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7536 validateOnBlur : true,
7538 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7540 validationDelay : 250,
7542 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7544 focusClass : "x-form-focus", // not needed???
7548 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7550 invalidClass : "has-warning",
7553 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7555 validClass : "has-success",
7558 * @cfg {Boolean} hasFeedback (true|false) default true
7563 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7565 invalidFeedbackClass : "glyphicon-warning-sign",
7568 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7570 validFeedbackClass : "glyphicon-ok",
7573 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7575 selectOnFocus : false,
7578 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7582 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7587 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7589 disableKeyFilter : false,
7592 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7596 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7600 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7602 blankText : "This field is required",
7605 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7609 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7611 maxLength : Number.MAX_VALUE,
7613 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7615 minLengthText : "The minimum length for this field is {0}",
7617 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7619 maxLengthText : "The maximum length for this field is {0}",
7623 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7624 * If available, this function will be called only after the basic validators all return true, and will be passed the
7625 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7629 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7630 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7631 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7635 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7639 autocomplete: false,
7658 formatedValue : false,
7660 parentLabelAlign : function()
7663 while (parent.parent()) {
7664 parent = parent.parent();
7665 if (typeof(parent.labelAlign) !='undefined') {
7666 return parent.labelAlign;
7673 getAutoCreate : function(){
7675 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7681 if(this.inputType != 'hidden'){
7682 cfg.cls = 'form-group' //input-group
7688 type : this.inputType,
7690 cls : 'form-control',
7691 placeholder : this.placeholder || '',
7692 autocomplete : this.autocomplete || 'new-password'
7697 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7700 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7701 input.maxLength = this.maxLength;
7704 if (this.disabled) {
7705 input.disabled=true;
7708 if (this.readOnly) {
7709 input.readonly=true;
7713 input.name = this.name;
7716 input.cls += ' input-' + this.size;
7719 ['xs','sm','md','lg'].map(function(size){
7720 if (settings[size]) {
7721 cfg.cls += ' col-' + size + '-' + settings[size];
7725 var inputblock = input;
7729 cls: 'glyphicon form-control-feedback'
7732 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7735 cls : 'has-feedback',
7743 if (this.before || this.after) {
7746 cls : 'input-group',
7750 if (this.before && typeof(this.before) == 'string') {
7752 inputblock.cn.push({
7754 cls : 'roo-input-before input-group-addon',
7758 if (this.before && typeof(this.before) == 'object') {
7759 this.before = Roo.factory(this.before);
7760 Roo.log(this.before);
7761 inputblock.cn.push({
7763 cls : 'roo-input-before input-group-' +
7764 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7768 inputblock.cn.push(input);
7770 if (this.after && typeof(this.after) == 'string') {
7771 inputblock.cn.push({
7773 cls : 'roo-input-after input-group-addon',
7777 if (this.after && typeof(this.after) == 'object') {
7778 this.after = Roo.factory(this.after);
7779 Roo.log(this.after);
7780 inputblock.cn.push({
7782 cls : 'roo-input-after input-group-' +
7783 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7787 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7788 inputblock.cls += ' has-feedback';
7789 inputblock.cn.push(feedback);
7793 if (align ==='left' && this.fieldLabel.length) {
7794 Roo.log("left and has label");
7800 cls : 'control-label col-sm-' + this.labelWidth,
7801 html : this.fieldLabel
7805 cls : "col-sm-" + (12 - this.labelWidth),
7812 } else if ( this.fieldLabel.length) {
7818 //cls : 'input-group-addon',
7819 html : this.fieldLabel
7829 Roo.log(" no label && no align");
7838 Roo.log('input-parentType: ' + this.parentType);
7840 if (this.parentType === 'Navbar' && this.parent().bar) {
7841 cfg.cls += ' navbar-form';
7849 * return the real input element.
7851 inputEl: function ()
7853 return this.el.select('input.form-control',true).first();
7856 tooltipEl : function()
7858 return this.inputEl();
7861 setDisabled : function(v)
7863 var i = this.inputEl().dom;
7865 i.removeAttribute('disabled');
7869 i.setAttribute('disabled','true');
7871 initEvents : function()
7874 this.inputEl().on("keydown" , this.fireKey, this);
7875 this.inputEl().on("focus", this.onFocus, this);
7876 this.inputEl().on("blur", this.onBlur, this);
7878 this.inputEl().relayEvent('keyup', this);
7880 // reference to original value for reset
7881 this.originalValue = this.getValue();
7882 //Roo.form.TextField.superclass.initEvents.call(this);
7883 if(this.validationEvent == 'keyup'){
7884 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7885 this.inputEl().on('keyup', this.filterValidation, this);
7887 else if(this.validationEvent !== false){
7888 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7891 if(this.selectOnFocus){
7892 this.on("focus", this.preFocus, this);
7895 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7896 this.inputEl().on("keypress", this.filterKeys, this);
7899 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7900 this.el.on("click", this.autoSize, this);
7903 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7904 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7907 if (typeof(this.before) == 'object') {
7908 this.before.render(this.el.select('.roo-input-before',true).first());
7910 if (typeof(this.after) == 'object') {
7911 this.after.render(this.el.select('.roo-input-after',true).first());
7916 filterValidation : function(e){
7917 if(!e.isNavKeyPress()){
7918 this.validationTask.delay(this.validationDelay);
7922 * Validates the field value
7923 * @return {Boolean} True if the value is valid, else false
7925 validate : function(){
7926 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7927 if(this.disabled || this.validateValue(this.getRawValue())){
7938 * Validates a value according to the field's validation rules and marks the field as invalid
7939 * if the validation fails
7940 * @param {Mixed} value The value to validate
7941 * @return {Boolean} True if the value is valid, else false
7943 validateValue : function(value){
7944 if(value.length < 1) { // if it's blank
7945 if(this.allowBlank){
7951 if(value.length < this.minLength){
7954 if(value.length > this.maxLength){
7958 var vt = Roo.form.VTypes;
7959 if(!vt[this.vtype](value, this)){
7963 if(typeof this.validator == "function"){
7964 var msg = this.validator(value);
7970 if(this.regex && !this.regex.test(value)){
7980 fireKey : function(e){
7981 //Roo.log('field ' + e.getKey());
7982 if(e.isNavKeyPress()){
7983 this.fireEvent("specialkey", this, e);
7986 focus : function (selectText){
7988 this.inputEl().focus();
7989 if(selectText === true){
7990 this.inputEl().dom.select();
7996 onFocus : function(){
7997 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7998 // this.el.addClass(this.focusClass);
8001 this.hasFocus = true;
8002 this.startValue = this.getValue();
8003 this.fireEvent("focus", this);
8007 beforeBlur : Roo.emptyFn,
8011 onBlur : function(){
8013 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8014 //this.el.removeClass(this.focusClass);
8016 this.hasFocus = false;
8017 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8020 var v = this.getValue();
8021 if(String(v) !== String(this.startValue)){
8022 this.fireEvent('change', this, v, this.startValue);
8024 this.fireEvent("blur", this);
8028 * Resets the current field value to the originally loaded value and clears any validation messages
8031 this.setValue(this.originalValue);
8035 * Returns the name of the field
8036 * @return {Mixed} name The name field
8038 getName: function(){
8042 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8043 * @return {Mixed} value The field value
8045 getValue : function(){
8047 var v = this.inputEl().getValue();
8052 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8053 * @return {Mixed} value The field value
8055 getRawValue : function(){
8056 var v = this.inputEl().getValue();
8062 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8063 * @param {Mixed} value The value to set
8065 setRawValue : function(v){
8066 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8069 selectText : function(start, end){
8070 var v = this.getRawValue();
8072 start = start === undefined ? 0 : start;
8073 end = end === undefined ? v.length : end;
8074 var d = this.inputEl().dom;
8075 if(d.setSelectionRange){
8076 d.setSelectionRange(start, end);
8077 }else if(d.createTextRange){
8078 var range = d.createTextRange();
8079 range.moveStart("character", start);
8080 range.moveEnd("character", v.length-end);
8087 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8088 * @param {Mixed} value The value to set
8090 setValue : function(v){
8093 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8099 processValue : function(value){
8100 if(this.stripCharsRe){
8101 var newValue = value.replace(this.stripCharsRe, '');
8102 if(newValue !== value){
8103 this.setRawValue(newValue);
8110 preFocus : function(){
8112 if(this.selectOnFocus){
8113 this.inputEl().dom.select();
8116 filterKeys : function(e){
8118 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8121 var c = e.getCharCode(), cc = String.fromCharCode(c);
8122 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8125 if(!this.maskRe.test(cc)){
8130 * Clear any invalid styles/messages for this field
8132 clearInvalid : function(){
8134 if(!this.el || this.preventMark){ // not rendered
8137 this.el.removeClass(this.invalidClass);
8139 this.fireEvent('valid', this);
8143 * Mark this field as valid
8145 markValid : function(){
8146 if(!this.el || this.preventMark){ // not rendered
8150 this.el.removeClass([this.invalidClass, this.validClass]);
8152 if(this.disabled || this.allowBlank){
8156 this.el.addClass(this.validClass);
8158 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8160 var feedback = this.el.select('.form-control-feedback', true).first();
8163 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8164 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8169 this.fireEvent('valid', this);
8173 * Mark this field as invalid
8174 * @param {String} msg The validation message
8176 markInvalid : function(msg){
8177 if(!this.el || this.preventMark){ // not rendered
8181 this.el.removeClass([this.invalidClass, this.validClass]);
8183 if(this.disabled || this.allowBlank){
8187 this.el.addClass(this.invalidClass);
8189 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8191 var feedback = this.el.select('.form-control-feedback', true).first();
8194 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8196 if(this.getValue().length){
8197 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8204 this.fireEvent('invalid', this, msg);
8207 SafariOnKeyDown : function(event)
8209 // this is a workaround for a password hang bug on chrome/ webkit.
8211 var isSelectAll = false;
8213 if(this.inputEl().dom.selectionEnd > 0){
8214 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8216 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8217 event.preventDefault();
8222 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8224 event.preventDefault();
8225 // this is very hacky as keydown always get's upper case.
8227 var cc = String.fromCharCode(event.getCharCode());
8228 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8232 adjustWidth : function(tag, w){
8233 tag = tag.toLowerCase();
8234 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8235 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8239 if(tag == 'textarea'){
8242 }else if(Roo.isOpera){
8246 if(tag == 'textarea'){
8265 * @class Roo.bootstrap.TextArea
8266 * @extends Roo.bootstrap.Input
8267 * Bootstrap TextArea class
8268 * @cfg {Number} cols Specifies the visible width of a text area
8269 * @cfg {Number} rows Specifies the visible number of lines in a text area
8270 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8271 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8272 * @cfg {string} html text
8275 * Create a new TextArea
8276 * @param {Object} config The config object
8279 Roo.bootstrap.TextArea = function(config){
8280 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8284 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8294 getAutoCreate : function(){
8296 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8307 value : this.value || '',
8308 html: this.html || '',
8309 cls : 'form-control',
8310 placeholder : this.placeholder || ''
8314 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8315 input.maxLength = this.maxLength;
8319 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8323 input.cols = this.cols;
8326 if (this.readOnly) {
8327 input.readonly = true;
8331 input.name = this.name;
8335 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8339 ['xs','sm','md','lg'].map(function(size){
8340 if (settings[size]) {
8341 cfg.cls += ' col-' + size + '-' + settings[size];
8345 var inputblock = input;
8347 if(this.hasFeedback && !this.allowBlank){
8351 cls: 'glyphicon form-control-feedback'
8355 cls : 'has-feedback',
8364 if (this.before || this.after) {
8367 cls : 'input-group',
8371 inputblock.cn.push({
8373 cls : 'input-group-addon',
8378 inputblock.cn.push(input);
8380 if(this.hasFeedback && !this.allowBlank){
8381 inputblock.cls += ' has-feedback';
8382 inputblock.cn.push(feedback);
8386 inputblock.cn.push({
8388 cls : 'input-group-addon',
8395 if (align ==='left' && this.fieldLabel.length) {
8396 Roo.log("left and has label");
8402 cls : 'control-label col-sm-' + this.labelWidth,
8403 html : this.fieldLabel
8407 cls : "col-sm-" + (12 - this.labelWidth),
8414 } else if ( this.fieldLabel.length) {
8420 //cls : 'input-group-addon',
8421 html : this.fieldLabel
8431 Roo.log(" no label && no align");
8441 if (this.disabled) {
8442 input.disabled=true;
8449 * return the real textarea element.
8451 inputEl: function ()
8453 return this.el.select('textarea.form-control',true).first();
8461 * trigger field - base class for combo..
8466 * @class Roo.bootstrap.TriggerField
8467 * @extends Roo.bootstrap.Input
8468 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8469 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8470 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8471 * for which you can provide a custom implementation. For example:
8473 var trigger = new Roo.bootstrap.TriggerField();
8474 trigger.onTriggerClick = myTriggerFn;
8475 trigger.applyTo('my-field');
8478 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8479 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8480 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8481 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8482 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8485 * Create a new TriggerField.
8486 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8487 * to the base TextField)
8489 Roo.bootstrap.TriggerField = function(config){
8490 this.mimicing = false;
8491 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8494 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8496 * @cfg {String} triggerClass A CSS class to apply to the trigger
8499 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8504 * @cfg {Boolean} removable (true|false) special filter default false
8508 /** @cfg {Boolean} grow @hide */
8509 /** @cfg {Number} growMin @hide */
8510 /** @cfg {Number} growMax @hide */
8516 autoSize: Roo.emptyFn,
8523 actionMode : 'wrap',
8528 getAutoCreate : function(){
8530 Roo.log('run????????????????????');
8531 var align = this.labelAlign || this.parentLabelAlign();
8536 cls: 'form-group' //input-group
8543 type : this.inputType,
8544 cls : 'form-control',
8545 autocomplete: 'new-password',
8546 placeholder : this.placeholder || ''
8550 input.name = this.name;
8553 input.cls += ' input-' + this.size;
8556 if (this.disabled) {
8557 input.disabled=true;
8560 var inputblock = input;
8562 if(this.hasFeedback && !this.allowBlank){
8566 cls: 'glyphicon form-control-feedback'
8569 if(this.removable && !this.editable && !this.tickable){
8571 cls : 'has-feedback',
8577 cls : 'roo-combo-removable-btn close'
8584 cls : 'has-feedback',
8593 if(this.removable && !this.editable && !this.tickable){
8595 cls : 'roo-removable',
8601 cls : 'roo-combo-removable-btn close'
8608 if (this.before || this.after) {
8611 cls : 'input-group',
8615 inputblock.cn.push({
8617 cls : 'input-group-addon',
8622 inputblock.cn.push(input);
8624 if(this.hasFeedback && !this.allowBlank){
8625 inputblock.cls += ' has-feedback';
8626 inputblock.cn.push(feedback);
8630 inputblock.cn.push({
8632 cls : 'input-group-addon',
8645 cls: 'form-hidden-field'
8653 Roo.log('multiple');
8661 cls: 'form-hidden-field'
8665 cls: 'select2-choices',
8669 cls: 'select2-search-field',
8682 cls: 'select2-container input-group',
8687 // cls: 'typeahead typeahead-long dropdown-menu',
8688 // style: 'display:none'
8693 if(!this.multiple && this.showToggleBtn){
8699 if (this.caret != false) {
8702 cls: 'fa fa-' + this.caret
8709 cls : 'input-group-addon btn dropdown-toggle',
8714 cls: 'combobox-clear',
8728 combobox.cls += ' select2-container-multi';
8731 if (align ==='left' && this.fieldLabel.length) {
8733 Roo.log("left and has label");
8739 cls : 'control-label col-sm-' + this.labelWidth,
8740 html : this.fieldLabel
8744 cls : "col-sm-" + (12 - this.labelWidth),
8751 } else if ( this.fieldLabel.length) {
8757 //cls : 'input-group-addon',
8758 html : this.fieldLabel
8768 Roo.log(" no label && no align");
8775 ['xs','sm','md','lg'].map(function(size){
8776 if (settings[size]) {
8777 cfg.cls += ' col-' + size + '-' + settings[size];
8788 onResize : function(w, h){
8789 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8790 // if(typeof w == 'number'){
8791 // var x = w - this.trigger.getWidth();
8792 // this.inputEl().setWidth(this.adjustWidth('input', x));
8793 // this.trigger.setStyle('left', x+'px');
8798 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8801 getResizeEl : function(){
8802 return this.inputEl();
8806 getPositionEl : function(){
8807 return this.inputEl();
8811 alignErrorIcon : function(){
8812 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8816 initEvents : function(){
8820 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8821 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8822 if(!this.multiple && this.showToggleBtn){
8823 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8824 if(this.hideTrigger){
8825 this.trigger.setDisplayed(false);
8827 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8831 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8834 if(this.removable && !this.editable && !this.tickable){
8835 var close = this.closeTriggerEl();
8838 close.setVisibilityMode(Roo.Element.DISPALY).hide();
8839 close.on('click', this.removeBtnClick, this, close);
8843 //this.trigger.addClassOnOver('x-form-trigger-over');
8844 //this.trigger.addClassOnClick('x-form-trigger-click');
8847 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8851 closeTriggerEl : function()
8853 var close = this.el.select('.roo-combo-removable-btn', true).first();
8854 return close ? close : false;
8857 removeBtnClick : function(e, h, el)
8861 if(this.fireEvent("remove", this) !== false){
8866 createList : function()
8868 this.list = Roo.get(document.body).createChild({
8870 cls: 'typeahead typeahead-long dropdown-menu',
8871 style: 'display:none'
8874 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8879 initTrigger : function(){
8884 onDestroy : function(){
8886 this.trigger.removeAllListeners();
8887 // this.trigger.remove();
8890 // this.wrap.remove();
8892 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8896 onFocus : function(){
8897 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8900 this.wrap.addClass('x-trigger-wrap-focus');
8901 this.mimicing = true;
8902 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8903 if(this.monitorTab){
8904 this.el.on("keydown", this.checkTab, this);
8911 checkTab : function(e){
8912 if(e.getKey() == e.TAB){
8918 onBlur : function(){
8923 mimicBlur : function(e, t){
8925 if(!this.wrap.contains(t) && this.validateBlur()){
8932 triggerBlur : function(){
8933 this.mimicing = false;
8934 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8935 if(this.monitorTab){
8936 this.el.un("keydown", this.checkTab, this);
8938 //this.wrap.removeClass('x-trigger-wrap-focus');
8939 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8943 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8944 validateBlur : function(e, t){
8949 onDisable : function(){
8950 this.inputEl().dom.disabled = true;
8951 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8953 // this.wrap.addClass('x-item-disabled');
8958 onEnable : function(){
8959 this.inputEl().dom.disabled = false;
8960 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8962 // this.el.removeClass('x-item-disabled');
8967 onShow : function(){
8968 var ae = this.getActionEl();
8971 ae.dom.style.display = '';
8972 ae.dom.style.visibility = 'visible';
8978 onHide : function(){
8979 var ae = this.getActionEl();
8980 ae.dom.style.display = 'none';
8984 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8985 * by an implementing function.
8987 * @param {EventObject} e
8989 onTriggerClick : Roo.emptyFn
8993 * Ext JS Library 1.1.1
8994 * Copyright(c) 2006-2007, Ext JS, LLC.
8996 * Originally Released Under LGPL - original licence link has changed is not relivant.
8999 * <script type="text/javascript">
9004 * @class Roo.data.SortTypes
9006 * Defines the default sorting (casting?) comparison functions used when sorting data.
9008 Roo.data.SortTypes = {
9010 * Default sort that does nothing
9011 * @param {Mixed} s The value being converted
9012 * @return {Mixed} The comparison value
9019 * The regular expression used to strip tags
9023 stripTagsRE : /<\/?[^>]+>/gi,
9026 * Strips all HTML tags to sort on text only
9027 * @param {Mixed} s The value being converted
9028 * @return {String} The comparison value
9030 asText : function(s){
9031 return String(s).replace(this.stripTagsRE, "");
9035 * Strips all HTML tags to sort on text only - Case insensitive
9036 * @param {Mixed} s The value being converted
9037 * @return {String} The comparison value
9039 asUCText : function(s){
9040 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9044 * Case insensitive string
9045 * @param {Mixed} s The value being converted
9046 * @return {String} The comparison value
9048 asUCString : function(s) {
9049 return String(s).toUpperCase();
9054 * @param {Mixed} s The value being converted
9055 * @return {Number} The comparison value
9057 asDate : function(s) {
9061 if(s instanceof Date){
9064 return Date.parse(String(s));
9069 * @param {Mixed} s The value being converted
9070 * @return {Float} The comparison value
9072 asFloat : function(s) {
9073 var val = parseFloat(String(s).replace(/,/g, ""));
9074 if(isNaN(val)) val = 0;
9080 * @param {Mixed} s The value being converted
9081 * @return {Number} The comparison value
9083 asInt : function(s) {
9084 var val = parseInt(String(s).replace(/,/g, ""));
9085 if(isNaN(val)) val = 0;
9090 * Ext JS Library 1.1.1
9091 * Copyright(c) 2006-2007, Ext JS, LLC.
9093 * Originally Released Under LGPL - original licence link has changed is not relivant.
9096 * <script type="text/javascript">
9100 * @class Roo.data.Record
9101 * Instances of this class encapsulate both record <em>definition</em> information, and record
9102 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9103 * to access Records cached in an {@link Roo.data.Store} object.<br>
9105 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9106 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9109 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9111 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9112 * {@link #create}. The parameters are the same.
9113 * @param {Array} data An associative Array of data values keyed by the field name.
9114 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9115 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9116 * not specified an integer id is generated.
9118 Roo.data.Record = function(data, id){
9119 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9124 * Generate a constructor for a specific record layout.
9125 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9126 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9127 * Each field definition object may contain the following properties: <ul>
9128 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
9129 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9130 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9131 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9132 * is being used, then this is a string containing the javascript expression to reference the data relative to
9133 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9134 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9135 * this may be omitted.</p></li>
9136 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9137 * <ul><li>auto (Default, implies no conversion)</li>
9142 * <li>date</li></ul></p></li>
9143 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9144 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9145 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9146 * by the Reader into an object that will be stored in the Record. It is passed the
9147 * following parameters:<ul>
9148 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9150 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9152 * <br>usage:<br><pre><code>
9153 var TopicRecord = Roo.data.Record.create(
9154 {name: 'title', mapping: 'topic_title'},
9155 {name: 'author', mapping: 'username'},
9156 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9157 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9158 {name: 'lastPoster', mapping: 'user2'},
9159 {name: 'excerpt', mapping: 'post_text'}
9162 var myNewRecord = new TopicRecord({
9163 title: 'Do my job please',
9166 lastPost: new Date(),
9167 lastPoster: 'Animal',
9168 excerpt: 'No way dude!'
9170 myStore.add(myNewRecord);
9175 Roo.data.Record.create = function(o){
9177 f.superclass.constructor.apply(this, arguments);
9179 Roo.extend(f, Roo.data.Record);
9180 var p = f.prototype;
9181 p.fields = new Roo.util.MixedCollection(false, function(field){
9184 for(var i = 0, len = o.length; i < len; i++){
9185 p.fields.add(new Roo.data.Field(o[i]));
9187 f.getField = function(name){
9188 return p.fields.get(name);
9193 Roo.data.Record.AUTO_ID = 1000;
9194 Roo.data.Record.EDIT = 'edit';
9195 Roo.data.Record.REJECT = 'reject';
9196 Roo.data.Record.COMMIT = 'commit';
9198 Roo.data.Record.prototype = {
9200 * Readonly flag - true if this record has been modified.
9209 join : function(store){
9214 * Set the named field to the specified value.
9215 * @param {String} name The name of the field to set.
9216 * @param {Object} value The value to set the field to.
9218 set : function(name, value){
9219 if(this.data[name] == value){
9226 if(typeof this.modified[name] == 'undefined'){
9227 this.modified[name] = this.data[name];
9229 this.data[name] = value;
9230 if(!this.editing && this.store){
9231 this.store.afterEdit(this);
9236 * Get the value of the named field.
9237 * @param {String} name The name of the field to get the value of.
9238 * @return {Object} The value of the field.
9240 get : function(name){
9241 return this.data[name];
9245 beginEdit : function(){
9246 this.editing = true;
9251 cancelEdit : function(){
9252 this.editing = false;
9253 delete this.modified;
9257 endEdit : function(){
9258 this.editing = false;
9259 if(this.dirty && this.store){
9260 this.store.afterEdit(this);
9265 * Usually called by the {@link Roo.data.Store} which owns the Record.
9266 * Rejects all changes made to the Record since either creation, or the last commit operation.
9267 * Modified fields are reverted to their original values.
9269 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9270 * of reject operations.
9272 reject : function(){
9273 var m = this.modified;
9275 if(typeof m[n] != "function"){
9276 this.data[n] = m[n];
9280 delete this.modified;
9281 this.editing = false;
9283 this.store.afterReject(this);
9288 * Usually called by the {@link Roo.data.Store} which owns the Record.
9289 * Commits all changes made to the Record since either creation, or the last commit operation.
9291 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9292 * of commit operations.
9294 commit : function(){
9296 delete this.modified;
9297 this.editing = false;
9299 this.store.afterCommit(this);
9304 hasError : function(){
9305 return this.error != null;
9309 clearError : function(){
9314 * Creates a copy of this record.
9315 * @param {String} id (optional) A new record id if you don't want to use this record's id
9318 copy : function(newId) {
9319 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9323 * Ext JS Library 1.1.1
9324 * Copyright(c) 2006-2007, Ext JS, LLC.
9326 * Originally Released Under LGPL - original licence link has changed is not relivant.
9329 * <script type="text/javascript">
9335 * @class Roo.data.Store
9336 * @extends Roo.util.Observable
9337 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9338 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9340 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
9341 * has no knowledge of the format of the data returned by the Proxy.<br>
9343 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9344 * instances from the data object. These records are cached and made available through accessor functions.
9346 * Creates a new Store.
9347 * @param {Object} config A config object containing the objects needed for the Store to access data,
9348 * and read the data into Records.
9350 Roo.data.Store = function(config){
9351 this.data = new Roo.util.MixedCollection(false);
9352 this.data.getKey = function(o){
9355 this.baseParams = {};
9362 "multisort" : "_multisort"
9365 if(config && config.data){
9366 this.inlineData = config.data;
9370 Roo.apply(this, config);
9372 if(this.reader){ // reader passed
9373 this.reader = Roo.factory(this.reader, Roo.data);
9374 this.reader.xmodule = this.xmodule || false;
9375 if(!this.recordType){
9376 this.recordType = this.reader.recordType;
9378 if(this.reader.onMetaChange){
9379 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9383 if(this.recordType){
9384 this.fields = this.recordType.prototype.fields;
9390 * @event datachanged
9391 * Fires when the data cache has changed, and a widget which is using this Store
9392 * as a Record cache should refresh its view.
9393 * @param {Store} this
9398 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9399 * @param {Store} this
9400 * @param {Object} meta The JSON metadata
9405 * Fires when Records have been added to the Store
9406 * @param {Store} this
9407 * @param {Roo.data.Record[]} records The array of Records added
9408 * @param {Number} index The index at which the record(s) were added
9413 * Fires when a Record has been removed from the Store
9414 * @param {Store} this
9415 * @param {Roo.data.Record} record The Record that was removed
9416 * @param {Number} index The index at which the record was removed
9421 * Fires when a Record has been updated
9422 * @param {Store} this
9423 * @param {Roo.data.Record} record The Record that was updated
9424 * @param {String} operation The update operation being performed. Value may be one of:
9426 Roo.data.Record.EDIT
9427 Roo.data.Record.REJECT
9428 Roo.data.Record.COMMIT
9434 * Fires when the data cache has been cleared.
9435 * @param {Store} this
9440 * Fires before a request is made for a new data object. If the beforeload handler returns false
9441 * the load action will be canceled.
9442 * @param {Store} this
9443 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9447 * @event beforeloadadd
9448 * Fires after a new set of Records has been loaded.
9449 * @param {Store} this
9450 * @param {Roo.data.Record[]} records The Records that were loaded
9451 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9453 beforeloadadd : true,
9456 * Fires after a new set of Records has been loaded, before they are added to the store.
9457 * @param {Store} this
9458 * @param {Roo.data.Record[]} records The Records that were loaded
9459 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9460 * @params {Object} return from reader
9464 * @event loadexception
9465 * Fires if an exception occurs in the Proxy during loading.
9466 * Called with the signature of the Proxy's "loadexception" event.
9467 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9470 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9471 * @param {Object} load options
9472 * @param {Object} jsonData from your request (normally this contains the Exception)
9474 loadexception : true
9478 this.proxy = Roo.factory(this.proxy, Roo.data);
9479 this.proxy.xmodule = this.xmodule || false;
9480 this.relayEvents(this.proxy, ["loadexception"]);
9482 this.sortToggle = {};
9483 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9485 Roo.data.Store.superclass.constructor.call(this);
9487 if(this.inlineData){
9488 this.loadData(this.inlineData);
9489 delete this.inlineData;
9493 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9495 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9496 * without a remote query - used by combo/forms at present.
9500 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9503 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9506 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9507 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9510 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9511 * on any HTTP request
9514 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9517 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9521 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9522 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9527 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9528 * loaded or when a record is removed. (defaults to false).
9530 pruneModifiedRecords : false,
9536 * Add Records to the Store and fires the add event.
9537 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9539 add : function(records){
9540 records = [].concat(records);
9541 for(var i = 0, len = records.length; i < len; i++){
9542 records[i].join(this);
9544 var index = this.data.length;
9545 this.data.addAll(records);
9546 this.fireEvent("add", this, records, index);
9550 * Remove a Record from the Store and fires the remove event.
9551 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9553 remove : function(record){
9554 var index = this.data.indexOf(record);
9555 this.data.removeAt(index);
9556 if(this.pruneModifiedRecords){
9557 this.modified.remove(record);
9559 this.fireEvent("remove", this, record, index);
9563 * Remove all Records from the Store and fires the clear event.
9565 removeAll : function(){
9567 if(this.pruneModifiedRecords){
9570 this.fireEvent("clear", this);
9574 * Inserts Records to the Store at the given index and fires the add event.
9575 * @param {Number} index The start index at which to insert the passed Records.
9576 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9578 insert : function(index, records){
9579 records = [].concat(records);
9580 for(var i = 0, len = records.length; i < len; i++){
9581 this.data.insert(index, records[i]);
9582 records[i].join(this);
9584 this.fireEvent("add", this, records, index);
9588 * Get the index within the cache of the passed Record.
9589 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9590 * @return {Number} The index of the passed Record. Returns -1 if not found.
9592 indexOf : function(record){
9593 return this.data.indexOf(record);
9597 * Get the index within the cache of the Record with the passed id.
9598 * @param {String} id The id of the Record to find.
9599 * @return {Number} The index of the Record. Returns -1 if not found.
9601 indexOfId : function(id){
9602 return this.data.indexOfKey(id);
9606 * Get the Record with the specified id.
9607 * @param {String} id The id of the Record to find.
9608 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9610 getById : function(id){
9611 return this.data.key(id);
9615 * Get the Record at the specified index.
9616 * @param {Number} index The index of the Record to find.
9617 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9619 getAt : function(index){
9620 return this.data.itemAt(index);
9624 * Returns a range of Records between specified indices.
9625 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9626 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9627 * @return {Roo.data.Record[]} An array of Records
9629 getRange : function(start, end){
9630 return this.data.getRange(start, end);
9634 storeOptions : function(o){
9635 o = Roo.apply({}, o);
9638 this.lastOptions = o;
9642 * Loads the Record cache from the configured Proxy using the configured Reader.
9644 * If using remote paging, then the first load call must specify the <em>start</em>
9645 * and <em>limit</em> properties in the options.params property to establish the initial
9646 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9648 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9649 * and this call will return before the new data has been loaded. Perform any post-processing
9650 * in a callback function, or in a "load" event handler.</strong>
9652 * @param {Object} options An object containing properties which control loading options:<ul>
9653 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9654 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9655 * passed the following arguments:<ul>
9656 * <li>r : Roo.data.Record[]</li>
9657 * <li>options: Options object from the load call</li>
9658 * <li>success: Boolean success indicator</li></ul></li>
9659 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9660 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9663 load : function(options){
9664 options = options || {};
9665 if(this.fireEvent("beforeload", this, options) !== false){
9666 this.storeOptions(options);
9667 var p = Roo.apply(options.params || {}, this.baseParams);
9668 // if meta was not loaded from remote source.. try requesting it.
9669 if (!this.reader.metaFromRemote) {
9672 if(this.sortInfo && this.remoteSort){
9673 var pn = this.paramNames;
9674 p[pn["sort"]] = this.sortInfo.field;
9675 p[pn["dir"]] = this.sortInfo.direction;
9677 if (this.multiSort) {
9678 var pn = this.paramNames;
9679 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9682 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9687 * Reloads the Record cache from the configured Proxy using the configured Reader and
9688 * the options from the last load operation performed.
9689 * @param {Object} options (optional) An object containing properties which may override the options
9690 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9691 * the most recently used options are reused).
9693 reload : function(options){
9694 this.load(Roo.applyIf(options||{}, this.lastOptions));
9698 // Called as a callback by the Reader during a load operation.
9699 loadRecords : function(o, options, success){
9700 if(!o || success === false){
9701 if(success !== false){
9702 this.fireEvent("load", this, [], options, o);
9704 if(options.callback){
9705 options.callback.call(options.scope || this, [], options, false);
9709 // if data returned failure - throw an exception.
9710 if (o.success === false) {
9711 // show a message if no listener is registered.
9712 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9713 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9715 // loadmask wil be hooked into this..
9716 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9719 var r = o.records, t = o.totalRecords || r.length;
9721 this.fireEvent("beforeloadadd", this, r, options, o);
9723 if(!options || options.add !== true){
9724 if(this.pruneModifiedRecords){
9727 for(var i = 0, len = r.length; i < len; i++){
9731 this.data = this.snapshot;
9732 delete this.snapshot;
9735 this.data.addAll(r);
9736 this.totalLength = t;
9738 this.fireEvent("datachanged", this);
9740 this.totalLength = Math.max(t, this.data.length+r.length);
9743 this.fireEvent("load", this, r, options, o);
9744 if(options.callback){
9745 options.callback.call(options.scope || this, r, options, true);
9751 * Loads data from a passed data block. A Reader which understands the format of the data
9752 * must have been configured in the constructor.
9753 * @param {Object} data The data block from which to read the Records. The format of the data expected
9754 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9755 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9757 loadData : function(o, append){
9758 var r = this.reader.readRecords(o);
9759 this.loadRecords(r, {add: append}, true);
9763 * Gets the number of cached records.
9765 * <em>If using paging, this may not be the total size of the dataset. If the data object
9766 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9767 * the data set size</em>
9769 getCount : function(){
9770 return this.data.length || 0;
9774 * Gets the total number of records in the dataset as returned by the server.
9776 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9777 * the dataset size</em>
9779 getTotalCount : function(){
9780 return this.totalLength || 0;
9784 * Returns the sort state of the Store as an object with two properties:
9786 field {String} The name of the field by which the Records are sorted
9787 direction {String} The sort order, "ASC" or "DESC"
9790 getSortState : function(){
9791 return this.sortInfo;
9795 applySort : function(){
9796 if(this.sortInfo && !this.remoteSort){
9797 var s = this.sortInfo, f = s.field;
9798 var st = this.fields.get(f).sortType;
9799 var fn = function(r1, r2){
9800 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9801 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9803 this.data.sort(s.direction, fn);
9804 if(this.snapshot && this.snapshot != this.data){
9805 this.snapshot.sort(s.direction, fn);
9811 * Sets the default sort column and order to be used by the next load operation.
9812 * @param {String} fieldName The name of the field to sort by.
9813 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9815 setDefaultSort : function(field, dir){
9816 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9821 * If remote sorting is used, the sort is performed on the server, and the cache is
9822 * reloaded. If local sorting is used, the cache is sorted internally.
9823 * @param {String} fieldName The name of the field to sort by.
9824 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9826 sort : function(fieldName, dir){
9827 var f = this.fields.get(fieldName);
9829 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9831 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9832 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9837 this.sortToggle[f.name] = dir;
9838 this.sortInfo = {field: f.name, direction: dir};
9839 if(!this.remoteSort){
9841 this.fireEvent("datachanged", this);
9843 this.load(this.lastOptions);
9848 * Calls the specified function for each of the Records in the cache.
9849 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9850 * Returning <em>false</em> aborts and exits the iteration.
9851 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9853 each : function(fn, scope){
9854 this.data.each(fn, scope);
9858 * Gets all records modified since the last commit. Modified records are persisted across load operations
9859 * (e.g., during paging).
9860 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9862 getModifiedRecords : function(){
9863 return this.modified;
9867 createFilterFn : function(property, value, anyMatch){
9868 if(!value.exec){ // not a regex
9869 value = String(value);
9870 if(value.length == 0){
9873 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9876 return value.test(r.data[property]);
9881 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9882 * @param {String} property A field on your records
9883 * @param {Number} start The record index to start at (defaults to 0)
9884 * @param {Number} end The last record index to include (defaults to length - 1)
9885 * @return {Number} The sum
9887 sum : function(property, start, end){
9888 var rs = this.data.items, v = 0;
9890 end = (end || end === 0) ? end : rs.length-1;
9892 for(var i = start; i <= end; i++){
9893 v += (rs[i].data[property] || 0);
9899 * Filter the records by a specified property.
9900 * @param {String} field A field on your records
9901 * @param {String/RegExp} value Either a string that the field
9902 * should start with or a RegExp to test against the field
9903 * @param {Boolean} anyMatch True to match any part not just the beginning
9905 filter : function(property, value, anyMatch){
9906 var fn = this.createFilterFn(property, value, anyMatch);
9907 return fn ? this.filterBy(fn) : this.clearFilter();
9911 * Filter by a function. The specified function will be called with each
9912 * record in this data source. If the function returns true the record is included,
9913 * otherwise it is filtered.
9914 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9915 * @param {Object} scope (optional) The scope of the function (defaults to this)
9917 filterBy : function(fn, scope){
9918 this.snapshot = this.snapshot || this.data;
9919 this.data = this.queryBy(fn, scope||this);
9920 this.fireEvent("datachanged", this);
9924 * Query the records by a specified property.
9925 * @param {String} field A field on your records
9926 * @param {String/RegExp} value Either a string that the field
9927 * should start with or a RegExp to test against the field
9928 * @param {Boolean} anyMatch True to match any part not just the beginning
9929 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9931 query : function(property, value, anyMatch){
9932 var fn = this.createFilterFn(property, value, anyMatch);
9933 return fn ? this.queryBy(fn) : this.data.clone();
9937 * Query by a function. The specified function will be called with each
9938 * record in this data source. If the function returns true the record is included
9940 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9941 * @param {Object} scope (optional) The scope of the function (defaults to this)
9942 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9944 queryBy : function(fn, scope){
9945 var data = this.snapshot || this.data;
9946 return data.filterBy(fn, scope||this);
9950 * Collects unique values for a particular dataIndex from this store.
9951 * @param {String} dataIndex The property to collect
9952 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9953 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9954 * @return {Array} An array of the unique values
9956 collect : function(dataIndex, allowNull, bypassFilter){
9957 var d = (bypassFilter === true && this.snapshot) ?
9958 this.snapshot.items : this.data.items;
9959 var v, sv, r = [], l = {};
9960 for(var i = 0, len = d.length; i < len; i++){
9961 v = d[i].data[dataIndex];
9963 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9972 * Revert to a view of the Record cache with no filtering applied.
9973 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9975 clearFilter : function(suppressEvent){
9976 if(this.snapshot && this.snapshot != this.data){
9977 this.data = this.snapshot;
9978 delete this.snapshot;
9979 if(suppressEvent !== true){
9980 this.fireEvent("datachanged", this);
9986 afterEdit : function(record){
9987 if(this.modified.indexOf(record) == -1){
9988 this.modified.push(record);
9990 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9994 afterReject : function(record){
9995 this.modified.remove(record);
9996 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10000 afterCommit : function(record){
10001 this.modified.remove(record);
10002 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10006 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10007 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10009 commitChanges : function(){
10010 var m = this.modified.slice(0);
10011 this.modified = [];
10012 for(var i = 0, len = m.length; i < len; i++){
10018 * Cancel outstanding changes on all changed records.
10020 rejectChanges : function(){
10021 var m = this.modified.slice(0);
10022 this.modified = [];
10023 for(var i = 0, len = m.length; i < len; i++){
10028 onMetaChange : function(meta, rtype, o){
10029 this.recordType = rtype;
10030 this.fields = rtype.prototype.fields;
10031 delete this.snapshot;
10032 this.sortInfo = meta.sortInfo || this.sortInfo;
10033 this.modified = [];
10034 this.fireEvent('metachange', this, this.reader.meta);
10037 moveIndex : function(data, type)
10039 var index = this.indexOf(data);
10041 var newIndex = index + type;
10045 this.insert(newIndex, data);
10050 * Ext JS Library 1.1.1
10051 * Copyright(c) 2006-2007, Ext JS, LLC.
10053 * Originally Released Under LGPL - original licence link has changed is not relivant.
10056 * <script type="text/javascript">
10060 * @class Roo.data.SimpleStore
10061 * @extends Roo.data.Store
10062 * Small helper class to make creating Stores from Array data easier.
10063 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10064 * @cfg {Array} fields An array of field definition objects, or field name strings.
10065 * @cfg {Array} data The multi-dimensional array of data
10067 * @param {Object} config
10069 Roo.data.SimpleStore = function(config){
10070 Roo.data.SimpleStore.superclass.constructor.call(this, {
10072 reader: new Roo.data.ArrayReader({
10075 Roo.data.Record.create(config.fields)
10077 proxy : new Roo.data.MemoryProxy(config.data)
10081 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10083 * Ext JS Library 1.1.1
10084 * Copyright(c) 2006-2007, Ext JS, LLC.
10086 * Originally Released Under LGPL - original licence link has changed is not relivant.
10089 * <script type="text/javascript">
10094 * @extends Roo.data.Store
10095 * @class Roo.data.JsonStore
10096 * Small helper class to make creating Stores for JSON data easier. <br/>
10098 var store = new Roo.data.JsonStore({
10099 url: 'get-images.php',
10101 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10104 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10105 * JsonReader and HttpProxy (unless inline data is provided).</b>
10106 * @cfg {Array} fields An array of field definition objects, or field name strings.
10108 * @param {Object} config
10110 Roo.data.JsonStore = function(c){
10111 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10112 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10113 reader: new Roo.data.JsonReader(c, c.fields)
10116 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10118 * Ext JS Library 1.1.1
10119 * Copyright(c) 2006-2007, Ext JS, LLC.
10121 * Originally Released Under LGPL - original licence link has changed is not relivant.
10124 * <script type="text/javascript">
10128 Roo.data.Field = function(config){
10129 if(typeof config == "string"){
10130 config = {name: config};
10132 Roo.apply(this, config);
10135 this.type = "auto";
10138 var st = Roo.data.SortTypes;
10139 // named sortTypes are supported, here we look them up
10140 if(typeof this.sortType == "string"){
10141 this.sortType = st[this.sortType];
10144 // set default sortType for strings and dates
10145 if(!this.sortType){
10148 this.sortType = st.asUCString;
10151 this.sortType = st.asDate;
10154 this.sortType = st.none;
10159 var stripRe = /[\$,%]/g;
10161 // prebuilt conversion function for this field, instead of
10162 // switching every time we're reading a value
10164 var cv, dateFormat = this.dateFormat;
10169 cv = function(v){ return v; };
10172 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10176 return v !== undefined && v !== null && v !== '' ?
10177 parseInt(String(v).replace(stripRe, ""), 10) : '';
10182 return v !== undefined && v !== null && v !== '' ?
10183 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10188 cv = function(v){ return v === true || v === "true" || v == 1; };
10195 if(v instanceof Date){
10199 if(dateFormat == "timestamp"){
10200 return new Date(v*1000);
10202 return Date.parseDate(v, dateFormat);
10204 var parsed = Date.parse(v);
10205 return parsed ? new Date(parsed) : null;
10214 Roo.data.Field.prototype = {
10222 * Ext JS Library 1.1.1
10223 * Copyright(c) 2006-2007, Ext JS, LLC.
10225 * Originally Released Under LGPL - original licence link has changed is not relivant.
10228 * <script type="text/javascript">
10231 // Base class for reading structured data from a data source. This class is intended to be
10232 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10235 * @class Roo.data.DataReader
10236 * Base class for reading structured data from a data source. This class is intended to be
10237 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10240 Roo.data.DataReader = function(meta, recordType){
10244 this.recordType = recordType instanceof Array ?
10245 Roo.data.Record.create(recordType) : recordType;
10248 Roo.data.DataReader.prototype = {
10250 * Create an empty record
10251 * @param {Object} data (optional) - overlay some values
10252 * @return {Roo.data.Record} record created.
10254 newRow : function(d) {
10256 this.recordType.prototype.fields.each(function(c) {
10258 case 'int' : da[c.name] = 0; break;
10259 case 'date' : da[c.name] = new Date(); break;
10260 case 'float' : da[c.name] = 0.0; break;
10261 case 'boolean' : da[c.name] = false; break;
10262 default : da[c.name] = ""; break;
10266 return new this.recordType(Roo.apply(da, d));
10271 * Ext JS Library 1.1.1
10272 * Copyright(c) 2006-2007, Ext JS, LLC.
10274 * Originally Released Under LGPL - original licence link has changed is not relivant.
10277 * <script type="text/javascript">
10281 * @class Roo.data.DataProxy
10282 * @extends Roo.data.Observable
10283 * This class is an abstract base class for implementations which provide retrieval of
10284 * unformatted data objects.<br>
10286 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10287 * (of the appropriate type which knows how to parse the data object) to provide a block of
10288 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10290 * Custom implementations must implement the load method as described in
10291 * {@link Roo.data.HttpProxy#load}.
10293 Roo.data.DataProxy = function(){
10296 * @event beforeload
10297 * Fires before a network request is made to retrieve a data object.
10298 * @param {Object} This DataProxy object.
10299 * @param {Object} params The params parameter to the load function.
10304 * Fires before the load method's callback is called.
10305 * @param {Object} This DataProxy object.
10306 * @param {Object} o The data object.
10307 * @param {Object} arg The callback argument object passed to the load function.
10311 * @event loadexception
10312 * Fires if an Exception occurs during data retrieval.
10313 * @param {Object} This DataProxy object.
10314 * @param {Object} o The data object.
10315 * @param {Object} arg The callback argument object passed to the load function.
10316 * @param {Object} e The Exception.
10318 loadexception : true
10320 Roo.data.DataProxy.superclass.constructor.call(this);
10323 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10326 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10330 * Ext JS Library 1.1.1
10331 * Copyright(c) 2006-2007, Ext JS, LLC.
10333 * Originally Released Under LGPL - original licence link has changed is not relivant.
10336 * <script type="text/javascript">
10339 * @class Roo.data.MemoryProxy
10340 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10341 * to the Reader when its load method is called.
10343 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10345 Roo.data.MemoryProxy = function(data){
10349 Roo.data.MemoryProxy.superclass.constructor.call(this);
10353 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10355 * Load data from the requested source (in this case an in-memory
10356 * data object passed to the constructor), read the data object into
10357 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10358 * process that block using the passed callback.
10359 * @param {Object} params This parameter is not used by the MemoryProxy class.
10360 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10361 * object into a block of Roo.data.Records.
10362 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10363 * The function must be passed <ul>
10364 * <li>The Record block object</li>
10365 * <li>The "arg" argument from the load function</li>
10366 * <li>A boolean success indicator</li>
10368 * @param {Object} scope The scope in which to call the callback
10369 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10371 load : function(params, reader, callback, scope, arg){
10372 params = params || {};
10375 result = reader.readRecords(this.data);
10377 this.fireEvent("loadexception", this, arg, null, e);
10378 callback.call(scope, null, arg, false);
10381 callback.call(scope, result, arg, true);
10385 update : function(params, records){
10390 * Ext JS Library 1.1.1
10391 * Copyright(c) 2006-2007, Ext JS, LLC.
10393 * Originally Released Under LGPL - original licence link has changed is not relivant.
10396 * <script type="text/javascript">
10399 * @class Roo.data.HttpProxy
10400 * @extends Roo.data.DataProxy
10401 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10402 * configured to reference a certain URL.<br><br>
10404 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10405 * from which the running page was served.<br><br>
10407 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10409 * Be aware that to enable the browser to parse an XML document, the server must set
10410 * the Content-Type header in the HTTP response to "text/xml".
10412 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10413 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10414 * will be used to make the request.
10416 Roo.data.HttpProxy = function(conn){
10417 Roo.data.HttpProxy.superclass.constructor.call(this);
10418 // is conn a conn config or a real conn?
10420 this.useAjax = !conn || !conn.events;
10424 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10425 // thse are take from connection...
10428 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10431 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10432 * extra parameters to each request made by this object. (defaults to undefined)
10435 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10436 * to each request made by this object. (defaults to undefined)
10439 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
10442 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10445 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10451 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10455 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10456 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10457 * a finer-grained basis than the DataProxy events.
10459 getConnection : function(){
10460 return this.useAjax ? Roo.Ajax : this.conn;
10464 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10465 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10466 * process that block using the passed callback.
10467 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10468 * for the request to the remote server.
10469 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10470 * object into a block of Roo.data.Records.
10471 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10472 * The function must be passed <ul>
10473 * <li>The Record block object</li>
10474 * <li>The "arg" argument from the load function</li>
10475 * <li>A boolean success indicator</li>
10477 * @param {Object} scope The scope in which to call the callback
10478 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10480 load : function(params, reader, callback, scope, arg){
10481 if(this.fireEvent("beforeload", this, params) !== false){
10483 params : params || {},
10485 callback : callback,
10490 callback : this.loadResponse,
10494 Roo.applyIf(o, this.conn);
10495 if(this.activeRequest){
10496 Roo.Ajax.abort(this.activeRequest);
10498 this.activeRequest = Roo.Ajax.request(o);
10500 this.conn.request(o);
10503 callback.call(scope||this, null, arg, false);
10508 loadResponse : function(o, success, response){
10509 delete this.activeRequest;
10511 this.fireEvent("loadexception", this, o, response);
10512 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10517 result = o.reader.read(response);
10519 this.fireEvent("loadexception", this, o, response, e);
10520 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10524 this.fireEvent("load", this, o, o.request.arg);
10525 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10529 update : function(dataSet){
10534 updateResponse : function(dataSet){
10539 * Ext JS Library 1.1.1
10540 * Copyright(c) 2006-2007, Ext JS, LLC.
10542 * Originally Released Under LGPL - original licence link has changed is not relivant.
10545 * <script type="text/javascript">
10549 * @class Roo.data.ScriptTagProxy
10550 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10551 * other than the originating domain of the running page.<br><br>
10553 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
10554 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10556 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10557 * source code that is used as the source inside a <script> tag.<br><br>
10559 * In order for the browser to process the returned data, the server must wrap the data object
10560 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10561 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10562 * depending on whether the callback name was passed:
10565 boolean scriptTag = false;
10566 String cb = request.getParameter("callback");
10569 response.setContentType("text/javascript");
10571 response.setContentType("application/x-json");
10573 Writer out = response.getWriter();
10575 out.write(cb + "(");
10577 out.print(dataBlock.toJsonString());
10584 * @param {Object} config A configuration object.
10586 Roo.data.ScriptTagProxy = function(config){
10587 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10588 Roo.apply(this, config);
10589 this.head = document.getElementsByTagName("head")[0];
10592 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10594 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10596 * @cfg {String} url The URL from which to request the data object.
10599 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10603 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10604 * the server the name of the callback function set up by the load call to process the returned data object.
10605 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10606 * javascript output which calls this named function passing the data object as its only parameter.
10608 callbackParam : "callback",
10610 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10611 * name to the request.
10616 * Load data from the configured URL, read the data object into
10617 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10618 * process that block using the passed callback.
10619 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10620 * for the request to the remote server.
10621 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10622 * object into a block of Roo.data.Records.
10623 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10624 * The function must be passed <ul>
10625 * <li>The Record block object</li>
10626 * <li>The "arg" argument from the load function</li>
10627 * <li>A boolean success indicator</li>
10629 * @param {Object} scope The scope in which to call the callback
10630 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10632 load : function(params, reader, callback, scope, arg){
10633 if(this.fireEvent("beforeload", this, params) !== false){
10635 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10637 var url = this.url;
10638 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10640 url += "&_dc=" + (new Date().getTime());
10642 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10645 cb : "stcCallback"+transId,
10646 scriptId : "stcScript"+transId,
10650 callback : callback,
10656 window[trans.cb] = function(o){
10657 conn.handleResponse(o, trans);
10660 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10662 if(this.autoAbort !== false){
10666 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10668 var script = document.createElement("script");
10669 script.setAttribute("src", url);
10670 script.setAttribute("type", "text/javascript");
10671 script.setAttribute("id", trans.scriptId);
10672 this.head.appendChild(script);
10674 this.trans = trans;
10676 callback.call(scope||this, null, arg, false);
10681 isLoading : function(){
10682 return this.trans ? true : false;
10686 * Abort the current server request.
10688 abort : function(){
10689 if(this.isLoading()){
10690 this.destroyTrans(this.trans);
10695 destroyTrans : function(trans, isLoaded){
10696 this.head.removeChild(document.getElementById(trans.scriptId));
10697 clearTimeout(trans.timeoutId);
10699 window[trans.cb] = undefined;
10701 delete window[trans.cb];
10704 // if hasn't been loaded, wait for load to remove it to prevent script error
10705 window[trans.cb] = function(){
10706 window[trans.cb] = undefined;
10708 delete window[trans.cb];
10715 handleResponse : function(o, trans){
10716 this.trans = false;
10717 this.destroyTrans(trans, true);
10720 result = trans.reader.readRecords(o);
10722 this.fireEvent("loadexception", this, o, trans.arg, e);
10723 trans.callback.call(trans.scope||window, null, trans.arg, false);
10726 this.fireEvent("load", this, o, trans.arg);
10727 trans.callback.call(trans.scope||window, result, trans.arg, true);
10731 handleFailure : function(trans){
10732 this.trans = false;
10733 this.destroyTrans(trans, false);
10734 this.fireEvent("loadexception", this, null, trans.arg);
10735 trans.callback.call(trans.scope||window, null, trans.arg, false);
10739 * Ext JS Library 1.1.1
10740 * Copyright(c) 2006-2007, Ext JS, LLC.
10742 * Originally Released Under LGPL - original licence link has changed is not relivant.
10745 * <script type="text/javascript">
10749 * @class Roo.data.JsonReader
10750 * @extends Roo.data.DataReader
10751 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10752 * based on mappings in a provided Roo.data.Record constructor.
10754 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10755 * in the reply previously.
10760 var RecordDef = Roo.data.Record.create([
10761 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10762 {name: 'occupation'} // This field will use "occupation" as the mapping.
10764 var myReader = new Roo.data.JsonReader({
10765 totalProperty: "results", // The property which contains the total dataset size (optional)
10766 root: "rows", // The property which contains an Array of row objects
10767 id: "id" // The property within each row object that provides an ID for the record (optional)
10771 * This would consume a JSON file like this:
10773 { 'results': 2, 'rows': [
10774 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10775 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10778 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10779 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10780 * paged from the remote server.
10781 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10782 * @cfg {String} root name of the property which contains the Array of row objects.
10783 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10784 * @cfg {Array} fields Array of field definition objects
10786 * Create a new JsonReader
10787 * @param {Object} meta Metadata configuration options
10788 * @param {Object} recordType Either an Array of field definition objects,
10789 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10791 Roo.data.JsonReader = function(meta, recordType){
10794 // set some defaults:
10795 Roo.applyIf(meta, {
10796 totalProperty: 'total',
10797 successProperty : 'success',
10802 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10804 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10807 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10808 * Used by Store query builder to append _requestMeta to params.
10811 metaFromRemote : false,
10813 * This method is only used by a DataProxy which has retrieved data from a remote server.
10814 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10815 * @return {Object} data A data block which is used by an Roo.data.Store object as
10816 * a cache of Roo.data.Records.
10818 read : function(response){
10819 var json = response.responseText;
10821 var o = /* eval:var:o */ eval("("+json+")");
10823 throw {message: "JsonReader.read: Json object not found"};
10829 this.metaFromRemote = true;
10830 this.meta = o.metaData;
10831 this.recordType = Roo.data.Record.create(o.metaData.fields);
10832 this.onMetaChange(this.meta, this.recordType, o);
10834 return this.readRecords(o);
10837 // private function a store will implement
10838 onMetaChange : function(meta, recordType, o){
10845 simpleAccess: function(obj, subsc) {
10852 getJsonAccessor: function(){
10854 return function(expr) {
10856 return(re.test(expr))
10857 ? new Function("obj", "return obj." + expr)
10862 return Roo.emptyFn;
10867 * Create a data block containing Roo.data.Records from an XML document.
10868 * @param {Object} o An object which contains an Array of row objects in the property specified
10869 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10870 * which contains the total size of the dataset.
10871 * @return {Object} data A data block which is used by an Roo.data.Store object as
10872 * a cache of Roo.data.Records.
10874 readRecords : function(o){
10876 * After any data loads, the raw JSON data is available for further custom processing.
10880 var s = this.meta, Record = this.recordType,
10881 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10883 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10885 if(s.totalProperty) {
10886 this.getTotal = this.getJsonAccessor(s.totalProperty);
10888 if(s.successProperty) {
10889 this.getSuccess = this.getJsonAccessor(s.successProperty);
10891 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10893 var g = this.getJsonAccessor(s.id);
10894 this.getId = function(rec) {
10896 return (r === undefined || r === "") ? null : r;
10899 this.getId = function(){return null;};
10902 for(var jj = 0; jj < fl; jj++){
10904 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10905 this.ef[jj] = this.getJsonAccessor(map);
10909 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10910 if(s.totalProperty){
10911 var vt = parseInt(this.getTotal(o), 10);
10916 if(s.successProperty){
10917 var vs = this.getSuccess(o);
10918 if(vs === false || vs === 'false'){
10923 for(var i = 0; i < c; i++){
10926 var id = this.getId(n);
10927 for(var j = 0; j < fl; j++){
10929 var v = this.ef[j](n);
10931 Roo.log('missing convert for ' + f.name);
10935 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10937 var record = new Record(values, id);
10939 records[i] = record;
10945 totalRecords : totalRecords
10950 * Ext JS Library 1.1.1
10951 * Copyright(c) 2006-2007, Ext JS, LLC.
10953 * Originally Released Under LGPL - original licence link has changed is not relivant.
10956 * <script type="text/javascript">
10960 * @class Roo.data.ArrayReader
10961 * @extends Roo.data.DataReader
10962 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10963 * Each element of that Array represents a row of data fields. The
10964 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10965 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10969 var RecordDef = Roo.data.Record.create([
10970 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10971 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10973 var myReader = new Roo.data.ArrayReader({
10974 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10978 * This would consume an Array like this:
10980 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10982 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10984 * Create a new JsonReader
10985 * @param {Object} meta Metadata configuration options.
10986 * @param {Object} recordType Either an Array of field definition objects
10987 * as specified to {@link Roo.data.Record#create},
10988 * or an {@link Roo.data.Record} object
10989 * created using {@link Roo.data.Record#create}.
10991 Roo.data.ArrayReader = function(meta, recordType){
10992 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10995 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10997 * Create a data block containing Roo.data.Records from an XML document.
10998 * @param {Object} o An Array of row objects which represents the dataset.
10999 * @return {Object} data A data block which is used by an Roo.data.Store object as
11000 * a cache of Roo.data.Records.
11002 readRecords : function(o){
11003 var sid = this.meta ? this.meta.id : null;
11004 var recordType = this.recordType, fields = recordType.prototype.fields;
11007 for(var i = 0; i < root.length; i++){
11010 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11011 for(var j = 0, jlen = fields.length; j < jlen; j++){
11012 var f = fields.items[j];
11013 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11014 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11016 values[f.name] = v;
11018 var record = new recordType(values, id);
11020 records[records.length] = record;
11024 totalRecords : records.length
11033 * @class Roo.bootstrap.ComboBox
11034 * @extends Roo.bootstrap.TriggerField
11035 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11036 * @cfg {Boolean} append (true|false) default false
11037 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11038 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11039 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11040 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11041 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11042 * @cfg {Boolean} animate default true
11043 * @cfg {Boolean} emptyResultText only for touch device
11045 * Create a new ComboBox.
11046 * @param {Object} config Configuration options
11048 Roo.bootstrap.ComboBox = function(config){
11049 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11053 * Fires when the dropdown list is expanded
11054 * @param {Roo.bootstrap.ComboBox} combo This combo box
11059 * Fires when the dropdown list is collapsed
11060 * @param {Roo.bootstrap.ComboBox} combo This combo box
11064 * @event beforeselect
11065 * Fires before a list item is selected. Return false to cancel the selection.
11066 * @param {Roo.bootstrap.ComboBox} combo This combo box
11067 * @param {Roo.data.Record} record The data record returned from the underlying store
11068 * @param {Number} index The index of the selected item in the dropdown list
11070 'beforeselect' : true,
11073 * Fires when a list item is selected
11074 * @param {Roo.bootstrap.ComboBox} combo This combo box
11075 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11076 * @param {Number} index The index of the selected item in the dropdown list
11080 * @event beforequery
11081 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11082 * The event object passed has these properties:
11083 * @param {Roo.bootstrap.ComboBox} combo This combo box
11084 * @param {String} query The query
11085 * @param {Boolean} forceAll true to force "all" query
11086 * @param {Boolean} cancel true to cancel the query
11087 * @param {Object} e The query event object
11089 'beforequery': true,
11092 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11093 * @param {Roo.bootstrap.ComboBox} combo This combo box
11098 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11099 * @param {Roo.bootstrap.ComboBox} combo This combo box
11100 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11105 * Fires when the remove value from the combobox array
11106 * @param {Roo.bootstrap.ComboBox} combo This combo box
11110 * @event specialfilter
11111 * Fires when specialfilter
11112 * @param {Roo.bootstrap.ComboBox} combo This combo box
11114 'specialfilter' : true
11119 this.tickItems = [];
11121 this.selectedIndex = -1;
11122 if(this.mode == 'local'){
11123 if(config.queryDelay === undefined){
11124 this.queryDelay = 10;
11126 if(config.minChars === undefined){
11132 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11135 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11136 * rendering into an Roo.Editor, defaults to false)
11139 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11140 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11143 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11146 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11147 * the dropdown list (defaults to undefined, with no header element)
11151 * @cfg {String/Roo.Template} tpl The template to use to render the output
11155 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11157 listWidth: undefined,
11159 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11160 * mode = 'remote' or 'text' if mode = 'local')
11162 displayField: undefined,
11165 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11166 * mode = 'remote' or 'value' if mode = 'local').
11167 * Note: use of a valueField requires the user make a selection
11168 * in order for a value to be mapped.
11170 valueField: undefined,
11174 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11175 * field's data value (defaults to the underlying DOM element's name)
11177 hiddenName: undefined,
11179 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11183 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11185 selectedClass: 'active',
11188 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11192 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11193 * anchor positions (defaults to 'tl-bl')
11195 listAlign: 'tl-bl?',
11197 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11201 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11202 * query specified by the allQuery config option (defaults to 'query')
11204 triggerAction: 'query',
11206 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11207 * (defaults to 4, does not apply if editable = false)
11211 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11212 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11216 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11217 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11221 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11222 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11226 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11227 * when editable = true (defaults to false)
11229 selectOnFocus:false,
11231 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11233 queryParam: 'query',
11235 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11236 * when mode = 'remote' (defaults to 'Loading...')
11238 loadingText: 'Loading...',
11240 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11244 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11248 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11249 * traditional select (defaults to true)
11253 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11257 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11261 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11262 * listWidth has a higher value)
11266 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11267 * allow the user to set arbitrary text into the field (defaults to false)
11269 forceSelection:false,
11271 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11272 * if typeAhead = true (defaults to 250)
11274 typeAheadDelay : 250,
11276 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11277 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11279 valueNotFoundText : undefined,
11281 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11283 blockFocus : false,
11286 * @cfg {Boolean} disableClear Disable showing of clear button.
11288 disableClear : false,
11290 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11292 alwaysQuery : false,
11295 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11300 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11302 invalidClass : "has-warning",
11305 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11307 validClass : "has-success",
11310 * @cfg {Boolean} specialFilter (true|false) special filter default false
11312 specialFilter : false,
11324 btnPosition : 'right',
11325 triggerList : true,
11326 showToggleBtn : true,
11328 emptyResultText: 'Empty',
11329 // element that contains real text value.. (when hidden is used..)
11331 getAutoCreate : function()
11340 cfg = this.getAutoCreateTouchView();
11347 if(!this.tickable){
11348 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11353 * ComboBox with tickable selections
11356 var align = this.labelAlign || this.parentLabelAlign();
11359 cls : 'form-group roo-combobox-tickable' //input-group
11364 cls : 'tickable-buttons',
11369 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11376 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11383 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11390 buttons.cn.unshift({
11392 cls: 'select2-search-field-input'
11398 Roo.each(buttons.cn, function(c){
11400 c.cls += ' btn-' + _this.size;
11403 if (_this.disabled) {
11414 cls: 'form-hidden-field'
11418 cls: 'select2-choices',
11422 cls: 'select2-search-field',
11434 cls: 'select2-container input-group select2-container-multi',
11439 // cls: 'typeahead typeahead-long dropdown-menu',
11440 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11445 if(this.hasFeedback && !this.allowBlank){
11449 cls: 'glyphicon form-control-feedback'
11452 combobox.cn.push(feedback);
11455 if (align ==='left' && this.fieldLabel.length) {
11457 Roo.log("left and has label");
11463 cls : 'control-label col-sm-' + this.labelWidth,
11464 html : this.fieldLabel
11468 cls : "col-sm-" + (12 - this.labelWidth),
11475 } else if ( this.fieldLabel.length) {
11481 //cls : 'input-group-addon',
11482 html : this.fieldLabel
11492 Roo.log(" no label && no align");
11499 ['xs','sm','md','lg'].map(function(size){
11500 if (settings[size]) {
11501 cfg.cls += ' col-' + size + '-' + settings[size];
11510 initEvents: function()
11514 throw "can not find store for combo";
11517 this.store = Roo.factory(this.store, Roo.data);
11524 this.initTouchView();
11529 this.initTickableEvents();
11533 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11535 if(this.hiddenName){
11537 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11539 this.hiddenField.dom.value =
11540 this.hiddenValue !== undefined ? this.hiddenValue :
11541 this.value !== undefined ? this.value : '';
11543 // prevent input submission
11544 this.el.dom.removeAttribute('name');
11545 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11550 // this.el.dom.setAttribute('autocomplete', 'off');
11553 var cls = 'x-combo-list';
11555 //this.list = new Roo.Layer({
11556 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11562 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11563 _this.list.setWidth(lw);
11566 this.list.on('mouseover', this.onViewOver, this);
11567 this.list.on('mousemove', this.onViewMove, this);
11569 this.list.on('scroll', this.onViewScroll, this);
11572 this.list.swallowEvent('mousewheel');
11573 this.assetHeight = 0;
11576 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11577 this.assetHeight += this.header.getHeight();
11580 this.innerList = this.list.createChild({cls:cls+'-inner'});
11581 this.innerList.on('mouseover', this.onViewOver, this);
11582 this.innerList.on('mousemove', this.onViewMove, this);
11583 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11585 if(this.allowBlank && !this.pageSize && !this.disableClear){
11586 this.footer = this.list.createChild({cls:cls+'-ft'});
11587 this.pageTb = new Roo.Toolbar(this.footer);
11591 this.footer = this.list.createChild({cls:cls+'-ft'});
11592 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11593 {pageSize: this.pageSize});
11597 if (this.pageTb && this.allowBlank && !this.disableClear) {
11599 this.pageTb.add(new Roo.Toolbar.Fill(), {
11600 cls: 'x-btn-icon x-btn-clear',
11602 handler: function()
11605 _this.clearValue();
11606 _this.onSelect(false, -1);
11611 this.assetHeight += this.footer.getHeight();
11616 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11619 this.view = new Roo.View(this.list, this.tpl, {
11620 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11622 //this.view.wrapEl.setDisplayed(false);
11623 this.view.on('click', this.onViewClick, this);
11627 this.store.on('beforeload', this.onBeforeLoad, this);
11628 this.store.on('load', this.onLoad, this);
11629 this.store.on('loadexception', this.onLoadException, this);
11631 if(this.resizable){
11632 this.resizer = new Roo.Resizable(this.list, {
11633 pinned:true, handles:'se'
11635 this.resizer.on('resize', function(r, w, h){
11636 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11637 this.listWidth = w;
11638 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11639 this.restrictHeight();
11641 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11644 if(!this.editable){
11645 this.editable = true;
11646 this.setEditable(false);
11651 if (typeof(this.events.add.listeners) != 'undefined') {
11653 this.addicon = this.wrap.createChild(
11654 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11656 this.addicon.on('click', function(e) {
11657 this.fireEvent('add', this);
11660 if (typeof(this.events.edit.listeners) != 'undefined') {
11662 this.editicon = this.wrap.createChild(
11663 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11664 if (this.addicon) {
11665 this.editicon.setStyle('margin-left', '40px');
11667 this.editicon.on('click', function(e) {
11669 // we fire even if inothing is selected..
11670 this.fireEvent('edit', this, this.lastData );
11676 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11677 "up" : function(e){
11678 this.inKeyMode = true;
11682 "down" : function(e){
11683 if(!this.isExpanded()){
11684 this.onTriggerClick();
11686 this.inKeyMode = true;
11691 "enter" : function(e){
11692 // this.onViewClick();
11696 if(this.fireEvent("specialkey", this, e)){
11697 this.onViewClick(false);
11703 "esc" : function(e){
11707 "tab" : function(e){
11710 if(this.fireEvent("specialkey", this, e)){
11711 this.onViewClick(false);
11719 doRelay : function(foo, bar, hname){
11720 if(hname == 'down' || this.scope.isExpanded()){
11721 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11730 this.queryDelay = Math.max(this.queryDelay || 10,
11731 this.mode == 'local' ? 10 : 250);
11734 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11736 if(this.typeAhead){
11737 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11739 if(this.editable !== false){
11740 this.inputEl().on("keyup", this.onKeyUp, this);
11742 if(this.forceSelection){
11743 this.inputEl().on('blur', this.doForce, this);
11747 this.choices = this.el.select('ul.select2-choices', true).first();
11748 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11752 initTickableEvents: function()
11756 if(this.hiddenName){
11758 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11760 this.hiddenField.dom.value =
11761 this.hiddenValue !== undefined ? this.hiddenValue :
11762 this.value !== undefined ? this.value : '';
11764 // prevent input submission
11765 this.el.dom.removeAttribute('name');
11766 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11771 // this.list = this.el.select('ul.dropdown-menu',true).first();
11773 this.choices = this.el.select('ul.select2-choices', true).first();
11774 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11775 if(this.triggerList){
11776 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11779 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11780 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11782 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11783 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11785 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11786 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11788 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11789 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11790 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11793 this.cancelBtn.hide();
11798 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11799 _this.list.setWidth(lw);
11802 this.list.on('mouseover', this.onViewOver, this);
11803 this.list.on('mousemove', this.onViewMove, this);
11805 this.list.on('scroll', this.onViewScroll, this);
11808 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
11811 this.view = new Roo.View(this.list, this.tpl, {
11812 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11815 //this.view.wrapEl.setDisplayed(false);
11816 this.view.on('click', this.onViewClick, this);
11820 this.store.on('beforeload', this.onBeforeLoad, this);
11821 this.store.on('load', this.onLoad, this);
11822 this.store.on('loadexception', this.onLoadException, this);
11825 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11826 "up" : function(e){
11827 this.inKeyMode = true;
11831 "down" : function(e){
11832 this.inKeyMode = true;
11836 "enter" : function(e){
11837 if(this.fireEvent("specialkey", this, e)){
11838 this.onViewClick(false);
11844 "esc" : function(e){
11845 this.onTickableFooterButtonClick(e, false, false);
11848 "tab" : function(e){
11849 this.fireEvent("specialkey", this, e);
11851 this.onTickableFooterButtonClick(e, false, false);
11858 doRelay : function(e, fn, key){
11859 if(this.scope.isExpanded()){
11860 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11869 this.queryDelay = Math.max(this.queryDelay || 10,
11870 this.mode == 'local' ? 10 : 250);
11873 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11875 if(this.typeAhead){
11876 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11879 if(this.editable !== false){
11880 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11885 onDestroy : function(){
11887 this.view.setStore(null);
11888 this.view.el.removeAllListeners();
11889 this.view.el.remove();
11890 this.view.purgeListeners();
11893 this.list.dom.innerHTML = '';
11897 this.store.un('beforeload', this.onBeforeLoad, this);
11898 this.store.un('load', this.onLoad, this);
11899 this.store.un('loadexception', this.onLoadException, this);
11901 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11905 fireKey : function(e){
11906 if(e.isNavKeyPress() && !this.list.isVisible()){
11907 this.fireEvent("specialkey", this, e);
11912 onResize: function(w, h){
11913 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11915 // if(typeof w != 'number'){
11916 // // we do not handle it!?!?
11919 // var tw = this.trigger.getWidth();
11920 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11921 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11923 // this.inputEl().setWidth( this.adjustWidth('input', x));
11925 // //this.trigger.setStyle('left', x+'px');
11927 // if(this.list && this.listWidth === undefined){
11928 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11929 // this.list.setWidth(lw);
11930 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11938 * Allow or prevent the user from directly editing the field text. If false is passed,
11939 * the user will only be able to select from the items defined in the dropdown list. This method
11940 * is the runtime equivalent of setting the 'editable' config option at config time.
11941 * @param {Boolean} value True to allow the user to directly edit the field text
11943 setEditable : function(value){
11944 if(value == this.editable){
11947 this.editable = value;
11949 this.inputEl().dom.setAttribute('readOnly', true);
11950 this.inputEl().on('mousedown', this.onTriggerClick, this);
11951 this.inputEl().addClass('x-combo-noedit');
11953 this.inputEl().dom.setAttribute('readOnly', false);
11954 this.inputEl().un('mousedown', this.onTriggerClick, this);
11955 this.inputEl().removeClass('x-combo-noedit');
11961 onBeforeLoad : function(combo,opts){
11962 if(!this.hasFocus){
11966 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11968 this.restrictHeight();
11969 this.selectedIndex = -1;
11973 onLoad : function(){
11975 this.hasQuery = false;
11977 if(!this.hasFocus){
11981 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11982 this.loading.hide();
11985 if(this.store.getCount() > 0){
11987 this.restrictHeight();
11988 if(this.lastQuery == this.allQuery){
11989 if(this.editable && !this.tickable){
11990 this.inputEl().dom.select();
11994 !this.selectByValue(this.value, true) &&
11997 !this.store.lastOptions ||
11998 typeof(this.store.lastOptions.add) == 'undefined' ||
11999 this.store.lastOptions.add != true
12002 this.select(0, true);
12005 if(this.autoFocus){
12008 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12009 this.taTask.delay(this.typeAheadDelay);
12013 this.onEmptyResults();
12019 onLoadException : function()
12021 this.hasQuery = false;
12023 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12024 this.loading.hide();
12027 if(this.tickable && this.editable){
12033 Roo.log(this.store.reader.jsonData);
12034 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12036 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12042 onTypeAhead : function(){
12043 if(this.store.getCount() > 0){
12044 var r = this.store.getAt(0);
12045 var newValue = r.data[this.displayField];
12046 var len = newValue.length;
12047 var selStart = this.getRawValue().length;
12049 if(selStart != len){
12050 this.setRawValue(newValue);
12051 this.selectText(selStart, newValue.length);
12057 onSelect : function(record, index){
12059 if(this.fireEvent('beforeselect', this, record, index) !== false){
12061 this.setFromData(index > -1 ? record.data : false);
12064 this.fireEvent('select', this, record, index);
12069 * Returns the currently selected field value or empty string if no value is set.
12070 * @return {String} value The selected value
12072 getValue : function(){
12075 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12078 if(this.valueField){
12079 return typeof this.value != 'undefined' ? this.value : '';
12081 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12086 * Clears any text/value currently set in the field
12088 clearValue : function(){
12089 if(this.hiddenField){
12090 this.hiddenField.dom.value = '';
12093 this.setRawValue('');
12094 this.lastSelectionText = '';
12095 this.lastData = false;
12097 var close = this.closeTriggerEl();
12106 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12107 * will be displayed in the field. If the value does not match the data value of an existing item,
12108 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12109 * Otherwise the field will be blank (although the value will still be set).
12110 * @param {String} value The value to match
12112 setValue : function(v){
12119 if(this.valueField){
12120 var r = this.findRecord(this.valueField, v);
12122 text = r.data[this.displayField];
12123 }else if(this.valueNotFoundText !== undefined){
12124 text = this.valueNotFoundText;
12127 this.lastSelectionText = text;
12128 if(this.hiddenField){
12129 this.hiddenField.dom.value = v;
12131 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12134 var close = this.closeTriggerEl();
12137 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
12141 * @property {Object} the last set data for the element
12146 * Sets the value of the field based on a object which is related to the record format for the store.
12147 * @param {Object} value the value to set as. or false on reset?
12149 setFromData : function(o){
12156 var dv = ''; // display value
12157 var vv = ''; // value value..
12159 if (this.displayField) {
12160 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12162 // this is an error condition!!!
12163 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12166 if(this.valueField){
12167 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12170 var close = this.closeTriggerEl();
12173 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12176 if(this.hiddenField){
12177 this.hiddenField.dom.value = vv;
12179 this.lastSelectionText = dv;
12180 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12184 // no hidden field.. - we store the value in 'value', but still display
12185 // display field!!!!
12186 this.lastSelectionText = dv;
12187 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12194 reset : function(){
12195 // overridden so that last data is reset..
12202 this.setValue(this.originalValue);
12203 this.clearInvalid();
12204 this.lastData = false;
12206 this.view.clearSelections();
12210 findRecord : function(prop, value){
12212 if(this.store.getCount() > 0){
12213 this.store.each(function(r){
12214 if(r.data[prop] == value){
12224 getName: function()
12226 // returns hidden if it's set..
12227 if (!this.rendered) {return ''};
12228 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12232 onViewMove : function(e, t){
12233 this.inKeyMode = false;
12237 onViewOver : function(e, t){
12238 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12241 var item = this.view.findItemFromChild(t);
12244 var index = this.view.indexOf(item);
12245 this.select(index, false);
12250 onViewClick : function(view, doFocus, el, e)
12252 var index = this.view.getSelectedIndexes()[0];
12254 var r = this.store.getAt(index);
12258 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12265 Roo.each(this.tickItems, function(v,k){
12267 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12268 _this.tickItems.splice(k, 1);
12270 if(typeof(e) == 'undefined' && view == false){
12271 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12283 this.tickItems.push(r.data);
12285 if(typeof(e) == 'undefined' && view == false){
12286 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12293 this.onSelect(r, index);
12295 if(doFocus !== false && !this.blockFocus){
12296 this.inputEl().focus();
12301 restrictHeight : function(){
12302 //this.innerList.dom.style.height = '';
12303 //var inner = this.innerList.dom;
12304 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12305 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12306 //this.list.beginUpdate();
12307 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12308 this.list.alignTo(this.inputEl(), this.listAlign);
12309 this.list.alignTo(this.inputEl(), this.listAlign);
12310 //this.list.endUpdate();
12314 onEmptyResults : function(){
12316 if(this.tickable && this.editable){
12317 this.restrictHeight();
12325 * Returns true if the dropdown list is expanded, else false.
12327 isExpanded : function(){
12328 return this.list.isVisible();
12332 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12333 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12334 * @param {String} value The data value of the item to select
12335 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12336 * selected item if it is not currently in view (defaults to true)
12337 * @return {Boolean} True if the value matched an item in the list, else false
12339 selectByValue : function(v, scrollIntoView){
12340 if(v !== undefined && v !== null){
12341 var r = this.findRecord(this.valueField || this.displayField, v);
12343 this.select(this.store.indexOf(r), scrollIntoView);
12351 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12352 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12353 * @param {Number} index The zero-based index of the list item to select
12354 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12355 * selected item if it is not currently in view (defaults to true)
12357 select : function(index, scrollIntoView){
12358 this.selectedIndex = index;
12359 this.view.select(index);
12360 if(scrollIntoView !== false){
12361 var el = this.view.getNode(index);
12363 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12366 this.list.scrollChildIntoView(el, false);
12372 selectNext : function(){
12373 var ct = this.store.getCount();
12375 if(this.selectedIndex == -1){
12377 }else if(this.selectedIndex < ct-1){
12378 this.select(this.selectedIndex+1);
12384 selectPrev : function(){
12385 var ct = this.store.getCount();
12387 if(this.selectedIndex == -1){
12389 }else if(this.selectedIndex != 0){
12390 this.select(this.selectedIndex-1);
12396 onKeyUp : function(e){
12397 if(this.editable !== false && !e.isSpecialKey()){
12398 this.lastKey = e.getKey();
12399 this.dqTask.delay(this.queryDelay);
12404 validateBlur : function(){
12405 return !this.list || !this.list.isVisible();
12409 initQuery : function(){
12411 var v = this.getRawValue();
12413 if(this.tickable && this.editable){
12414 v = this.tickableInputEl().getValue();
12421 doForce : function(){
12422 if(this.inputEl().dom.value.length > 0){
12423 this.inputEl().dom.value =
12424 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12430 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12431 * query allowing the query action to be canceled if needed.
12432 * @param {String} query The SQL query to execute
12433 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12434 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12435 * saved in the current store (defaults to false)
12437 doQuery : function(q, forceAll){
12439 if(q === undefined || q === null){
12444 forceAll: forceAll,
12448 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12453 forceAll = qe.forceAll;
12454 if(forceAll === true || (q.length >= this.minChars)){
12456 this.hasQuery = true;
12458 if(this.lastQuery != q || this.alwaysQuery){
12459 this.lastQuery = q;
12460 if(this.mode == 'local'){
12461 this.selectedIndex = -1;
12463 this.store.clearFilter();
12466 if(this.specialFilter){
12467 this.fireEvent('specialfilter', this);
12472 this.store.filter(this.displayField, q);
12475 this.store.fireEvent("datachanged", this.store);
12482 this.store.baseParams[this.queryParam] = q;
12484 var options = {params : this.getParams(q)};
12487 options.add = true;
12488 options.params.start = this.page * this.pageSize;
12491 this.store.load(options);
12494 * this code will make the page width larger, at the beginning, the list not align correctly,
12495 * we should expand the list on onLoad
12496 * so command out it
12501 this.selectedIndex = -1;
12506 this.loadNext = false;
12510 getParams : function(q){
12512 //p[this.queryParam] = q;
12516 p.limit = this.pageSize;
12522 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12524 collapse : function(){
12525 if(!this.isExpanded()){
12532 this.hasFocus = false;
12534 this.cancelBtn.hide();
12535 this.trigger.show();
12538 this.tickableInputEl().dom.value = '';
12539 this.tickableInputEl().blur();
12544 Roo.get(document).un('mousedown', this.collapseIf, this);
12545 Roo.get(document).un('mousewheel', this.collapseIf, this);
12546 if (!this.editable) {
12547 Roo.get(document).un('keydown', this.listKeyPress, this);
12549 this.fireEvent('collapse', this);
12553 collapseIf : function(e){
12554 var in_combo = e.within(this.el);
12555 var in_list = e.within(this.list);
12556 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12558 if (in_combo || in_list || is_list) {
12559 //e.stopPropagation();
12564 this.onTickableFooterButtonClick(e, false, false);
12572 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12574 expand : function(){
12576 if(this.isExpanded() || !this.hasFocus){
12580 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12581 this.list.setWidth(lw);
12588 this.restrictHeight();
12592 this.tickItems = Roo.apply([], this.item);
12595 this.cancelBtn.show();
12596 this.trigger.hide();
12599 this.tickableInputEl().focus();
12604 Roo.get(document).on('mousedown', this.collapseIf, this);
12605 Roo.get(document).on('mousewheel', this.collapseIf, this);
12606 if (!this.editable) {
12607 Roo.get(document).on('keydown', this.listKeyPress, this);
12610 this.fireEvent('expand', this);
12614 // Implements the default empty TriggerField.onTriggerClick function
12615 onTriggerClick : function(e)
12617 Roo.log('trigger click');
12619 if(this.disabled || !this.triggerList){
12624 this.loadNext = false;
12626 if(this.isExpanded()){
12628 if (!this.blockFocus) {
12629 this.inputEl().focus();
12633 this.hasFocus = true;
12634 if(this.triggerAction == 'all') {
12635 this.doQuery(this.allQuery, true);
12637 this.doQuery(this.getRawValue());
12639 if (!this.blockFocus) {
12640 this.inputEl().focus();
12645 onTickableTriggerClick : function(e)
12652 this.loadNext = false;
12653 this.hasFocus = true;
12655 if(this.triggerAction == 'all') {
12656 this.doQuery(this.allQuery, true);
12658 this.doQuery(this.getRawValue());
12662 onSearchFieldClick : function(e)
12664 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12665 this.onTickableFooterButtonClick(e, false, false);
12669 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12674 this.loadNext = false;
12675 this.hasFocus = true;
12677 if(this.triggerAction == 'all') {
12678 this.doQuery(this.allQuery, true);
12680 this.doQuery(this.getRawValue());
12684 listKeyPress : function(e)
12686 //Roo.log('listkeypress');
12687 // scroll to first matching element based on key pres..
12688 if (e.isSpecialKey()) {
12691 var k = String.fromCharCode(e.getKey()).toUpperCase();
12694 var csel = this.view.getSelectedNodes();
12695 var cselitem = false;
12697 var ix = this.view.indexOf(csel[0]);
12698 cselitem = this.store.getAt(ix);
12699 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12705 this.store.each(function(v) {
12707 // start at existing selection.
12708 if (cselitem.id == v.id) {
12714 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12715 match = this.store.indexOf(v);
12721 if (match === false) {
12722 return true; // no more action?
12725 this.view.select(match);
12726 var sn = Roo.get(this.view.getSelectedNodes()[0])
12727 sn.scrollIntoView(sn.dom.parentNode, false);
12730 onViewScroll : function(e, t){
12732 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
12736 this.hasQuery = true;
12738 this.loading = this.list.select('.loading', true).first();
12740 if(this.loading === null){
12741 this.list.createChild({
12743 cls: 'loading select2-more-results select2-active',
12744 html: 'Loading more results...'
12747 this.loading = this.list.select('.loading', true).first();
12749 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12751 this.loading.hide();
12754 this.loading.show();
12759 this.loadNext = true;
12761 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12766 addItem : function(o)
12768 var dv = ''; // display value
12770 if (this.displayField) {
12771 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12773 // this is an error condition!!!
12774 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12781 var choice = this.choices.createChild({
12783 cls: 'select2-search-choice',
12792 cls: 'select2-search-choice-close',
12797 }, this.searchField);
12799 var close = choice.select('a.select2-search-choice-close', true).first()
12801 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12809 this.inputEl().dom.value = '';
12814 onRemoveItem : function(e, _self, o)
12816 e.preventDefault();
12818 this.lastItem = Roo.apply([], this.item);
12820 var index = this.item.indexOf(o.data) * 1;
12823 Roo.log('not this item?!');
12827 this.item.splice(index, 1);
12832 this.fireEvent('remove', this, e);
12838 syncValue : function()
12840 if(!this.item.length){
12847 Roo.each(this.item, function(i){
12848 if(_this.valueField){
12849 value.push(i[_this.valueField]);
12856 this.value = value.join(',');
12858 if(this.hiddenField){
12859 this.hiddenField.dom.value = this.value;
12862 this.store.fireEvent("datachanged", this.store);
12865 clearItem : function()
12867 if(!this.multiple){
12873 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12882 inputEl: function ()
12884 if(this.tickable && !Roo.isTouch){
12885 return this.searchField;
12887 return this.el.select('input.form-control',true).first();
12891 onTickableFooterButtonClick : function(e, btn, el)
12893 e.preventDefault();
12895 this.lastItem = Roo.apply([], this.item);
12897 if(btn && btn.name == 'cancel'){
12898 this.tickItems = Roo.apply([], this.item);
12907 Roo.each(this.tickItems, function(o){
12915 validate : function()
12917 var v = this.getRawValue();
12920 v = this.getValue();
12923 if(this.disabled || this.allowBlank || v.length){
12928 this.markInvalid();
12932 tickableInputEl : function()
12934 if(!this.tickable || !this.editable){
12935 return this.inputEl();
12938 return this.inputEl().select('.select2-search-field-input', true).first();
12942 getAutoCreateTouchView : function()
12947 cls: 'form-group' //input-group
12953 type : this.inputType,
12954 cls : 'form-control x-combo-noedit',
12955 autocomplete: 'new-password',
12956 placeholder : this.placeholder || '',
12961 input.name = this.name;
12965 input.cls += ' input-' + this.size;
12968 if (this.disabled) {
12969 input.disabled = true;
12980 inputblock.cls += ' input-group';
12982 inputblock.cn.unshift({
12984 cls : 'input-group-addon',
12989 if(this.removable && !this.multiple){
12990 inputblock.cls += ' roo-removable';
12992 inputblock.cn.push({
12995 cls : 'roo-combo-removable-btn close'
12999 if(this.hasFeedback && !this.allowBlank){
13001 inputblock.cls += ' has-feedback';
13003 inputblock.cn.push({
13005 cls: 'glyphicon form-control-feedback'
13012 inputblock.cls += (this.before) ? '' : ' input-group';
13014 inputblock.cn.push({
13016 cls : 'input-group-addon',
13027 cls: 'form-hidden-field'
13041 cls: 'form-hidden-field'
13045 cls: 'select2-choices',
13049 cls: 'select2-search-field',
13062 cls: 'select2-container input-group',
13069 combobox.cls += ' select2-container-multi';
13072 var align = this.labelAlign || this.parentLabelAlign();
13076 if(this.fieldLabel.length){
13078 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13079 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13084 cls : 'control-label ' + lw,
13085 html : this.fieldLabel
13097 var settings = this;
13099 ['xs','sm','md','lg'].map(function(size){
13100 if (settings[size]) {
13101 cfg.cls += ' col-' + size + '-' + settings[size];
13108 initTouchView : function()
13110 this.renderTouchView();
13112 this.inputEl().on("click", this.showTouchView, this);
13113 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13114 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13116 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13118 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13119 this.store.on('load', this.onTouchViewLoad, this);
13120 this.store.on('loadexception', this.onTouchViewLoadException, this);
13122 if(this.hiddenName){
13124 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13126 this.hiddenField.dom.value =
13127 this.hiddenValue !== undefined ? this.hiddenValue :
13128 this.value !== undefined ? this.value : '';
13130 this.el.dom.removeAttribute('name');
13131 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13135 this.choices = this.el.select('ul.select2-choices', true).first();
13136 this.searchField = this.el.select('ul li.select2-search-field', true).first();
13139 if(this.removable && !this.multiple){
13140 var close = this.closeTriggerEl();
13143 close.setVisibilityMode(Roo.Element.DISPALY).hide();
13144 close.on('click', this.removeBtnClick, this, close);
13153 renderTouchView : function()
13155 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13156 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13158 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13159 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13161 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13162 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13163 this.touchViewBodyEl.setStyle('overflow', 'auto');
13165 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13166 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13168 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13169 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13173 showTouchView : function()
13175 this.touchViewHeaderEl.hide();
13177 if(this.fieldLabel.length){
13178 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
13179 this.touchViewHeaderEl.show();
13182 this.touchViewEl.show();
13184 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
13185 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13187 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
13189 if(this.fieldLabel.length){
13190 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
13193 this.touchViewBodyEl.setHeight(bodyHeight);
13197 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
13199 this.touchViewEl.addClass('in');
13202 this.doTouchViewQuery();
13206 hideTouchView : function()
13208 this.touchViewEl.removeClass('in');
13212 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
13214 this.touchViewEl.setStyle('display', 'none');
13219 setTouchViewValue : function()
13226 Roo.each(this.tickItems, function(o){
13231 this.hideTouchView();
13234 doTouchViewQuery : function()
13236 Roo.log('doTouchViewQuery');
13245 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
13249 if(!this.alwaysQuery || this.mode == 'local'){
13250 this.onTouchViewLoad();
13257 onTouchViewBeforeLoad : function(combo,opts)
13259 Roo.log('onTouchViewBeforeLoad');
13265 onTouchViewLoad : function()
13267 Roo.log('onTouchViewLoad');
13269 if(this.store.getCount() < 1){
13270 this.onTouchViewEmptyResults();
13274 this.clearTouchView();
13276 var rawValue = this.getRawValue();
13278 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
13280 this.tickItems = [];
13282 this.store.data.each(function(d, rowIndex){
13283 var row = this.touchViewListGroup.createChild(template);
13285 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
13286 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = d.data[this.displayField];
13289 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
13290 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13293 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
13294 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13295 this.tickItems.push(d.data);
13298 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
13302 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
13305 firstChecked.findParent('li').scrollIntoView(this.touchViewListGroup.dom);
13310 onTouchViewLoadException : function()
13312 Roo.log('onTouchViewLoadException');
13314 this.hideTouchView();
13317 onTouchViewEmptyResults : function()
13319 Roo.log('onTouchViewEmptyResults');
13321 this.clearTouchView();
13323 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
13325 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
13329 clearTouchView : function()
13331 this.touchViewListGroup.dom.innerHTML = '';
13334 onTouchViewClick : function(e, el, o)
13336 e.preventDefault();
13339 var rowIndex = o.rowIndex;
13341 var r = this.store.getAt(rowIndex);
13343 if(!this.multiple){
13344 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
13345 c.dom.removeAttribute('checked');
13348 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13350 this.setFromData(r.data);
13352 var close = this.closeTriggerEl();
13358 this.hideTouchView();
13363 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
13364 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
13365 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
13369 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13370 this.addItem(r.data);
13371 this.tickItems.push(r.data);
13379 * @cfg {Boolean} grow
13383 * @cfg {Number} growMin
13387 * @cfg {Number} growMax
13396 Roo.apply(Roo.bootstrap.ComboBox, {
13400 cls: 'modal-header',
13422 cls: 'list-group-item',
13426 cls: 'roo-combobox-list-group-item-value'
13430 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
13444 listItemCheckbox : {
13446 cls: 'list-group-item',
13450 cls: 'roo-combobox-list-group-item-value'
13454 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
13470 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
13475 cls: 'modal-footer',
13483 cls: 'col-xs-6 text-left',
13486 cls: 'btn btn-danger roo-touch-view-cancel',
13492 cls: 'col-xs-6 text-right',
13495 cls: 'btn btn-success roo-touch-view-ok',
13506 Roo.apply(Roo.bootstrap.ComboBox, {
13508 touchViewTemplate : {
13510 cls: 'modal fade roo-combobox-touch-view',
13514 cls: 'modal-dialog',
13518 cls: 'modal-content',
13520 Roo.bootstrap.ComboBox.header,
13521 Roo.bootstrap.ComboBox.body,
13522 Roo.bootstrap.ComboBox.footer
13531 * Ext JS Library 1.1.1
13532 * Copyright(c) 2006-2007, Ext JS, LLC.
13534 * Originally Released Under LGPL - original licence link has changed is not relivant.
13537 * <script type="text/javascript">
13542 * @extends Roo.util.Observable
13543 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
13544 * This class also supports single and multi selection modes. <br>
13545 * Create a data model bound view:
13547 var store = new Roo.data.Store(...);
13549 var view = new Roo.View({
13551 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
13553 singleSelect: true,
13554 selectedClass: "ydataview-selected",
13558 // listen for node click?
13559 view.on("click", function(vw, index, node, e){
13560 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
13564 dataModel.load("foobar.xml");
13566 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
13568 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
13569 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
13571 * Note: old style constructor is still suported (container, template, config)
13574 * Create a new View
13575 * @param {Object} config The config object
13578 Roo.View = function(config, depreciated_tpl, depreciated_config){
13580 this.parent = false;
13582 if (typeof(depreciated_tpl) == 'undefined') {
13583 // new way.. - universal constructor.
13584 Roo.apply(this, config);
13585 this.el = Roo.get(this.el);
13588 this.el = Roo.get(config);
13589 this.tpl = depreciated_tpl;
13590 Roo.apply(this, depreciated_config);
13592 this.wrapEl = this.el.wrap().wrap();
13593 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
13596 if(typeof(this.tpl) == "string"){
13597 this.tpl = new Roo.Template(this.tpl);
13599 // support xtype ctors..
13600 this.tpl = new Roo.factory(this.tpl, Roo);
13604 this.tpl.compile();
13609 * @event beforeclick
13610 * Fires before a click is processed. Returns false to cancel the default action.
13611 * @param {Roo.View} this
13612 * @param {Number} index The index of the target node
13613 * @param {HTMLElement} node The target node
13614 * @param {Roo.EventObject} e The raw event object
13616 "beforeclick" : true,
13619 * Fires when a template node is clicked.
13620 * @param {Roo.View} this
13621 * @param {Number} index The index of the target node
13622 * @param {HTMLElement} node The target node
13623 * @param {Roo.EventObject} e The raw event object
13628 * Fires when a template node is double clicked.
13629 * @param {Roo.View} this
13630 * @param {Number} index The index of the target node
13631 * @param {HTMLElement} node The target node
13632 * @param {Roo.EventObject} e The raw event object
13636 * @event contextmenu
13637 * Fires when a template node is right clicked.
13638 * @param {Roo.View} this
13639 * @param {Number} index The index of the target node
13640 * @param {HTMLElement} node The target node
13641 * @param {Roo.EventObject} e The raw event object
13643 "contextmenu" : true,
13645 * @event selectionchange
13646 * Fires when the selected nodes change.
13647 * @param {Roo.View} this
13648 * @param {Array} selections Array of the selected nodes
13650 "selectionchange" : true,
13653 * @event beforeselect
13654 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
13655 * @param {Roo.View} this
13656 * @param {HTMLElement} node The node to be selected
13657 * @param {Array} selections Array of currently selected nodes
13659 "beforeselect" : true,
13661 * @event preparedata
13662 * Fires on every row to render, to allow you to change the data.
13663 * @param {Roo.View} this
13664 * @param {Object} data to be rendered (change this)
13666 "preparedata" : true
13674 "click": this.onClick,
13675 "dblclick": this.onDblClick,
13676 "contextmenu": this.onContextMenu,
13680 this.selections = [];
13682 this.cmp = new Roo.CompositeElementLite([]);
13684 this.store = Roo.factory(this.store, Roo.data);
13685 this.setStore(this.store, true);
13688 if ( this.footer && this.footer.xtype) {
13690 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13692 this.footer.dataSource = this.store
13693 this.footer.container = fctr;
13694 this.footer = Roo.factory(this.footer, Roo);
13695 fctr.insertFirst(this.el);
13697 // this is a bit insane - as the paging toolbar seems to detach the el..
13698 // dom.parentNode.parentNode.parentNode
13699 // they get detached?
13703 Roo.View.superclass.constructor.call(this);
13708 Roo.extend(Roo.View, Roo.util.Observable, {
13711 * @cfg {Roo.data.Store} store Data store to load data from.
13716 * @cfg {String|Roo.Element} el The container element.
13721 * @cfg {String|Roo.Template} tpl The template used by this View
13725 * @cfg {String} dataName the named area of the template to use as the data area
13726 * Works with domtemplates roo-name="name"
13730 * @cfg {String} selectedClass The css class to add to selected nodes
13732 selectedClass : "x-view-selected",
13734 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13739 * @cfg {String} text to display on mask (default Loading)
13743 * @cfg {Boolean} multiSelect Allow multiple selection
13745 multiSelect : false,
13747 * @cfg {Boolean} singleSelect Allow single selection
13749 singleSelect: false,
13752 * @cfg {Boolean} toggleSelect - selecting
13754 toggleSelect : false,
13757 * @cfg {Boolean} tickable - selecting
13762 * Returns the element this view is bound to.
13763 * @return {Roo.Element}
13765 getEl : function(){
13766 return this.wrapEl;
13772 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13774 refresh : function(){
13775 //Roo.log('refresh');
13778 // if we are using something like 'domtemplate', then
13779 // the what gets used is:
13780 // t.applySubtemplate(NAME, data, wrapping data..)
13781 // the outer template then get' applied with
13782 // the store 'extra data'
13783 // and the body get's added to the
13784 // roo-name="data" node?
13785 // <span class='roo-tpl-{name}'></span> ?????
13789 this.clearSelections();
13790 this.el.update("");
13792 var records = this.store.getRange();
13793 if(records.length < 1) {
13795 // is this valid?? = should it render a template??
13797 this.el.update(this.emptyText);
13801 if (this.dataName) {
13802 this.el.update(t.apply(this.store.meta)); //????
13803 el = this.el.child('.roo-tpl-' + this.dataName);
13806 for(var i = 0, len = records.length; i < len; i++){
13807 var data = this.prepareData(records[i].data, i, records[i]);
13808 this.fireEvent("preparedata", this, data, i, records[i]);
13810 var d = Roo.apply({}, data);
13813 Roo.apply(d, {'roo-id' : Roo.id()});
13817 Roo.each(this.parent.item, function(item){
13818 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13821 Roo.apply(d, {'roo-data-checked' : 'checked'});
13825 html[html.length] = Roo.util.Format.trim(
13827 t.applySubtemplate(this.dataName, d, this.store.meta) :
13834 el.update(html.join(""));
13835 this.nodes = el.dom.childNodes;
13836 this.updateIndexes(0);
13841 * Function to override to reformat the data that is sent to
13842 * the template for each node.
13843 * DEPRICATED - use the preparedata event handler.
13844 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13845 * a JSON object for an UpdateManager bound view).
13847 prepareData : function(data, index, record)
13849 this.fireEvent("preparedata", this, data, index, record);
13853 onUpdate : function(ds, record){
13854 // Roo.log('on update');
13855 this.clearSelections();
13856 var index = this.store.indexOf(record);
13857 var n = this.nodes[index];
13858 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13859 n.parentNode.removeChild(n);
13860 this.updateIndexes(index, index);
13866 onAdd : function(ds, records, index)
13868 //Roo.log(['on Add', ds, records, index] );
13869 this.clearSelections();
13870 if(this.nodes.length == 0){
13874 var n = this.nodes[index];
13875 for(var i = 0, len = records.length; i < len; i++){
13876 var d = this.prepareData(records[i].data, i, records[i]);
13878 this.tpl.insertBefore(n, d);
13881 this.tpl.append(this.el, d);
13884 this.updateIndexes(index);
13887 onRemove : function(ds, record, index){
13888 // Roo.log('onRemove');
13889 this.clearSelections();
13890 var el = this.dataName ?
13891 this.el.child('.roo-tpl-' + this.dataName) :
13894 el.dom.removeChild(this.nodes[index]);
13895 this.updateIndexes(index);
13899 * Refresh an individual node.
13900 * @param {Number} index
13902 refreshNode : function(index){
13903 this.onUpdate(this.store, this.store.getAt(index));
13906 updateIndexes : function(startIndex, endIndex){
13907 var ns = this.nodes;
13908 startIndex = startIndex || 0;
13909 endIndex = endIndex || ns.length - 1;
13910 for(var i = startIndex; i <= endIndex; i++){
13911 ns[i].nodeIndex = i;
13916 * Changes the data store this view uses and refresh the view.
13917 * @param {Store} store
13919 setStore : function(store, initial){
13920 if(!initial && this.store){
13921 this.store.un("datachanged", this.refresh);
13922 this.store.un("add", this.onAdd);
13923 this.store.un("remove", this.onRemove);
13924 this.store.un("update", this.onUpdate);
13925 this.store.un("clear", this.refresh);
13926 this.store.un("beforeload", this.onBeforeLoad);
13927 this.store.un("load", this.onLoad);
13928 this.store.un("loadexception", this.onLoad);
13932 store.on("datachanged", this.refresh, this);
13933 store.on("add", this.onAdd, this);
13934 store.on("remove", this.onRemove, this);
13935 store.on("update", this.onUpdate, this);
13936 store.on("clear", this.refresh, this);
13937 store.on("beforeload", this.onBeforeLoad, this);
13938 store.on("load", this.onLoad, this);
13939 store.on("loadexception", this.onLoad, this);
13947 * onbeforeLoad - masks the loading area.
13950 onBeforeLoad : function(store,opts)
13952 //Roo.log('onBeforeLoad');
13954 this.el.update("");
13956 this.el.mask(this.mask ? this.mask : "Loading" );
13958 onLoad : function ()
13965 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13966 * @param {HTMLElement} node
13967 * @return {HTMLElement} The template node
13969 findItemFromChild : function(node){
13970 var el = this.dataName ?
13971 this.el.child('.roo-tpl-' + this.dataName,true) :
13974 if(!node || node.parentNode == el){
13977 var p = node.parentNode;
13978 while(p && p != el){
13979 if(p.parentNode == el){
13988 onClick : function(e){
13989 var item = this.findItemFromChild(e.getTarget());
13991 var index = this.indexOf(item);
13992 if(this.onItemClick(item, index, e) !== false){
13993 this.fireEvent("click", this, index, item, e);
13996 this.clearSelections();
14001 onContextMenu : function(e){
14002 var item = this.findItemFromChild(e.getTarget());
14004 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
14009 onDblClick : function(e){
14010 var item = this.findItemFromChild(e.getTarget());
14012 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
14016 onItemClick : function(item, index, e)
14018 if(this.fireEvent("beforeclick", this, index, item, e) === false){
14021 if (this.toggleSelect) {
14022 var m = this.isSelected(item) ? 'unselect' : 'select';
14025 _t[m](item, true, false);
14028 if(this.multiSelect || this.singleSelect){
14029 if(this.multiSelect && e.shiftKey && this.lastSelection){
14030 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
14032 this.select(item, this.multiSelect && e.ctrlKey);
14033 this.lastSelection = item;
14036 if(!this.tickable){
14037 e.preventDefault();
14045 * Get the number of selected nodes.
14048 getSelectionCount : function(){
14049 return this.selections.length;
14053 * Get the currently selected nodes.
14054 * @return {Array} An array of HTMLElements
14056 getSelectedNodes : function(){
14057 return this.selections;
14061 * Get the indexes of the selected nodes.
14064 getSelectedIndexes : function(){
14065 var indexes = [], s = this.selections;
14066 for(var i = 0, len = s.length; i < len; i++){
14067 indexes.push(s[i].nodeIndex);
14073 * Clear all selections
14074 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
14076 clearSelections : function(suppressEvent){
14077 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
14078 this.cmp.elements = this.selections;
14079 this.cmp.removeClass(this.selectedClass);
14080 this.selections = [];
14081 if(!suppressEvent){
14082 this.fireEvent("selectionchange", this, this.selections);
14088 * Returns true if the passed node is selected
14089 * @param {HTMLElement/Number} node The node or node index
14090 * @return {Boolean}
14092 isSelected : function(node){
14093 var s = this.selections;
14097 node = this.getNode(node);
14098 return s.indexOf(node) !== -1;
14103 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
14104 * @param {Boolean} keepExisting (optional) true to keep existing selections
14105 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14107 select : function(nodeInfo, keepExisting, suppressEvent){
14108 if(nodeInfo instanceof Array){
14110 this.clearSelections(true);
14112 for(var i = 0, len = nodeInfo.length; i < len; i++){
14113 this.select(nodeInfo[i], true, true);
14117 var node = this.getNode(nodeInfo);
14118 if(!node || this.isSelected(node)){
14119 return; // already selected.
14122 this.clearSelections(true);
14125 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
14126 Roo.fly(node).addClass(this.selectedClass);
14127 this.selections.push(node);
14128 if(!suppressEvent){
14129 this.fireEvent("selectionchange", this, this.selections);
14137 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
14138 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
14139 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14141 unselect : function(nodeInfo, keepExisting, suppressEvent)
14143 if(nodeInfo instanceof Array){
14144 Roo.each(this.selections, function(s) {
14145 this.unselect(s, nodeInfo);
14149 var node = this.getNode(nodeInfo);
14150 if(!node || !this.isSelected(node)){
14151 //Roo.log("not selected");
14152 return; // not selected.
14156 Roo.each(this.selections, function(s) {
14158 Roo.fly(node).removeClass(this.selectedClass);
14165 this.selections= ns;
14166 this.fireEvent("selectionchange", this, this.selections);
14170 * Gets a template node.
14171 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14172 * @return {HTMLElement} The node or null if it wasn't found
14174 getNode : function(nodeInfo){
14175 if(typeof nodeInfo == "string"){
14176 return document.getElementById(nodeInfo);
14177 }else if(typeof nodeInfo == "number"){
14178 return this.nodes[nodeInfo];
14184 * Gets a range template nodes.
14185 * @param {Number} startIndex
14186 * @param {Number} endIndex
14187 * @return {Array} An array of nodes
14189 getNodes : function(start, end){
14190 var ns = this.nodes;
14191 start = start || 0;
14192 end = typeof end == "undefined" ? ns.length - 1 : end;
14195 for(var i = start; i <= end; i++){
14199 for(var i = start; i >= end; i--){
14207 * Finds the index of the passed node
14208 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14209 * @return {Number} The index of the node or -1
14211 indexOf : function(node){
14212 node = this.getNode(node);
14213 if(typeof node.nodeIndex == "number"){
14214 return node.nodeIndex;
14216 var ns = this.nodes;
14217 for(var i = 0, len = ns.length; i < len; i++){
14228 * based on jquery fullcalendar
14232 Roo.bootstrap = Roo.bootstrap || {};
14234 * @class Roo.bootstrap.Calendar
14235 * @extends Roo.bootstrap.Component
14236 * Bootstrap Calendar class
14237 * @cfg {Boolean} loadMask (true|false) default false
14238 * @cfg {Object} header generate the user specific header of the calendar, default false
14241 * Create a new Container
14242 * @param {Object} config The config object
14247 Roo.bootstrap.Calendar = function(config){
14248 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
14252 * Fires when a date is selected
14253 * @param {DatePicker} this
14254 * @param {Date} date The selected date
14258 * @event monthchange
14259 * Fires when the displayed month changes
14260 * @param {DatePicker} this
14261 * @param {Date} date The selected month
14263 'monthchange': true,
14265 * @event evententer
14266 * Fires when mouse over an event
14267 * @param {Calendar} this
14268 * @param {event} Event
14270 'evententer': true,
14272 * @event eventleave
14273 * Fires when the mouse leaves an
14274 * @param {Calendar} this
14277 'eventleave': true,
14279 * @event eventclick
14280 * Fires when the mouse click an
14281 * @param {Calendar} this
14290 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
14293 * @cfg {Number} startDay
14294 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
14302 getAutoCreate : function(){
14305 var fc_button = function(name, corner, style, content ) {
14306 return Roo.apply({},{
14308 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
14310 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
14313 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
14324 style : 'width:100%',
14331 cls : 'fc-header-left',
14333 fc_button('prev', 'left', 'arrow', '‹' ),
14334 fc_button('next', 'right', 'arrow', '›' ),
14335 { tag: 'span', cls: 'fc-header-space' },
14336 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
14344 cls : 'fc-header-center',
14348 cls: 'fc-header-title',
14351 html : 'month / year'
14359 cls : 'fc-header-right',
14361 /* fc_button('month', 'left', '', 'month' ),
14362 fc_button('week', '', '', 'week' ),
14363 fc_button('day', 'right', '', 'day' )
14375 header = this.header;
14378 var cal_heads = function() {
14380 // fixme - handle this.
14382 for (var i =0; i < Date.dayNames.length; i++) {
14383 var d = Date.dayNames[i];
14386 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
14387 html : d.substring(0,3)
14391 ret[0].cls += ' fc-first';
14392 ret[6].cls += ' fc-last';
14395 var cal_cell = function(n) {
14398 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
14403 cls: 'fc-day-number',
14407 cls: 'fc-day-content',
14411 style: 'position: relative;' // height: 17px;
14423 var cal_rows = function() {
14426 for (var r = 0; r < 6; r++) {
14433 for (var i =0; i < Date.dayNames.length; i++) {
14434 var d = Date.dayNames[i];
14435 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
14438 row.cn[0].cls+=' fc-first';
14439 row.cn[0].cn[0].style = 'min-height:90px';
14440 row.cn[6].cls+=' fc-last';
14444 ret[0].cls += ' fc-first';
14445 ret[4].cls += ' fc-prev-last';
14446 ret[5].cls += ' fc-last';
14453 cls: 'fc-border-separate',
14454 style : 'width:100%',
14462 cls : 'fc-first fc-last',
14480 cls : 'fc-content',
14481 style : "position: relative;",
14484 cls : 'fc-view fc-view-month fc-grid',
14485 style : 'position: relative',
14486 unselectable : 'on',
14489 cls : 'fc-event-container',
14490 style : 'position:absolute;z-index:8;top:0;left:0;'
14508 initEvents : function()
14511 throw "can not find store for calendar";
14517 style: "text-align:center",
14521 style: "background-color:white;width:50%;margin:250 auto",
14525 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
14536 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
14538 var size = this.el.select('.fc-content', true).first().getSize();
14539 this.maskEl.setSize(size.width, size.height);
14540 this.maskEl.enableDisplayMode("block");
14541 if(!this.loadMask){
14542 this.maskEl.hide();
14545 this.store = Roo.factory(this.store, Roo.data);
14546 this.store.on('load', this.onLoad, this);
14547 this.store.on('beforeload', this.onBeforeLoad, this);
14551 this.cells = this.el.select('.fc-day',true);
14552 //Roo.log(this.cells);
14553 this.textNodes = this.el.query('.fc-day-number');
14554 this.cells.addClassOnOver('fc-state-hover');
14556 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
14557 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
14558 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
14559 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
14561 this.on('monthchange', this.onMonthChange, this);
14563 this.update(new Date().clearTime());
14566 resize : function() {
14567 var sz = this.el.getSize();
14569 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
14570 this.el.select('.fc-day-content div',true).setHeight(34);
14575 showPrevMonth : function(e){
14576 this.update(this.activeDate.add("mo", -1));
14578 showToday : function(e){
14579 this.update(new Date().clearTime());
14582 showNextMonth : function(e){
14583 this.update(this.activeDate.add("mo", 1));
14587 showPrevYear : function(){
14588 this.update(this.activeDate.add("y", -1));
14592 showNextYear : function(){
14593 this.update(this.activeDate.add("y", 1));
14598 update : function(date)
14600 var vd = this.activeDate;
14601 this.activeDate = date;
14602 // if(vd && this.el){
14603 // var t = date.getTime();
14604 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
14605 // Roo.log('using add remove');
14607 // this.fireEvent('monthchange', this, date);
14609 // this.cells.removeClass("fc-state-highlight");
14610 // this.cells.each(function(c){
14611 // if(c.dateValue == t){
14612 // c.addClass("fc-state-highlight");
14613 // setTimeout(function(){
14614 // try{c.dom.firstChild.focus();}catch(e){}
14624 var days = date.getDaysInMonth();
14626 var firstOfMonth = date.getFirstDateOfMonth();
14627 var startingPos = firstOfMonth.getDay()-this.startDay;
14629 if(startingPos < this.startDay){
14633 var pm = date.add(Date.MONTH, -1);
14634 var prevStart = pm.getDaysInMonth()-startingPos;
14636 this.cells = this.el.select('.fc-day',true);
14637 this.textNodes = this.el.query('.fc-day-number');
14638 this.cells.addClassOnOver('fc-state-hover');
14640 var cells = this.cells.elements;
14641 var textEls = this.textNodes;
14643 Roo.each(cells, function(cell){
14644 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
14647 days += startingPos;
14649 // convert everything to numbers so it's fast
14650 var day = 86400000;
14651 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
14654 //Roo.log(prevStart);
14656 var today = new Date().clearTime().getTime();
14657 var sel = date.clearTime().getTime();
14658 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
14659 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
14660 var ddMatch = this.disabledDatesRE;
14661 var ddText = this.disabledDatesText;
14662 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
14663 var ddaysText = this.disabledDaysText;
14664 var format = this.format;
14666 var setCellClass = function(cal, cell){
14670 //Roo.log('set Cell Class');
14672 var t = d.getTime();
14676 cell.dateValue = t;
14678 cell.className += " fc-today";
14679 cell.className += " fc-state-highlight";
14680 cell.title = cal.todayText;
14683 // disable highlight in other month..
14684 //cell.className += " fc-state-highlight";
14689 cell.className = " fc-state-disabled";
14690 cell.title = cal.minText;
14694 cell.className = " fc-state-disabled";
14695 cell.title = cal.maxText;
14699 if(ddays.indexOf(d.getDay()) != -1){
14700 cell.title = ddaysText;
14701 cell.className = " fc-state-disabled";
14704 if(ddMatch && format){
14705 var fvalue = d.dateFormat(format);
14706 if(ddMatch.test(fvalue)){
14707 cell.title = ddText.replace("%0", fvalue);
14708 cell.className = " fc-state-disabled";
14712 if (!cell.initialClassName) {
14713 cell.initialClassName = cell.dom.className;
14716 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14721 for(; i < startingPos; i++) {
14722 textEls[i].innerHTML = (++prevStart);
14723 d.setDate(d.getDate()+1);
14725 cells[i].className = "fc-past fc-other-month";
14726 setCellClass(this, cells[i]);
14731 for(; i < days; i++){
14732 intDay = i - startingPos + 1;
14733 textEls[i].innerHTML = (intDay);
14734 d.setDate(d.getDate()+1);
14736 cells[i].className = ''; // "x-date-active";
14737 setCellClass(this, cells[i]);
14741 for(; i < 42; i++) {
14742 textEls[i].innerHTML = (++extraDays);
14743 d.setDate(d.getDate()+1);
14745 cells[i].className = "fc-future fc-other-month";
14746 setCellClass(this, cells[i]);
14749 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14751 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14753 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14754 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14756 if(totalRows != 6){
14757 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14758 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14761 this.fireEvent('monthchange', this, date);
14765 if(!this.internalRender){
14766 var main = this.el.dom.firstChild;
14767 var w = main.offsetWidth;
14768 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14769 Roo.fly(main).setWidth(w);
14770 this.internalRender = true;
14771 // opera does not respect the auto grow header center column
14772 // then, after it gets a width opera refuses to recalculate
14773 // without a second pass
14774 if(Roo.isOpera && !this.secondPass){
14775 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14776 this.secondPass = true;
14777 this.update.defer(10, this, [date]);
14784 findCell : function(dt) {
14785 dt = dt.clearTime().getTime();
14787 this.cells.each(function(c){
14788 //Roo.log("check " +c.dateValue + '?=' + dt);
14789 if(c.dateValue == dt){
14799 findCells : function(ev) {
14800 var s = ev.start.clone().clearTime().getTime();
14802 var e= ev.end.clone().clearTime().getTime();
14805 this.cells.each(function(c){
14806 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14808 if(c.dateValue > e){
14811 if(c.dateValue < s){
14820 // findBestRow: function(cells)
14824 // for (var i =0 ; i < cells.length;i++) {
14825 // ret = Math.max(cells[i].rows || 0,ret);
14832 addItem : function(ev)
14834 // look for vertical location slot in
14835 var cells = this.findCells(ev);
14837 // ev.row = this.findBestRow(cells);
14839 // work out the location.
14843 for(var i =0; i < cells.length; i++) {
14845 cells[i].row = cells[0].row;
14848 cells[i].row = cells[i].row + 1;
14858 if (crow.start.getY() == cells[i].getY()) {
14860 crow.end = cells[i];
14877 cells[0].events.push(ev);
14879 this.calevents.push(ev);
14882 clearEvents: function() {
14884 if(!this.calevents){
14888 Roo.each(this.cells.elements, function(c){
14894 Roo.each(this.calevents, function(e) {
14895 Roo.each(e.els, function(el) {
14896 el.un('mouseenter' ,this.onEventEnter, this);
14897 el.un('mouseleave' ,this.onEventLeave, this);
14902 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14908 renderEvents: function()
14912 this.cells.each(function(c) {
14921 if(c.row != c.events.length){
14922 r = 4 - (4 - (c.row - c.events.length));
14925 c.events = ev.slice(0, r);
14926 c.more = ev.slice(r);
14928 if(c.more.length && c.more.length == 1){
14929 c.events.push(c.more.pop());
14932 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14936 this.cells.each(function(c) {
14938 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14941 for (var e = 0; e < c.events.length; e++){
14942 var ev = c.events[e];
14943 var rows = ev.rows;
14945 for(var i = 0; i < rows.length; i++) {
14947 // how many rows should it span..
14950 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14951 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14953 unselectable : "on",
14956 cls: 'fc-event-inner',
14960 // cls: 'fc-event-time',
14961 // html : cells.length > 1 ? '' : ev.time
14965 cls: 'fc-event-title',
14966 html : String.format('{0}', ev.title)
14973 cls: 'ui-resizable-handle ui-resizable-e',
14974 html : '  '
14981 cfg.cls += ' fc-event-start';
14983 if ((i+1) == rows.length) {
14984 cfg.cls += ' fc-event-end';
14987 var ctr = _this.el.select('.fc-event-container',true).first();
14988 var cg = ctr.createChild(cfg);
14990 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14991 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14993 var r = (c.more.length) ? 1 : 0;
14994 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14995 cg.setWidth(ebox.right - sbox.x -2);
14997 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14998 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14999 cg.on('click', _this.onEventClick, _this, ev);
15010 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
15011 style : 'position: absolute',
15012 unselectable : "on",
15015 cls: 'fc-event-inner',
15019 cls: 'fc-event-title',
15027 cls: 'ui-resizable-handle ui-resizable-e',
15028 html : '  '
15034 var ctr = _this.el.select('.fc-event-container',true).first();
15035 var cg = ctr.createChild(cfg);
15037 var sbox = c.select('.fc-day-content',true).first().getBox();
15038 var ebox = c.select('.fc-day-content',true).first().getBox();
15040 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
15041 cg.setWidth(ebox.right - sbox.x -2);
15043 cg.on('click', _this.onMoreEventClick, _this, c.more);
15053 onEventEnter: function (e, el,event,d) {
15054 this.fireEvent('evententer', this, el, event);
15057 onEventLeave: function (e, el,event,d) {
15058 this.fireEvent('eventleave', this, el, event);
15061 onEventClick: function (e, el,event,d) {
15062 this.fireEvent('eventclick', this, el, event);
15065 onMonthChange: function () {
15069 onMoreEventClick: function(e, el, more)
15073 this.calpopover.placement = 'right';
15074 this.calpopover.setTitle('More');
15076 this.calpopover.setContent('');
15078 var ctr = this.calpopover.el.select('.popover-content', true).first();
15080 Roo.each(more, function(m){
15082 cls : 'fc-event-hori fc-event-draggable',
15085 var cg = ctr.createChild(cfg);
15087 cg.on('click', _this.onEventClick, _this, m);
15090 this.calpopover.show(el);
15095 onLoad: function ()
15097 this.calevents = [];
15100 if(this.store.getCount() > 0){
15101 this.store.data.each(function(d){
15104 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
15105 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
15106 time : d.data.start_time,
15107 title : d.data.title,
15108 description : d.data.description,
15109 venue : d.data.venue
15114 this.renderEvents();
15116 if(this.calevents.length && this.loadMask){
15117 this.maskEl.hide();
15121 onBeforeLoad: function()
15123 this.clearEvents();
15125 this.maskEl.show();
15139 * @class Roo.bootstrap.Popover
15140 * @extends Roo.bootstrap.Component
15141 * Bootstrap Popover class
15142 * @cfg {String} html contents of the popover (or false to use children..)
15143 * @cfg {String} title of popover (or false to hide)
15144 * @cfg {String} placement how it is placed
15145 * @cfg {String} trigger click || hover (or false to trigger manually)
15146 * @cfg {String} over what (parent or false to trigger manually.)
15147 * @cfg {Number} delay - delay before showing
15150 * Create a new Popover
15151 * @param {Object} config The config object
15154 Roo.bootstrap.Popover = function(config){
15155 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
15158 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
15160 title: 'Fill in a title',
15163 placement : 'right',
15164 trigger : 'hover', // hover
15170 can_build_overlaid : false,
15172 getChildContainer : function()
15174 return this.el.select('.popover-content',true).first();
15177 getAutoCreate : function(){
15178 Roo.log('make popover?');
15180 cls : 'popover roo-dynamic',
15181 style: 'display:block',
15187 cls : 'popover-inner',
15191 cls: 'popover-title',
15195 cls : 'popover-content',
15206 setTitle: function(str)
15208 this.el.select('.popover-title',true).first().dom.innerHTML = str;
15210 setContent: function(str)
15212 this.el.select('.popover-content',true).first().dom.innerHTML = str;
15214 // as it get's added to the bottom of the page.
15215 onRender : function(ct, position)
15217 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
15219 var cfg = Roo.apply({}, this.getAutoCreate());
15223 cfg.cls += ' ' + this.cls;
15226 cfg.style = this.style;
15228 Roo.log("adding to ")
15229 this.el = Roo.get(document.body).createChild(cfg, position);
15235 initEvents : function()
15237 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
15238 this.el.enableDisplayMode('block');
15240 if (this.over === false) {
15243 if (this.triggers === false) {
15246 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15247 var triggers = this.trigger ? this.trigger.split(' ') : [];
15248 Roo.each(triggers, function(trigger) {
15250 if (trigger == 'click') {
15251 on_el.on('click', this.toggle, this);
15252 } else if (trigger != 'manual') {
15253 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
15254 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
15256 on_el.on(eventIn ,this.enter, this);
15257 on_el.on(eventOut, this.leave, this);
15268 toggle : function () {
15269 this.hoverState == 'in' ? this.leave() : this.enter();
15272 enter : function () {
15275 clearTimeout(this.timeout);
15277 this.hoverState = 'in';
15279 if (!this.delay || !this.delay.show) {
15284 this.timeout = setTimeout(function () {
15285 if (_t.hoverState == 'in') {
15288 }, this.delay.show)
15290 leave : function() {
15291 clearTimeout(this.timeout);
15293 this.hoverState = 'out';
15295 if (!this.delay || !this.delay.hide) {
15300 this.timeout = setTimeout(function () {
15301 if (_t.hoverState == 'out') {
15304 }, this.delay.hide)
15307 show : function (on_el)
15310 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15313 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
15314 if (this.html !== false) {
15315 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
15317 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
15318 if (!this.title.length) {
15319 this.el.select('.popover-title',true).hide();
15322 var placement = typeof this.placement == 'function' ?
15323 this.placement.call(this, this.el, on_el) :
15326 var autoToken = /\s?auto?\s?/i;
15327 var autoPlace = autoToken.test(placement);
15329 placement = placement.replace(autoToken, '') || 'top';
15333 //this.el.setXY([0,0]);
15335 this.el.dom.style.display='block';
15336 this.el.addClass(placement);
15338 //this.el.appendTo(on_el);
15340 var p = this.getPosition();
15341 var box = this.el.getBox();
15346 var align = Roo.bootstrap.Popover.alignment[placement];
15347 this.el.alignTo(on_el, align[0],align[1]);
15348 //var arrow = this.el.select('.arrow',true).first();
15349 //arrow.set(align[2],
15351 this.el.addClass('in');
15352 this.hoverState = null;
15354 if (this.el.hasClass('fade')) {
15361 this.el.setXY([0,0]);
15362 this.el.removeClass('in');
15369 Roo.bootstrap.Popover.alignment = {
15370 'left' : ['r-l', [-10,0], 'right'],
15371 'right' : ['l-r', [10,0], 'left'],
15372 'bottom' : ['t-b', [0,10], 'top'],
15373 'top' : [ 'b-t', [0,-10], 'bottom']
15384 * @class Roo.bootstrap.Progress
15385 * @extends Roo.bootstrap.Component
15386 * Bootstrap Progress class
15387 * @cfg {Boolean} striped striped of the progress bar
15388 * @cfg {Boolean} active animated of the progress bar
15392 * Create a new Progress
15393 * @param {Object} config The config object
15396 Roo.bootstrap.Progress = function(config){
15397 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
15400 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
15405 getAutoCreate : function(){
15413 cfg.cls += ' progress-striped';
15417 cfg.cls += ' active';
15436 * @class Roo.bootstrap.ProgressBar
15437 * @extends Roo.bootstrap.Component
15438 * Bootstrap ProgressBar class
15439 * @cfg {Number} aria_valuenow aria-value now
15440 * @cfg {Number} aria_valuemin aria-value min
15441 * @cfg {Number} aria_valuemax aria-value max
15442 * @cfg {String} label label for the progress bar
15443 * @cfg {String} panel (success | info | warning | danger )
15444 * @cfg {String} role role of the progress bar
15445 * @cfg {String} sr_only text
15449 * Create a new ProgressBar
15450 * @param {Object} config The config object
15453 Roo.bootstrap.ProgressBar = function(config){
15454 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
15457 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
15461 aria_valuemax : 100,
15467 getAutoCreate : function()
15472 cls: 'progress-bar',
15473 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
15485 cfg.role = this.role;
15488 if(this.aria_valuenow){
15489 cfg['aria-valuenow'] = this.aria_valuenow;
15492 if(this.aria_valuemin){
15493 cfg['aria-valuemin'] = this.aria_valuemin;
15496 if(this.aria_valuemax){
15497 cfg['aria-valuemax'] = this.aria_valuemax;
15500 if(this.label && !this.sr_only){
15501 cfg.html = this.label;
15505 cfg.cls += ' progress-bar-' + this.panel;
15511 update : function(aria_valuenow)
15513 this.aria_valuenow = aria_valuenow;
15515 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
15530 * @class Roo.bootstrap.TabGroup
15531 * @extends Roo.bootstrap.Column
15532 * Bootstrap Column class
15533 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
15534 * @cfg {Boolean} carousel true to make the group behave like a carousel
15535 * @cfg {Number} bullets show the panel pointer.. default 0
15536 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
15537 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
15538 * @cfg {Number} timer auto slide timer .. default 0 millisecond
15541 * Create a new TabGroup
15542 * @param {Object} config The config object
15545 Roo.bootstrap.TabGroup = function(config){
15546 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
15548 this.navId = Roo.id();
15551 Roo.bootstrap.TabGroup.register(this);
15555 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
15558 transition : false,
15563 slideOnTouch : false,
15565 getAutoCreate : function()
15567 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
15569 cfg.cls += ' tab-content';
15571 Roo.log('get auto create...............');
15573 if (this.carousel) {
15574 cfg.cls += ' carousel slide';
15577 cls : 'carousel-inner'
15580 if(this.bullets > 0 && !Roo.isTouch){
15583 cls : 'carousel-bullets',
15587 if(this.bullets_cls){
15588 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
15591 for (var i = 0; i < this.bullets; i++){
15593 cls : 'bullet bullet-' + i
15601 cfg.cn[0].cn = bullets;
15608 initEvents: function()
15610 Roo.log('-------- init events on tab group ---------');
15612 if(this.bullets > 0 && !Roo.isTouch){
15618 if(Roo.isTouch && this.slideOnTouch){
15619 this.el.on("touchstart", this.onTouchStart, this);
15622 if(this.autoslide){
15625 this.slideFn = window.setInterval(function() {
15626 _this.showPanelNext();
15632 onTouchStart : function(e, el, o)
15634 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15638 this.showPanelNext();
15641 getChildContainer : function()
15643 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15647 * register a Navigation item
15648 * @param {Roo.bootstrap.NavItem} the navitem to add
15650 register : function(item)
15652 this.tabs.push( item);
15653 item.navId = this.navId; // not really needed..
15657 getActivePanel : function()
15660 Roo.each(this.tabs, function(t) {
15670 getPanelByName : function(n)
15673 Roo.each(this.tabs, function(t) {
15674 if (t.tabId == n) {
15682 indexOfPanel : function(p)
15685 Roo.each(this.tabs, function(t,i) {
15686 if (t.tabId == p.tabId) {
15695 * show a specific panel
15696 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15697 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15699 showPanel : function (pan)
15701 if(this.transition){
15702 Roo.log("waiting for the transitionend");
15706 if (typeof(pan) == 'number') {
15707 pan = this.tabs[pan];
15709 if (typeof(pan) == 'string') {
15710 pan = this.getPanelByName(pan);
15712 if (pan.tabId == this.getActivePanel().tabId) {
15715 var cur = this.getActivePanel();
15717 if (false === cur.fireEvent('beforedeactivate')) {
15721 if(this.bullets > 0 && !Roo.isTouch){
15722 this.setActiveBullet(this.indexOfPanel(pan));
15725 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15727 this.transition = true;
15728 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15729 var lr = dir == 'next' ? 'left' : 'right';
15730 pan.el.addClass(dir); // or prev
15731 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15732 cur.el.addClass(lr); // or right
15733 pan.el.addClass(lr);
15736 cur.el.on('transitionend', function() {
15737 Roo.log("trans end?");
15739 pan.el.removeClass([lr,dir]);
15740 pan.setActive(true);
15742 cur.el.removeClass([lr]);
15743 cur.setActive(false);
15745 _this.transition = false;
15747 }, this, { single: true } );
15752 cur.setActive(false);
15753 pan.setActive(true);
15758 showPanelNext : function()
15760 var i = this.indexOfPanel(this.getActivePanel());
15762 if (i >= this.tabs.length - 1 && !this.autoslide) {
15766 if (i >= this.tabs.length - 1 && this.autoslide) {
15770 this.showPanel(this.tabs[i+1]);
15773 showPanelPrev : function()
15775 var i = this.indexOfPanel(this.getActivePanel());
15777 if (i < 1 && !this.autoslide) {
15781 if (i < 1 && this.autoslide) {
15782 i = this.tabs.length;
15785 this.showPanel(this.tabs[i-1]);
15788 initBullet : function()
15796 for (var i = 0; i < this.bullets; i++){
15797 var bullet = this.el.select('.bullet-' + i, true).first();
15803 bullet.on('click', (function(e, el, o, ii, t){
15805 e.preventDefault();
15807 _this.showPanel(ii);
15809 if(_this.autoslide && _this.slideFn){
15810 clearInterval(_this.slideFn);
15811 _this.slideFn = window.setInterval(function() {
15812 _this.showPanelNext();
15816 }).createDelegate(this, [i, bullet], true));
15820 setActiveBullet : function(i)
15826 Roo.each(this.el.select('.bullet', true).elements, function(el){
15827 el.removeClass('selected');
15830 var bullet = this.el.select('.bullet-' + i, true).first();
15836 bullet.addClass('selected');
15847 Roo.apply(Roo.bootstrap.TabGroup, {
15851 * register a Navigation Group
15852 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15854 register : function(navgrp)
15856 this.groups[navgrp.navId] = navgrp;
15860 * fetch a Navigation Group based on the navigation ID
15861 * if one does not exist , it will get created.
15862 * @param {string} the navgroup to add
15863 * @returns {Roo.bootstrap.NavGroup} the navgroup
15865 get: function(navId) {
15866 if (typeof(this.groups[navId]) == 'undefined') {
15867 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15869 return this.groups[navId] ;
15884 * @class Roo.bootstrap.TabPanel
15885 * @extends Roo.bootstrap.Component
15886 * Bootstrap TabPanel class
15887 * @cfg {Boolean} active panel active
15888 * @cfg {String} html panel content
15889 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15890 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15894 * Create a new TabPanel
15895 * @param {Object} config The config object
15898 Roo.bootstrap.TabPanel = function(config){
15899 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15903 * Fires when the active status changes
15904 * @param {Roo.bootstrap.TabPanel} this
15905 * @param {Boolean} state the new state
15910 * @event beforedeactivate
15911 * Fires before a tab is de-activated - can be used to do validation on a form.
15912 * @param {Roo.bootstrap.TabPanel} this
15913 * @return {Boolean} false if there is an error
15916 'beforedeactivate': true
15919 this.tabId = this.tabId || Roo.id();
15923 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15930 getAutoCreate : function(){
15933 // item is needed for carousel - not sure if it has any effect otherwise
15934 cls: 'tab-pane item',
15935 html: this.html || ''
15939 cfg.cls += ' active';
15943 cfg.tabId = this.tabId;
15950 initEvents: function()
15952 Roo.log('-------- init events on tab panel ---------');
15954 var p = this.parent();
15955 this.navId = this.navId || p.navId;
15957 if (typeof(this.navId) != 'undefined') {
15958 // not really needed.. but just in case.. parent should be a NavGroup.
15959 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15960 Roo.log(['register', tg, this]);
15963 var i = tg.tabs.length - 1;
15965 if(this.active && tg.bullets > 0 && i < tg.bullets){
15966 tg.setActiveBullet(i);
15973 onRender : function(ct, position)
15975 // Roo.log("Call onRender: " + this.xtype);
15977 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15985 setActive: function(state)
15987 Roo.log("panel - set active " + this.tabId + "=" + state);
15989 this.active = state;
15991 this.el.removeClass('active');
15993 } else if (!this.el.hasClass('active')) {
15994 this.el.addClass('active');
15997 this.fireEvent('changed', this, state);
16014 * @class Roo.bootstrap.DateField
16015 * @extends Roo.bootstrap.Input
16016 * Bootstrap DateField class
16017 * @cfg {Number} weekStart default 0
16018 * @cfg {String} viewMode default empty, (months|years)
16019 * @cfg {String} minViewMode default empty, (months|years)
16020 * @cfg {Number} startDate default -Infinity
16021 * @cfg {Number} endDate default Infinity
16022 * @cfg {Boolean} todayHighlight default false
16023 * @cfg {Boolean} todayBtn default false
16024 * @cfg {Boolean} calendarWeeks default false
16025 * @cfg {Object} daysOfWeekDisabled default empty
16026 * @cfg {Boolean} singleMode default false (true | false)
16028 * @cfg {Boolean} keyboardNavigation default true
16029 * @cfg {String} language default en
16032 * Create a new DateField
16033 * @param {Object} config The config object
16036 Roo.bootstrap.DateField = function(config){
16037 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16041 * Fires when this field show.
16042 * @param {Roo.bootstrap.DateField} this
16043 * @param {Mixed} date The date value
16048 * Fires when this field hide.
16049 * @param {Roo.bootstrap.DateField} this
16050 * @param {Mixed} date The date value
16055 * Fires when select a date.
16056 * @param {Roo.bootstrap.DateField} this
16057 * @param {Mixed} date The date value
16063 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16066 * @cfg {String} format
16067 * The default date format string which can be overriden for localization support. The format must be
16068 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16072 * @cfg {String} altFormats
16073 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16074 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16076 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16084 todayHighlight : false,
16090 keyboardNavigation: true,
16092 calendarWeeks: false,
16094 startDate: -Infinity,
16098 daysOfWeekDisabled: [],
16102 singleMode : false,
16104 UTCDate: function()
16106 return new Date(Date.UTC.apply(Date, arguments));
16109 UTCToday: function()
16111 var today = new Date();
16112 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16115 getDate: function() {
16116 var d = this.getUTCDate();
16117 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16120 getUTCDate: function() {
16124 setDate: function(d) {
16125 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
16128 setUTCDate: function(d) {
16130 this.setValue(this.formatDate(this.date));
16133 onRender: function(ct, position)
16136 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
16138 this.language = this.language || 'en';
16139 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
16140 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
16142 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
16143 this.format = this.format || 'm/d/y';
16144 this.isInline = false;
16145 this.isInput = true;
16146 this.component = this.el.select('.add-on', true).first() || false;
16147 this.component = (this.component && this.component.length === 0) ? false : this.component;
16148 this.hasInput = this.component && this.inputEL().length;
16150 if (typeof(this.minViewMode === 'string')) {
16151 switch (this.minViewMode) {
16153 this.minViewMode = 1;
16156 this.minViewMode = 2;
16159 this.minViewMode = 0;
16164 if (typeof(this.viewMode === 'string')) {
16165 switch (this.viewMode) {
16178 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
16180 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
16182 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16184 this.picker().on('mousedown', this.onMousedown, this);
16185 this.picker().on('click', this.onClick, this);
16187 this.picker().addClass('datepicker-dropdown');
16189 this.startViewMode = this.viewMode;
16191 if(this.singleMode){
16192 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
16193 v.setVisibilityMode(Roo.Element.DISPLAY)
16197 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16198 v.setStyle('width', '189px');
16202 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
16203 if(!this.calendarWeeks){
16208 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16209 v.attr('colspan', function(i, val){
16210 return parseInt(val) + 1;
16215 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
16217 this.setStartDate(this.startDate);
16218 this.setEndDate(this.endDate);
16220 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
16227 if(this.isInline) {
16232 picker : function()
16234 return this.pickerEl;
16235 // return this.el.select('.datepicker', true).first();
16238 fillDow: function()
16240 var dowCnt = this.weekStart;
16249 if(this.calendarWeeks){
16257 while (dowCnt < this.weekStart + 7) {
16261 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
16265 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
16268 fillMonths: function()
16271 var months = this.picker().select('>.datepicker-months td', true).first();
16273 months.dom.innerHTML = '';
16279 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
16282 months.createChild(month);
16289 this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
16291 if (this.date < this.startDate) {
16292 this.viewDate = new Date(this.startDate);
16293 } else if (this.date > this.endDate) {
16294 this.viewDate = new Date(this.endDate);
16296 this.viewDate = new Date(this.date);
16304 var d = new Date(this.viewDate),
16305 year = d.getUTCFullYear(),
16306 month = d.getUTCMonth(),
16307 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
16308 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
16309 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
16310 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
16311 currentDate = this.date && this.date.valueOf(),
16312 today = this.UTCToday();
16314 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
16316 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16318 // this.picker.select('>tfoot th.today').
16319 // .text(dates[this.language].today)
16320 // .toggle(this.todayBtn !== false);
16322 this.updateNavArrows();
16325 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
16327 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
16329 prevMonth.setUTCDate(day);
16331 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
16333 var nextMonth = new Date(prevMonth);
16335 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
16337 nextMonth = nextMonth.valueOf();
16339 var fillMonths = false;
16341 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
16343 while(prevMonth.valueOf() < nextMonth) {
16346 if (prevMonth.getUTCDay() === this.weekStart) {
16348 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
16356 if(this.calendarWeeks){
16357 // ISO 8601: First week contains first thursday.
16358 // ISO also states week starts on Monday, but we can be more abstract here.
16360 // Start of current week: based on weekstart/current date
16361 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
16362 // Thursday of this week
16363 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
16364 // First Thursday of year, year from thursday
16365 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
16366 // Calendar week: ms between thursdays, div ms per day, div 7 days
16367 calWeek = (th - yth) / 864e5 / 7 + 1;
16369 fillMonths.cn.push({
16377 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
16379 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
16382 if (this.todayHighlight &&
16383 prevMonth.getUTCFullYear() == today.getFullYear() &&
16384 prevMonth.getUTCMonth() == today.getMonth() &&
16385 prevMonth.getUTCDate() == today.getDate()) {
16386 clsName += ' today';
16389 if (currentDate && prevMonth.valueOf() === currentDate) {
16390 clsName += ' active';
16393 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
16394 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
16395 clsName += ' disabled';
16398 fillMonths.cn.push({
16400 cls: 'day ' + clsName,
16401 html: prevMonth.getDate()
16404 prevMonth.setDate(prevMonth.getDate()+1);
16407 var currentYear = this.date && this.date.getUTCFullYear();
16408 var currentMonth = this.date && this.date.getUTCMonth();
16410 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
16412 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
16413 v.removeClass('active');
16415 if(currentYear === year && k === currentMonth){
16416 v.addClass('active');
16419 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
16420 v.addClass('disabled');
16426 year = parseInt(year/10, 10) * 10;
16428 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
16430 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
16433 for (var i = -1; i < 11; i++) {
16434 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
16436 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
16444 showMode: function(dir)
16447 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
16450 Roo.each(this.picker().select('>div',true).elements, function(v){
16451 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16454 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
16459 if(this.isInline) return;
16461 this.picker().removeClass(['bottom', 'top']);
16463 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16465 * place to the top of element!
16469 this.picker().addClass('top');
16470 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16475 this.picker().addClass('bottom');
16477 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16480 parseDate : function(value)
16482 if(!value || value instanceof Date){
16485 var v = Date.parseDate(value, this.format);
16486 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
16487 v = Date.parseDate(value, 'Y-m-d');
16489 if(!v && this.altFormats){
16490 if(!this.altFormatsArray){
16491 this.altFormatsArray = this.altFormats.split("|");
16493 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
16494 v = Date.parseDate(value, this.altFormatsArray[i]);
16500 formatDate : function(date, fmt)
16502 return (!date || !(date instanceof Date)) ?
16503 date : date.dateFormat(fmt || this.format);
16506 onFocus : function()
16508 Roo.bootstrap.DateField.superclass.onFocus.call(this);
16512 onBlur : function()
16514 Roo.bootstrap.DateField.superclass.onBlur.call(this);
16516 var d = this.inputEl().getValue();
16525 this.picker().show();
16529 this.fireEvent('show', this, this.date);
16534 if(this.isInline) return;
16535 this.picker().hide();
16536 this.viewMode = this.startViewMode;
16539 this.fireEvent('hide', this, this.date);
16543 onMousedown: function(e)
16545 e.stopPropagation();
16546 e.preventDefault();
16551 Roo.bootstrap.DateField.superclass.keyup.call(this);
16555 setValue: function(v)
16558 // v can be a string or a date..
16561 var d = new Date(this.parseDate(v) ).clearTime();
16563 if(isNaN(d.getTime())){
16564 this.date = this.viewDate = '';
16565 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
16569 v = this.formatDate(d);
16571 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
16573 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
16577 this.fireEvent('select', this, this.date);
16581 getValue: function()
16583 return this.formatDate(this.date);
16586 fireKey: function(e)
16588 if (!this.picker().isVisible()){
16589 if (e.keyCode == 27) // allow escape to hide and re-show picker
16594 var dateChanged = false,
16596 newDate, newViewDate;
16601 e.preventDefault();
16605 if (!this.keyboardNavigation) break;
16606 dir = e.keyCode == 37 ? -1 : 1;
16609 newDate = this.moveYear(this.date, dir);
16610 newViewDate = this.moveYear(this.viewDate, dir);
16611 } else if (e.shiftKey){
16612 newDate = this.moveMonth(this.date, dir);
16613 newViewDate = this.moveMonth(this.viewDate, dir);
16615 newDate = new Date(this.date);
16616 newDate.setUTCDate(this.date.getUTCDate() + dir);
16617 newViewDate = new Date(this.viewDate);
16618 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16620 if (this.dateWithinRange(newDate)){
16621 this.date = newDate;
16622 this.viewDate = newViewDate;
16623 this.setValue(this.formatDate(this.date));
16625 e.preventDefault();
16626 dateChanged = true;
16631 if (!this.keyboardNavigation) break;
16632 dir = e.keyCode == 38 ? -1 : 1;
16634 newDate = this.moveYear(this.date, dir);
16635 newViewDate = this.moveYear(this.viewDate, dir);
16636 } else if (e.shiftKey){
16637 newDate = this.moveMonth(this.date, dir);
16638 newViewDate = this.moveMonth(this.viewDate, dir);
16640 newDate = new Date(this.date);
16641 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16642 newViewDate = new Date(this.viewDate);
16643 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16645 if (this.dateWithinRange(newDate)){
16646 this.date = newDate;
16647 this.viewDate = newViewDate;
16648 this.setValue(this.formatDate(this.date));
16650 e.preventDefault();
16651 dateChanged = true;
16655 this.setValue(this.formatDate(this.date));
16657 e.preventDefault();
16660 this.setValue(this.formatDate(this.date));
16674 onClick: function(e)
16676 e.stopPropagation();
16677 e.preventDefault();
16679 var target = e.getTarget();
16681 if(target.nodeName.toLowerCase() === 'i'){
16682 target = Roo.get(target).dom.parentNode;
16685 var nodeName = target.nodeName;
16686 var className = target.className;
16687 var html = target.innerHTML;
16688 //Roo.log(nodeName);
16690 switch(nodeName.toLowerCase()) {
16692 switch(className) {
16698 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16699 switch(this.viewMode){
16701 this.viewDate = this.moveMonth(this.viewDate, dir);
16705 this.viewDate = this.moveYear(this.viewDate, dir);
16711 var date = new Date();
16712 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16714 this.setValue(this.formatDate(this.date));
16721 if (className.indexOf('disabled') < 0) {
16722 this.viewDate.setUTCDate(1);
16723 if (className.indexOf('month') > -1) {
16724 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16726 var year = parseInt(html, 10) || 0;
16727 this.viewDate.setUTCFullYear(year);
16731 if(this.singleMode){
16732 this.setValue(this.formatDate(this.viewDate));
16743 //Roo.log(className);
16744 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16745 var day = parseInt(html, 10) || 1;
16746 var year = this.viewDate.getUTCFullYear(),
16747 month = this.viewDate.getUTCMonth();
16749 if (className.indexOf('old') > -1) {
16756 } else if (className.indexOf('new') > -1) {
16764 //Roo.log([year,month,day]);
16765 this.date = this.UTCDate(year, month, day,0,0,0,0);
16766 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16768 //Roo.log(this.formatDate(this.date));
16769 this.setValue(this.formatDate(this.date));
16776 setStartDate: function(startDate)
16778 this.startDate = startDate || -Infinity;
16779 if (this.startDate !== -Infinity) {
16780 this.startDate = this.parseDate(this.startDate);
16783 this.updateNavArrows();
16786 setEndDate: function(endDate)
16788 this.endDate = endDate || Infinity;
16789 if (this.endDate !== Infinity) {
16790 this.endDate = this.parseDate(this.endDate);
16793 this.updateNavArrows();
16796 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16798 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16799 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16800 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16802 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16803 return parseInt(d, 10);
16806 this.updateNavArrows();
16809 updateNavArrows: function()
16811 if(this.singleMode){
16815 var d = new Date(this.viewDate),
16816 year = d.getUTCFullYear(),
16817 month = d.getUTCMonth();
16819 Roo.each(this.picker().select('.prev', true).elements, function(v){
16821 switch (this.viewMode) {
16824 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16830 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16837 Roo.each(this.picker().select('.next', true).elements, function(v){
16839 switch (this.viewMode) {
16842 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16848 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16856 moveMonth: function(date, dir)
16858 if (!dir) return date;
16859 var new_date = new Date(date.valueOf()),
16860 day = new_date.getUTCDate(),
16861 month = new_date.getUTCMonth(),
16862 mag = Math.abs(dir),
16864 dir = dir > 0 ? 1 : -1;
16867 // If going back one month, make sure month is not current month
16868 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16870 return new_date.getUTCMonth() == month;
16872 // If going forward one month, make sure month is as expected
16873 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16875 return new_date.getUTCMonth() != new_month;
16877 new_month = month + dir;
16878 new_date.setUTCMonth(new_month);
16879 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16880 if (new_month < 0 || new_month > 11)
16881 new_month = (new_month + 12) % 12;
16883 // For magnitudes >1, move one month at a time...
16884 for (var i=0; i<mag; i++)
16885 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16886 new_date = this.moveMonth(new_date, dir);
16887 // ...then reset the day, keeping it in the new month
16888 new_month = new_date.getUTCMonth();
16889 new_date.setUTCDate(day);
16891 return new_month != new_date.getUTCMonth();
16894 // Common date-resetting loop -- if date is beyond end of month, make it
16897 new_date.setUTCDate(--day);
16898 new_date.setUTCMonth(new_month);
16903 moveYear: function(date, dir)
16905 return this.moveMonth(date, dir*12);
16908 dateWithinRange: function(date)
16910 return date >= this.startDate && date <= this.endDate;
16916 this.picker().remove();
16921 Roo.apply(Roo.bootstrap.DateField, {
16932 html: '<i class="fa fa-arrow-left"/>'
16942 html: '<i class="fa fa-arrow-right"/>'
16984 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16985 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16986 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16987 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16988 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17001 navFnc: 'FullYear',
17006 navFnc: 'FullYear',
17011 Roo.apply(Roo.bootstrap.DateField, {
17015 cls: 'datepicker dropdown-menu roo-dynamic',
17019 cls: 'datepicker-days',
17023 cls: 'table-condensed',
17025 Roo.bootstrap.DateField.head,
17029 Roo.bootstrap.DateField.footer
17036 cls: 'datepicker-months',
17040 cls: 'table-condensed',
17042 Roo.bootstrap.DateField.head,
17043 Roo.bootstrap.DateField.content,
17044 Roo.bootstrap.DateField.footer
17051 cls: 'datepicker-years',
17055 cls: 'table-condensed',
17057 Roo.bootstrap.DateField.head,
17058 Roo.bootstrap.DateField.content,
17059 Roo.bootstrap.DateField.footer
17078 * @class Roo.bootstrap.TimeField
17079 * @extends Roo.bootstrap.Input
17080 * Bootstrap DateField class
17084 * Create a new TimeField
17085 * @param {Object} config The config object
17088 Roo.bootstrap.TimeField = function(config){
17089 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17093 * Fires when this field show.
17094 * @param {Roo.bootstrap.DateField} thisthis
17095 * @param {Mixed} date The date value
17100 * Fires when this field hide.
17101 * @param {Roo.bootstrap.DateField} this
17102 * @param {Mixed} date The date value
17107 * Fires when select a date.
17108 * @param {Roo.bootstrap.DateField} this
17109 * @param {Mixed} date The date value
17115 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
17118 * @cfg {String} format
17119 * The default time format string which can be overriden for localization support. The format must be
17120 * valid according to {@link Date#parseDate} (defaults to 'H:i').
17124 onRender: function(ct, position)
17127 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
17129 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
17131 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17133 this.pop = this.picker().select('>.datepicker-time',true).first();
17134 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17136 this.picker().on('mousedown', this.onMousedown, this);
17137 this.picker().on('click', this.onClick, this);
17139 this.picker().addClass('datepicker-dropdown');
17144 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
17145 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
17146 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
17147 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
17148 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
17149 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
17153 fireKey: function(e){
17154 if (!this.picker().isVisible()){
17155 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17161 e.preventDefault();
17169 this.onTogglePeriod();
17172 this.onIncrementMinutes();
17175 this.onDecrementMinutes();
17184 onClick: function(e) {
17185 e.stopPropagation();
17186 e.preventDefault();
17189 picker : function()
17191 return this.el.select('.datepicker', true).first();
17194 fillTime: function()
17196 var time = this.pop.select('tbody', true).first();
17198 time.dom.innerHTML = '';
17213 cls: 'hours-up glyphicon glyphicon-chevron-up'
17233 cls: 'minutes-up glyphicon glyphicon-chevron-up'
17254 cls: 'timepicker-hour',
17269 cls: 'timepicker-minute',
17284 cls: 'btn btn-primary period',
17306 cls: 'hours-down glyphicon glyphicon-chevron-down'
17326 cls: 'minutes-down glyphicon glyphicon-chevron-down'
17344 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
17351 var hours = this.time.getHours();
17352 var minutes = this.time.getMinutes();
17365 hours = hours - 12;
17369 hours = '0' + hours;
17373 minutes = '0' + minutes;
17376 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
17377 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
17378 this.pop.select('button', true).first().dom.innerHTML = period;
17384 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
17386 var cls = ['bottom'];
17388 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
17395 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
17400 this.picker().addClass(cls.join('-'));
17404 Roo.each(cls, function(c){
17406 _this.picker().setTop(_this.inputEl().getHeight());
17410 _this.picker().setTop(0 - _this.picker().getHeight());
17415 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
17419 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
17426 onFocus : function()
17428 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
17432 onBlur : function()
17434 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
17440 this.picker().show();
17445 this.fireEvent('show', this, this.date);
17450 this.picker().hide();
17453 this.fireEvent('hide', this, this.date);
17456 setTime : function()
17459 this.setValue(this.time.format(this.format));
17461 this.fireEvent('select', this, this.date);
17466 onMousedown: function(e){
17467 e.stopPropagation();
17468 e.preventDefault();
17471 onIncrementHours: function()
17473 Roo.log('onIncrementHours');
17474 this.time = this.time.add(Date.HOUR, 1);
17479 onDecrementHours: function()
17481 Roo.log('onDecrementHours');
17482 this.time = this.time.add(Date.HOUR, -1);
17486 onIncrementMinutes: function()
17488 Roo.log('onIncrementMinutes');
17489 this.time = this.time.add(Date.MINUTE, 1);
17493 onDecrementMinutes: function()
17495 Roo.log('onDecrementMinutes');
17496 this.time = this.time.add(Date.MINUTE, -1);
17500 onTogglePeriod: function()
17502 Roo.log('onTogglePeriod');
17503 this.time = this.time.add(Date.HOUR, 12);
17510 Roo.apply(Roo.bootstrap.TimeField, {
17540 cls: 'btn btn-info ok',
17552 Roo.apply(Roo.bootstrap.TimeField, {
17556 cls: 'datepicker dropdown-menu',
17560 cls: 'datepicker-time',
17564 cls: 'table-condensed',
17566 Roo.bootstrap.TimeField.content,
17567 Roo.bootstrap.TimeField.footer
17586 * @class Roo.bootstrap.MonthField
17587 * @extends Roo.bootstrap.Input
17588 * Bootstrap MonthField class
17590 * @cfg {String} language default en
17593 * Create a new MonthField
17594 * @param {Object} config The config object
17597 Roo.bootstrap.MonthField = function(config){
17598 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
17603 * Fires when this field show.
17604 * @param {Roo.bootstrap.MonthField} this
17605 * @param {Mixed} date The date value
17610 * Fires when this field hide.
17611 * @param {Roo.bootstrap.MonthField} this
17612 * @param {Mixed} date The date value
17617 * Fires when select a date.
17618 * @param {Roo.bootstrap.MonthField} this
17619 * @param {String} oldvalue The old value
17620 * @param {String} newvalue The new value
17626 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17628 onRender: function(ct, position)
17631 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17633 this.language = this.language || 'en';
17634 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17635 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17637 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17638 this.isInline = false;
17639 this.isInput = true;
17640 this.component = this.el.select('.add-on', true).first() || false;
17641 this.component = (this.component && this.component.length === 0) ? false : this.component;
17642 this.hasInput = this.component && this.inputEL().length;
17644 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17646 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17648 this.picker().on('mousedown', this.onMousedown, this);
17649 this.picker().on('click', this.onClick, this);
17651 this.picker().addClass('datepicker-dropdown');
17653 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17654 v.setStyle('width', '189px');
17661 if(this.isInline) {
17667 setValue: function(v, suppressEvent)
17669 var o = this.getValue();
17671 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17675 if(suppressEvent !== true){
17676 this.fireEvent('select', this, o, v);
17681 getValue: function()
17686 onClick: function(e)
17688 e.stopPropagation();
17689 e.preventDefault();
17691 var target = e.getTarget();
17693 if(target.nodeName.toLowerCase() === 'i'){
17694 target = Roo.get(target).dom.parentNode;
17697 var nodeName = target.nodeName;
17698 var className = target.className;
17699 var html = target.innerHTML;
17701 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17705 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17707 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17713 picker : function()
17715 return this.pickerEl;
17718 fillMonths: function()
17721 var months = this.picker().select('>.datepicker-months td', true).first();
17723 months.dom.innerHTML = '';
17729 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17732 months.createChild(month);
17741 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17742 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17745 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17746 e.removeClass('active');
17748 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17749 e.addClass('active');
17756 if(this.isInline) return;
17758 this.picker().removeClass(['bottom', 'top']);
17760 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17762 * place to the top of element!
17766 this.picker().addClass('top');
17767 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17772 this.picker().addClass('bottom');
17774 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17777 onFocus : function()
17779 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17783 onBlur : function()
17785 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17787 var d = this.inputEl().getValue();
17796 this.picker().show();
17797 this.picker().select('>.datepicker-months', true).first().show();
17801 this.fireEvent('show', this, this.date);
17806 if(this.isInline) return;
17807 this.picker().hide();
17808 this.fireEvent('hide', this, this.date);
17812 onMousedown: function(e)
17814 e.stopPropagation();
17815 e.preventDefault();
17820 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17824 fireKey: function(e)
17826 if (!this.picker().isVisible()){
17827 if (e.keyCode == 27) // allow escape to hide and re-show picker
17837 e.preventDefault();
17841 dir = e.keyCode == 37 ? -1 : 1;
17843 this.vIndex = this.vIndex + dir;
17845 if(this.vIndex < 0){
17849 if(this.vIndex > 11){
17853 if(isNaN(this.vIndex)){
17857 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17863 dir = e.keyCode == 38 ? -1 : 1;
17865 this.vIndex = this.vIndex + dir * 4;
17867 if(this.vIndex < 0){
17871 if(this.vIndex > 11){
17875 if(isNaN(this.vIndex)){
17879 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17884 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17885 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17889 e.preventDefault();
17892 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17893 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17909 this.picker().remove();
17914 Roo.apply(Roo.bootstrap.MonthField, {
17933 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17934 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17939 Roo.apply(Roo.bootstrap.MonthField, {
17943 cls: 'datepicker dropdown-menu roo-dynamic',
17947 cls: 'datepicker-months',
17951 cls: 'table-condensed',
17953 Roo.bootstrap.DateField.content
17973 * @class Roo.bootstrap.CheckBox
17974 * @extends Roo.bootstrap.Input
17975 * Bootstrap CheckBox class
17977 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17978 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17979 * @cfg {String} boxLabel The text that appears beside the checkbox
17980 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17981 * @cfg {Boolean} checked initnal the element
17982 * @cfg {Boolean} inline inline the element (default false)
17983 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17986 * Create a new CheckBox
17987 * @param {Object} config The config object
17990 Roo.bootstrap.CheckBox = function(config){
17991 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17996 * Fires when the element is checked or unchecked.
17997 * @param {Roo.bootstrap.CheckBox} this This input
17998 * @param {Boolean} checked The new checked value
18005 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18007 inputType: 'checkbox',
18015 getAutoCreate : function()
18017 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18023 cfg.cls = 'form-group ' + this.inputType; //input-group
18026 cfg.cls += ' ' + this.inputType + '-inline';
18032 type : this.inputType,
18033 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18034 cls : 'roo-' + this.inputType, //'form-box',
18035 placeholder : this.placeholder || ''
18039 if (this.weight) { // Validity check?
18040 cfg.cls += " " + this.inputType + "-" + this.weight;
18043 if (this.disabled) {
18044 input.disabled=true;
18048 input.checked = this.checked;
18052 input.name = this.name;
18056 input.cls += ' input-' + this.size;
18061 ['xs','sm','md','lg'].map(function(size){
18062 if (settings[size]) {
18063 cfg.cls += ' col-' + size + '-' + settings[size];
18067 var inputblock = input;
18069 if (this.before || this.after) {
18072 cls : 'input-group',
18077 inputblock.cn.push({
18079 cls : 'input-group-addon',
18084 inputblock.cn.push(input);
18087 inputblock.cn.push({
18089 cls : 'input-group-addon',
18096 if (align ==='left' && this.fieldLabel.length) {
18097 Roo.log("left and has label");
18103 cls : 'control-label col-md-' + this.labelWidth,
18104 html : this.fieldLabel
18108 cls : "col-md-" + (12 - this.labelWidth),
18115 } else if ( this.fieldLabel.length) {
18120 tag: this.boxLabel ? 'span' : 'label',
18122 cls: 'control-label box-input-label',
18123 //cls : 'input-group-addon',
18124 html : this.fieldLabel
18134 Roo.log(" no label && no align");
18135 cfg.cn = [ inputblock ] ;
18140 var boxLabelCfg = {
18142 //'for': id, // box label is handled by onclick - so no for...
18144 html: this.boxLabel
18148 boxLabelCfg.tooltip = this.tooltip;
18151 cfg.cn.push(boxLabelCfg);
18161 * return the real input element.
18163 inputEl: function ()
18165 return this.el.select('input.roo-' + this.inputType,true).first();
18168 labelEl: function()
18170 return this.el.select('label.control-label',true).first();
18172 /* depricated... */
18176 return this.labelEl();
18179 initEvents : function()
18181 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18183 this.inputEl().on('click', this.onClick, this);
18185 if (this.boxLabel) {
18186 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
18189 this.startValue = this.getValue();
18192 Roo.bootstrap.CheckBox.register(this);
18196 onClick : function()
18198 this.setChecked(!this.checked);
18201 setChecked : function(state,suppressEvent)
18203 this.startValue = this.getValue();
18205 if(this.inputType == 'radio'){
18207 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18208 e.dom.checked = false;
18211 this.inputEl().dom.checked = true;
18213 this.inputEl().dom.value = this.inputValue;
18215 if(suppressEvent !== true){
18216 this.fireEvent('check', this, true);
18224 this.checked = state;
18226 this.inputEl().dom.checked = state;
18228 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18230 if(suppressEvent !== true){
18231 this.fireEvent('check', this, state);
18237 getValue : function()
18239 if(this.inputType == 'radio'){
18240 return this.getGroupValue();
18243 return this.inputEl().getValue();
18247 getGroupValue : function()
18249 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
18253 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
18256 setValue : function(v,suppressEvent)
18258 if(this.inputType == 'radio'){
18259 this.setGroupValue(v, suppressEvent);
18263 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
18268 setGroupValue : function(v, suppressEvent)
18270 this.startValue = this.getValue();
18272 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18273 e.dom.checked = false;
18275 if(e.dom.value == v){
18276 e.dom.checked = true;
18280 if(suppressEvent !== true){
18281 this.fireEvent('check', this, true);
18289 validate : function()
18293 (this.inputType == 'radio' && this.validateRadio()) ||
18294 (this.inputType == 'checkbox' && this.validateCheckbox())
18300 this.markInvalid();
18304 validateRadio : function()
18308 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18309 if(!e.dom.checked){
18321 validateCheckbox : function()
18324 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
18327 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18335 for(var i in group){
18340 r = (group[i].getValue() == group[i].inputValue) ? true : false;
18347 * Mark this field as valid
18349 markValid : function()
18351 if(this.allowBlank){
18357 this.fireEvent('valid', this);
18359 if(this.inputType == 'radio'){
18360 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18361 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
18362 e.findParent('.form-group', false, true).addClass(_this.validClass);
18369 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18370 this.el.findParent('.form-group', false, true).addClass(this.validClass);
18374 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18380 for(var i in group){
18381 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18382 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
18387 * Mark this field as invalid
18388 * @param {String} msg The validation message
18390 markInvalid : function(msg)
18392 if(this.allowBlank){
18398 this.fireEvent('invalid', this, msg);
18400 if(this.inputType == 'radio'){
18401 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18402 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
18403 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
18410 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18411 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
18415 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18421 for(var i in group){
18422 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18423 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
18430 Roo.apply(Roo.bootstrap.CheckBox, {
18435 * register a CheckBox Group
18436 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
18438 register : function(checkbox)
18440 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
18441 this.groups[checkbox.groupId] = {};
18444 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
18448 this.groups[checkbox.groupId][checkbox.name] = checkbox;
18452 * fetch a CheckBox Group based on the group ID
18453 * @param {string} the group ID
18454 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
18456 get: function(groupId) {
18457 if (typeof(this.groups[groupId]) == 'undefined') {
18461 return this.groups[groupId] ;
18473 *<div class="radio">
18475 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
18476 Option one is this and that—be sure to include why it's great
18483 *<label class="radio-inline">fieldLabel</label>
18484 *<label class="radio-inline">
18485 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
18493 * @class Roo.bootstrap.Radio
18494 * @extends Roo.bootstrap.CheckBox
18495 * Bootstrap Radio class
18498 * Create a new Radio
18499 * @param {Object} config The config object
18502 Roo.bootstrap.Radio = function(config){
18503 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
18507 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
18509 inputType: 'radio',
18513 getAutoCreate : function()
18515 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18516 align = align || 'left'; // default...
18523 tag : this.inline ? 'span' : 'div',
18528 var inline = this.inline ? ' radio-inline' : '';
18532 // does not need for, as we wrap the input with it..
18534 cls : 'control-label box-label' + inline,
18537 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
18541 //cls : 'control-label' + inline,
18542 html : this.fieldLabel,
18543 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
18552 type : this.inputType,
18553 //value : (!this.checked) ? this.valueOff : this.inputValue,
18554 value : this.inputValue,
18556 placeholder : this.placeholder || '' // ?? needed????
18559 if (this.weight) { // Validity check?
18560 input.cls += " radio-" + this.weight;
18562 if (this.disabled) {
18563 input.disabled=true;
18567 input.checked = this.checked;
18571 input.name = this.name;
18575 input.cls += ' input-' + this.size;
18578 //?? can span's inline have a width??
18581 ['xs','sm','md','lg'].map(function(size){
18582 if (settings[size]) {
18583 cfg.cls += ' col-' + size + '-' + settings[size];
18587 var inputblock = input;
18589 if (this.before || this.after) {
18592 cls : 'input-group',
18597 inputblock.cn.push({
18599 cls : 'input-group-addon',
18603 inputblock.cn.push(input);
18605 inputblock.cn.push({
18607 cls : 'input-group-addon',
18615 if (this.fieldLabel && this.fieldLabel.length) {
18616 cfg.cn.push(fieldLabel);
18619 // normal bootstrap puts the input inside the label.
18620 // however with our styled version - it has to go after the input.
18622 //lbl.cn.push(inputblock);
18626 cls: 'radio' + inline,
18633 cfg.cn.push( lblwrap);
18638 html: this.boxLabel
18647 initEvents : function()
18649 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18651 this.inputEl().on('click', this.onClick, this);
18652 if (this.boxLabel) {
18653 Roo.log('find label')
18654 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18659 inputEl: function ()
18661 return this.el.select('input.roo-radio',true).first();
18663 onClick : function()
18666 this.setChecked(true);
18669 setChecked : function(state,suppressEvent)
18672 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18673 v.dom.checked = false;
18676 Roo.log(this.inputEl().dom);
18677 this.checked = state;
18678 this.inputEl().dom.checked = state;
18680 if(suppressEvent !== true){
18681 this.fireEvent('check', this, state);
18684 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18688 getGroupValue : function()
18691 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18692 if(v.dom.checked == true){
18693 value = v.dom.value;
18701 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18702 * @return {Mixed} value The field value
18704 getValue : function(){
18705 return this.getGroupValue();
18711 //<script type="text/javascript">
18714 * Based Ext JS Library 1.1.1
18715 * Copyright(c) 2006-2007, Ext JS, LLC.
18721 * @class Roo.HtmlEditorCore
18722 * @extends Roo.Component
18723 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18725 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18728 Roo.HtmlEditorCore = function(config){
18731 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18736 * @event initialize
18737 * Fires when the editor is fully initialized (including the iframe)
18738 * @param {Roo.HtmlEditorCore} this
18743 * Fires when the editor is first receives the focus. Any insertion must wait
18744 * until after this event.
18745 * @param {Roo.HtmlEditorCore} this
18749 * @event beforesync
18750 * Fires before the textarea is updated with content from the editor iframe. Return false
18751 * to cancel the sync.
18752 * @param {Roo.HtmlEditorCore} this
18753 * @param {String} html
18757 * @event beforepush
18758 * Fires before the iframe editor is updated with content from the textarea. Return false
18759 * to cancel the push.
18760 * @param {Roo.HtmlEditorCore} this
18761 * @param {String} html
18766 * Fires when the textarea is updated with content from the editor iframe.
18767 * @param {Roo.HtmlEditorCore} this
18768 * @param {String} html
18773 * Fires when the iframe editor is updated with content from the textarea.
18774 * @param {Roo.HtmlEditorCore} this
18775 * @param {String} html
18780 * @event editorevent
18781 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18782 * @param {Roo.HtmlEditorCore} this
18788 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18790 // defaults : white / black...
18791 this.applyBlacklists();
18798 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18802 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18808 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18813 * @cfg {Number} height (in pixels)
18817 * @cfg {Number} width (in pixels)
18822 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18825 stylesheets: false,
18830 // private properties
18831 validationEvent : false,
18833 initialized : false,
18835 sourceEditMode : false,
18836 onFocus : Roo.emptyFn,
18838 hideMode:'offsets',
18842 // blacklist + whitelisted elements..
18849 * Protected method that will not generally be called directly. It
18850 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18851 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18853 getDocMarkup : function(){
18857 // inherit styels from page...??
18858 if (this.stylesheets === false) {
18860 Roo.get(document.head).select('style').each(function(node) {
18861 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18864 Roo.get(document.head).select('link').each(function(node) {
18865 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18868 } else if (!this.stylesheets.length) {
18870 st = '<style type="text/css">' +
18871 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18877 st += '<style type="text/css">' +
18878 'IMG { cursor: pointer } ' +
18882 return '<html><head>' + st +
18883 //<style type="text/css">' +
18884 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18886 ' </head><body class="roo-htmleditor-body"></body></html>';
18890 onRender : function(ct, position)
18893 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18894 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18897 this.el.dom.style.border = '0 none';
18898 this.el.dom.setAttribute('tabIndex', -1);
18899 this.el.addClass('x-hidden hide');
18903 if(Roo.isIE){ // fix IE 1px bogus margin
18904 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18908 this.frameId = Roo.id();
18912 var iframe = this.owner.wrap.createChild({
18914 cls: 'form-control', // bootstrap..
18916 name: this.frameId,
18917 frameBorder : 'no',
18918 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18923 this.iframe = iframe.dom;
18925 this.assignDocWin();
18927 this.doc.designMode = 'on';
18930 this.doc.write(this.getDocMarkup());
18934 var task = { // must defer to wait for browser to be ready
18936 //console.log("run task?" + this.doc.readyState);
18937 this.assignDocWin();
18938 if(this.doc.body || this.doc.readyState == 'complete'){
18940 this.doc.designMode="on";
18944 Roo.TaskMgr.stop(task);
18945 this.initEditor.defer(10, this);
18952 Roo.TaskMgr.start(task);
18957 onResize : function(w, h)
18959 Roo.log('resize: ' +w + ',' + h );
18960 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18964 if(typeof w == 'number'){
18966 this.iframe.style.width = w + 'px';
18968 if(typeof h == 'number'){
18970 this.iframe.style.height = h + 'px';
18972 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18979 * Toggles the editor between standard and source edit mode.
18980 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18982 toggleSourceEdit : function(sourceEditMode){
18984 this.sourceEditMode = sourceEditMode === true;
18986 if(this.sourceEditMode){
18988 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18991 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18992 //this.iframe.className = '';
18995 //this.setSize(this.owner.wrap.getSize());
18996 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19003 * Protected method that will not generally be called directly. If you need/want
19004 * custom HTML cleanup, this is the method you should override.
19005 * @param {String} html The HTML to be cleaned
19006 * return {String} The cleaned HTML
19008 cleanHtml : function(html){
19009 html = String(html);
19010 if(html.length > 5){
19011 if(Roo.isSafari){ // strip safari nonsense
19012 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19015 if(html == ' '){
19022 * HTML Editor -> Textarea
19023 * Protected method that will not generally be called directly. Syncs the contents
19024 * of the editor iframe with the textarea.
19026 syncValue : function(){
19027 if(this.initialized){
19028 var bd = (this.doc.body || this.doc.documentElement);
19029 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19030 var html = bd.innerHTML;
19032 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19033 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19035 html = '<div style="'+m[0]+'">' + html + '</div>';
19038 html = this.cleanHtml(html);
19039 // fix up the special chars.. normaly like back quotes in word...
19040 // however we do not want to do this with chinese..
19041 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19042 var cc = b.charCodeAt();
19044 (cc >= 0x4E00 && cc < 0xA000 ) ||
19045 (cc >= 0x3400 && cc < 0x4E00 ) ||
19046 (cc >= 0xf900 && cc < 0xfb00 )
19052 if(this.owner.fireEvent('beforesync', this, html) !== false){
19053 this.el.dom.value = html;
19054 this.owner.fireEvent('sync', this, html);
19060 * Protected method that will not generally be called directly. Pushes the value of the textarea
19061 * into the iframe editor.
19063 pushValue : function(){
19064 if(this.initialized){
19065 var v = this.el.dom.value.trim();
19067 // if(v.length < 1){
19071 if(this.owner.fireEvent('beforepush', this, v) !== false){
19072 var d = (this.doc.body || this.doc.documentElement);
19074 this.cleanUpPaste();
19075 this.el.dom.value = d.innerHTML;
19076 this.owner.fireEvent('push', this, v);
19082 deferFocus : function(){
19083 this.focus.defer(10, this);
19087 focus : function(){
19088 if(this.win && !this.sourceEditMode){
19095 assignDocWin: function()
19097 var iframe = this.iframe;
19100 this.doc = iframe.contentWindow.document;
19101 this.win = iframe.contentWindow;
19103 // if (!Roo.get(this.frameId)) {
19106 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19107 // this.win = Roo.get(this.frameId).dom.contentWindow;
19109 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
19113 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19114 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
19119 initEditor : function(){
19120 //console.log("INIT EDITOR");
19121 this.assignDocWin();
19125 this.doc.designMode="on";
19127 this.doc.write(this.getDocMarkup());
19130 var dbody = (this.doc.body || this.doc.documentElement);
19131 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
19132 // this copies styles from the containing element into thsi one..
19133 // not sure why we need all of this..
19134 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
19136 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
19137 //ss['background-attachment'] = 'fixed'; // w3c
19138 dbody.bgProperties = 'fixed'; // ie
19139 //Roo.DomHelper.applyStyles(dbody, ss);
19140 Roo.EventManager.on(this.doc, {
19141 //'mousedown': this.onEditorEvent,
19142 'mouseup': this.onEditorEvent,
19143 'dblclick': this.onEditorEvent,
19144 'click': this.onEditorEvent,
19145 'keyup': this.onEditorEvent,
19150 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
19152 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
19153 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
19155 this.initialized = true;
19157 this.owner.fireEvent('initialize', this);
19162 onDestroy : function(){
19168 //for (var i =0; i < this.toolbars.length;i++) {
19169 // // fixme - ask toolbars for heights?
19170 // this.toolbars[i].onDestroy();
19173 //this.wrap.dom.innerHTML = '';
19174 //this.wrap.remove();
19179 onFirstFocus : function(){
19181 this.assignDocWin();
19184 this.activated = true;
19187 if(Roo.isGecko){ // prevent silly gecko errors
19189 var s = this.win.getSelection();
19190 if(!s.focusNode || s.focusNode.nodeType != 3){
19191 var r = s.getRangeAt(0);
19192 r.selectNodeContents((this.doc.body || this.doc.documentElement));
19197 this.execCmd('useCSS', true);
19198 this.execCmd('styleWithCSS', false);
19201 this.owner.fireEvent('activate', this);
19205 adjustFont: function(btn){
19206 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
19207 //if(Roo.isSafari){ // safari
19210 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
19211 if(Roo.isSafari){ // safari
19212 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
19213 v = (v < 10) ? 10 : v;
19214 v = (v > 48) ? 48 : v;
19215 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
19220 v = Math.max(1, v+adjust);
19222 this.execCmd('FontSize', v );
19225 onEditorEvent : function(e)
19227 this.owner.fireEvent('editorevent', this, e);
19228 // this.updateToolbar();
19229 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
19232 insertTag : function(tg)
19234 // could be a bit smarter... -> wrap the current selected tRoo..
19235 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
19237 range = this.createRange(this.getSelection());
19238 var wrappingNode = this.doc.createElement(tg.toLowerCase());
19239 wrappingNode.appendChild(range.extractContents());
19240 range.insertNode(wrappingNode);
19247 this.execCmd("formatblock", tg);
19251 insertText : function(txt)
19255 var range = this.createRange();
19256 range.deleteContents();
19257 //alert(Sender.getAttribute('label'));
19259 range.insertNode(this.doc.createTextNode(txt));
19265 * Executes a Midas editor command on the editor document and performs necessary focus and
19266 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
19267 * @param {String} cmd The Midas command
19268 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
19270 relayCmd : function(cmd, value){
19272 this.execCmd(cmd, value);
19273 this.owner.fireEvent('editorevent', this);
19274 //this.updateToolbar();
19275 this.owner.deferFocus();
19279 * Executes a Midas editor command directly on the editor document.
19280 * For visual commands, you should use {@link #relayCmd} instead.
19281 * <b>This should only be called after the editor is initialized.</b>
19282 * @param {String} cmd The Midas command
19283 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
19285 execCmd : function(cmd, value){
19286 this.doc.execCommand(cmd, false, value === undefined ? null : value);
19293 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
19295 * @param {String} text | dom node..
19297 insertAtCursor : function(text)
19302 if(!this.activated){
19308 var r = this.doc.selection.createRange();
19319 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
19323 // from jquery ui (MIT licenced)
19325 var win = this.win;
19327 if (win.getSelection && win.getSelection().getRangeAt) {
19328 range = win.getSelection().getRangeAt(0);
19329 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
19330 range.insertNode(node);
19331 } else if (win.document.selection && win.document.selection.createRange) {
19332 // no firefox support
19333 var txt = typeof(text) == 'string' ? text : text.outerHTML;
19334 win.document.selection.createRange().pasteHTML(txt);
19336 // no firefox support
19337 var txt = typeof(text) == 'string' ? text : text.outerHTML;
19338 this.execCmd('InsertHTML', txt);
19347 mozKeyPress : function(e){
19349 var c = e.getCharCode(), cmd;
19352 c = String.fromCharCode(c).toLowerCase();
19366 this.cleanUpPaste.defer(100, this);
19374 e.preventDefault();
19382 fixKeys : function(){ // load time branching for fastest keydown performance
19384 return function(e){
19385 var k = e.getKey(), r;
19388 r = this.doc.selection.createRange();
19391 r.pasteHTML('    ');
19398 r = this.doc.selection.createRange();
19400 var target = r.parentElement();
19401 if(!target || target.tagName.toLowerCase() != 'li'){
19403 r.pasteHTML('<br />');
19409 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19410 this.cleanUpPaste.defer(100, this);
19416 }else if(Roo.isOpera){
19417 return function(e){
19418 var k = e.getKey();
19422 this.execCmd('InsertHTML','    ');
19425 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19426 this.cleanUpPaste.defer(100, this);
19431 }else if(Roo.isSafari){
19432 return function(e){
19433 var k = e.getKey();
19437 this.execCmd('InsertText','\t');
19441 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19442 this.cleanUpPaste.defer(100, this);
19450 getAllAncestors: function()
19452 var p = this.getSelectedNode();
19455 a.push(p); // push blank onto stack..
19456 p = this.getParentElement();
19460 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
19464 a.push(this.doc.body);
19468 lastSelNode : false,
19471 getSelection : function()
19473 this.assignDocWin();
19474 return Roo.isIE ? this.doc.selection : this.win.getSelection();
19477 getSelectedNode: function()
19479 // this may only work on Gecko!!!
19481 // should we cache this!!!!
19486 var range = this.createRange(this.getSelection()).cloneRange();
19489 var parent = range.parentElement();
19491 var testRange = range.duplicate();
19492 testRange.moveToElementText(parent);
19493 if (testRange.inRange(range)) {
19496 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
19499 parent = parent.parentElement;
19504 // is ancestor a text element.
19505 var ac = range.commonAncestorContainer;
19506 if (ac.nodeType == 3) {
19507 ac = ac.parentNode;
19510 var ar = ac.childNodes;
19513 var other_nodes = [];
19514 var has_other_nodes = false;
19515 for (var i=0;i<ar.length;i++) {
19516 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
19519 // fullly contained node.
19521 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
19526 // probably selected..
19527 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
19528 other_nodes.push(ar[i]);
19532 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
19537 has_other_nodes = true;
19539 if (!nodes.length && other_nodes.length) {
19540 nodes= other_nodes;
19542 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
19548 createRange: function(sel)
19550 // this has strange effects when using with
19551 // top toolbar - not sure if it's a great idea.
19552 //this.editor.contentWindow.focus();
19553 if (typeof sel != "undefined") {
19555 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
19557 return this.doc.createRange();
19560 return this.doc.createRange();
19563 getParentElement: function()
19566 this.assignDocWin();
19567 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
19569 var range = this.createRange(sel);
19572 var p = range.commonAncestorContainer;
19573 while (p.nodeType == 3) { // text node
19584 * Range intersection.. the hard stuff...
19588 * [ -- selected range --- ]
19592 * if end is before start or hits it. fail.
19593 * if start is after end or hits it fail.
19595 * if either hits (but other is outside. - then it's not
19601 // @see http://www.thismuchiknow.co.uk/?p=64.
19602 rangeIntersectsNode : function(range, node)
19604 var nodeRange = node.ownerDocument.createRange();
19606 nodeRange.selectNode(node);
19608 nodeRange.selectNodeContents(node);
19611 var rangeStartRange = range.cloneRange();
19612 rangeStartRange.collapse(true);
19614 var rangeEndRange = range.cloneRange();
19615 rangeEndRange.collapse(false);
19617 var nodeStartRange = nodeRange.cloneRange();
19618 nodeStartRange.collapse(true);
19620 var nodeEndRange = nodeRange.cloneRange();
19621 nodeEndRange.collapse(false);
19623 return rangeStartRange.compareBoundaryPoints(
19624 Range.START_TO_START, nodeEndRange) == -1 &&
19625 rangeEndRange.compareBoundaryPoints(
19626 Range.START_TO_START, nodeStartRange) == 1;
19630 rangeCompareNode : function(range, node)
19632 var nodeRange = node.ownerDocument.createRange();
19634 nodeRange.selectNode(node);
19636 nodeRange.selectNodeContents(node);
19640 range.collapse(true);
19642 nodeRange.collapse(true);
19644 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19645 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19647 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19649 var nodeIsBefore = ss == 1;
19650 var nodeIsAfter = ee == -1;
19652 if (nodeIsBefore && nodeIsAfter)
19654 if (!nodeIsBefore && nodeIsAfter)
19655 return 1; //right trailed.
19657 if (nodeIsBefore && !nodeIsAfter)
19658 return 2; // left trailed.
19663 // private? - in a new class?
19664 cleanUpPaste : function()
19666 // cleans up the whole document..
19667 Roo.log('cleanuppaste');
19669 this.cleanUpChildren(this.doc.body);
19670 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19671 if (clean != this.doc.body.innerHTML) {
19672 this.doc.body.innerHTML = clean;
19677 cleanWordChars : function(input) {// change the chars to hex code
19678 var he = Roo.HtmlEditorCore;
19680 var output = input;
19681 Roo.each(he.swapCodes, function(sw) {
19682 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19684 output = output.replace(swapper, sw[1]);
19691 cleanUpChildren : function (n)
19693 if (!n.childNodes.length) {
19696 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19697 this.cleanUpChild(n.childNodes[i]);
19704 cleanUpChild : function (node)
19707 //console.log(node);
19708 if (node.nodeName == "#text") {
19709 // clean up silly Windows -- stuff?
19712 if (node.nodeName == "#comment") {
19713 node.parentNode.removeChild(node);
19714 // clean up silly Windows -- stuff?
19717 var lcname = node.tagName.toLowerCase();
19718 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19719 // whitelist of tags..
19721 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19723 node.parentNode.removeChild(node);
19728 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19730 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19731 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19733 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19734 // remove_keep_children = true;
19737 if (remove_keep_children) {
19738 this.cleanUpChildren(node);
19739 // inserts everything just before this node...
19740 while (node.childNodes.length) {
19741 var cn = node.childNodes[0];
19742 node.removeChild(cn);
19743 node.parentNode.insertBefore(cn, node);
19745 node.parentNode.removeChild(node);
19749 if (!node.attributes || !node.attributes.length) {
19750 this.cleanUpChildren(node);
19754 function cleanAttr(n,v)
19757 if (v.match(/^\./) || v.match(/^\//)) {
19760 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19763 if (v.match(/^#/)) {
19766 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19767 node.removeAttribute(n);
19771 var cwhite = this.cwhite;
19772 var cblack = this.cblack;
19774 function cleanStyle(n,v)
19776 if (v.match(/expression/)) { //XSS?? should we even bother..
19777 node.removeAttribute(n);
19781 var parts = v.split(/;/);
19784 Roo.each(parts, function(p) {
19785 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19789 var l = p.split(':').shift().replace(/\s+/g,'');
19790 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19792 if ( cwhite.length && cblack.indexOf(l) > -1) {
19793 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19794 //node.removeAttribute(n);
19798 // only allow 'c whitelisted system attributes'
19799 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19800 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19801 //node.removeAttribute(n);
19811 if (clean.length) {
19812 node.setAttribute(n, clean.join(';'));
19814 node.removeAttribute(n);
19820 for (var i = node.attributes.length-1; i > -1 ; i--) {
19821 var a = node.attributes[i];
19824 if (a.name.toLowerCase().substr(0,2)=='on') {
19825 node.removeAttribute(a.name);
19828 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19829 node.removeAttribute(a.name);
19832 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19833 cleanAttr(a.name,a.value); // fixme..
19836 if (a.name == 'style') {
19837 cleanStyle(a.name,a.value);
19840 /// clean up MS crap..
19841 // tecnically this should be a list of valid class'es..
19844 if (a.name == 'class') {
19845 if (a.value.match(/^Mso/)) {
19846 node.className = '';
19849 if (a.value.match(/body/)) {
19850 node.className = '';
19861 this.cleanUpChildren(node);
19867 * Clean up MS wordisms...
19869 cleanWord : function(node)
19874 this.cleanWord(this.doc.body);
19877 if (node.nodeName == "#text") {
19878 // clean up silly Windows -- stuff?
19881 if (node.nodeName == "#comment") {
19882 node.parentNode.removeChild(node);
19883 // clean up silly Windows -- stuff?
19887 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19888 node.parentNode.removeChild(node);
19892 // remove - but keep children..
19893 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19894 while (node.childNodes.length) {
19895 var cn = node.childNodes[0];
19896 node.removeChild(cn);
19897 node.parentNode.insertBefore(cn, node);
19899 node.parentNode.removeChild(node);
19900 this.iterateChildren(node, this.cleanWord);
19904 if (node.className.length) {
19906 var cn = node.className.split(/\W+/);
19908 Roo.each(cn, function(cls) {
19909 if (cls.match(/Mso[a-zA-Z]+/)) {
19914 node.className = cna.length ? cna.join(' ') : '';
19916 node.removeAttribute("class");
19920 if (node.hasAttribute("lang")) {
19921 node.removeAttribute("lang");
19924 if (node.hasAttribute("style")) {
19926 var styles = node.getAttribute("style").split(";");
19928 Roo.each(styles, function(s) {
19929 if (!s.match(/:/)) {
19932 var kv = s.split(":");
19933 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19936 // what ever is left... we allow.
19939 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19940 if (!nstyle.length) {
19941 node.removeAttribute('style');
19944 this.iterateChildren(node, this.cleanWord);
19950 * iterateChildren of a Node, calling fn each time, using this as the scole..
19951 * @param {DomNode} node node to iterate children of.
19952 * @param {Function} fn method of this class to call on each item.
19954 iterateChildren : function(node, fn)
19956 if (!node.childNodes.length) {
19959 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19960 fn.call(this, node.childNodes[i])
19966 * cleanTableWidths.
19968 * Quite often pasting from word etc.. results in tables with column and widths.
19969 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19972 cleanTableWidths : function(node)
19977 this.cleanTableWidths(this.doc.body);
19982 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19985 Roo.log(node.tagName);
19986 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19987 this.iterateChildren(node, this.cleanTableWidths);
19990 if (node.hasAttribute('width')) {
19991 node.removeAttribute('width');
19995 if (node.hasAttribute("style")) {
19998 var styles = node.getAttribute("style").split(";");
20000 Roo.each(styles, function(s) {
20001 if (!s.match(/:/)) {
20004 var kv = s.split(":");
20005 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20008 // what ever is left... we allow.
20011 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20012 if (!nstyle.length) {
20013 node.removeAttribute('style');
20017 this.iterateChildren(node, this.cleanTableWidths);
20025 domToHTML : function(currentElement, depth, nopadtext) {
20027 depth = depth || 0;
20028 nopadtext = nopadtext || false;
20030 if (!currentElement) {
20031 return this.domToHTML(this.doc.body);
20034 //Roo.log(currentElement);
20036 var allText = false;
20037 var nodeName = currentElement.nodeName;
20038 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20040 if (nodeName == '#text') {
20042 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20047 if (nodeName != 'BODY') {
20050 // Prints the node tagName, such as <A>, <IMG>, etc
20053 for(i = 0; i < currentElement.attributes.length;i++) {
20055 var aname = currentElement.attributes.item(i).name;
20056 if (!currentElement.attributes.item(i).value.length) {
20059 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20062 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20071 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20074 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20079 // Traverse the tree
20081 var currentElementChild = currentElement.childNodes.item(i);
20082 var allText = true;
20083 var innerHTML = '';
20085 while (currentElementChild) {
20086 // Formatting code (indent the tree so it looks nice on the screen)
20087 var nopad = nopadtext;
20088 if (lastnode == 'SPAN') {
20092 if (currentElementChild.nodeName == '#text') {
20093 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
20094 toadd = nopadtext ? toadd : toadd.trim();
20095 if (!nopad && toadd.length > 80) {
20096 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
20098 innerHTML += toadd;
20101 currentElementChild = currentElement.childNodes.item(i);
20107 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
20109 // Recursively traverse the tree structure of the child node
20110 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
20111 lastnode = currentElementChild.nodeName;
20113 currentElementChild=currentElement.childNodes.item(i);
20119 // The remaining code is mostly for formatting the tree
20120 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
20125 ret+= "</"+tagName+">";
20131 applyBlacklists : function()
20133 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
20134 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
20138 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
20139 if (b.indexOf(tag) > -1) {
20142 this.white.push(tag);
20146 Roo.each(w, function(tag) {
20147 if (b.indexOf(tag) > -1) {
20150 if (this.white.indexOf(tag) > -1) {
20153 this.white.push(tag);
20158 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
20159 if (w.indexOf(tag) > -1) {
20162 this.black.push(tag);
20166 Roo.each(b, function(tag) {
20167 if (w.indexOf(tag) > -1) {
20170 if (this.black.indexOf(tag) > -1) {
20173 this.black.push(tag);
20178 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
20179 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
20183 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
20184 if (b.indexOf(tag) > -1) {
20187 this.cwhite.push(tag);
20191 Roo.each(w, function(tag) {
20192 if (b.indexOf(tag) > -1) {
20195 if (this.cwhite.indexOf(tag) > -1) {
20198 this.cwhite.push(tag);
20203 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
20204 if (w.indexOf(tag) > -1) {
20207 this.cblack.push(tag);
20211 Roo.each(b, function(tag) {
20212 if (w.indexOf(tag) > -1) {
20215 if (this.cblack.indexOf(tag) > -1) {
20218 this.cblack.push(tag);
20223 setStylesheets : function(stylesheets)
20225 if(typeof(stylesheets) == 'string'){
20226 Roo.get(this.iframe.contentDocument.head).createChild({
20228 rel : 'stylesheet',
20237 Roo.each(stylesheets, function(s) {
20242 Roo.get(_this.iframe.contentDocument.head).createChild({
20244 rel : 'stylesheet',
20253 removeStylesheets : function()
20257 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
20262 // hide stuff that is not compatible
20276 * @event specialkey
20280 * @cfg {String} fieldClass @hide
20283 * @cfg {String} focusClass @hide
20286 * @cfg {String} autoCreate @hide
20289 * @cfg {String} inputType @hide
20292 * @cfg {String} invalidClass @hide
20295 * @cfg {String} invalidText @hide
20298 * @cfg {String} msgFx @hide
20301 * @cfg {String} validateOnBlur @hide
20305 Roo.HtmlEditorCore.white = [
20306 'area', 'br', 'img', 'input', 'hr', 'wbr',
20308 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
20309 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
20310 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
20311 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
20312 'table', 'ul', 'xmp',
20314 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
20317 'dir', 'menu', 'ol', 'ul', 'dl',
20323 Roo.HtmlEditorCore.black = [
20324 // 'embed', 'object', // enable - backend responsiblity to clean thiese
20326 'base', 'basefont', 'bgsound', 'blink', 'body',
20327 'frame', 'frameset', 'head', 'html', 'ilayer',
20328 'iframe', 'layer', 'link', 'meta', 'object',
20329 'script', 'style' ,'title', 'xml' // clean later..
20331 Roo.HtmlEditorCore.clean = [
20332 'script', 'style', 'title', 'xml'
20334 Roo.HtmlEditorCore.remove = [
20339 Roo.HtmlEditorCore.ablack = [
20343 Roo.HtmlEditorCore.aclean = [
20344 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
20348 Roo.HtmlEditorCore.pwhite= [
20349 'http', 'https', 'mailto'
20352 // white listed style attributes.
20353 Roo.HtmlEditorCore.cwhite= [
20354 // 'text-align', /// default is to allow most things..
20360 // black listed style attributes.
20361 Roo.HtmlEditorCore.cblack= [
20362 // 'font-size' -- this can be set by the project
20366 Roo.HtmlEditorCore.swapCodes =[
20385 * @class Roo.bootstrap.HtmlEditor
20386 * @extends Roo.bootstrap.TextArea
20387 * Bootstrap HtmlEditor class
20390 * Create a new HtmlEditor
20391 * @param {Object} config The config object
20394 Roo.bootstrap.HtmlEditor = function(config){
20395 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
20396 if (!this.toolbars) {
20397 this.toolbars = [];
20399 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
20402 * @event initialize
20403 * Fires when the editor is fully initialized (including the iframe)
20404 * @param {HtmlEditor} this
20409 * Fires when the editor is first receives the focus. Any insertion must wait
20410 * until after this event.
20411 * @param {HtmlEditor} this
20415 * @event beforesync
20416 * Fires before the textarea is updated with content from the editor iframe. Return false
20417 * to cancel the sync.
20418 * @param {HtmlEditor} this
20419 * @param {String} html
20423 * @event beforepush
20424 * Fires before the iframe editor is updated with content from the textarea. Return false
20425 * to cancel the push.
20426 * @param {HtmlEditor} this
20427 * @param {String} html
20432 * Fires when the textarea is updated with content from the editor iframe.
20433 * @param {HtmlEditor} this
20434 * @param {String} html
20439 * Fires when the iframe editor is updated with content from the textarea.
20440 * @param {HtmlEditor} this
20441 * @param {String} html
20445 * @event editmodechange
20446 * Fires when the editor switches edit modes
20447 * @param {HtmlEditor} this
20448 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
20450 editmodechange: true,
20452 * @event editorevent
20453 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20454 * @param {HtmlEditor} this
20458 * @event firstfocus
20459 * Fires when on first focus - needed by toolbars..
20460 * @param {HtmlEditor} this
20465 * Auto save the htmlEditor value as a file into Events
20466 * @param {HtmlEditor} this
20470 * @event savedpreview
20471 * preview the saved version of htmlEditor
20472 * @param {HtmlEditor} this
20479 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
20483 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
20488 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20493 * @cfg {Number} height (in pixels)
20497 * @cfg {Number} width (in pixels)
20502 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20505 stylesheets: false,
20510 // private properties
20511 validationEvent : false,
20513 initialized : false,
20516 onFocus : Roo.emptyFn,
20518 hideMode:'offsets',
20521 tbContainer : false,
20523 toolbarContainer :function() {
20524 return this.wrap.select('.x-html-editor-tb',true).first();
20528 * Protected method that will not generally be called directly. It
20529 * is called when the editor creates its toolbar. Override this method if you need to
20530 * add custom toolbar buttons.
20531 * @param {HtmlEditor} editor
20533 createToolbar : function(){
20535 Roo.log("create toolbars");
20537 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
20538 this.toolbars[0].render(this.toolbarContainer());
20542 // if (!editor.toolbars || !editor.toolbars.length) {
20543 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
20546 // for (var i =0 ; i < editor.toolbars.length;i++) {
20547 // editor.toolbars[i] = Roo.factory(
20548 // typeof(editor.toolbars[i]) == 'string' ?
20549 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
20550 // Roo.bootstrap.HtmlEditor);
20551 // editor.toolbars[i].init(editor);
20557 onRender : function(ct, position)
20559 // Roo.log("Call onRender: " + this.xtype);
20561 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
20563 this.wrap = this.inputEl().wrap({
20564 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
20567 this.editorcore.onRender(ct, position);
20569 if (this.resizable) {
20570 this.resizeEl = new Roo.Resizable(this.wrap, {
20574 minHeight : this.height,
20575 height: this.height,
20576 handles : this.resizable,
20579 resize : function(r, w, h) {
20580 _t.onResize(w,h); // -something
20586 this.createToolbar(this);
20589 if(!this.width && this.resizable){
20590 this.setSize(this.wrap.getSize());
20592 if (this.resizeEl) {
20593 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
20594 // should trigger onReize..
20600 onResize : function(w, h)
20602 Roo.log('resize: ' +w + ',' + h );
20603 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20607 if(this.inputEl() ){
20608 if(typeof w == 'number'){
20609 var aw = w - this.wrap.getFrameWidth('lr');
20610 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20613 if(typeof h == 'number'){
20614 var tbh = -11; // fixme it needs to tool bar size!
20615 for (var i =0; i < this.toolbars.length;i++) {
20616 // fixme - ask toolbars for heights?
20617 tbh += this.toolbars[i].el.getHeight();
20618 //if (this.toolbars[i].footer) {
20619 // tbh += this.toolbars[i].footer.el.getHeight();
20627 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20628 ah -= 5; // knock a few pixes off for look..
20629 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20633 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20634 this.editorcore.onResize(ew,eh);
20639 * Toggles the editor between standard and source edit mode.
20640 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20642 toggleSourceEdit : function(sourceEditMode)
20644 this.editorcore.toggleSourceEdit(sourceEditMode);
20646 if(this.editorcore.sourceEditMode){
20647 Roo.log('editor - showing textarea');
20650 // Roo.log(this.syncValue());
20652 this.inputEl().removeClass(['hide', 'x-hidden']);
20653 this.inputEl().dom.removeAttribute('tabIndex');
20654 this.inputEl().focus();
20656 Roo.log('editor - hiding textarea');
20658 // Roo.log(this.pushValue());
20661 this.inputEl().addClass(['hide', 'x-hidden']);
20662 this.inputEl().dom.setAttribute('tabIndex', -1);
20663 //this.deferFocus();
20666 if(this.resizable){
20667 this.setSize(this.wrap.getSize());
20670 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20673 // private (for BoxComponent)
20674 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20676 // private (for BoxComponent)
20677 getResizeEl : function(){
20681 // private (for BoxComponent)
20682 getPositionEl : function(){
20687 initEvents : function(){
20688 this.originalValue = this.getValue();
20692 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20695 // markInvalid : Roo.emptyFn,
20697 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20700 // clearInvalid : Roo.emptyFn,
20702 setValue : function(v){
20703 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20704 this.editorcore.pushValue();
20709 deferFocus : function(){
20710 this.focus.defer(10, this);
20714 focus : function(){
20715 this.editorcore.focus();
20721 onDestroy : function(){
20727 for (var i =0; i < this.toolbars.length;i++) {
20728 // fixme - ask toolbars for heights?
20729 this.toolbars[i].onDestroy();
20732 this.wrap.dom.innerHTML = '';
20733 this.wrap.remove();
20738 onFirstFocus : function(){
20739 //Roo.log("onFirstFocus");
20740 this.editorcore.onFirstFocus();
20741 for (var i =0; i < this.toolbars.length;i++) {
20742 this.toolbars[i].onFirstFocus();
20748 syncValue : function()
20750 this.editorcore.syncValue();
20753 pushValue : function()
20755 this.editorcore.pushValue();
20759 // hide stuff that is not compatible
20773 * @event specialkey
20777 * @cfg {String} fieldClass @hide
20780 * @cfg {String} focusClass @hide
20783 * @cfg {String} autoCreate @hide
20786 * @cfg {String} inputType @hide
20789 * @cfg {String} invalidClass @hide
20792 * @cfg {String} invalidText @hide
20795 * @cfg {String} msgFx @hide
20798 * @cfg {String} validateOnBlur @hide
20807 Roo.namespace('Roo.bootstrap.htmleditor');
20809 * @class Roo.bootstrap.HtmlEditorToolbar1
20814 new Roo.bootstrap.HtmlEditor({
20817 new Roo.bootstrap.HtmlEditorToolbar1({
20818 disable : { fonts: 1 , format: 1, ..., ... , ...],
20824 * @cfg {Object} disable List of elements to disable..
20825 * @cfg {Array} btns List of additional buttons.
20829 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20832 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20835 Roo.apply(this, config);
20837 // default disabled, based on 'good practice'..
20838 this.disable = this.disable || {};
20839 Roo.applyIf(this.disable, {
20842 specialElements : true
20844 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20846 this.editor = config.editor;
20847 this.editorcore = config.editor.editorcore;
20849 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20851 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20852 // dont call parent... till later.
20854 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20859 editorcore : false,
20864 "h1","h2","h3","h4","h5","h6",
20866 "abbr", "acronym", "address", "cite", "samp", "var",
20870 onRender : function(ct, position)
20872 // Roo.log("Call onRender: " + this.xtype);
20874 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20876 this.el.dom.style.marginBottom = '0';
20878 var editorcore = this.editorcore;
20879 var editor= this.editor;
20882 var btn = function(id,cmd , toggle, handler){
20884 var event = toggle ? 'toggle' : 'click';
20889 xns: Roo.bootstrap,
20892 enableToggle:toggle !== false,
20894 pressed : toggle ? false : null,
20897 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20898 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20907 xns: Roo.bootstrap,
20908 glyphicon : 'font',
20912 xns: Roo.bootstrap,
20916 Roo.each(this.formats, function(f) {
20917 style.menu.items.push({
20919 xns: Roo.bootstrap,
20920 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20925 editorcore.insertTag(this.tagname);
20932 children.push(style);
20935 btn('bold',false,true);
20936 btn('italic',false,true);
20937 btn('align-left', 'justifyleft',true);
20938 btn('align-center', 'justifycenter',true);
20939 btn('align-right' , 'justifyright',true);
20940 btn('link', false, false, function(btn) {
20941 //Roo.log("create link?");
20942 var url = prompt(this.createLinkText, this.defaultLinkValue);
20943 if(url && url != 'http:/'+'/'){
20944 this.editorcore.relayCmd('createlink', url);
20947 btn('list','insertunorderedlist',true);
20948 btn('pencil', false,true, function(btn){
20951 this.toggleSourceEdit(btn.pressed);
20957 xns: Roo.bootstrap,
20962 xns: Roo.bootstrap,
20967 cog.menu.items.push({
20969 xns: Roo.bootstrap,
20970 html : Clean styles,
20975 editorcore.insertTag(this.tagname);
20984 this.xtype = 'NavSimplebar';
20986 for(var i=0;i< children.length;i++) {
20988 this.buttons.add(this.addxtypeChild(children[i]));
20992 editor.on('editorevent', this.updateToolbar, this);
20994 onBtnClick : function(id)
20996 this.editorcore.relayCmd(id);
20997 this.editorcore.focus();
21001 * Protected method that will not generally be called directly. It triggers
21002 * a toolbar update by reading the markup state of the current selection in the editor.
21004 updateToolbar: function(){
21006 if(!this.editorcore.activated){
21007 this.editor.onFirstFocus(); // is this neeed?
21011 var btns = this.buttons;
21012 var doc = this.editorcore.doc;
21013 btns.get('bold').setActive(doc.queryCommandState('bold'));
21014 btns.get('italic').setActive(doc.queryCommandState('italic'));
21015 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21017 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21018 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21019 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21021 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21022 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21025 var ans = this.editorcore.getAllAncestors();
21026 if (this.formatCombo) {
21029 var store = this.formatCombo.store;
21030 this.formatCombo.setValue("");
21031 for (var i =0; i < ans.length;i++) {
21032 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21034 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21042 // hides menus... - so this cant be on a menu...
21043 Roo.bootstrap.MenuMgr.hideAll();
21045 Roo.bootstrap.MenuMgr.hideAll();
21046 //this.editorsyncValue();
21048 onFirstFocus: function() {
21049 this.buttons.each(function(item){
21053 toggleSourceEdit : function(sourceEditMode){
21056 if(sourceEditMode){
21057 Roo.log("disabling buttons");
21058 this.buttons.each( function(item){
21059 if(item.cmd != 'pencil'){
21065 Roo.log("enabling buttons");
21066 if(this.editorcore.initialized){
21067 this.buttons.each( function(item){
21073 Roo.log("calling toggole on editor");
21074 // tell the editor that it's been pressed..
21075 this.editor.toggleSourceEdit(sourceEditMode);
21085 * @class Roo.bootstrap.Table.AbstractSelectionModel
21086 * @extends Roo.util.Observable
21087 * Abstract base class for grid SelectionModels. It provides the interface that should be
21088 * implemented by descendant classes. This class should not be directly instantiated.
21091 Roo.bootstrap.Table.AbstractSelectionModel = function(){
21092 this.locked = false;
21093 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
21097 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
21098 /** @ignore Called by the grid automatically. Do not call directly. */
21099 init : function(grid){
21105 * Locks the selections.
21108 this.locked = true;
21112 * Unlocks the selections.
21114 unlock : function(){
21115 this.locked = false;
21119 * Returns true if the selections are locked.
21120 * @return {Boolean}
21122 isLocked : function(){
21123 return this.locked;
21127 * @extends Roo.bootstrap.Table.AbstractSelectionModel
21128 * @class Roo.bootstrap.Table.RowSelectionModel
21129 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
21130 * It supports multiple selections and keyboard selection/navigation.
21132 * @param {Object} config
21135 Roo.bootstrap.Table.RowSelectionModel = function(config){
21136 Roo.apply(this, config);
21137 this.selections = new Roo.util.MixedCollection(false, function(o){
21142 this.lastActive = false;
21146 * @event selectionchange
21147 * Fires when the selection changes
21148 * @param {SelectionModel} this
21150 "selectionchange" : true,
21152 * @event afterselectionchange
21153 * Fires after the selection changes (eg. by key press or clicking)
21154 * @param {SelectionModel} this
21156 "afterselectionchange" : true,
21158 * @event beforerowselect
21159 * Fires when a row is selected being selected, return false to cancel.
21160 * @param {SelectionModel} this
21161 * @param {Number} rowIndex The selected index
21162 * @param {Boolean} keepExisting False if other selections will be cleared
21164 "beforerowselect" : true,
21167 * Fires when a row is selected.
21168 * @param {SelectionModel} this
21169 * @param {Number} rowIndex The selected index
21170 * @param {Roo.data.Record} r The record
21172 "rowselect" : true,
21174 * @event rowdeselect
21175 * Fires when a row is deselected.
21176 * @param {SelectionModel} this
21177 * @param {Number} rowIndex The selected index
21179 "rowdeselect" : true
21181 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
21182 this.locked = false;
21185 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
21187 * @cfg {Boolean} singleSelect
21188 * True to allow selection of only one row at a time (defaults to false)
21190 singleSelect : false,
21193 initEvents : function(){
21195 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
21196 this.grid.on("mousedown", this.handleMouseDown, this);
21197 }else{ // allow click to work like normal
21198 this.grid.on("rowclick", this.handleDragableRowClick, this);
21201 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
21202 "up" : function(e){
21204 this.selectPrevious(e.shiftKey);
21205 }else if(this.last !== false && this.lastActive !== false){
21206 var last = this.last;
21207 this.selectRange(this.last, this.lastActive-1);
21208 this.grid.getView().focusRow(this.lastActive);
21209 if(last !== false){
21213 this.selectFirstRow();
21215 this.fireEvent("afterselectionchange", this);
21217 "down" : function(e){
21219 this.selectNext(e.shiftKey);
21220 }else if(this.last !== false && this.lastActive !== false){
21221 var last = this.last;
21222 this.selectRange(this.last, this.lastActive+1);
21223 this.grid.getView().focusRow(this.lastActive);
21224 if(last !== false){
21228 this.selectFirstRow();
21230 this.fireEvent("afterselectionchange", this);
21235 var view = this.grid.view;
21236 view.on("refresh", this.onRefresh, this);
21237 view.on("rowupdated", this.onRowUpdated, this);
21238 view.on("rowremoved", this.onRemove, this);
21242 onRefresh : function(){
21243 var ds = this.grid.dataSource, i, v = this.grid.view;
21244 var s = this.selections;
21245 s.each(function(r){
21246 if((i = ds.indexOfId(r.id)) != -1){
21255 onRemove : function(v, index, r){
21256 this.selections.remove(r);
21260 onRowUpdated : function(v, index, r){
21261 if(this.isSelected(r)){
21262 v.onRowSelect(index);
21268 * @param {Array} records The records to select
21269 * @param {Boolean} keepExisting (optional) True to keep existing selections
21271 selectRecords : function(records, keepExisting){
21273 this.clearSelections();
21275 var ds = this.grid.dataSource;
21276 for(var i = 0, len = records.length; i < len; i++){
21277 this.selectRow(ds.indexOf(records[i]), true);
21282 * Gets the number of selected rows.
21285 getCount : function(){
21286 return this.selections.length;
21290 * Selects the first row in the grid.
21292 selectFirstRow : function(){
21297 * Select the last row.
21298 * @param {Boolean} keepExisting (optional) True to keep existing selections
21300 selectLastRow : function(keepExisting){
21301 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
21305 * Selects the row immediately following the last selected row.
21306 * @param {Boolean} keepExisting (optional) True to keep existing selections
21308 selectNext : function(keepExisting){
21309 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
21310 this.selectRow(this.last+1, keepExisting);
21311 this.grid.getView().focusRow(this.last);
21316 * Selects the row that precedes the last selected row.
21317 * @param {Boolean} keepExisting (optional) True to keep existing selections
21319 selectPrevious : function(keepExisting){
21321 this.selectRow(this.last-1, keepExisting);
21322 this.grid.getView().focusRow(this.last);
21327 * Returns the selected records
21328 * @return {Array} Array of selected records
21330 getSelections : function(){
21331 return [].concat(this.selections.items);
21335 * Returns the first selected record.
21338 getSelected : function(){
21339 return this.selections.itemAt(0);
21344 * Clears all selections.
21346 clearSelections : function(fast){
21347 if(this.locked) return;
21349 var ds = this.grid.dataSource;
21350 var s = this.selections;
21351 s.each(function(r){
21352 this.deselectRow(ds.indexOfId(r.id));
21356 this.selections.clear();
21363 * Selects all rows.
21365 selectAll : function(){
21366 if(this.locked) return;
21367 this.selections.clear();
21368 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
21369 this.selectRow(i, true);
21374 * Returns True if there is a selection.
21375 * @return {Boolean}
21377 hasSelection : function(){
21378 return this.selections.length > 0;
21382 * Returns True if the specified row is selected.
21383 * @param {Number/Record} record The record or index of the record to check
21384 * @return {Boolean}
21386 isSelected : function(index){
21387 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
21388 return (r && this.selections.key(r.id) ? true : false);
21392 * Returns True if the specified record id is selected.
21393 * @param {String} id The id of record to check
21394 * @return {Boolean}
21396 isIdSelected : function(id){
21397 return (this.selections.key(id) ? true : false);
21401 handleMouseDown : function(e, t){
21402 var view = this.grid.getView(), rowIndex;
21403 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
21406 if(e.shiftKey && this.last !== false){
21407 var last = this.last;
21408 this.selectRange(last, rowIndex, e.ctrlKey);
21409 this.last = last; // reset the last
21410 view.focusRow(rowIndex);
21412 var isSelected = this.isSelected(rowIndex);
21413 if(e.button !== 0 && isSelected){
21414 view.focusRow(rowIndex);
21415 }else if(e.ctrlKey && isSelected){
21416 this.deselectRow(rowIndex);
21417 }else if(!isSelected){
21418 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
21419 view.focusRow(rowIndex);
21422 this.fireEvent("afterselectionchange", this);
21425 handleDragableRowClick : function(grid, rowIndex, e)
21427 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
21428 this.selectRow(rowIndex, false);
21429 grid.view.focusRow(rowIndex);
21430 this.fireEvent("afterselectionchange", this);
21435 * Selects multiple rows.
21436 * @param {Array} rows Array of the indexes of the row to select
21437 * @param {Boolean} keepExisting (optional) True to keep existing selections
21439 selectRows : function(rows, keepExisting){
21441 this.clearSelections();
21443 for(var i = 0, len = rows.length; i < len; i++){
21444 this.selectRow(rows[i], true);
21449 * Selects a range of rows. All rows in between startRow and endRow are also selected.
21450 * @param {Number} startRow The index of the first row in the range
21451 * @param {Number} endRow The index of the last row in the range
21452 * @param {Boolean} keepExisting (optional) True to retain existing selections
21454 selectRange : function(startRow, endRow, keepExisting){
21455 if(this.locked) return;
21457 this.clearSelections();
21459 if(startRow <= endRow){
21460 for(var i = startRow; i <= endRow; i++){
21461 this.selectRow(i, true);
21464 for(var i = startRow; i >= endRow; i--){
21465 this.selectRow(i, true);
21471 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
21472 * @param {Number} startRow The index of the first row in the range
21473 * @param {Number} endRow The index of the last row in the range
21475 deselectRange : function(startRow, endRow, preventViewNotify){
21476 if(this.locked) return;
21477 for(var i = startRow; i <= endRow; i++){
21478 this.deselectRow(i, preventViewNotify);
21484 * @param {Number} row The index of the row to select
21485 * @param {Boolean} keepExisting (optional) True to keep existing selections
21487 selectRow : function(index, keepExisting, preventViewNotify){
21488 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
21489 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
21490 if(!keepExisting || this.singleSelect){
21491 this.clearSelections();
21493 var r = this.grid.dataSource.getAt(index);
21494 this.selections.add(r);
21495 this.last = this.lastActive = index;
21496 if(!preventViewNotify){
21497 this.grid.getView().onRowSelect(index);
21499 this.fireEvent("rowselect", this, index, r);
21500 this.fireEvent("selectionchange", this);
21506 * @param {Number} row The index of the row to deselect
21508 deselectRow : function(index, preventViewNotify){
21509 if(this.locked) return;
21510 if(this.last == index){
21513 if(this.lastActive == index){
21514 this.lastActive = false;
21516 var r = this.grid.dataSource.getAt(index);
21517 this.selections.remove(r);
21518 if(!preventViewNotify){
21519 this.grid.getView().onRowDeselect(index);
21521 this.fireEvent("rowdeselect", this, index);
21522 this.fireEvent("selectionchange", this);
21526 restoreLast : function(){
21528 this.last = this._last;
21533 acceptsNav : function(row, col, cm){
21534 return !cm.isHidden(col) && cm.isCellEditable(col, row);
21538 onEditorKey : function(field, e){
21539 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
21544 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
21546 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
21548 }else if(k == e.ENTER && !e.ctrlKey){
21552 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
21554 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
21556 }else if(k == e.ESC){
21560 g.startEditing(newCell[0], newCell[1]);
21565 * Ext JS Library 1.1.1
21566 * Copyright(c) 2006-2007, Ext JS, LLC.
21568 * Originally Released Under LGPL - original licence link has changed is not relivant.
21571 * <script type="text/javascript">
21575 * @class Roo.bootstrap.PagingToolbar
21577 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
21579 * Create a new PagingToolbar
21580 * @param {Object} config The config object
21582 Roo.bootstrap.PagingToolbar = function(config)
21584 // old args format still supported... - xtype is prefered..
21585 // created from xtype...
21586 var ds = config.dataSource;
21587 this.toolbarItems = [];
21588 if (config.items) {
21589 this.toolbarItems = config.items;
21590 // config.items = [];
21593 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
21600 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
21604 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21606 * @cfg {Roo.data.Store} dataSource
21607 * The underlying data store providing the paged data
21610 * @cfg {String/HTMLElement/Element} container
21611 * container The id or element that will contain the toolbar
21614 * @cfg {Boolean} displayInfo
21615 * True to display the displayMsg (defaults to false)
21618 * @cfg {Number} pageSize
21619 * The number of records to display per page (defaults to 20)
21623 * @cfg {String} displayMsg
21624 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21626 displayMsg : 'Displaying {0} - {1} of {2}',
21628 * @cfg {String} emptyMsg
21629 * The message to display when no records are found (defaults to "No data to display")
21631 emptyMsg : 'No data to display',
21633 * Customizable piece of the default paging text (defaults to "Page")
21636 beforePageText : "Page",
21638 * Customizable piece of the default paging text (defaults to "of %0")
21641 afterPageText : "of {0}",
21643 * Customizable piece of the default paging text (defaults to "First Page")
21646 firstText : "First Page",
21648 * Customizable piece of the default paging text (defaults to "Previous Page")
21651 prevText : "Previous Page",
21653 * Customizable piece of the default paging text (defaults to "Next Page")
21656 nextText : "Next Page",
21658 * Customizable piece of the default paging text (defaults to "Last Page")
21661 lastText : "Last Page",
21663 * Customizable piece of the default paging text (defaults to "Refresh")
21666 refreshText : "Refresh",
21670 onRender : function(ct, position)
21672 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21673 this.navgroup.parentId = this.id;
21674 this.navgroup.onRender(this.el, null);
21675 // add the buttons to the navgroup
21677 if(this.displayInfo){
21678 Roo.log(this.el.select('ul.navbar-nav',true).first());
21679 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21680 this.displayEl = this.el.select('.x-paging-info', true).first();
21681 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21682 // this.displayEl = navel.el.select('span',true).first();
21688 Roo.each(_this.buttons, function(e){
21689 Roo.factory(e).onRender(_this.el, null);
21693 Roo.each(_this.toolbarItems, function(e) {
21694 _this.navgroup.addItem(e);
21698 this.first = this.navgroup.addItem({
21699 tooltip: this.firstText,
21701 icon : 'fa fa-backward',
21703 preventDefault: true,
21704 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21707 this.prev = this.navgroup.addItem({
21708 tooltip: this.prevText,
21710 icon : 'fa fa-step-backward',
21712 preventDefault: true,
21713 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21715 //this.addSeparator();
21718 var field = this.navgroup.addItem( {
21720 cls : 'x-paging-position',
21722 html : this.beforePageText +
21723 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21724 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21727 this.field = field.el.select('input', true).first();
21728 this.field.on("keydown", this.onPagingKeydown, this);
21729 this.field.on("focus", function(){this.dom.select();});
21732 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21733 //this.field.setHeight(18);
21734 //this.addSeparator();
21735 this.next = this.navgroup.addItem({
21736 tooltip: this.nextText,
21738 html : ' <i class="fa fa-step-forward">',
21740 preventDefault: true,
21741 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21743 this.last = this.navgroup.addItem({
21744 tooltip: this.lastText,
21745 icon : 'fa fa-forward',
21748 preventDefault: true,
21749 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21751 //this.addSeparator();
21752 this.loading = this.navgroup.addItem({
21753 tooltip: this.refreshText,
21754 icon: 'fa fa-refresh',
21755 preventDefault: true,
21756 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21762 updateInfo : function(){
21763 if(this.displayEl){
21764 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21765 var msg = count == 0 ?
21769 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21771 this.displayEl.update(msg);
21776 onLoad : function(ds, r, o){
21777 this.cursor = o.params ? o.params.start : 0;
21778 var d = this.getPageData(),
21782 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21783 this.field.dom.value = ap;
21784 this.first.setDisabled(ap == 1);
21785 this.prev.setDisabled(ap == 1);
21786 this.next.setDisabled(ap == ps);
21787 this.last.setDisabled(ap == ps);
21788 this.loading.enable();
21793 getPageData : function(){
21794 var total = this.ds.getTotalCount();
21797 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21798 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21803 onLoadError : function(){
21804 this.loading.enable();
21808 onPagingKeydown : function(e){
21809 var k = e.getKey();
21810 var d = this.getPageData();
21812 var v = this.field.dom.value, pageNum;
21813 if(!v || isNaN(pageNum = parseInt(v, 10))){
21814 this.field.dom.value = d.activePage;
21817 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21818 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21821 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
21823 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21824 this.field.dom.value = pageNum;
21825 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21828 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21830 var v = this.field.dom.value, pageNum;
21831 var increment = (e.shiftKey) ? 10 : 1;
21832 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21834 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21835 this.field.dom.value = d.activePage;
21838 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21840 this.field.dom.value = parseInt(v, 10) + increment;
21841 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21842 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21849 beforeLoad : function(){
21851 this.loading.disable();
21856 onClick : function(which){
21865 ds.load({params:{start: 0, limit: this.pageSize}});
21868 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21871 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21874 var total = ds.getTotalCount();
21875 var extra = total % this.pageSize;
21876 var lastStart = extra ? (total - extra) : total-this.pageSize;
21877 ds.load({params:{start: lastStart, limit: this.pageSize}});
21880 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21886 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21887 * @param {Roo.data.Store} store The data store to unbind
21889 unbind : function(ds){
21890 ds.un("beforeload", this.beforeLoad, this);
21891 ds.un("load", this.onLoad, this);
21892 ds.un("loadexception", this.onLoadError, this);
21893 ds.un("remove", this.updateInfo, this);
21894 ds.un("add", this.updateInfo, this);
21895 this.ds = undefined;
21899 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21900 * @param {Roo.data.Store} store The data store to bind
21902 bind : function(ds){
21903 ds.on("beforeload", this.beforeLoad, this);
21904 ds.on("load", this.onLoad, this);
21905 ds.on("loadexception", this.onLoadError, this);
21906 ds.on("remove", this.updateInfo, this);
21907 ds.on("add", this.updateInfo, this);
21918 * @class Roo.bootstrap.MessageBar
21919 * @extends Roo.bootstrap.Component
21920 * Bootstrap MessageBar class
21921 * @cfg {String} html contents of the MessageBar
21922 * @cfg {String} weight (info | success | warning | danger) default info
21923 * @cfg {String} beforeClass insert the bar before the given class
21924 * @cfg {Boolean} closable (true | false) default false
21925 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21928 * Create a new Element
21929 * @param {Object} config The config object
21932 Roo.bootstrap.MessageBar = function(config){
21933 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21936 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21942 beforeClass: 'bootstrap-sticky-wrap',
21944 getAutoCreate : function(){
21948 cls: 'alert alert-dismissable alert-' + this.weight,
21953 html: this.html || ''
21959 cfg.cls += ' alert-messages-fixed';
21973 onRender : function(ct, position)
21975 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21978 var cfg = Roo.apply({}, this.getAutoCreate());
21982 cfg.cls += ' ' + this.cls;
21985 cfg.style = this.style;
21987 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21989 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21992 this.el.select('>button.close').on('click', this.hide, this);
21998 if (!this.rendered) {
22004 this.fireEvent('show', this);
22010 if (!this.rendered) {
22016 this.fireEvent('hide', this);
22019 update : function()
22021 // var e = this.el.dom.firstChild;
22023 // if(this.closable){
22024 // e = e.nextSibling;
22027 // e.data = this.html || '';
22029 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22045 * @class Roo.bootstrap.Graph
22046 * @extends Roo.bootstrap.Component
22047 * Bootstrap Graph class
22051 @cfg {String} graphtype bar | vbar | pie
22052 @cfg {number} g_x coodinator | centre x (pie)
22053 @cfg {number} g_y coodinator | centre y (pie)
22054 @cfg {number} g_r radius (pie)
22055 @cfg {number} g_height height of the chart (respected by all elements in the set)
22056 @cfg {number} g_width width of the chart (respected by all elements in the set)
22057 @cfg {Object} title The title of the chart
22060 -opts (object) options for the chart
22062 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
22063 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
22065 o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
22066 o stacked (boolean) whether or not to tread values as in a stacked bar chart
22068 o stretch (boolean)
22070 -opts (object) options for the pie
22073 o startAngle (number)
22074 o endAngle (number)
22078 * Create a new Input
22079 * @param {Object} config The config object
22082 Roo.bootstrap.Graph = function(config){
22083 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
22089 * The img click event for the img.
22090 * @param {Roo.EventObject} e
22096 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
22107 //g_colors: this.colors,
22114 getAutoCreate : function(){
22125 onRender : function(ct,position){
22126 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
22127 this.raphael = Raphael(this.el.dom);
22129 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22130 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22131 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22132 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
22134 r.text(160, 10, "Single Series Chart").attr(txtattr);
22135 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
22136 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
22137 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
22139 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
22140 r.barchart(330, 10, 300, 220, data1);
22141 r.barchart(10, 250, 300, 220, data2, {stacked: true});
22142 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
22145 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22146 // r.barchart(30, 30, 560, 250, xdata, {
22147 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
22148 // axis : "0 0 1 1",
22149 // axisxlabels : xdata
22150 // //yvalues : cols,
22153 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22155 // this.load(null,xdata,{
22156 // axis : "0 0 1 1",
22157 // axisxlabels : xdata
22162 load : function(graphtype,xdata,opts){
22163 this.raphael.clear();
22165 graphtype = this.graphtype;
22170 var r = this.raphael,
22171 fin = function () {
22172 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
22174 fout = function () {
22175 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
22177 pfin = function() {
22178 this.sector.stop();
22179 this.sector.scale(1.1, 1.1, this.cx, this.cy);
22182 this.label[0].stop();
22183 this.label[0].attr({ r: 7.5 });
22184 this.label[1].attr({ "font-weight": 800 });
22187 pfout = function() {
22188 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
22191 this.label[0].animate({ r: 5 }, 500, "bounce");
22192 this.label[1].attr({ "font-weight": 400 });
22198 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
22201 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
22204 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
22205 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
22207 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
22214 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
22219 setTitle: function(o)
22224 initEvents: function() {
22227 this.el.on('click', this.onClick, this);
22231 onClick : function(e)
22233 Roo.log('img onclick');
22234 this.fireEvent('click', this, e);
22246 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22249 * @class Roo.bootstrap.dash.NumberBox
22250 * @extends Roo.bootstrap.Component
22251 * Bootstrap NumberBox class
22252 * @cfg {String} headline Box headline
22253 * @cfg {String} content Box content
22254 * @cfg {String} icon Box icon
22255 * @cfg {String} footer Footer text
22256 * @cfg {String} fhref Footer href
22259 * Create a new NumberBox
22260 * @param {Object} config The config object
22264 Roo.bootstrap.dash.NumberBox = function(config){
22265 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
22269 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
22278 getAutoCreate : function(){
22282 cls : 'small-box ',
22290 cls : 'roo-headline',
22291 html : this.headline
22295 cls : 'roo-content',
22296 html : this.content
22310 cls : 'ion ' + this.icon
22319 cls : 'small-box-footer',
22320 href : this.fhref || '#',
22324 cfg.cn.push(footer);
22331 onRender : function(ct,position){
22332 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
22339 setHeadline: function (value)
22341 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
22344 setFooter: function (value, href)
22346 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
22349 this.el.select('a.small-box-footer',true).first().attr('href', href);
22354 setContent: function (value)
22356 this.el.select('.roo-content',true).first().dom.innerHTML = value;
22359 initEvents: function()
22373 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22376 * @class Roo.bootstrap.dash.TabBox
22377 * @extends Roo.bootstrap.Component
22378 * Bootstrap TabBox class
22379 * @cfg {String} title Title of the TabBox
22380 * @cfg {String} icon Icon of the TabBox
22381 * @cfg {Boolean} showtabs (true|false) show the tabs default true
22382 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
22385 * Create a new TabBox
22386 * @param {Object} config The config object
22390 Roo.bootstrap.dash.TabBox = function(config){
22391 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
22396 * When a pane is added
22397 * @param {Roo.bootstrap.dash.TabPane} pane
22401 * @event activatepane
22402 * When a pane is activated
22403 * @param {Roo.bootstrap.dash.TabPane} pane
22405 "activatepane" : true
22413 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
22418 tabScrollable : false,
22420 getChildContainer : function()
22422 return this.el.select('.tab-content', true).first();
22425 getAutoCreate : function(){
22429 cls: 'pull-left header',
22437 cls: 'fa ' + this.icon
22443 cls: 'nav nav-tabs pull-right',
22449 if(this.tabScrollable){
22456 cls: 'nav nav-tabs pull-right',
22467 cls: 'nav-tabs-custom',
22472 cls: 'tab-content no-padding',
22480 initEvents : function()
22482 //Roo.log('add add pane handler');
22483 this.on('addpane', this.onAddPane, this);
22486 * Updates the box title
22487 * @param {String} html to set the title to.
22489 setTitle : function(value)
22491 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
22493 onAddPane : function(pane)
22495 this.panes.push(pane);
22496 //Roo.log('addpane');
22498 // tabs are rendere left to right..
22499 if(!this.showtabs){
22503 var ctr = this.el.select('.nav-tabs', true).first();
22506 var existing = ctr.select('.nav-tab',true);
22507 var qty = existing.getCount();;
22510 var tab = ctr.createChild({
22512 cls : 'nav-tab' + (qty ? '' : ' active'),
22520 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
22523 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
22525 pane.el.addClass('active');
22530 onTabClick : function(ev,un,ob,pane)
22532 //Roo.log('tab - prev default');
22533 ev.preventDefault();
22536 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
22537 pane.tab.addClass('active');
22538 //Roo.log(pane.title);
22539 this.getChildContainer().select('.tab-pane',true).removeClass('active');
22540 // technically we should have a deactivate event.. but maybe add later.
22541 // and it should not de-activate the selected tab...
22542 this.fireEvent('activatepane', pane);
22543 pane.el.addClass('active');
22544 pane.fireEvent('activate');
22549 getActivePane : function()
22552 Roo.each(this.panes, function(p) {
22553 if(p.el.hasClass('active')){
22574 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22576 * @class Roo.bootstrap.TabPane
22577 * @extends Roo.bootstrap.Component
22578 * Bootstrap TabPane class
22579 * @cfg {Boolean} active (false | true) Default false
22580 * @cfg {String} title title of panel
22584 * Create a new TabPane
22585 * @param {Object} config The config object
22588 Roo.bootstrap.dash.TabPane = function(config){
22589 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
22595 * When a pane is activated
22596 * @param {Roo.bootstrap.dash.TabPane} pane
22603 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22608 // the tabBox that this is attached to.
22611 getAutoCreate : function()
22619 cfg.cls += ' active';
22624 initEvents : function()
22626 //Roo.log('trigger add pane handler');
22627 this.parent().fireEvent('addpane', this)
22631 * Updates the tab title
22632 * @param {String} html to set the title to.
22634 setTitle: function(str)
22640 this.tab.select('a', true).first().dom.innerHTML = str;
22657 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22660 * @class Roo.bootstrap.menu.Menu
22661 * @extends Roo.bootstrap.Component
22662 * Bootstrap Menu class - container for Menu
22663 * @cfg {String} html Text of the menu
22664 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22665 * @cfg {String} icon Font awesome icon
22666 * @cfg {String} pos Menu align to (top | bottom) default bottom
22670 * Create a new Menu
22671 * @param {Object} config The config object
22675 Roo.bootstrap.menu.Menu = function(config){
22676 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22680 * @event beforeshow
22681 * Fires before this menu is displayed
22682 * @param {Roo.bootstrap.menu.Menu} this
22686 * @event beforehide
22687 * Fires before this menu is hidden
22688 * @param {Roo.bootstrap.menu.Menu} this
22693 * Fires after this menu is displayed
22694 * @param {Roo.bootstrap.menu.Menu} this
22699 * Fires after this menu is hidden
22700 * @param {Roo.bootstrap.menu.Menu} this
22705 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22706 * @param {Roo.bootstrap.menu.Menu} this
22707 * @param {Roo.EventObject} e
22714 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22718 weight : 'default',
22723 getChildContainer : function() {
22724 if(this.isSubMenu){
22728 return this.el.select('ul.dropdown-menu', true).first();
22731 getAutoCreate : function()
22736 cls : 'roo-menu-text',
22744 cls : 'fa ' + this.icon
22755 cls : 'dropdown-button btn btn-' + this.weight,
22760 cls : 'dropdown-toggle btn btn-' + this.weight,
22770 cls : 'dropdown-menu'
22776 if(this.pos == 'top'){
22777 cfg.cls += ' dropup';
22780 if(this.isSubMenu){
22783 cls : 'dropdown-menu'
22790 onRender : function(ct, position)
22792 this.isSubMenu = ct.hasClass('dropdown-submenu');
22794 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22797 initEvents : function()
22799 if(this.isSubMenu){
22803 this.hidden = true;
22805 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22806 this.triggerEl.on('click', this.onTriggerPress, this);
22808 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22809 this.buttonEl.on('click', this.onClick, this);
22815 if(this.isSubMenu){
22819 return this.el.select('ul.dropdown-menu', true).first();
22822 onClick : function(e)
22824 this.fireEvent("click", this, e);
22827 onTriggerPress : function(e)
22829 if (this.isVisible()) {
22836 isVisible : function(){
22837 return !this.hidden;
22842 this.fireEvent("beforeshow", this);
22844 this.hidden = false;
22845 this.el.addClass('open');
22847 Roo.get(document).on("mouseup", this.onMouseUp, this);
22849 this.fireEvent("show", this);
22856 this.fireEvent("beforehide", this);
22858 this.hidden = true;
22859 this.el.removeClass('open');
22861 Roo.get(document).un("mouseup", this.onMouseUp);
22863 this.fireEvent("hide", this);
22866 onMouseUp : function()
22880 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22883 * @class Roo.bootstrap.menu.Item
22884 * @extends Roo.bootstrap.Component
22885 * Bootstrap MenuItem class
22886 * @cfg {Boolean} submenu (true | false) default false
22887 * @cfg {String} html text of the item
22888 * @cfg {String} href the link
22889 * @cfg {Boolean} disable (true | false) default false
22890 * @cfg {Boolean} preventDefault (true | false) default true
22891 * @cfg {String} icon Font awesome icon
22892 * @cfg {String} pos Submenu align to (left | right) default right
22896 * Create a new Item
22897 * @param {Object} config The config object
22901 Roo.bootstrap.menu.Item = function(config){
22902 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22906 * Fires when the mouse is hovering over this menu
22907 * @param {Roo.bootstrap.menu.Item} this
22908 * @param {Roo.EventObject} e
22913 * Fires when the mouse exits this menu
22914 * @param {Roo.bootstrap.menu.Item} this
22915 * @param {Roo.EventObject} e
22921 * The raw click event for the entire grid.
22922 * @param {Roo.EventObject} e
22928 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22933 preventDefault: true,
22938 getAutoCreate : function()
22943 cls : 'roo-menu-item-text',
22951 cls : 'fa ' + this.icon
22960 href : this.href || '#',
22967 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22971 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22973 if(this.pos == 'left'){
22974 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22981 initEvents : function()
22983 this.el.on('mouseover', this.onMouseOver, this);
22984 this.el.on('mouseout', this.onMouseOut, this);
22986 this.el.select('a', true).first().on('click', this.onClick, this);
22990 onClick : function(e)
22992 if(this.preventDefault){
22993 e.preventDefault();
22996 this.fireEvent("click", this, e);
22999 onMouseOver : function(e)
23001 if(this.submenu && this.pos == 'left'){
23002 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23005 this.fireEvent("mouseover", this, e);
23008 onMouseOut : function(e)
23010 this.fireEvent("mouseout", this, e);
23022 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23025 * @class Roo.bootstrap.menu.Separator
23026 * @extends Roo.bootstrap.Component
23027 * Bootstrap Separator class
23030 * Create a new Separator
23031 * @param {Object} config The config object
23035 Roo.bootstrap.menu.Separator = function(config){
23036 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23039 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23041 getAutoCreate : function(){
23062 * @class Roo.bootstrap.Tooltip
23063 * Bootstrap Tooltip class
23064 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
23065 * to determine which dom element triggers the tooltip.
23067 * It needs to add support for additional attributes like tooltip-position
23070 * Create a new Toolti
23071 * @param {Object} config The config object
23074 Roo.bootstrap.Tooltip = function(config){
23075 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
23078 Roo.apply(Roo.bootstrap.Tooltip, {
23080 * @function init initialize tooltip monitoring.
23084 currentTip : false,
23085 currentRegion : false,
23091 Roo.get(document).on('mouseover', this.enter ,this);
23092 Roo.get(document).on('mouseout', this.leave, this);
23095 this.currentTip = new Roo.bootstrap.Tooltip();
23098 enter : function(ev)
23100 var dom = ev.getTarget();
23102 //Roo.log(['enter',dom]);
23103 var el = Roo.fly(dom);
23104 if (this.currentEl) {
23106 //Roo.log(this.currentEl);
23107 //Roo.log(this.currentEl.contains(dom));
23108 if (this.currentEl == el) {
23111 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
23119 if (this.currentTip.el) {
23120 this.currentTip.el.hide(); // force hiding...
23125 // you can not look for children, as if el is the body.. then everythign is the child..
23126 if (!el.attr('tooltip')) { //
23127 if (!el.select("[tooltip]").elements.length) {
23130 // is the mouse over this child...?
23131 bindEl = el.select("[tooltip]").first();
23132 var xy = ev.getXY();
23133 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
23134 //Roo.log("not in region.");
23137 //Roo.log("child element over..");
23140 this.currentEl = bindEl;
23141 this.currentTip.bind(bindEl);
23142 this.currentRegion = Roo.lib.Region.getRegion(dom);
23143 this.currentTip.enter();
23146 leave : function(ev)
23148 var dom = ev.getTarget();
23149 //Roo.log(['leave',dom]);
23150 if (!this.currentEl) {
23155 if (dom != this.currentEl.dom) {
23158 var xy = ev.getXY();
23159 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
23162 // only activate leave if mouse cursor is outside... bounding box..
23167 if (this.currentTip) {
23168 this.currentTip.leave();
23170 //Roo.log('clear currentEl');
23171 this.currentEl = false;
23176 'left' : ['r-l', [-2,0], 'right'],
23177 'right' : ['l-r', [2,0], 'left'],
23178 'bottom' : ['t-b', [0,2], 'top'],
23179 'top' : [ 'b-t', [0,-2], 'bottom']
23185 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
23190 delay : null, // can be { show : 300 , hide: 500}
23194 hoverState : null, //???
23196 placement : 'bottom',
23198 getAutoCreate : function(){
23205 cls : 'tooltip-arrow'
23208 cls : 'tooltip-inner'
23215 bind : function(el)
23221 enter : function () {
23223 if (this.timeout != null) {
23224 clearTimeout(this.timeout);
23227 this.hoverState = 'in';
23228 //Roo.log("enter - show");
23229 if (!this.delay || !this.delay.show) {
23234 this.timeout = setTimeout(function () {
23235 if (_t.hoverState == 'in') {
23238 }, this.delay.show);
23242 clearTimeout(this.timeout);
23244 this.hoverState = 'out';
23245 if (!this.delay || !this.delay.hide) {
23251 this.timeout = setTimeout(function () {
23252 //Roo.log("leave - timeout");
23254 if (_t.hoverState == 'out') {
23256 Roo.bootstrap.Tooltip.currentEl = false;
23264 this.render(document.body);
23267 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
23269 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
23271 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
23273 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
23275 var placement = typeof this.placement == 'function' ?
23276 this.placement.call(this, this.el, on_el) :
23279 var autoToken = /\s?auto?\s?/i;
23280 var autoPlace = autoToken.test(placement);
23282 placement = placement.replace(autoToken, '') || 'top';
23286 //this.el.setXY([0,0]);
23288 //this.el.dom.style.display='block';
23289 this.el.addClass(placement);
23291 //this.el.appendTo(on_el);
23293 var p = this.getPosition();
23294 var box = this.el.getBox();
23299 var align = Roo.bootstrap.Tooltip.alignment[placement];
23300 this.el.alignTo(this.bindEl, align[0],align[1]);
23301 //var arrow = this.el.select('.arrow',true).first();
23302 //arrow.set(align[2],
23304 this.el.addClass('in fade');
23305 this.hoverState = null;
23307 if (this.el.hasClass('fade')) {
23318 //this.el.setXY([0,0]);
23319 this.el.removeClass('in');
23335 * @class Roo.bootstrap.LocationPicker
23336 * @extends Roo.bootstrap.Component
23337 * Bootstrap LocationPicker class
23338 * @cfg {Number} latitude Position when init default 0
23339 * @cfg {Number} longitude Position when init default 0
23340 * @cfg {Number} zoom default 15
23341 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
23342 * @cfg {Boolean} mapTypeControl default false
23343 * @cfg {Boolean} disableDoubleClickZoom default false
23344 * @cfg {Boolean} scrollwheel default true
23345 * @cfg {Boolean} streetViewControl default false
23346 * @cfg {Number} radius default 0
23347 * @cfg {String} locationName
23348 * @cfg {Boolean} draggable default true
23349 * @cfg {Boolean} enableAutocomplete default false
23350 * @cfg {Boolean} enableReverseGeocode default true
23351 * @cfg {String} markerTitle
23354 * Create a new LocationPicker
23355 * @param {Object} config The config object
23359 Roo.bootstrap.LocationPicker = function(config){
23361 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
23366 * Fires when the picker initialized.
23367 * @param {Roo.bootstrap.LocationPicker} this
23368 * @param {Google Location} location
23372 * @event positionchanged
23373 * Fires when the picker position changed.
23374 * @param {Roo.bootstrap.LocationPicker} this
23375 * @param {Google Location} location
23377 positionchanged : true,
23380 * Fires when the map resize.
23381 * @param {Roo.bootstrap.LocationPicker} this
23386 * Fires when the map show.
23387 * @param {Roo.bootstrap.LocationPicker} this
23392 * Fires when the map hide.
23393 * @param {Roo.bootstrap.LocationPicker} this
23398 * Fires when click the map.
23399 * @param {Roo.bootstrap.LocationPicker} this
23400 * @param {Map event} e
23404 * @event mapRightClick
23405 * Fires when right click the map.
23406 * @param {Roo.bootstrap.LocationPicker} this
23407 * @param {Map event} e
23409 mapRightClick : true,
23411 * @event markerClick
23412 * Fires when click the marker.
23413 * @param {Roo.bootstrap.LocationPicker} this
23414 * @param {Map event} e
23416 markerClick : true,
23418 * @event markerRightClick
23419 * Fires when right click the marker.
23420 * @param {Roo.bootstrap.LocationPicker} this
23421 * @param {Map event} e
23423 markerRightClick : true,
23425 * @event OverlayViewDraw
23426 * Fires when OverlayView Draw
23427 * @param {Roo.bootstrap.LocationPicker} this
23429 OverlayViewDraw : true,
23431 * @event OverlayViewOnAdd
23432 * Fires when OverlayView Draw
23433 * @param {Roo.bootstrap.LocationPicker} this
23435 OverlayViewOnAdd : true,
23437 * @event OverlayViewOnRemove
23438 * Fires when OverlayView Draw
23439 * @param {Roo.bootstrap.LocationPicker} this
23441 OverlayViewOnRemove : true,
23443 * @event OverlayViewShow
23444 * Fires when OverlayView Draw
23445 * @param {Roo.bootstrap.LocationPicker} this
23446 * @param {Pixel} cpx
23448 OverlayViewShow : true,
23450 * @event OverlayViewHide
23451 * Fires when OverlayView Draw
23452 * @param {Roo.bootstrap.LocationPicker} this
23454 OverlayViewHide : true
23459 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
23461 gMapContext: false,
23467 mapTypeControl: false,
23468 disableDoubleClickZoom: false,
23470 streetViewControl: false,
23474 enableAutocomplete: false,
23475 enableReverseGeocode: true,
23478 getAutoCreate: function()
23483 cls: 'roo-location-picker'
23489 initEvents: function(ct, position)
23491 if(!this.el.getWidth() || this.isApplied()){
23495 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23500 initial: function()
23502 if(!this.mapTypeId){
23503 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
23506 this.gMapContext = this.GMapContext();
23508 this.initOverlayView();
23510 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
23514 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
23515 _this.setPosition(_this.gMapContext.marker.position);
23518 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
23519 _this.fireEvent('mapClick', this, event);
23523 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
23524 _this.fireEvent('mapRightClick', this, event);
23528 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
23529 _this.fireEvent('markerClick', this, event);
23533 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
23534 _this.fireEvent('markerRightClick', this, event);
23538 this.setPosition(this.gMapContext.location);
23540 this.fireEvent('initial', this, this.gMapContext.location);
23543 initOverlayView: function()
23547 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
23551 _this.fireEvent('OverlayViewDraw', _this);
23556 _this.fireEvent('OverlayViewOnAdd', _this);
23559 onRemove: function()
23561 _this.fireEvent('OverlayViewOnRemove', _this);
23564 show: function(cpx)
23566 _this.fireEvent('OverlayViewShow', _this, cpx);
23571 _this.fireEvent('OverlayViewHide', _this);
23577 fromLatLngToContainerPixel: function(event)
23579 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
23582 isApplied: function()
23584 return this.getGmapContext() == false ? false : true;
23587 getGmapContext: function()
23589 return this.gMapContext
23592 GMapContext: function()
23594 var position = new google.maps.LatLng(this.latitude, this.longitude);
23596 var _map = new google.maps.Map(this.el.dom, {
23599 mapTypeId: this.mapTypeId,
23600 mapTypeControl: this.mapTypeControl,
23601 disableDoubleClickZoom: this.disableDoubleClickZoom,
23602 scrollwheel: this.scrollwheel,
23603 streetViewControl: this.streetViewControl,
23604 locationName: this.locationName,
23605 draggable: this.draggable,
23606 enableAutocomplete: this.enableAutocomplete,
23607 enableReverseGeocode: this.enableReverseGeocode
23610 var _marker = new google.maps.Marker({
23611 position: position,
23613 title: this.markerTitle,
23614 draggable: this.draggable
23621 location: position,
23622 radius: this.radius,
23623 locationName: this.locationName,
23624 addressComponents: {
23625 formatted_address: null,
23626 addressLine1: null,
23627 addressLine2: null,
23629 streetNumber: null,
23633 stateOrProvince: null
23636 domContainer: this.el.dom,
23637 geodecoder: new google.maps.Geocoder()
23641 drawCircle: function(center, radius, options)
23643 if (this.gMapContext.circle != null) {
23644 this.gMapContext.circle.setMap(null);
23648 options = Roo.apply({}, options, {
23649 strokeColor: "#0000FF",
23650 strokeOpacity: .35,
23652 fillColor: "#0000FF",
23656 options.map = this.gMapContext.map;
23657 options.radius = radius;
23658 options.center = center;
23659 this.gMapContext.circle = new google.maps.Circle(options);
23660 return this.gMapContext.circle;
23666 setPosition: function(location)
23668 this.gMapContext.location = location;
23669 this.gMapContext.marker.setPosition(location);
23670 this.gMapContext.map.panTo(location);
23671 this.drawCircle(location, this.gMapContext.radius, {});
23675 if (this.gMapContext.settings.enableReverseGeocode) {
23676 this.gMapContext.geodecoder.geocode({
23677 latLng: this.gMapContext.location
23678 }, function(results, status) {
23680 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23681 _this.gMapContext.locationName = results[0].formatted_address;
23682 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23684 _this.fireEvent('positionchanged', this, location);
23691 this.fireEvent('positionchanged', this, location);
23696 google.maps.event.trigger(this.gMapContext.map, "resize");
23698 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23700 this.fireEvent('resize', this);
23703 setPositionByLatLng: function(latitude, longitude)
23705 this.setPosition(new google.maps.LatLng(latitude, longitude));
23708 getCurrentPosition: function()
23711 latitude: this.gMapContext.location.lat(),
23712 longitude: this.gMapContext.location.lng()
23716 getAddressName: function()
23718 return this.gMapContext.locationName;
23721 getAddressComponents: function()
23723 return this.gMapContext.addressComponents;
23726 address_component_from_google_geocode: function(address_components)
23730 for (var i = 0; i < address_components.length; i++) {
23731 var component = address_components[i];
23732 if (component.types.indexOf("postal_code") >= 0) {
23733 result.postalCode = component.short_name;
23734 } else if (component.types.indexOf("street_number") >= 0) {
23735 result.streetNumber = component.short_name;
23736 } else if (component.types.indexOf("route") >= 0) {
23737 result.streetName = component.short_name;
23738 } else if (component.types.indexOf("neighborhood") >= 0) {
23739 result.city = component.short_name;
23740 } else if (component.types.indexOf("locality") >= 0) {
23741 result.city = component.short_name;
23742 } else if (component.types.indexOf("sublocality") >= 0) {
23743 result.district = component.short_name;
23744 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23745 result.stateOrProvince = component.short_name;
23746 } else if (component.types.indexOf("country") >= 0) {
23747 result.country = component.short_name;
23751 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23752 result.addressLine2 = "";
23756 setZoomLevel: function(zoom)
23758 this.gMapContext.map.setZoom(zoom);
23771 this.fireEvent('show', this);
23782 this.fireEvent('hide', this);
23787 Roo.apply(Roo.bootstrap.LocationPicker, {
23789 OverlayView : function(map, options)
23791 options = options || {};
23805 * @class Roo.bootstrap.Alert
23806 * @extends Roo.bootstrap.Component
23807 * Bootstrap Alert class
23808 * @cfg {String} title The title of alert
23809 * @cfg {String} html The content of alert
23810 * @cfg {String} weight ( success | info | warning | danger )
23811 * @cfg {String} faicon font-awesomeicon
23814 * Create a new alert
23815 * @param {Object} config The config object
23819 Roo.bootstrap.Alert = function(config){
23820 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23824 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23831 getAutoCreate : function()
23840 cls : 'roo-alert-icon'
23845 cls : 'roo-alert-title',
23850 cls : 'roo-alert-text',
23857 cfg.cn[0].cls += ' fa ' + this.faicon;
23861 cfg.cls += ' alert-' + this.weight;
23867 initEvents: function()
23869 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23872 setTitle : function(str)
23874 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23877 setText : function(str)
23879 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23882 setWeight : function(weight)
23885 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23888 this.weight = weight;
23890 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23893 setIcon : function(icon)
23896 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23901 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);