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]);
2459 getAutoCreate : function(){
2464 html : this.html || ''
2469 cls : 'modal-title',
2473 if(this.specificTitle){
2479 if (this.allow_close) {
2490 style : 'display: none',
2493 cls: "modal-dialog",
2496 cls : "modal-content",
2499 cls : 'modal-header',
2504 cls : 'modal-footer',
2508 cls: 'btn-' + this.buttonPosition
2525 modal.cls += ' fade';
2531 getChildContainer : function() {
2536 getButtonContainer : function() {
2537 return this.el.select('.modal-footer div',true).first();
2540 initEvents : function()
2542 if (this.allow_close) {
2543 this.closeEl.on('click', this.hide, this);
2549 if (!this.rendered) {
2553 this.el.setStyle('display', 'block');
2557 (function(){ _this.el.addClass('in'); }).defer(50);
2559 this.el.addClass('in');
2562 // not sure how we can show data in here..
2564 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2567 Roo.get(document.body).addClass("x-body-masked");
2568 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2570 this.el.setStyle('zIndex', '10001');
2572 this.fireEvent('show', this);
2579 Roo.get(document.body).removeClass("x-body-masked");
2580 this.el.removeClass('in');
2584 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2586 this.el.setStyle('display', 'none');
2589 this.fireEvent('hide', this);
2592 addButton : function(str, cb)
2596 var b = Roo.apply({}, { html : str } );
2597 b.xns = b.xns || Roo.bootstrap;
2598 b.xtype = b.xtype || 'Button';
2599 if (typeof(b.listeners) == 'undefined') {
2600 b.listeners = { click : cb.createDelegate(this) };
2603 var btn = Roo.factory(b);
2605 btn.onRender(this.el.select('.modal-footer div').first());
2611 setDefaultButton : function(btn)
2613 //this.el.select('.modal-footer').()
2615 resizeTo: function(w,h)
2619 setContentSize : function(w, h)
2623 onButtonClick: function(btn,e)
2626 this.fireEvent('btnclick', btn.name, e);
2629 * Set the title of the Dialog
2630 * @param {String} str new Title
2632 setTitle: function(str) {
2633 this.titleEl.dom.innerHTML = str;
2636 * Set the body of the Dialog
2637 * @param {String} str new Title
2639 setBody: function(str) {
2640 this.bodyEl.dom.innerHTML = str;
2643 * Set the body of the Dialog using the template
2644 * @param {Obj} data - apply this data to the template and replace the body contents.
2646 applyBody: function(obj)
2649 Roo.log("Error - using apply Body without a template");
2652 this.tmpl.overwrite(this.bodyEl, obj);
2658 Roo.apply(Roo.bootstrap.Modal, {
2660 * Button config that displays a single OK button
2669 * Button config that displays Yes and No buttons
2685 * Button config that displays OK and Cancel buttons
2700 * Button config that displays Yes, No and Cancel buttons
2723 * messagebox - can be used as a replace
2727 * @class Roo.MessageBox
2728 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2732 Roo.Msg.alert('Status', 'Changes saved successfully.');
2734 // Prompt for user data:
2735 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2737 // process text value...
2741 // Show a dialog using config options:
2743 title:'Save Changes?',
2744 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2745 buttons: Roo.Msg.YESNOCANCEL,
2752 Roo.bootstrap.MessageBox = function(){
2753 var dlg, opt, mask, waitTimer;
2754 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2755 var buttons, activeTextEl, bwidth;
2759 var handleButton = function(button){
2761 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2765 var handleHide = function(){
2767 dlg.el.removeClass(opt.cls);
2770 // Roo.TaskMgr.stop(waitTimer);
2771 // waitTimer = null;
2776 var updateButtons = function(b){
2779 buttons["ok"].hide();
2780 buttons["cancel"].hide();
2781 buttons["yes"].hide();
2782 buttons["no"].hide();
2783 //dlg.footer.dom.style.display = 'none';
2786 dlg.footerEl.dom.style.display = '';
2787 for(var k in buttons){
2788 if(typeof buttons[k] != "function"){
2791 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2792 width += buttons[k].el.getWidth()+15;
2802 var handleEsc = function(d, k, e){
2803 if(opt && opt.closable !== false){
2813 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2814 * @return {Roo.BasicDialog} The BasicDialog element
2816 getDialog : function(){
2818 dlg = new Roo.bootstrap.Modal( {
2821 //constraintoviewport:false,
2823 //collapsible : false,
2828 //buttonAlign:"center",
2829 closeClick : function(){
2830 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2833 handleButton("cancel");
2838 dlg.on("hide", handleHide);
2840 //dlg.addKeyListener(27, handleEsc);
2842 this.buttons = buttons;
2843 var bt = this.buttonText;
2844 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2845 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2846 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2847 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2849 bodyEl = dlg.bodyEl.createChild({
2851 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2852 '<textarea class="roo-mb-textarea"></textarea>' +
2853 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2855 msgEl = bodyEl.dom.firstChild;
2856 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2857 textboxEl.enableDisplayMode();
2858 textboxEl.addKeyListener([10,13], function(){
2859 if(dlg.isVisible() && opt && opt.buttons){
2862 }else if(opt.buttons.yes){
2863 handleButton("yes");
2867 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2868 textareaEl.enableDisplayMode();
2869 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2870 progressEl.enableDisplayMode();
2871 var pf = progressEl.dom.firstChild;
2873 pp = Roo.get(pf.firstChild);
2874 pp.setHeight(pf.offsetHeight);
2882 * Updates the message box body text
2883 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2884 * the XHTML-compliant non-breaking space character '&#160;')
2885 * @return {Roo.MessageBox} This message box
2887 updateText : function(text){
2888 if(!dlg.isVisible() && !opt.width){
2889 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2891 msgEl.innerHTML = text || ' ';
2893 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2894 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2896 Math.min(opt.width || cw , this.maxWidth),
2897 Math.max(opt.minWidth || this.minWidth, bwidth)
2900 activeTextEl.setWidth(w);
2902 if(dlg.isVisible()){
2903 dlg.fixedcenter = false;
2905 // to big, make it scroll. = But as usual stupid IE does not support
2908 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2909 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2910 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2912 bodyEl.dom.style.height = '';
2913 bodyEl.dom.style.overflowY = '';
2916 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2918 bodyEl.dom.style.overflowX = '';
2921 dlg.setContentSize(w, bodyEl.getHeight());
2922 if(dlg.isVisible()){
2923 dlg.fixedcenter = true;
2929 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2930 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2931 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2932 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2933 * @return {Roo.MessageBox} This message box
2935 updateProgress : function(value, text){
2937 this.updateText(text);
2939 if (pp) { // weird bug on my firefox - for some reason this is not defined
2940 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2946 * Returns true if the message box is currently displayed
2947 * @return {Boolean} True if the message box is visible, else false
2949 isVisible : function(){
2950 return dlg && dlg.isVisible();
2954 * Hides the message box if it is displayed
2957 if(this.isVisible()){
2963 * Displays a new message box, or reinitializes an existing message box, based on the config options
2964 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2965 * The following config object properties are supported:
2967 Property Type Description
2968 ---------- --------------- ------------------------------------------------------------------------------------
2969 animEl String/Element An id or Element from which the message box should animate as it opens and
2970 closes (defaults to undefined)
2971 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2972 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2973 closable Boolean False to hide the top-right close button (defaults to true). Note that
2974 progress and wait dialogs will ignore this property and always hide the
2975 close button as they can only be closed programmatically.
2976 cls String A custom CSS class to apply to the message box element
2977 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2978 displayed (defaults to 75)
2979 fn Function A callback function to execute after closing the dialog. The arguments to the
2980 function will be btn (the name of the button that was clicked, if applicable,
2981 e.g. "ok"), and text (the value of the active text field, if applicable).
2982 Progress and wait dialogs will ignore this option since they do not respond to
2983 user actions and can only be closed programmatically, so any required function
2984 should be called by the same code after it closes the dialog.
2985 icon String A CSS class that provides a background image to be used as an icon for
2986 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2987 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2988 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2989 modal Boolean False to allow user interaction with the page while the message box is
2990 displayed (defaults to true)
2991 msg String A string that will replace the existing message box body text (defaults
2992 to the XHTML-compliant non-breaking space character ' ')
2993 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2994 progress Boolean True to display a progress bar (defaults to false)
2995 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2996 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2997 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2998 title String The title text
2999 value String The string value to set into the active textbox element if displayed
3000 wait Boolean True to display a progress bar (defaults to false)
3001 width Number The width of the dialog in pixels
3008 msg: 'Please enter your address:',
3010 buttons: Roo.MessageBox.OKCANCEL,
3013 animEl: 'addAddressBtn'
3016 * @param {Object} config Configuration options
3017 * @return {Roo.MessageBox} This message box
3019 show : function(options)
3022 // this causes nightmares if you show one dialog after another
3023 // especially on callbacks..
3025 if(this.isVisible()){
3028 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3029 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3030 Roo.log("New Dialog Message:" + options.msg )
3031 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3032 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3035 var d = this.getDialog();
3037 d.setTitle(opt.title || " ");
3038 d.closeEl.setDisplayed(opt.closable !== false);
3039 activeTextEl = textboxEl;
3040 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3045 textareaEl.setHeight(typeof opt.multiline == "number" ?
3046 opt.multiline : this.defaultTextHeight);
3047 activeTextEl = textareaEl;
3056 progressEl.setDisplayed(opt.progress === true);
3057 this.updateProgress(0);
3058 activeTextEl.dom.value = opt.value || "";
3060 dlg.setDefaultButton(activeTextEl);
3062 var bs = opt.buttons;
3066 }else if(bs && bs.yes){
3067 db = buttons["yes"];
3069 dlg.setDefaultButton(db);
3071 bwidth = updateButtons(opt.buttons);
3072 this.updateText(opt.msg);
3074 d.el.addClass(opt.cls);
3076 d.proxyDrag = opt.proxyDrag === true;
3077 d.modal = opt.modal !== false;
3078 d.mask = opt.modal !== false ? mask : false;
3080 // force it to the end of the z-index stack so it gets a cursor in FF
3081 document.body.appendChild(dlg.el.dom);
3082 d.animateTarget = null;
3083 d.show(options.animEl);
3089 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3090 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3091 * and closing the message box when the process is complete.
3092 * @param {String} title The title bar text
3093 * @param {String} msg The message box body text
3094 * @return {Roo.MessageBox} This message box
3096 progress : function(title, msg){
3103 minWidth: this.minProgressWidth,
3110 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3111 * If a callback function is passed it will be called after the user clicks the button, and the
3112 * id of the button that was clicked will be passed as the only parameter to the callback
3113 * (could also be the top-right close button).
3114 * @param {String} title The title bar text
3115 * @param {String} msg The message box body text
3116 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3117 * @param {Object} scope (optional) The scope of the callback function
3118 * @return {Roo.MessageBox} This message box
3120 alert : function(title, msg, fn, scope){
3133 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3134 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3135 * You are responsible for closing the message box when the process is complete.
3136 * @param {String} msg The message box body text
3137 * @param {String} title (optional) The title bar text
3138 * @return {Roo.MessageBox} This message box
3140 wait : function(msg, title){
3151 waitTimer = Roo.TaskMgr.start({
3153 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3161 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3162 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3163 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3164 * @param {String} title The title bar text
3165 * @param {String} msg The message box body text
3166 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3167 * @param {Object} scope (optional) The scope of the callback function
3168 * @return {Roo.MessageBox} This message box
3170 confirm : function(title, msg, fn, scope){
3174 buttons: this.YESNO,
3183 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3184 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3185 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3186 * (could also be the top-right close button) and the text that was entered will be passed as the two
3187 * parameters to the callback.
3188 * @param {String} title The title bar text
3189 * @param {String} msg The message box body text
3190 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3191 * @param {Object} scope (optional) The scope of the callback function
3192 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3193 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3194 * @return {Roo.MessageBox} This message box
3196 prompt : function(title, msg, fn, scope, multiline){
3200 buttons: this.OKCANCEL,
3205 multiline: multiline,
3212 * Button config that displays a single OK button
3217 * Button config that displays Yes and No buttons
3220 YESNO : {yes:true, no:true},
3222 * Button config that displays OK and Cancel buttons
3225 OKCANCEL : {ok:true, cancel:true},
3227 * Button config that displays Yes, No and Cancel buttons
3230 YESNOCANCEL : {yes:true, no:true, cancel:true},
3233 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3236 defaultTextHeight : 75,
3238 * The maximum width in pixels of the message box (defaults to 600)
3243 * The minimum width in pixels of the message box (defaults to 100)
3248 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3249 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3252 minProgressWidth : 250,
3254 * An object containing the default button text strings that can be overriden for localized language support.
3255 * Supported properties are: ok, cancel, yes and no.
3256 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3269 * Shorthand for {@link Roo.MessageBox}
3271 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3272 Roo.Msg = Roo.Msg || Roo.MessageBox;
3281 * @class Roo.bootstrap.Navbar
3282 * @extends Roo.bootstrap.Component
3283 * Bootstrap Navbar class
3286 * Create a new Navbar
3287 * @param {Object} config The config object
3291 Roo.bootstrap.Navbar = function(config){
3292 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3296 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3305 getAutoCreate : function(){
3308 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3312 initEvents :function ()
3314 //Roo.log(this.el.select('.navbar-toggle',true));
3315 this.el.select('.navbar-toggle',true).on('click', function() {
3316 // Roo.log('click');
3317 this.el.select('.navbar-collapse',true).toggleClass('in');
3325 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3327 var size = this.el.getSize();
3328 this.maskEl.setSize(size.width, size.height);
3329 this.maskEl.enableDisplayMode("block");
3338 getChildContainer : function()
3340 if (this.el.select('.collapse').getCount()) {
3341 return this.el.select('.collapse',true).first();
3374 * @class Roo.bootstrap.NavSimplebar
3375 * @extends Roo.bootstrap.Navbar
3376 * Bootstrap Sidebar class
3378 * @cfg {Boolean} inverse is inverted color
3380 * @cfg {String} type (nav | pills | tabs)
3381 * @cfg {Boolean} arrangement stacked | justified
3382 * @cfg {String} align (left | right) alignment
3384 * @cfg {Boolean} main (true|false) main nav bar? default false
3385 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3387 * @cfg {String} tag (header|footer|nav|div) default is nav
3393 * Create a new Sidebar
3394 * @param {Object} config The config object
3398 Roo.bootstrap.NavSimplebar = function(config){
3399 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3402 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3418 getAutoCreate : function(){
3422 tag : this.tag || 'div',
3435 this.type = this.type || 'nav';
3436 if (['tabs','pills'].indexOf(this.type)!==-1) {
3437 cfg.cn[0].cls += ' nav-' + this.type
3441 if (this.type!=='nav') {
3442 Roo.log('nav type must be nav/tabs/pills')
3444 cfg.cn[0].cls += ' navbar-nav'
3450 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3451 cfg.cn[0].cls += ' nav-' + this.arrangement;
3455 if (this.align === 'right') {
3456 cfg.cn[0].cls += ' navbar-right';
3460 cfg.cls += ' navbar-inverse';
3487 * @class Roo.bootstrap.NavHeaderbar
3488 * @extends Roo.bootstrap.NavSimplebar
3489 * Bootstrap Sidebar class
3491 * @cfg {String} brand what is brand
3492 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3493 * @cfg {String} brand_href href of the brand
3494 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3495 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3496 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3497 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3500 * Create a new Sidebar
3501 * @param {Object} config The config object
3505 Roo.bootstrap.NavHeaderbar = function(config){
3506 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3510 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3517 desktopCenter : false,
3520 getAutoCreate : function(){
3523 tag: this.nav || 'nav',
3530 if (this.desktopCenter) {
3531 cn.push({cls : 'container', cn : []});
3538 cls: 'navbar-header',
3543 cls: 'navbar-toggle',
3544 'data-toggle': 'collapse',
3549 html: 'Toggle navigation'
3571 cls: 'collapse navbar-collapse',
3575 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3577 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3578 cfg.cls += ' navbar-' + this.position;
3580 // tag can override this..
3582 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3585 if (this.brand !== '') {
3588 href: this.brand_href ? this.brand_href : '#',
3589 cls: 'navbar-brand',
3597 cfg.cls += ' main-nav';
3605 getHeaderChildContainer : function()
3607 if (this.el.select('.navbar-header').getCount()) {
3608 return this.el.select('.navbar-header',true).first();
3611 return this.getChildContainer();
3615 initEvents : function()
3617 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3619 if (this.autohide) {
3624 Roo.get(document).on('scroll',function(e) {
3625 var ns = Roo.get(document).getScroll().top;
3626 var os = prevScroll;
3630 ft.removeClass('slideDown');
3631 ft.addClass('slideUp');
3634 ft.removeClass('slideUp');
3635 ft.addClass('slideDown');
3656 * @class Roo.bootstrap.NavSidebar
3657 * @extends Roo.bootstrap.Navbar
3658 * Bootstrap Sidebar class
3661 * Create a new Sidebar
3662 * @param {Object} config The config object
3666 Roo.bootstrap.NavSidebar = function(config){
3667 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3670 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3672 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3674 getAutoCreate : function(){
3679 cls: 'sidebar sidebar-nav'
3701 * @class Roo.bootstrap.NavGroup
3702 * @extends Roo.bootstrap.Component
3703 * Bootstrap NavGroup class
3704 * @cfg {String} align (left|right)
3705 * @cfg {Boolean} inverse
3706 * @cfg {String} type (nav|pills|tab) default nav
3707 * @cfg {String} navId - reference Id for navbar.
3711 * Create a new nav group
3712 * @param {Object} config The config object
3715 Roo.bootstrap.NavGroup = function(config){
3716 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3719 Roo.bootstrap.NavGroup.register(this);
3723 * Fires when the active item changes
3724 * @param {Roo.bootstrap.NavGroup} this
3725 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3726 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3733 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3744 getAutoCreate : function()
3746 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3753 if (['tabs','pills'].indexOf(this.type)!==-1) {
3754 cfg.cls += ' nav-' + this.type
3756 if (this.type!=='nav') {
3757 Roo.log('nav type must be nav/tabs/pills')
3759 cfg.cls += ' navbar-nav'
3762 if (this.parent().sidebar) {
3765 cls: 'dashboard-menu sidebar-menu'
3771 if (this.form === true) {
3777 if (this.align === 'right') {
3778 cfg.cls += ' navbar-right';
3780 cfg.cls += ' navbar-left';
3784 if (this.align === 'right') {
3785 cfg.cls += ' navbar-right';
3789 cfg.cls += ' navbar-inverse';
3797 * sets the active Navigation item
3798 * @param {Roo.bootstrap.NavItem} the new current navitem
3800 setActiveItem : function(item)
3803 Roo.each(this.navItems, function(v){
3808 v.setActive(false, true);
3815 item.setActive(true, true);
3816 this.fireEvent('changed', this, item, prev);
3821 * gets the active Navigation item
3822 * @return {Roo.bootstrap.NavItem} the current navitem
3824 getActive : function()
3828 Roo.each(this.navItems, function(v){
3839 indexOfNav : function()
3843 Roo.each(this.navItems, function(v,i){
3854 * adds a Navigation item
3855 * @param {Roo.bootstrap.NavItem} the navitem to add
3857 addItem : function(cfg)
3859 var cn = new Roo.bootstrap.NavItem(cfg);
3861 cn.parentId = this.id;
3862 cn.onRender(this.el, null);
3866 * register a Navigation item
3867 * @param {Roo.bootstrap.NavItem} the navitem to add
3869 register : function(item)
3871 this.navItems.push( item);
3872 item.navId = this.navId;
3877 * clear all the Navigation item
3880 clearAll : function()
3883 this.el.dom.innerHTML = '';
3886 getNavItem: function(tabId)
3889 Roo.each(this.navItems, function(e) {
3890 if (e.tabId == tabId) {
3900 setActiveNext : function()
3902 var i = this.indexOfNav(this.getActive());
3903 if (i > this.navItems.length) {
3906 this.setActiveItem(this.navItems[i+1]);
3908 setActivePrev : function()
3910 var i = this.indexOfNav(this.getActive());
3914 this.setActiveItem(this.navItems[i-1]);
3916 clearWasActive : function(except) {
3917 Roo.each(this.navItems, function(e) {
3918 if (e.tabId != except.tabId && e.was_active) {
3919 e.was_active = false;
3926 getWasActive : function ()
3929 Roo.each(this.navItems, function(e) {
3944 Roo.apply(Roo.bootstrap.NavGroup, {
3948 * register a Navigation Group
3949 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3951 register : function(navgrp)
3953 this.groups[navgrp.navId] = navgrp;
3957 * fetch a Navigation Group based on the navigation ID
3958 * @param {string} the navgroup to add
3959 * @returns {Roo.bootstrap.NavGroup} the navgroup
3961 get: function(navId) {
3962 if (typeof(this.groups[navId]) == 'undefined') {
3964 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3966 return this.groups[navId] ;
3981 * @class Roo.bootstrap.NavItem
3982 * @extends Roo.bootstrap.Component
3983 * Bootstrap Navbar.NavItem class
3984 * @cfg {String} href link to
3985 * @cfg {String} html content of button
3986 * @cfg {String} badge text inside badge
3987 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3988 * @cfg {String} glyphicon name of glyphicon
3989 * @cfg {String} icon name of font awesome icon
3990 * @cfg {Boolean} active Is item active
3991 * @cfg {Boolean} disabled Is item disabled
3993 * @cfg {Boolean} preventDefault (true | false) default false
3994 * @cfg {String} tabId the tab that this item activates.
3995 * @cfg {String} tagtype (a|span) render as a href or span?
3996 * @cfg {Boolean} animateRef (true|false) link to element default false
3999 * Create a new Navbar Item
4000 * @param {Object} config The config object
4002 Roo.bootstrap.NavItem = function(config){
4003 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4008 * The raw click event for the entire grid.
4009 * @param {Roo.EventObject} e
4014 * Fires when the active item active state changes
4015 * @param {Roo.bootstrap.NavItem} this
4016 * @param {boolean} state the new state
4022 * Fires when scroll to element
4023 * @param {Roo.bootstrap.NavItem} this
4024 * @param {Object} options
4025 * @param {Roo.EventObject} e
4033 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4041 preventDefault : false,
4048 getAutoCreate : function(){
4056 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4058 if (this.disabled) {
4059 cfg.cls += ' disabled';
4062 if (this.href || this.html || this.glyphicon || this.icon) {
4066 href : this.href || "#",
4067 html: this.html || ''
4072 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4075 if(this.glyphicon) {
4076 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4081 cfg.cn[0].html += " <span class='caret'></span>";
4085 if (this.badge !== '') {
4087 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4095 initEvents: function()
4097 if (typeof (this.menu) != 'undefined') {
4098 this.menu.parentType = this.xtype;
4099 this.menu.triggerEl = this.el;
4100 this.menu = this.addxtype(Roo.apply({}, this.menu));
4103 this.el.select('a',true).on('click', this.onClick, this);
4105 if(this.tagtype == 'span'){
4106 this.el.select('span',true).on('click', this.onClick, this);
4109 // at this point parent should be available..
4110 this.parent().register(this);
4113 onClick : function(e)
4116 this.preventDefault ||
4123 if (this.disabled) {
4127 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4128 if (tg && tg.transition) {
4129 Roo.log("waiting for the transitionend");
4135 //Roo.log("fire event clicked");
4136 if(this.fireEvent('click', this, e) === false){
4140 if(this.tagtype == 'span'){
4144 //Roo.log(this.href);
4145 var ael = this.el.select('a',true).first();
4148 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4149 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4150 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4151 return; // ignore... - it's a 'hash' to another page.
4155 this.scrollToElement(e);
4159 var p = this.parent();
4161 if (['tabs','pills'].indexOf(p.type)!==-1) {
4162 if (typeof(p.setActiveItem) !== 'undefined') {
4163 p.setActiveItem(this);
4167 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4168 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4169 // remove the collapsed menu expand...
4170 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4174 isActive: function () {
4177 setActive : function(state, fire, is_was_active)
4179 if (this.active && !state & this.navId) {
4180 this.was_active = true;
4181 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4183 nv.clearWasActive(this);
4187 this.active = state;
4190 this.el.removeClass('active');
4191 } else if (!this.el.hasClass('active')) {
4192 this.el.addClass('active');
4195 this.fireEvent('changed', this, state);
4198 // show a panel if it's registered and related..
4200 if (!this.navId || !this.tabId || !state || is_was_active) {
4204 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4208 var pan = tg.getPanelByName(this.tabId);
4212 // if we can not flip to new panel - go back to old nav highlight..
4213 if (false == tg.showPanel(pan)) {
4214 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4216 var onav = nv.getWasActive();
4218 onav.setActive(true, false, true);
4227 // this should not be here...
4228 setDisabled : function(state)
4230 this.disabled = state;
4232 this.el.removeClass('disabled');
4233 } else if (!this.el.hasClass('disabled')) {
4234 this.el.addClass('disabled');
4240 * Fetch the element to display the tooltip on.
4241 * @return {Roo.Element} defaults to this.el
4243 tooltipEl : function()
4245 return this.el.select('' + this.tagtype + '', true).first();
4248 scrollToElement : function(e)
4250 var c = document.body;
4253 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4255 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4256 c = document.documentElement;
4259 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4265 var o = target.calcOffsetsTo(c);
4272 this.fireEvent('scrollto', this, options, e);
4274 Roo.get(c).scrollTo('top', options.value, true);
4287 * <span> icon </span>
4288 * <span> text </span>
4289 * <span>badge </span>
4293 * @class Roo.bootstrap.NavSidebarItem
4294 * @extends Roo.bootstrap.NavItem
4295 * Bootstrap Navbar.NavSidebarItem class
4297 * Create a new Navbar Button
4298 * @param {Object} config The config object
4300 Roo.bootstrap.NavSidebarItem = function(config){
4301 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4306 * The raw click event for the entire grid.
4307 * @param {Roo.EventObject} e
4312 * Fires when the active item active state changes
4313 * @param {Roo.bootstrap.NavSidebarItem} this
4314 * @param {boolean} state the new state
4322 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4325 getAutoCreate : function(){
4330 href : this.href || '#',
4342 html : this.html || ''
4347 cfg.cls += ' active';
4351 if (this.glyphicon || this.icon) {
4352 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4353 a.cn.push({ tag : 'i', cls : c }) ;
4358 if (this.badge !== '') {
4359 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4363 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4364 a.cls += 'dropdown-toggle treeview' ;
4388 * @class Roo.bootstrap.Row
4389 * @extends Roo.bootstrap.Component
4390 * Bootstrap Row class (contains columns...)
4394 * @param {Object} config The config object
4397 Roo.bootstrap.Row = function(config){
4398 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4401 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4403 getAutoCreate : function(){
4422 * @class Roo.bootstrap.Element
4423 * @extends Roo.bootstrap.Component
4424 * Bootstrap Element class
4425 * @cfg {String} html contents of the element
4426 * @cfg {String} tag tag of the element
4427 * @cfg {String} cls class of the element
4428 * @cfg {Boolean} preventDefault (true|false) default false
4429 * @cfg {Boolean} clickable (true|false) default false
4432 * Create a new Element
4433 * @param {Object} config The config object
4436 Roo.bootstrap.Element = function(config){
4437 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4443 * When a element is chick
4444 * @param {Roo.bootstrap.Element} this
4445 * @param {Roo.EventObject} e
4451 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4456 preventDefault: false,
4459 getAutoCreate : function(){
4470 initEvents: function()
4472 Roo.bootstrap.Element.superclass.initEvents.call(this);
4475 this.el.on('click', this.onClick, this);
4480 onClick : function(e)
4482 if(this.preventDefault){
4486 this.fireEvent('click', this, e);
4489 getValue : function()
4491 return this.el.dom.innerHTML;
4494 setValue : function(value)
4496 this.el.dom.innerHTML = value;
4511 * @class Roo.bootstrap.Pagination
4512 * @extends Roo.bootstrap.Component
4513 * Bootstrap Pagination class
4514 * @cfg {String} size xs | sm | md | lg
4515 * @cfg {Boolean} inverse false | true
4518 * Create a new Pagination
4519 * @param {Object} config The config object
4522 Roo.bootstrap.Pagination = function(config){
4523 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4526 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4532 getAutoCreate : function(){
4538 cfg.cls += ' inverse';
4544 cfg.cls += " " + this.cls;
4562 * @class Roo.bootstrap.PaginationItem
4563 * @extends Roo.bootstrap.Component
4564 * Bootstrap PaginationItem class
4565 * @cfg {String} html text
4566 * @cfg {String} href the link
4567 * @cfg {Boolean} preventDefault (true | false) default true
4568 * @cfg {Boolean} active (true | false) default false
4569 * @cfg {Boolean} disabled default false
4573 * Create a new PaginationItem
4574 * @param {Object} config The config object
4578 Roo.bootstrap.PaginationItem = function(config){
4579 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4584 * The raw click event for the entire grid.
4585 * @param {Roo.EventObject} e
4591 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4595 preventDefault: true,
4600 getAutoCreate : function(){
4606 href : this.href ? this.href : '#',
4607 html : this.html ? this.html : ''
4617 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4621 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4627 initEvents: function() {
4629 this.el.on('click', this.onClick, this);
4632 onClick : function(e)
4634 Roo.log('PaginationItem on click ');
4635 if(this.preventDefault){
4643 this.fireEvent('click', this, e);
4659 * @class Roo.bootstrap.Slider
4660 * @extends Roo.bootstrap.Component
4661 * Bootstrap Slider class
4664 * Create a new Slider
4665 * @param {Object} config The config object
4668 Roo.bootstrap.Slider = function(config){
4669 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4672 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4674 getAutoCreate : function(){
4678 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4682 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4694 * Ext JS Library 1.1.1
4695 * Copyright(c) 2006-2007, Ext JS, LLC.
4697 * Originally Released Under LGPL - original licence link has changed is not relivant.
4700 * <script type="text/javascript">
4705 * @class Roo.grid.ColumnModel
4706 * @extends Roo.util.Observable
4707 * This is the default implementation of a ColumnModel used by the Grid. It defines
4708 * the columns in the grid.
4711 var colModel = new Roo.grid.ColumnModel([
4712 {header: "Ticker", width: 60, sortable: true, locked: true},
4713 {header: "Company Name", width: 150, sortable: true},
4714 {header: "Market Cap.", width: 100, sortable: true},
4715 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4716 {header: "Employees", width: 100, sortable: true, resizable: false}
4721 * The config options listed for this class are options which may appear in each
4722 * individual column definition.
4723 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4725 * @param {Object} config An Array of column config objects. See this class's
4726 * config objects for details.
4728 Roo.grid.ColumnModel = function(config){
4730 * The config passed into the constructor
4732 this.config = config;
4735 // if no id, create one
4736 // if the column does not have a dataIndex mapping,
4737 // map it to the order it is in the config
4738 for(var i = 0, len = config.length; i < len; i++){
4740 if(typeof c.dataIndex == "undefined"){
4743 if(typeof c.renderer == "string"){
4744 c.renderer = Roo.util.Format[c.renderer];
4746 if(typeof c.id == "undefined"){
4749 if(c.editor && c.editor.xtype){
4750 c.editor = Roo.factory(c.editor, Roo.grid);
4752 if(c.editor && c.editor.isFormField){
4753 c.editor = new Roo.grid.GridEditor(c.editor);
4755 this.lookup[c.id] = c;
4759 * The width of columns which have no width specified (defaults to 100)
4762 this.defaultWidth = 100;
4765 * Default sortable of columns which have no sortable specified (defaults to false)
4768 this.defaultSortable = false;
4772 * @event widthchange
4773 * Fires when the width of a column changes.
4774 * @param {ColumnModel} this
4775 * @param {Number} columnIndex The column index
4776 * @param {Number} newWidth The new width
4778 "widthchange": true,
4780 * @event headerchange
4781 * Fires when the text of a header changes.
4782 * @param {ColumnModel} this
4783 * @param {Number} columnIndex The column index
4784 * @param {Number} newText The new header text
4786 "headerchange": true,
4788 * @event hiddenchange
4789 * Fires when a column is hidden or "unhidden".
4790 * @param {ColumnModel} this
4791 * @param {Number} columnIndex The column index
4792 * @param {Boolean} hidden true if hidden, false otherwise
4794 "hiddenchange": true,
4796 * @event columnmoved
4797 * Fires when a column is moved.
4798 * @param {ColumnModel} this
4799 * @param {Number} oldIndex
4800 * @param {Number} newIndex
4802 "columnmoved" : true,
4804 * @event columlockchange
4805 * Fires when a column's locked state is changed
4806 * @param {ColumnModel} this
4807 * @param {Number} colIndex
4808 * @param {Boolean} locked true if locked
4810 "columnlockchange" : true
4812 Roo.grid.ColumnModel.superclass.constructor.call(this);
4814 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4816 * @cfg {String} header The header text to display in the Grid view.
4819 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4820 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4821 * specified, the column's index is used as an index into the Record's data Array.
4824 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4825 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4828 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4829 * Defaults to the value of the {@link #defaultSortable} property.
4830 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4833 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4836 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4839 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4842 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4845 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4846 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4847 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4848 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4851 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4854 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4857 * @cfg {String} cursor (Optional)
4860 * @cfg {String} tooltip (Optional)
4863 * Returns the id of the column at the specified index.
4864 * @param {Number} index The column index
4865 * @return {String} the id
4867 getColumnId : function(index){
4868 return this.config[index].id;
4872 * Returns the column for a specified id.
4873 * @param {String} id The column id
4874 * @return {Object} the column
4876 getColumnById : function(id){
4877 return this.lookup[id];
4882 * Returns the column for a specified dataIndex.
4883 * @param {String} dataIndex The column dataIndex
4884 * @return {Object|Boolean} the column or false if not found
4886 getColumnByDataIndex: function(dataIndex){
4887 var index = this.findColumnIndex(dataIndex);
4888 return index > -1 ? this.config[index] : false;
4892 * Returns the index for a specified column id.
4893 * @param {String} id The column id
4894 * @return {Number} the index, or -1 if not found
4896 getIndexById : function(id){
4897 for(var i = 0, len = this.config.length; i < len; i++){
4898 if(this.config[i].id == id){
4906 * Returns the index for a specified column dataIndex.
4907 * @param {String} dataIndex The column dataIndex
4908 * @return {Number} the index, or -1 if not found
4911 findColumnIndex : function(dataIndex){
4912 for(var i = 0, len = this.config.length; i < len; i++){
4913 if(this.config[i].dataIndex == dataIndex){
4921 moveColumn : function(oldIndex, newIndex){
4922 var c = this.config[oldIndex];
4923 this.config.splice(oldIndex, 1);
4924 this.config.splice(newIndex, 0, c);
4925 this.dataMap = null;
4926 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4929 isLocked : function(colIndex){
4930 return this.config[colIndex].locked === true;
4933 setLocked : function(colIndex, value, suppressEvent){
4934 if(this.isLocked(colIndex) == value){
4937 this.config[colIndex].locked = value;
4939 this.fireEvent("columnlockchange", this, colIndex, value);
4943 getTotalLockedWidth : function(){
4945 for(var i = 0; i < this.config.length; i++){
4946 if(this.isLocked(i) && !this.isHidden(i)){
4947 this.totalWidth += this.getColumnWidth(i);
4953 getLockedCount : function(){
4954 for(var i = 0, len = this.config.length; i < len; i++){
4955 if(!this.isLocked(i)){
4962 * Returns the number of columns.
4965 getColumnCount : function(visibleOnly){
4966 if(visibleOnly === true){
4968 for(var i = 0, len = this.config.length; i < len; i++){
4969 if(!this.isHidden(i)){
4975 return this.config.length;
4979 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4980 * @param {Function} fn
4981 * @param {Object} scope (optional)
4982 * @return {Array} result
4984 getColumnsBy : function(fn, scope){
4986 for(var i = 0, len = this.config.length; i < len; i++){
4987 var c = this.config[i];
4988 if(fn.call(scope||this, c, i) === true){
4996 * Returns true if the specified column is sortable.
4997 * @param {Number} col The column index
5000 isSortable : function(col){
5001 if(typeof this.config[col].sortable == "undefined"){
5002 return this.defaultSortable;
5004 return this.config[col].sortable;
5008 * Returns the rendering (formatting) function defined for the column.
5009 * @param {Number} col The column index.
5010 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5012 getRenderer : function(col){
5013 if(!this.config[col].renderer){
5014 return Roo.grid.ColumnModel.defaultRenderer;
5016 return this.config[col].renderer;
5020 * Sets the rendering (formatting) function for a column.
5021 * @param {Number} col The column index
5022 * @param {Function} fn The function to use to process the cell's raw data
5023 * to return HTML markup for the grid view. The render function is called with
5024 * the following parameters:<ul>
5025 * <li>Data value.</li>
5026 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5027 * <li>css A CSS style string to apply to the table cell.</li>
5028 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5029 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5030 * <li>Row index</li>
5031 * <li>Column index</li>
5032 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5034 setRenderer : function(col, fn){
5035 this.config[col].renderer = fn;
5039 * Returns the width for the specified column.
5040 * @param {Number} col The column index
5043 getColumnWidth : function(col){
5044 return this.config[col].width * 1 || this.defaultWidth;
5048 * Sets the width for a column.
5049 * @param {Number} col The column index
5050 * @param {Number} width The new width
5052 setColumnWidth : function(col, width, suppressEvent){
5053 this.config[col].width = width;
5054 this.totalWidth = null;
5056 this.fireEvent("widthchange", this, col, width);
5061 * Returns the total width of all columns.
5062 * @param {Boolean} includeHidden True to include hidden column widths
5065 getTotalWidth : function(includeHidden){
5066 if(!this.totalWidth){
5067 this.totalWidth = 0;
5068 for(var i = 0, len = this.config.length; i < len; i++){
5069 if(includeHidden || !this.isHidden(i)){
5070 this.totalWidth += this.getColumnWidth(i);
5074 return this.totalWidth;
5078 * Returns the header for the specified column.
5079 * @param {Number} col The column index
5082 getColumnHeader : function(col){
5083 return this.config[col].header;
5087 * Sets the header for a column.
5088 * @param {Number} col The column index
5089 * @param {String} header The new header
5091 setColumnHeader : function(col, header){
5092 this.config[col].header = header;
5093 this.fireEvent("headerchange", this, col, header);
5097 * Returns the tooltip for the specified column.
5098 * @param {Number} col The column index
5101 getColumnTooltip : function(col){
5102 return this.config[col].tooltip;
5105 * Sets the tooltip for a column.
5106 * @param {Number} col The column index
5107 * @param {String} tooltip The new tooltip
5109 setColumnTooltip : function(col, tooltip){
5110 this.config[col].tooltip = tooltip;
5114 * Returns the dataIndex for the specified column.
5115 * @param {Number} col The column index
5118 getDataIndex : function(col){
5119 return this.config[col].dataIndex;
5123 * Sets the dataIndex for a column.
5124 * @param {Number} col The column index
5125 * @param {Number} dataIndex The new dataIndex
5127 setDataIndex : function(col, dataIndex){
5128 this.config[col].dataIndex = dataIndex;
5134 * Returns true if the cell is editable.
5135 * @param {Number} colIndex The column index
5136 * @param {Number} rowIndex The row index
5139 isCellEditable : function(colIndex, rowIndex){
5140 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5144 * Returns the editor defined for the cell/column.
5145 * return false or null to disable editing.
5146 * @param {Number} colIndex The column index
5147 * @param {Number} rowIndex The row index
5150 getCellEditor : function(colIndex, rowIndex){
5151 return this.config[colIndex].editor;
5155 * Sets if a column is editable.
5156 * @param {Number} col The column index
5157 * @param {Boolean} editable True if the column is editable
5159 setEditable : function(col, editable){
5160 this.config[col].editable = editable;
5165 * Returns true if the column is hidden.
5166 * @param {Number} colIndex The column index
5169 isHidden : function(colIndex){
5170 return this.config[colIndex].hidden;
5175 * Returns true if the column width cannot be changed
5177 isFixed : function(colIndex){
5178 return this.config[colIndex].fixed;
5182 * Returns true if the column can be resized
5185 isResizable : function(colIndex){
5186 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5189 * Sets if a column is hidden.
5190 * @param {Number} colIndex The column index
5191 * @param {Boolean} hidden True if the column is hidden
5193 setHidden : function(colIndex, hidden){
5194 this.config[colIndex].hidden = hidden;
5195 this.totalWidth = null;
5196 this.fireEvent("hiddenchange", this, colIndex, hidden);
5200 * Sets the editor for a column.
5201 * @param {Number} col The column index
5202 * @param {Object} editor The editor object
5204 setEditor : function(col, editor){
5205 this.config[col].editor = editor;
5209 Roo.grid.ColumnModel.defaultRenderer = function(value){
5210 if(typeof value == "string" && value.length < 1){
5216 // Alias for backwards compatibility
5217 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5220 * Ext JS Library 1.1.1
5221 * Copyright(c) 2006-2007, Ext JS, LLC.
5223 * Originally Released Under LGPL - original licence link has changed is not relivant.
5226 * <script type="text/javascript">
5230 * @class Roo.LoadMask
5231 * A simple utility class for generically masking elements while loading data. If the element being masked has
5232 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5233 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5234 * element's UpdateManager load indicator and will be destroyed after the initial load.
5236 * Create a new LoadMask
5237 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5238 * @param {Object} config The config object
5240 Roo.LoadMask = function(el, config){
5241 this.el = Roo.get(el);
5242 Roo.apply(this, config);
5244 this.store.on('beforeload', this.onBeforeLoad, this);
5245 this.store.on('load', this.onLoad, this);
5246 this.store.on('loadexception', this.onLoadException, this);
5247 this.removeMask = false;
5249 var um = this.el.getUpdateManager();
5250 um.showLoadIndicator = false; // disable the default indicator
5251 um.on('beforeupdate', this.onBeforeLoad, this);
5252 um.on('update', this.onLoad, this);
5253 um.on('failure', this.onLoad, this);
5254 this.removeMask = true;
5258 Roo.LoadMask.prototype = {
5260 * @cfg {Boolean} removeMask
5261 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5262 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5266 * The text to display in a centered loading message box (defaults to 'Loading...')
5270 * @cfg {String} msgCls
5271 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5273 msgCls : 'x-mask-loading',
5276 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5282 * Disables the mask to prevent it from being displayed
5284 disable : function(){
5285 this.disabled = true;
5289 * Enables the mask so that it can be displayed
5291 enable : function(){
5292 this.disabled = false;
5295 onLoadException : function()
5299 if (typeof(arguments[3]) != 'undefined') {
5300 Roo.MessageBox.alert("Error loading",arguments[3]);
5304 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5305 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5314 this.el.unmask(this.removeMask);
5319 this.el.unmask(this.removeMask);
5323 onBeforeLoad : function(){
5325 this.el.mask(this.msg, this.msgCls);
5330 destroy : function(){
5332 this.store.un('beforeload', this.onBeforeLoad, this);
5333 this.store.un('load', this.onLoad, this);
5334 this.store.un('loadexception', this.onLoadException, this);
5336 var um = this.el.getUpdateManager();
5337 um.un('beforeupdate', this.onBeforeLoad, this);
5338 um.un('update', this.onLoad, this);
5339 um.un('failure', this.onLoad, this);
5350 * @class Roo.bootstrap.Table
5351 * @extends Roo.bootstrap.Component
5352 * Bootstrap Table class
5353 * @cfg {String} cls table class
5354 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5355 * @cfg {String} bgcolor Specifies the background color for a table
5356 * @cfg {Number} border Specifies whether the table cells should have borders or not
5357 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5358 * @cfg {Number} cellspacing Specifies the space between cells
5359 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5360 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5361 * @cfg {String} sortable Specifies that the table should be sortable
5362 * @cfg {String} summary Specifies a summary of the content of a table
5363 * @cfg {Number} width Specifies the width of a table
5364 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5366 * @cfg {boolean} striped Should the rows be alternative striped
5367 * @cfg {boolean} bordered Add borders to the table
5368 * @cfg {boolean} hover Add hover highlighting
5369 * @cfg {boolean} condensed Format condensed
5370 * @cfg {boolean} responsive Format condensed
5371 * @cfg {Boolean} loadMask (true|false) default false
5372 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5373 * @cfg {Boolean} thead (true|false) generate thead, default true
5374 * @cfg {Boolean} RowSelection (true|false) default false
5375 * @cfg {Boolean} CellSelection (true|false) default false
5376 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5380 * Create a new Table
5381 * @param {Object} config The config object
5384 Roo.bootstrap.Table = function(config){
5385 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5388 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5389 this.sm = this.selModel;
5390 this.sm.xmodule = this.xmodule || false;
5392 if (this.cm && typeof(this.cm.config) == 'undefined') {
5393 this.colModel = new Roo.grid.ColumnModel(this.cm);
5394 this.cm = this.colModel;
5395 this.cm.xmodule = this.xmodule || false;
5398 this.store= Roo.factory(this.store, Roo.data);
5399 this.ds = this.store;
5400 this.ds.xmodule = this.xmodule || false;
5403 if (this.footer && this.store) {
5404 this.footer.dataSource = this.ds;
5405 this.footer = Roo.factory(this.footer);
5412 * Fires when a cell is clicked
5413 * @param {Roo.bootstrap.Table} this
5414 * @param {Roo.Element} el
5415 * @param {Number} rowIndex
5416 * @param {Number} columnIndex
5417 * @param {Roo.EventObject} e
5421 * @event celldblclick
5422 * Fires when a cell is double clicked
5423 * @param {Roo.bootstrap.Table} this
5424 * @param {Roo.Element} el
5425 * @param {Number} rowIndex
5426 * @param {Number} columnIndex
5427 * @param {Roo.EventObject} e
5429 "celldblclick" : true,
5432 * Fires when a row is clicked
5433 * @param {Roo.bootstrap.Table} this
5434 * @param {Roo.Element} el
5435 * @param {Number} rowIndex
5436 * @param {Roo.EventObject} e
5440 * @event rowdblclick
5441 * Fires when a row is double clicked
5442 * @param {Roo.bootstrap.Table} this
5443 * @param {Roo.Element} el
5444 * @param {Number} rowIndex
5445 * @param {Roo.EventObject} e
5447 "rowdblclick" : true,
5450 * Fires when a mouseover occur
5451 * @param {Roo.bootstrap.Table} this
5452 * @param {Roo.Element} el
5453 * @param {Number} rowIndex
5454 * @param {Number} columnIndex
5455 * @param {Roo.EventObject} e
5460 * Fires when a mouseout occur
5461 * @param {Roo.bootstrap.Table} this
5462 * @param {Roo.Element} el
5463 * @param {Number} rowIndex
5464 * @param {Number} columnIndex
5465 * @param {Roo.EventObject} e
5470 * Fires when a row is rendered, so you can change add a style to it.
5471 * @param {Roo.bootstrap.Table} this
5472 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5476 * @event rowsrendered
5477 * Fires when all the rows have been rendered
5478 * @param {Roo.bootstrap.Table} this
5480 'rowsrendered' : true
5485 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5509 RowSelection : false,
5510 CellSelection : false,
5513 // Roo.Element - the tbody
5516 getAutoCreate : function(){
5517 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5526 cfg.cls += ' table-striped';
5530 cfg.cls += ' table-hover';
5532 if (this.bordered) {
5533 cfg.cls += ' table-bordered';
5535 if (this.condensed) {
5536 cfg.cls += ' table-condensed';
5538 if (this.responsive) {
5539 cfg.cls += ' table-responsive';
5543 cfg.cls+= ' ' +this.cls;
5546 // this lot should be simplifed...
5549 cfg.align=this.align;
5552 cfg.bgcolor=this.bgcolor;
5555 cfg.border=this.border;
5557 if (this.cellpadding) {
5558 cfg.cellpadding=this.cellpadding;
5560 if (this.cellspacing) {
5561 cfg.cellspacing=this.cellspacing;
5564 cfg.frame=this.frame;
5567 cfg.rules=this.rules;
5569 if (this.sortable) {
5570 cfg.sortable=this.sortable;
5573 cfg.summary=this.summary;
5576 cfg.width=this.width;
5579 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5582 if(this.store || this.cm){
5584 cfg.cn.push(this.renderHeader());
5587 cfg.cn.push(this.renderBody());
5590 cfg.cn.push(this.renderFooter());
5593 cfg.cls+= ' TableGrid';
5596 return { cn : [ cfg ] };
5599 initEvents : function()
5601 if(!this.store || !this.cm){
5605 //Roo.log('initEvents with ds!!!!');
5607 this.mainBody = this.el.select('tbody', true).first();
5612 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5613 e.on('click', _this.sort, _this);
5616 this.el.on("click", this.onClick, this);
5617 this.el.on("dblclick", this.onDblClick, this);
5619 // why is this done????? = it breaks dialogs??
5620 //this.parent().el.setStyle('position', 'relative');
5624 this.footer.parentId = this.id;
5625 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5628 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5630 this.store.on('load', this.onLoad, this);
5631 this.store.on('beforeload', this.onBeforeLoad, this);
5632 this.store.on('update', this.onUpdate, this);
5633 this.store.on('add', this.onAdd, this);
5637 onMouseover : function(e, el)
5639 var cell = Roo.get(el);
5645 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5646 cell = cell.findParent('td', false, true);
5649 var row = cell.findParent('tr', false, true);
5650 var cellIndex = cell.dom.cellIndex;
5651 var rowIndex = row.dom.rowIndex - 1; // start from 0
5653 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5657 onMouseout : function(e, el)
5659 var cell = Roo.get(el);
5665 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5666 cell = cell.findParent('td', false, true);
5669 var row = cell.findParent('tr', false, true);
5670 var cellIndex = cell.dom.cellIndex;
5671 var rowIndex = row.dom.rowIndex - 1; // start from 0
5673 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5677 onClick : function(e, el)
5679 var cell = Roo.get(el);
5681 if(!cell || (!this.CellSelection && !this.RowSelection)){
5685 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5686 cell = cell.findParent('td', false, true);
5689 if(!cell || typeof(cell) == 'undefined'){
5693 var row = cell.findParent('tr', false, true);
5695 if(!row || typeof(row) == 'undefined'){
5699 var cellIndex = cell.dom.cellIndex;
5700 var rowIndex = this.getRowIndex(row);
5702 if(this.CellSelection){
5703 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5706 if(this.RowSelection){
5707 this.fireEvent('rowclick', this, row, rowIndex, e);
5713 onDblClick : function(e,el)
5715 var cell = Roo.get(el);
5717 if(!cell || (!this.CellSelection && !this.RowSelection)){
5721 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5722 cell = cell.findParent('td', false, true);
5725 if(!cell || typeof(cell) == 'undefined'){
5729 var row = cell.findParent('tr', false, true);
5731 if(!row || typeof(row) == 'undefined'){
5735 var cellIndex = cell.dom.cellIndex;
5736 var rowIndex = this.getRowIndex(row);
5738 if(this.CellSelection){
5739 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5742 if(this.RowSelection){
5743 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5747 sort : function(e,el)
5749 var col = Roo.get(el);
5751 if(!col.hasClass('sortable')){
5755 var sort = col.attr('sort');
5758 if(col.hasClass('glyphicon-arrow-up')){
5762 this.store.sortInfo = {field : sort, direction : dir};
5765 Roo.log("calling footer first");
5766 this.footer.onClick('first');
5769 this.store.load({ params : { start : 0 } });
5773 renderHeader : function()
5782 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5784 var config = cm.config[i];
5789 html: cm.getColumnHeader(i)
5792 if(typeof(config.tooltip) != 'undefined'){
5793 c.tooltip = config.tooltip;
5796 if(typeof(config.colspan) != 'undefined'){
5797 c.colspan = config.colspan;
5800 if(typeof(config.hidden) != 'undefined' && config.hidden){
5801 c.style += ' display:none;';
5804 if(typeof(config.dataIndex) != 'undefined'){
5805 c.sort = config.dataIndex;
5808 if(typeof(config.sortable) != 'undefined' && config.sortable){
5812 if(typeof(config.align) != 'undefined' && config.align.length){
5813 c.style += ' text-align:' + config.align + ';';
5816 if(typeof(config.width) != 'undefined'){
5817 c.style += ' width:' + config.width + 'px;';
5820 if(typeof(config.cls) != 'undefined'){
5821 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5830 renderBody : function()
5840 colspan : this.cm.getColumnCount()
5850 renderFooter : function()
5860 colspan : this.cm.getColumnCount()
5874 Roo.log('ds onload');
5879 var ds = this.store;
5881 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5882 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5884 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5885 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5888 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5889 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5893 var tbody = this.mainBody;
5895 if(ds.getCount() > 0){
5896 ds.data.each(function(d,rowIndex){
5897 var row = this.renderRow(cm, ds, rowIndex);
5899 tbody.createChild(row);
5903 if(row.cellObjects.length){
5904 Roo.each(row.cellObjects, function(r){
5905 _this.renderCellObject(r);
5912 Roo.each(this.el.select('tbody td', true).elements, function(e){
5913 e.on('mouseover', _this.onMouseover, _this);
5916 Roo.each(this.el.select('tbody td', true).elements, function(e){
5917 e.on('mouseout', _this.onMouseout, _this);
5919 this.fireEvent('rowsrendered', this);
5920 //if(this.loadMask){
5921 // this.maskEl.hide();
5926 onUpdate : function(ds,record)
5928 this.refreshRow(record);
5931 onRemove : function(ds, record, index, isUpdate){
5932 if(isUpdate !== true){
5933 this.fireEvent("beforerowremoved", this, index, record);
5935 var bt = this.mainBody.dom;
5937 var rows = this.el.select('tbody > tr', true).elements;
5939 if(typeof(rows[index]) != 'undefined'){
5940 bt.removeChild(rows[index].dom);
5943 // if(bt.rows[index]){
5944 // bt.removeChild(bt.rows[index]);
5947 if(isUpdate !== true){
5948 //this.stripeRows(index);
5949 //this.syncRowHeights(index, index);
5951 this.fireEvent("rowremoved", this, index, record);
5955 onAdd : function(ds, records, rowIndex)
5957 //Roo.log('on Add called');
5958 // - note this does not handle multiple adding very well..
5959 var bt = this.mainBody.dom;
5960 for (var i =0 ; i < records.length;i++) {
5961 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5962 //Roo.log(records[i]);
5963 //Roo.log(this.store.getAt(rowIndex+i));
5964 this.insertRow(this.store, rowIndex + i, false);
5971 refreshRow : function(record){
5972 var ds = this.store, index;
5973 if(typeof record == 'number'){
5975 record = ds.getAt(index);
5977 index = ds.indexOf(record);
5979 this.insertRow(ds, index, true);
5980 this.onRemove(ds, record, index+1, true);
5981 //this.syncRowHeights(index, index);
5983 this.fireEvent("rowupdated", this, index, record);
5986 insertRow : function(dm, rowIndex, isUpdate){
5989 this.fireEvent("beforerowsinserted", this, rowIndex);
5991 //var s = this.getScrollState();
5992 var row = this.renderRow(this.cm, this.store, rowIndex);
5993 // insert before rowIndex..
5994 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5998 if(row.cellObjects.length){
5999 Roo.each(row.cellObjects, function(r){
6000 _this.renderCellObject(r);
6005 this.fireEvent("rowsinserted", this, rowIndex);
6006 //this.syncRowHeights(firstRow, lastRow);
6007 //this.stripeRows(firstRow);
6014 getRowDom : function(rowIndex)
6016 var rows = this.el.select('tbody > tr', true).elements;
6018 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6021 // returns the object tree for a tr..
6024 renderRow : function(cm, ds, rowIndex)
6027 var d = ds.getAt(rowIndex);
6034 var cellObjects = [];
6036 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6037 var config = cm.config[i];
6039 var renderer = cm.getRenderer(i);
6043 if(typeof(renderer) !== 'undefined'){
6044 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6046 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6047 // and are rendered into the cells after the row is rendered - using the id for the element.
6049 if(typeof(value) === 'object'){
6059 rowIndex : rowIndex,
6064 this.fireEvent('rowclass', this, rowcfg);
6068 cls : rowcfg.rowClass,
6070 html: (typeof(value) === 'object') ? '' : value
6077 if(typeof(config.colspan) != 'undefined'){
6078 td.colspan = config.colspan;
6081 if(typeof(config.hidden) != 'undefined' && config.hidden){
6082 td.style += ' display:none;';
6085 if(typeof(config.align) != 'undefined' && config.align.length){
6086 td.style += ' text-align:' + config.align + ';';
6089 if(typeof(config.width) != 'undefined'){
6090 td.style += ' width:' + config.width + 'px;';
6093 if(typeof(config.cursor) != 'undefined'){
6094 td.style += ' cursor:' + config.cursor + ';';
6097 if(typeof(config.cls) != 'undefined'){
6098 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6105 row.cellObjects = cellObjects;
6113 onBeforeLoad : function()
6115 //Roo.log('ds onBeforeLoad');
6119 //if(this.loadMask){
6120 // this.maskEl.show();
6128 this.el.select('tbody', true).first().dom.innerHTML = '';
6131 * Show or hide a row.
6132 * @param {Number} rowIndex to show or hide
6133 * @param {Boolean} state hide
6135 setRowVisibility : function(rowIndex, state)
6137 var bt = this.mainBody.dom;
6139 var rows = this.el.select('tbody > tr', true).elements;
6141 if(typeof(rows[rowIndex]) == 'undefined'){
6144 rows[rowIndex].dom.style.display = state ? '' : 'none';
6148 getSelectionModel : function(){
6150 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6152 return this.selModel;
6155 * Render the Roo.bootstrap object from renderder
6157 renderCellObject : function(r)
6161 var t = r.cfg.render(r.container);
6164 Roo.each(r.cfg.cn, function(c){
6166 container: t.getChildContainer(),
6169 _this.renderCellObject(child);
6174 getRowIndex : function(row)
6178 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6201 * @class Roo.bootstrap.TableCell
6202 * @extends Roo.bootstrap.Component
6203 * Bootstrap TableCell class
6204 * @cfg {String} html cell contain text
6205 * @cfg {String} cls cell class
6206 * @cfg {String} tag cell tag (td|th) default td
6207 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6208 * @cfg {String} align Aligns the content in a cell
6209 * @cfg {String} axis Categorizes cells
6210 * @cfg {String} bgcolor Specifies the background color of a cell
6211 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6212 * @cfg {Number} colspan Specifies the number of columns a cell should span
6213 * @cfg {String} headers Specifies one or more header cells a cell is related to
6214 * @cfg {Number} height Sets the height of a cell
6215 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6216 * @cfg {Number} rowspan Sets the number of rows a cell should span
6217 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6218 * @cfg {String} valign Vertical aligns the content in a cell
6219 * @cfg {Number} width Specifies the width of a cell
6222 * Create a new TableCell
6223 * @param {Object} config The config object
6226 Roo.bootstrap.TableCell = function(config){
6227 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6230 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6250 getAutoCreate : function(){
6251 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6271 cfg.align=this.align
6277 cfg.bgcolor=this.bgcolor
6280 cfg.charoff=this.charoff
6283 cfg.colspan=this.colspan
6286 cfg.headers=this.headers
6289 cfg.height=this.height
6292 cfg.nowrap=this.nowrap
6295 cfg.rowspan=this.rowspan
6298 cfg.scope=this.scope
6301 cfg.valign=this.valign
6304 cfg.width=this.width
6323 * @class Roo.bootstrap.TableRow
6324 * @extends Roo.bootstrap.Component
6325 * Bootstrap TableRow class
6326 * @cfg {String} cls row class
6327 * @cfg {String} align Aligns the content in a table row
6328 * @cfg {String} bgcolor Specifies a background color for a table row
6329 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6330 * @cfg {String} valign Vertical aligns the content in a table row
6333 * Create a new TableRow
6334 * @param {Object} config The config object
6337 Roo.bootstrap.TableRow = function(config){
6338 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6341 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6349 getAutoCreate : function(){
6350 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6360 cfg.align = this.align;
6363 cfg.bgcolor = this.bgcolor;
6366 cfg.charoff = this.charoff;
6369 cfg.valign = this.valign;
6387 * @class Roo.bootstrap.TableBody
6388 * @extends Roo.bootstrap.Component
6389 * Bootstrap TableBody class
6390 * @cfg {String} cls element class
6391 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6392 * @cfg {String} align Aligns the content inside the element
6393 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6394 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6397 * Create a new TableBody
6398 * @param {Object} config The config object
6401 Roo.bootstrap.TableBody = function(config){
6402 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6405 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6413 getAutoCreate : function(){
6414 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6428 cfg.align = this.align;
6431 cfg.charoff = this.charoff;
6434 cfg.valign = this.valign;
6441 // initEvents : function()
6448 // this.store = Roo.factory(this.store, Roo.data);
6449 // this.store.on('load', this.onLoad, this);
6451 // this.store.load();
6455 // onLoad: function ()
6457 // this.fireEvent('load', this);
6467 * Ext JS Library 1.1.1
6468 * Copyright(c) 2006-2007, Ext JS, LLC.
6470 * Originally Released Under LGPL - original licence link has changed is not relivant.
6473 * <script type="text/javascript">
6476 // as we use this in bootstrap.
6477 Roo.namespace('Roo.form');
6479 * @class Roo.form.Action
6480 * Internal Class used to handle form actions
6482 * @param {Roo.form.BasicForm} el The form element or its id
6483 * @param {Object} config Configuration options
6488 // define the action interface
6489 Roo.form.Action = function(form, options){
6491 this.options = options || {};
6494 * Client Validation Failed
6497 Roo.form.Action.CLIENT_INVALID = 'client';
6499 * Server Validation Failed
6502 Roo.form.Action.SERVER_INVALID = 'server';
6504 * Connect to Server Failed
6507 Roo.form.Action.CONNECT_FAILURE = 'connect';
6509 * Reading Data from Server Failed
6512 Roo.form.Action.LOAD_FAILURE = 'load';
6514 Roo.form.Action.prototype = {
6516 failureType : undefined,
6517 response : undefined,
6521 run : function(options){
6526 success : function(response){
6531 handleResponse : function(response){
6535 // default connection failure
6536 failure : function(response){
6538 this.response = response;
6539 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6540 this.form.afterAction(this, false);
6543 processResponse : function(response){
6544 this.response = response;
6545 if(!response.responseText){
6548 this.result = this.handleResponse(response);
6552 // utility functions used internally
6553 getUrl : function(appendParams){
6554 var url = this.options.url || this.form.url || this.form.el.dom.action;
6556 var p = this.getParams();
6558 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6564 getMethod : function(){
6565 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6568 getParams : function(){
6569 var bp = this.form.baseParams;
6570 var p = this.options.params;
6572 if(typeof p == "object"){
6573 p = Roo.urlEncode(Roo.applyIf(p, bp));
6574 }else if(typeof p == 'string' && bp){
6575 p += '&' + Roo.urlEncode(bp);
6578 p = Roo.urlEncode(bp);
6583 createCallback : function(){
6585 success: this.success,
6586 failure: this.failure,
6588 timeout: (this.form.timeout*1000),
6589 upload: this.form.fileUpload ? this.success : undefined
6594 Roo.form.Action.Submit = function(form, options){
6595 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6598 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6601 haveProgress : false,
6602 uploadComplete : false,
6604 // uploadProgress indicator.
6605 uploadProgress : function()
6607 if (!this.form.progressUrl) {
6611 if (!this.haveProgress) {
6612 Roo.MessageBox.progress("Uploading", "Uploading");
6614 if (this.uploadComplete) {
6615 Roo.MessageBox.hide();
6619 this.haveProgress = true;
6621 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6623 var c = new Roo.data.Connection();
6625 url : this.form.progressUrl,
6630 success : function(req){
6631 //console.log(data);
6635 rdata = Roo.decode(req.responseText)
6637 Roo.log("Invalid data from server..");
6641 if (!rdata || !rdata.success) {
6643 Roo.MessageBox.alert(Roo.encode(rdata));
6646 var data = rdata.data;
6648 if (this.uploadComplete) {
6649 Roo.MessageBox.hide();
6654 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6655 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6658 this.uploadProgress.defer(2000,this);
6661 failure: function(data) {
6662 Roo.log('progress url failed ');
6673 // run get Values on the form, so it syncs any secondary forms.
6674 this.form.getValues();
6676 var o = this.options;
6677 var method = this.getMethod();
6678 var isPost = method == 'POST';
6679 if(o.clientValidation === false || this.form.isValid()){
6681 if (this.form.progressUrl) {
6682 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6683 (new Date() * 1) + '' + Math.random());
6688 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6689 form:this.form.el.dom,
6690 url:this.getUrl(!isPost),
6692 params:isPost ? this.getParams() : null,
6693 isUpload: this.form.fileUpload
6696 this.uploadProgress();
6698 }else if (o.clientValidation !== false){ // client validation failed
6699 this.failureType = Roo.form.Action.CLIENT_INVALID;
6700 this.form.afterAction(this, false);
6704 success : function(response)
6706 this.uploadComplete= true;
6707 if (this.haveProgress) {
6708 Roo.MessageBox.hide();
6712 var result = this.processResponse(response);
6713 if(result === true || result.success){
6714 this.form.afterAction(this, true);
6718 this.form.markInvalid(result.errors);
6719 this.failureType = Roo.form.Action.SERVER_INVALID;
6721 this.form.afterAction(this, false);
6723 failure : function(response)
6725 this.uploadComplete= true;
6726 if (this.haveProgress) {
6727 Roo.MessageBox.hide();
6730 this.response = response;
6731 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6732 this.form.afterAction(this, false);
6735 handleResponse : function(response){
6736 if(this.form.errorReader){
6737 var rs = this.form.errorReader.read(response);
6740 for(var i = 0, len = rs.records.length; i < len; i++) {
6741 var r = rs.records[i];
6745 if(errors.length < 1){
6749 success : rs.success,
6755 ret = Roo.decode(response.responseText);
6759 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6769 Roo.form.Action.Load = function(form, options){
6770 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6771 this.reader = this.form.reader;
6774 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6779 Roo.Ajax.request(Roo.apply(
6780 this.createCallback(), {
6781 method:this.getMethod(),
6782 url:this.getUrl(false),
6783 params:this.getParams()
6787 success : function(response){
6789 var result = this.processResponse(response);
6790 if(result === true || !result.success || !result.data){
6791 this.failureType = Roo.form.Action.LOAD_FAILURE;
6792 this.form.afterAction(this, false);
6795 this.form.clearInvalid();
6796 this.form.setValues(result.data);
6797 this.form.afterAction(this, true);
6800 handleResponse : function(response){
6801 if(this.form.reader){
6802 var rs = this.form.reader.read(response);
6803 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6805 success : rs.success,
6809 return Roo.decode(response.responseText);
6813 Roo.form.Action.ACTION_TYPES = {
6814 'load' : Roo.form.Action.Load,
6815 'submit' : Roo.form.Action.Submit
6824 * @class Roo.bootstrap.Form
6825 * @extends Roo.bootstrap.Component
6826 * Bootstrap Form class
6827 * @cfg {String} method GET | POST (default POST)
6828 * @cfg {String} labelAlign top | left (default top)
6829 * @cfg {String} align left | right - for navbars
6830 * @cfg {Boolean} loadMask load mask when submit (default true)
6835 * @param {Object} config The config object
6839 Roo.bootstrap.Form = function(config){
6840 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6843 * @event clientvalidation
6844 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6845 * @param {Form} this
6846 * @param {Boolean} valid true if the form has passed client-side validation
6848 clientvalidation: true,
6850 * @event beforeaction
6851 * Fires before any action is performed. Return false to cancel the action.
6852 * @param {Form} this
6853 * @param {Action} action The action to be performed
6857 * @event actionfailed
6858 * Fires when an action fails.
6859 * @param {Form} this
6860 * @param {Action} action The action that failed
6862 actionfailed : true,
6864 * @event actioncomplete
6865 * Fires when an action is completed.
6866 * @param {Form} this
6867 * @param {Action} action The action that completed
6869 actioncomplete : true
6874 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6877 * @cfg {String} method
6878 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6883 * The URL to use for form actions if one isn't supplied in the action options.
6886 * @cfg {Boolean} fileUpload
6887 * Set to true if this form is a file upload.
6891 * @cfg {Object} baseParams
6892 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6896 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6900 * @cfg {Sting} align (left|right) for navbar forms
6905 activeAction : null,
6908 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6909 * element by passing it or its id or mask the form itself by passing in true.
6912 waitMsgTarget : false,
6916 getAutoCreate : function(){
6920 method : this.method || 'POST',
6921 id : this.id || Roo.id(),
6924 if (this.parent().xtype.match(/^Nav/)) {
6925 cfg.cls = 'navbar-form navbar-' + this.align;
6929 if (this.labelAlign == 'left' ) {
6930 cfg.cls += ' form-horizontal';
6936 initEvents : function()
6938 this.el.on('submit', this.onSubmit, this);
6939 // this was added as random key presses on the form where triggering form submit.
6940 this.el.on('keypress', function(e) {
6941 if (e.getCharCode() != 13) {
6944 // we might need to allow it for textareas.. and some other items.
6945 // check e.getTarget().
6947 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6951 Roo.log("keypress blocked");
6959 onSubmit : function(e){
6964 * Returns true if client-side validation on the form is successful.
6967 isValid : function(){
6968 var items = this.getItems();
6970 items.each(function(f){
6979 * Returns true if any fields in this form have changed since their original load.
6982 isDirty : function(){
6984 var items = this.getItems();
6985 items.each(function(f){
6995 * Performs a predefined action (submit or load) or custom actions you define on this form.
6996 * @param {String} actionName The name of the action type
6997 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6998 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6999 * accept other config options):
7001 Property Type Description
7002 ---------------- --------------- ----------------------------------------------------------------------------------
7003 url String The url for the action (defaults to the form's url)
7004 method String The form method to use (defaults to the form's method, or POST if not defined)
7005 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7006 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7007 validate the form on the client (defaults to false)
7009 * @return {BasicForm} this
7011 doAction : function(action, options){
7012 if(typeof action == 'string'){
7013 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7015 if(this.fireEvent('beforeaction', this, action) !== false){
7016 this.beforeAction(action);
7017 action.run.defer(100, action);
7023 beforeAction : function(action){
7024 var o = action.options;
7027 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7029 // not really supported yet.. ??
7031 //if(this.waitMsgTarget === true){
7032 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7033 //}else if(this.waitMsgTarget){
7034 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7035 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7037 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7043 afterAction : function(action, success){
7044 this.activeAction = null;
7045 var o = action.options;
7047 //if(this.waitMsgTarget === true){
7049 //}else if(this.waitMsgTarget){
7050 // this.waitMsgTarget.unmask();
7052 // Roo.MessageBox.updateProgress(1);
7053 // Roo.MessageBox.hide();
7060 Roo.callback(o.success, o.scope, [this, action]);
7061 this.fireEvent('actioncomplete', this, action);
7065 // failure condition..
7066 // we have a scenario where updates need confirming.
7067 // eg. if a locking scenario exists..
7068 // we look for { errors : { needs_confirm : true }} in the response.
7070 (typeof(action.result) != 'undefined') &&
7071 (typeof(action.result.errors) != 'undefined') &&
7072 (typeof(action.result.errors.needs_confirm) != 'undefined')
7075 Roo.log("not supported yet");
7078 Roo.MessageBox.confirm(
7079 "Change requires confirmation",
7080 action.result.errorMsg,
7085 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7095 Roo.callback(o.failure, o.scope, [this, action]);
7096 // show an error message if no failed handler is set..
7097 if (!this.hasListener('actionfailed')) {
7098 Roo.log("need to add dialog support");
7100 Roo.MessageBox.alert("Error",
7101 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7102 action.result.errorMsg :
7103 "Saving Failed, please check your entries or try again"
7108 this.fireEvent('actionfailed', this, action);
7113 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7114 * @param {String} id The value to search for
7117 findField : function(id){
7118 var items = this.getItems();
7119 var field = items.get(id);
7121 items.each(function(f){
7122 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7129 return field || null;
7132 * Mark fields in this form invalid in bulk.
7133 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7134 * @return {BasicForm} this
7136 markInvalid : function(errors){
7137 if(errors instanceof Array){
7138 for(var i = 0, len = errors.length; i < len; i++){
7139 var fieldError = errors[i];
7140 var f = this.findField(fieldError.id);
7142 f.markInvalid(fieldError.msg);
7148 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7149 field.markInvalid(errors[id]);
7153 //Roo.each(this.childForms || [], function (f) {
7154 // f.markInvalid(errors);
7161 * Set values for fields in this form in bulk.
7162 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7163 * @return {BasicForm} this
7165 setValues : function(values){
7166 if(values instanceof Array){ // array of objects
7167 for(var i = 0, len = values.length; i < len; i++){
7169 var f = this.findField(v.id);
7171 f.setValue(v.value);
7172 if(this.trackResetOnLoad){
7173 f.originalValue = f.getValue();
7177 }else{ // object hash
7180 if(typeof values[id] != 'function' && (field = this.findField(id))){
7182 if (field.setFromData &&
7184 field.displayField &&
7185 // combos' with local stores can
7186 // be queried via setValue()
7187 // to set their value..
7188 (field.store && !field.store.isLocal)
7192 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7193 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7194 field.setFromData(sd);
7197 field.setValue(values[id]);
7201 if(this.trackResetOnLoad){
7202 field.originalValue = field.getValue();
7208 //Roo.each(this.childForms || [], function (f) {
7209 // f.setValues(values);
7216 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7217 * they are returned as an array.
7218 * @param {Boolean} asString
7221 getValues : function(asString){
7222 //if (this.childForms) {
7223 // copy values from the child forms
7224 // Roo.each(this.childForms, function (f) {
7225 // this.setValues(f.getValues());
7231 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7232 if(asString === true){
7235 return Roo.urlDecode(fs);
7239 * Returns the fields in this form as an object with key/value pairs.
7240 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7243 getFieldValues : function(with_hidden)
7245 var items = this.getItems();
7247 items.each(function(f){
7251 var v = f.getValue();
7252 if (f.inputType =='radio') {
7253 if (typeof(ret[f.getName()]) == 'undefined') {
7254 ret[f.getName()] = ''; // empty..
7257 if (!f.el.dom.checked) {
7265 // not sure if this supported any more..
7266 if ((typeof(v) == 'object') && f.getRawValue) {
7267 v = f.getRawValue() ; // dates..
7269 // combo boxes where name != hiddenName...
7270 if (f.name != f.getName()) {
7271 ret[f.name] = f.getRawValue();
7273 ret[f.getName()] = v;
7280 * Clears all invalid messages in this form.
7281 * @return {BasicForm} this
7283 clearInvalid : function(){
7284 var items = this.getItems();
7286 items.each(function(f){
7297 * @return {BasicForm} this
7300 var items = this.getItems();
7301 items.each(function(f){
7305 Roo.each(this.childForms || [], function (f) {
7312 getItems : function()
7314 var r=new Roo.util.MixedCollection(false, function(o){
7315 return o.id || (o.id = Roo.id());
7317 var iter = function(el) {
7324 Roo.each(el.items,function(e) {
7344 * Ext JS Library 1.1.1
7345 * Copyright(c) 2006-2007, Ext JS, LLC.
7347 * Originally Released Under LGPL - original licence link has changed is not relivant.
7350 * <script type="text/javascript">
7353 * @class Roo.form.VTypes
7354 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7357 Roo.form.VTypes = function(){
7358 // closure these in so they are only created once.
7359 var alpha = /^[a-zA-Z_]+$/;
7360 var alphanum = /^[a-zA-Z0-9_]+$/;
7361 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7362 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7364 // All these messages and functions are configurable
7367 * The function used to validate email addresses
7368 * @param {String} value The email address
7370 'email' : function(v){
7371 return email.test(v);
7374 * The error text to display when the email validation function returns false
7377 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7379 * The keystroke filter mask to be applied on email input
7382 'emailMask' : /[a-z0-9_\.\-@]/i,
7385 * The function used to validate URLs
7386 * @param {String} value The URL
7388 'url' : function(v){
7392 * The error text to display when the url validation function returns false
7395 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7398 * The function used to validate alpha values
7399 * @param {String} value The value
7401 'alpha' : function(v){
7402 return alpha.test(v);
7405 * The error text to display when the alpha validation function returns false
7408 'alphaText' : 'This field should only contain letters and _',
7410 * The keystroke filter mask to be applied on alpha input
7413 'alphaMask' : /[a-z_]/i,
7416 * The function used to validate alphanumeric values
7417 * @param {String} value The value
7419 'alphanum' : function(v){
7420 return alphanum.test(v);
7423 * The error text to display when the alphanumeric validation function returns false
7426 'alphanumText' : 'This field should only contain letters, numbers and _',
7428 * The keystroke filter mask to be applied on alphanumeric input
7431 'alphanumMask' : /[a-z0-9_]/i
7441 * @class Roo.bootstrap.Input
7442 * @extends Roo.bootstrap.Component
7443 * Bootstrap Input class
7444 * @cfg {Boolean} disabled is it disabled
7445 * @cfg {String} fieldLabel - the label associated
7446 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7447 * @cfg {String} name name of the input
7448 * @cfg {string} fieldLabel - the label associated
7449 * @cfg {string} inputType - input / file submit ...
7450 * @cfg {string} placeholder - placeholder to put in text.
7451 * @cfg {string} before - input group add on before
7452 * @cfg {string} after - input group add on after
7453 * @cfg {string} size - (lg|sm) or leave empty..
7454 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7455 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7456 * @cfg {Number} md colspan out of 12 for computer-sized screens
7457 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7458 * @cfg {string} value default value of the input
7459 * @cfg {Number} labelWidth set the width of label (0-12)
7460 * @cfg {String} labelAlign (top|left)
7461 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7462 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7464 * @cfg {String} align (left|center|right) Default left
7469 * Create a new Input
7470 * @param {Object} config The config object
7473 Roo.bootstrap.Input = function(config){
7474 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7479 * Fires when this field receives input focus.
7480 * @param {Roo.form.Field} this
7485 * Fires when this field loses input focus.
7486 * @param {Roo.form.Field} this
7491 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7492 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7493 * @param {Roo.form.Field} this
7494 * @param {Roo.EventObject} e The event object
7499 * Fires just before the field blurs if the field value has changed.
7500 * @param {Roo.form.Field} this
7501 * @param {Mixed} newValue The new value
7502 * @param {Mixed} oldValue The original value
7507 * Fires after the field has been marked as invalid.
7508 * @param {Roo.form.Field} this
7509 * @param {String} msg The validation message
7514 * Fires after the field has been validated with no errors.
7515 * @param {Roo.form.Field} this
7520 * Fires after the key up
7521 * @param {Roo.form.Field} this
7522 * @param {Roo.EventObject} e The event Object
7528 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7530 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7531 automatic validation (defaults to "keyup").
7533 validationEvent : "keyup",
7535 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7537 validateOnBlur : true,
7539 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7541 validationDelay : 250,
7543 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7545 focusClass : "x-form-focus", // not needed???
7549 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7551 invalidClass : "has-warning",
7554 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7556 validClass : "has-success",
7559 * @cfg {Boolean} hasFeedback (true|false) default true
7564 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7566 invalidFeedbackClass : "glyphicon-warning-sign",
7569 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7571 validFeedbackClass : "glyphicon-ok",
7574 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7576 selectOnFocus : false,
7579 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7583 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7588 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7590 disableKeyFilter : false,
7593 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7597 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7601 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7603 blankText : "This field is required",
7606 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7610 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7612 maxLength : Number.MAX_VALUE,
7614 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7616 minLengthText : "The minimum length for this field is {0}",
7618 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7620 maxLengthText : "The maximum length for this field is {0}",
7624 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7625 * If available, this function will be called only after the basic validators all return true, and will be passed the
7626 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7630 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7631 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7632 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7636 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7640 autocomplete: false,
7659 formatedValue : false,
7661 parentLabelAlign : function()
7664 while (parent.parent()) {
7665 parent = parent.parent();
7666 if (typeof(parent.labelAlign) !='undefined') {
7667 return parent.labelAlign;
7674 getAutoCreate : function(){
7676 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7682 if(this.inputType != 'hidden'){
7683 cfg.cls = 'form-group' //input-group
7689 type : this.inputType,
7691 cls : 'form-control',
7692 placeholder : this.placeholder || '',
7693 autocomplete : this.autocomplete || 'new-password'
7698 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7701 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7702 input.maxLength = this.maxLength;
7705 if (this.disabled) {
7706 input.disabled=true;
7709 if (this.readOnly) {
7710 input.readonly=true;
7714 input.name = this.name;
7717 input.cls += ' input-' + this.size;
7720 ['xs','sm','md','lg'].map(function(size){
7721 if (settings[size]) {
7722 cfg.cls += ' col-' + size + '-' + settings[size];
7726 var inputblock = input;
7730 cls: 'glyphicon form-control-feedback'
7733 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7736 cls : 'has-feedback',
7744 if (this.before || this.after) {
7747 cls : 'input-group',
7751 if (this.before && typeof(this.before) == 'string') {
7753 inputblock.cn.push({
7755 cls : 'roo-input-before input-group-addon',
7759 if (this.before && typeof(this.before) == 'object') {
7760 this.before = Roo.factory(this.before);
7761 Roo.log(this.before);
7762 inputblock.cn.push({
7764 cls : 'roo-input-before input-group-' +
7765 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7769 inputblock.cn.push(input);
7771 if (this.after && typeof(this.after) == 'string') {
7772 inputblock.cn.push({
7774 cls : 'roo-input-after input-group-addon',
7778 if (this.after && typeof(this.after) == 'object') {
7779 this.after = Roo.factory(this.after);
7780 Roo.log(this.after);
7781 inputblock.cn.push({
7783 cls : 'roo-input-after input-group-' +
7784 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7788 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7789 inputblock.cls += ' has-feedback';
7790 inputblock.cn.push(feedback);
7794 if (align ==='left' && this.fieldLabel.length) {
7795 Roo.log("left and has label");
7801 cls : 'control-label col-sm-' + this.labelWidth,
7802 html : this.fieldLabel
7806 cls : "col-sm-" + (12 - this.labelWidth),
7813 } else if ( this.fieldLabel.length) {
7819 //cls : 'input-group-addon',
7820 html : this.fieldLabel
7830 Roo.log(" no label && no align");
7839 Roo.log('input-parentType: ' + this.parentType);
7841 if (this.parentType === 'Navbar' && this.parent().bar) {
7842 cfg.cls += ' navbar-form';
7850 * return the real input element.
7852 inputEl: function ()
7854 return this.el.select('input.form-control',true).first();
7857 tooltipEl : function()
7859 return this.inputEl();
7862 setDisabled : function(v)
7864 var i = this.inputEl().dom;
7866 i.removeAttribute('disabled');
7870 i.setAttribute('disabled','true');
7872 initEvents : function()
7875 this.inputEl().on("keydown" , this.fireKey, this);
7876 this.inputEl().on("focus", this.onFocus, this);
7877 this.inputEl().on("blur", this.onBlur, this);
7879 this.inputEl().relayEvent('keyup', this);
7881 // reference to original value for reset
7882 this.originalValue = this.getValue();
7883 //Roo.form.TextField.superclass.initEvents.call(this);
7884 if(this.validationEvent == 'keyup'){
7885 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7886 this.inputEl().on('keyup', this.filterValidation, this);
7888 else if(this.validationEvent !== false){
7889 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7892 if(this.selectOnFocus){
7893 this.on("focus", this.preFocus, this);
7896 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7897 this.inputEl().on("keypress", this.filterKeys, this);
7900 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7901 this.el.on("click", this.autoSize, this);
7904 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7905 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7908 if (typeof(this.before) == 'object') {
7909 this.before.render(this.el.select('.roo-input-before',true).first());
7911 if (typeof(this.after) == 'object') {
7912 this.after.render(this.el.select('.roo-input-after',true).first());
7917 filterValidation : function(e){
7918 if(!e.isNavKeyPress()){
7919 this.validationTask.delay(this.validationDelay);
7923 * Validates the field value
7924 * @return {Boolean} True if the value is valid, else false
7926 validate : function(){
7927 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7928 if(this.disabled || this.validateValue(this.getRawValue())){
7939 * Validates a value according to the field's validation rules and marks the field as invalid
7940 * if the validation fails
7941 * @param {Mixed} value The value to validate
7942 * @return {Boolean} True if the value is valid, else false
7944 validateValue : function(value){
7945 if(value.length < 1) { // if it's blank
7946 if(this.allowBlank){
7952 if(value.length < this.minLength){
7955 if(value.length > this.maxLength){
7959 var vt = Roo.form.VTypes;
7960 if(!vt[this.vtype](value, this)){
7964 if(typeof this.validator == "function"){
7965 var msg = this.validator(value);
7971 if(this.regex && !this.regex.test(value)){
7981 fireKey : function(e){
7982 //Roo.log('field ' + e.getKey());
7983 if(e.isNavKeyPress()){
7984 this.fireEvent("specialkey", this, e);
7987 focus : function (selectText){
7989 this.inputEl().focus();
7990 if(selectText === true){
7991 this.inputEl().dom.select();
7997 onFocus : function(){
7998 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7999 // this.el.addClass(this.focusClass);
8002 this.hasFocus = true;
8003 this.startValue = this.getValue();
8004 this.fireEvent("focus", this);
8008 beforeBlur : Roo.emptyFn,
8012 onBlur : function(){
8014 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8015 //this.el.removeClass(this.focusClass);
8017 this.hasFocus = false;
8018 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8021 var v = this.getValue();
8022 if(String(v) !== String(this.startValue)){
8023 this.fireEvent('change', this, v, this.startValue);
8025 this.fireEvent("blur", this);
8029 * Resets the current field value to the originally loaded value and clears any validation messages
8032 this.setValue(this.originalValue);
8036 * Returns the name of the field
8037 * @return {Mixed} name The name field
8039 getName: function(){
8043 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8044 * @return {Mixed} value The field value
8046 getValue : function(){
8048 var v = this.inputEl().getValue();
8053 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8054 * @return {Mixed} value The field value
8056 getRawValue : function(){
8057 var v = this.inputEl().getValue();
8063 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8064 * @param {Mixed} value The value to set
8066 setRawValue : function(v){
8067 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8070 selectText : function(start, end){
8071 var v = this.getRawValue();
8073 start = start === undefined ? 0 : start;
8074 end = end === undefined ? v.length : end;
8075 var d = this.inputEl().dom;
8076 if(d.setSelectionRange){
8077 d.setSelectionRange(start, end);
8078 }else if(d.createTextRange){
8079 var range = d.createTextRange();
8080 range.moveStart("character", start);
8081 range.moveEnd("character", v.length-end);
8088 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8089 * @param {Mixed} value The value to set
8091 setValue : function(v){
8094 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8100 processValue : function(value){
8101 if(this.stripCharsRe){
8102 var newValue = value.replace(this.stripCharsRe, '');
8103 if(newValue !== value){
8104 this.setRawValue(newValue);
8111 preFocus : function(){
8113 if(this.selectOnFocus){
8114 this.inputEl().dom.select();
8117 filterKeys : function(e){
8119 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8122 var c = e.getCharCode(), cc = String.fromCharCode(c);
8123 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8126 if(!this.maskRe.test(cc)){
8131 * Clear any invalid styles/messages for this field
8133 clearInvalid : function(){
8135 if(!this.el || this.preventMark){ // not rendered
8138 this.el.removeClass(this.invalidClass);
8140 this.fireEvent('valid', this);
8144 * Mark this field as valid
8146 markValid : function(){
8147 if(!this.el || this.preventMark){ // not rendered
8151 this.el.removeClass([this.invalidClass, this.validClass]);
8153 if(this.disabled || this.allowBlank){
8157 this.el.addClass(this.validClass);
8159 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8161 var feedback = this.el.select('.form-control-feedback', true).first();
8164 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8165 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8170 this.fireEvent('valid', this);
8174 * Mark this field as invalid
8175 * @param {String} msg The validation message
8177 markInvalid : function(msg){
8178 if(!this.el || this.preventMark){ // not rendered
8182 this.el.removeClass([this.invalidClass, this.validClass]);
8184 if(this.disabled || this.allowBlank){
8188 this.el.addClass(this.invalidClass);
8190 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8192 var feedback = this.el.select('.form-control-feedback', true).first();
8195 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8197 if(this.getValue().length){
8198 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8205 this.fireEvent('invalid', this, msg);
8208 SafariOnKeyDown : function(event)
8210 // this is a workaround for a password hang bug on chrome/ webkit.
8212 var isSelectAll = false;
8214 if(this.inputEl().dom.selectionEnd > 0){
8215 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8217 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8218 event.preventDefault();
8223 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8225 event.preventDefault();
8226 // this is very hacky as keydown always get's upper case.
8228 var cc = String.fromCharCode(event.getCharCode());
8229 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8233 adjustWidth : function(tag, w){
8234 tag = tag.toLowerCase();
8235 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8236 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8240 if(tag == 'textarea'){
8243 }else if(Roo.isOpera){
8247 if(tag == 'textarea'){
8266 * @class Roo.bootstrap.TextArea
8267 * @extends Roo.bootstrap.Input
8268 * Bootstrap TextArea class
8269 * @cfg {Number} cols Specifies the visible width of a text area
8270 * @cfg {Number} rows Specifies the visible number of lines in a text area
8271 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8272 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8273 * @cfg {string} html text
8276 * Create a new TextArea
8277 * @param {Object} config The config object
8280 Roo.bootstrap.TextArea = function(config){
8281 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8285 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8295 getAutoCreate : function(){
8297 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8308 value : this.value || '',
8309 html: this.html || '',
8310 cls : 'form-control',
8311 placeholder : this.placeholder || ''
8315 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8316 input.maxLength = this.maxLength;
8320 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8324 input.cols = this.cols;
8327 if (this.readOnly) {
8328 input.readonly = true;
8332 input.name = this.name;
8336 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8340 ['xs','sm','md','lg'].map(function(size){
8341 if (settings[size]) {
8342 cfg.cls += ' col-' + size + '-' + settings[size];
8346 var inputblock = input;
8348 if(this.hasFeedback && !this.allowBlank){
8352 cls: 'glyphicon form-control-feedback'
8356 cls : 'has-feedback',
8365 if (this.before || this.after) {
8368 cls : 'input-group',
8372 inputblock.cn.push({
8374 cls : 'input-group-addon',
8379 inputblock.cn.push(input);
8381 if(this.hasFeedback && !this.allowBlank){
8382 inputblock.cls += ' has-feedback';
8383 inputblock.cn.push(feedback);
8387 inputblock.cn.push({
8389 cls : 'input-group-addon',
8396 if (align ==='left' && this.fieldLabel.length) {
8397 Roo.log("left and has label");
8403 cls : 'control-label col-sm-' + this.labelWidth,
8404 html : this.fieldLabel
8408 cls : "col-sm-" + (12 - this.labelWidth),
8415 } else if ( this.fieldLabel.length) {
8421 //cls : 'input-group-addon',
8422 html : this.fieldLabel
8432 Roo.log(" no label && no align");
8442 if (this.disabled) {
8443 input.disabled=true;
8450 * return the real textarea element.
8452 inputEl: function ()
8454 return this.el.select('textarea.form-control',true).first();
8462 * trigger field - base class for combo..
8467 * @class Roo.bootstrap.TriggerField
8468 * @extends Roo.bootstrap.Input
8469 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8470 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8471 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8472 * for which you can provide a custom implementation. For example:
8474 var trigger = new Roo.bootstrap.TriggerField();
8475 trigger.onTriggerClick = myTriggerFn;
8476 trigger.applyTo('my-field');
8479 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8480 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8481 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8482 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8483 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8486 * Create a new TriggerField.
8487 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8488 * to the base TextField)
8490 Roo.bootstrap.TriggerField = function(config){
8491 this.mimicing = false;
8492 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8495 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8497 * @cfg {String} triggerClass A CSS class to apply to the trigger
8500 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8505 * @cfg {Boolean} removable (true|false) special filter default false
8509 /** @cfg {Boolean} grow @hide */
8510 /** @cfg {Number} growMin @hide */
8511 /** @cfg {Number} growMax @hide */
8517 autoSize: Roo.emptyFn,
8524 actionMode : 'wrap',
8529 getAutoCreate : function(){
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.DISPLAY).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,
11315 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
11317 mobileTouchView : true,
11329 btnPosition : 'right',
11330 triggerList : true,
11331 showToggleBtn : true,
11333 emptyResultText: 'Empty',
11334 // element that contains real text value.. (when hidden is used..)
11336 getAutoCreate : function()
11344 if(Roo.isTouch && this.mobileTouchView){
11345 cfg = this.getAutoCreateTouchView();
11352 if(!this.tickable){
11353 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11358 * ComboBox with tickable selections
11361 var align = this.labelAlign || this.parentLabelAlign();
11364 cls : 'form-group roo-combobox-tickable' //input-group
11369 cls : 'tickable-buttons',
11374 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11381 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11388 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11395 buttons.cn.unshift({
11397 cls: 'select2-search-field-input'
11403 Roo.each(buttons.cn, function(c){
11405 c.cls += ' btn-' + _this.size;
11408 if (_this.disabled) {
11419 cls: 'form-hidden-field'
11423 cls: 'select2-choices',
11427 cls: 'select2-search-field',
11439 cls: 'select2-container input-group select2-container-multi',
11444 // cls: 'typeahead typeahead-long dropdown-menu',
11445 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11450 if(this.hasFeedback && !this.allowBlank){
11454 cls: 'glyphicon form-control-feedback'
11457 combobox.cn.push(feedback);
11460 if (align ==='left' && this.fieldLabel.length) {
11462 Roo.log("left and has label");
11468 cls : 'control-label col-sm-' + this.labelWidth,
11469 html : this.fieldLabel
11473 cls : "col-sm-" + (12 - this.labelWidth),
11480 } else if ( this.fieldLabel.length) {
11486 //cls : 'input-group-addon',
11487 html : this.fieldLabel
11497 Roo.log(" no label && no align");
11504 ['xs','sm','md','lg'].map(function(size){
11505 if (settings[size]) {
11506 cfg.cls += ' col-' + size + '-' + settings[size];
11515 initEvents: function()
11519 throw "can not find store for combo";
11522 this.store = Roo.factory(this.store, Roo.data);
11528 if(Roo.isTouch && this.mobileTouchView){
11529 this.initTouchView();
11534 this.initTickableEvents();
11538 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11540 if(this.hiddenName){
11542 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11544 this.hiddenField.dom.value =
11545 this.hiddenValue !== undefined ? this.hiddenValue :
11546 this.value !== undefined ? this.value : '';
11548 // prevent input submission
11549 this.el.dom.removeAttribute('name');
11550 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11555 // this.el.dom.setAttribute('autocomplete', 'off');
11558 var cls = 'x-combo-list';
11560 //this.list = new Roo.Layer({
11561 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11567 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11568 _this.list.setWidth(lw);
11571 this.list.on('mouseover', this.onViewOver, this);
11572 this.list.on('mousemove', this.onViewMove, this);
11574 this.list.on('scroll', this.onViewScroll, this);
11577 this.list.swallowEvent('mousewheel');
11578 this.assetHeight = 0;
11581 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11582 this.assetHeight += this.header.getHeight();
11585 this.innerList = this.list.createChild({cls:cls+'-inner'});
11586 this.innerList.on('mouseover', this.onViewOver, this);
11587 this.innerList.on('mousemove', this.onViewMove, this);
11588 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11590 if(this.allowBlank && !this.pageSize && !this.disableClear){
11591 this.footer = this.list.createChild({cls:cls+'-ft'});
11592 this.pageTb = new Roo.Toolbar(this.footer);
11596 this.footer = this.list.createChild({cls:cls+'-ft'});
11597 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11598 {pageSize: this.pageSize});
11602 if (this.pageTb && this.allowBlank && !this.disableClear) {
11604 this.pageTb.add(new Roo.Toolbar.Fill(), {
11605 cls: 'x-btn-icon x-btn-clear',
11607 handler: function()
11610 _this.clearValue();
11611 _this.onSelect(false, -1);
11616 this.assetHeight += this.footer.getHeight();
11621 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11624 this.view = new Roo.View(this.list, this.tpl, {
11625 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11627 //this.view.wrapEl.setDisplayed(false);
11628 this.view.on('click', this.onViewClick, this);
11632 this.store.on('beforeload', this.onBeforeLoad, this);
11633 this.store.on('load', this.onLoad, this);
11634 this.store.on('loadexception', this.onLoadException, this);
11636 if(this.resizable){
11637 this.resizer = new Roo.Resizable(this.list, {
11638 pinned:true, handles:'se'
11640 this.resizer.on('resize', function(r, w, h){
11641 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11642 this.listWidth = w;
11643 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11644 this.restrictHeight();
11646 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11649 if(!this.editable){
11650 this.editable = true;
11651 this.setEditable(false);
11656 if (typeof(this.events.add.listeners) != 'undefined') {
11658 this.addicon = this.wrap.createChild(
11659 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11661 this.addicon.on('click', function(e) {
11662 this.fireEvent('add', this);
11665 if (typeof(this.events.edit.listeners) != 'undefined') {
11667 this.editicon = this.wrap.createChild(
11668 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11669 if (this.addicon) {
11670 this.editicon.setStyle('margin-left', '40px');
11672 this.editicon.on('click', function(e) {
11674 // we fire even if inothing is selected..
11675 this.fireEvent('edit', this, this.lastData );
11681 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11682 "up" : function(e){
11683 this.inKeyMode = true;
11687 "down" : function(e){
11688 if(!this.isExpanded()){
11689 this.onTriggerClick();
11691 this.inKeyMode = true;
11696 "enter" : function(e){
11697 // this.onViewClick();
11701 if(this.fireEvent("specialkey", this, e)){
11702 this.onViewClick(false);
11708 "esc" : function(e){
11712 "tab" : function(e){
11715 if(this.fireEvent("specialkey", this, e)){
11716 this.onViewClick(false);
11724 doRelay : function(foo, bar, hname){
11725 if(hname == 'down' || this.scope.isExpanded()){
11726 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11735 this.queryDelay = Math.max(this.queryDelay || 10,
11736 this.mode == 'local' ? 10 : 250);
11739 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11741 if(this.typeAhead){
11742 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11744 if(this.editable !== false){
11745 this.inputEl().on("keyup", this.onKeyUp, this);
11747 if(this.forceSelection){
11748 this.inputEl().on('blur', this.doForce, this);
11752 this.choices = this.el.select('ul.select2-choices', true).first();
11753 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11757 initTickableEvents: function()
11761 if(this.hiddenName){
11763 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11765 this.hiddenField.dom.value =
11766 this.hiddenValue !== undefined ? this.hiddenValue :
11767 this.value !== undefined ? this.value : '';
11769 // prevent input submission
11770 this.el.dom.removeAttribute('name');
11771 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11776 // this.list = this.el.select('ul.dropdown-menu',true).first();
11778 this.choices = this.el.select('ul.select2-choices', true).first();
11779 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11780 if(this.triggerList){
11781 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11784 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11785 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11787 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11788 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11790 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11791 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11793 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11794 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11795 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11798 this.cancelBtn.hide();
11803 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11804 _this.list.setWidth(lw);
11807 this.list.on('mouseover', this.onViewOver, this);
11808 this.list.on('mousemove', this.onViewMove, this);
11810 this.list.on('scroll', this.onViewScroll, this);
11813 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>';
11816 this.view = new Roo.View(this.list, this.tpl, {
11817 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11820 //this.view.wrapEl.setDisplayed(false);
11821 this.view.on('click', this.onViewClick, this);
11825 this.store.on('beforeload', this.onBeforeLoad, this);
11826 this.store.on('load', this.onLoad, this);
11827 this.store.on('loadexception', this.onLoadException, this);
11830 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11831 "up" : function(e){
11832 this.inKeyMode = true;
11836 "down" : function(e){
11837 this.inKeyMode = true;
11841 "enter" : function(e){
11842 if(this.fireEvent("specialkey", this, e)){
11843 this.onViewClick(false);
11849 "esc" : function(e){
11850 this.onTickableFooterButtonClick(e, false, false);
11853 "tab" : function(e){
11854 this.fireEvent("specialkey", this, e);
11856 this.onTickableFooterButtonClick(e, false, false);
11863 doRelay : function(e, fn, key){
11864 if(this.scope.isExpanded()){
11865 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11874 this.queryDelay = Math.max(this.queryDelay || 10,
11875 this.mode == 'local' ? 10 : 250);
11878 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11880 if(this.typeAhead){
11881 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11884 if(this.editable !== false){
11885 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11890 onDestroy : function(){
11892 this.view.setStore(null);
11893 this.view.el.removeAllListeners();
11894 this.view.el.remove();
11895 this.view.purgeListeners();
11898 this.list.dom.innerHTML = '';
11902 this.store.un('beforeload', this.onBeforeLoad, this);
11903 this.store.un('load', this.onLoad, this);
11904 this.store.un('loadexception', this.onLoadException, this);
11906 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11910 fireKey : function(e){
11911 if(e.isNavKeyPress() && !this.list.isVisible()){
11912 this.fireEvent("specialkey", this, e);
11917 onResize: function(w, h){
11918 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11920 // if(typeof w != 'number'){
11921 // // we do not handle it!?!?
11924 // var tw = this.trigger.getWidth();
11925 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11926 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11928 // this.inputEl().setWidth( this.adjustWidth('input', x));
11930 // //this.trigger.setStyle('left', x+'px');
11932 // if(this.list && this.listWidth === undefined){
11933 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11934 // this.list.setWidth(lw);
11935 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11943 * Allow or prevent the user from directly editing the field text. If false is passed,
11944 * the user will only be able to select from the items defined in the dropdown list. This method
11945 * is the runtime equivalent of setting the 'editable' config option at config time.
11946 * @param {Boolean} value True to allow the user to directly edit the field text
11948 setEditable : function(value){
11949 if(value == this.editable){
11952 this.editable = value;
11954 this.inputEl().dom.setAttribute('readOnly', true);
11955 this.inputEl().on('mousedown', this.onTriggerClick, this);
11956 this.inputEl().addClass('x-combo-noedit');
11958 this.inputEl().dom.setAttribute('readOnly', false);
11959 this.inputEl().un('mousedown', this.onTriggerClick, this);
11960 this.inputEl().removeClass('x-combo-noedit');
11966 onBeforeLoad : function(combo,opts){
11967 if(!this.hasFocus){
11971 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11973 this.restrictHeight();
11974 this.selectedIndex = -1;
11978 onLoad : function(){
11980 this.hasQuery = false;
11982 if(!this.hasFocus){
11986 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11987 this.loading.hide();
11990 if(this.store.getCount() > 0){
11992 this.restrictHeight();
11993 if(this.lastQuery == this.allQuery){
11994 if(this.editable && !this.tickable){
11995 this.inputEl().dom.select();
11999 !this.selectByValue(this.value, true) &&
12002 !this.store.lastOptions ||
12003 typeof(this.store.lastOptions.add) == 'undefined' ||
12004 this.store.lastOptions.add != true
12007 this.select(0, true);
12010 if(this.autoFocus){
12013 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12014 this.taTask.delay(this.typeAheadDelay);
12018 this.onEmptyResults();
12024 onLoadException : function()
12026 this.hasQuery = false;
12028 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12029 this.loading.hide();
12032 if(this.tickable && this.editable){
12038 Roo.log(this.store.reader.jsonData);
12039 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12041 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12047 onTypeAhead : function(){
12048 if(this.store.getCount() > 0){
12049 var r = this.store.getAt(0);
12050 var newValue = r.data[this.displayField];
12051 var len = newValue.length;
12052 var selStart = this.getRawValue().length;
12054 if(selStart != len){
12055 this.setRawValue(newValue);
12056 this.selectText(selStart, newValue.length);
12062 onSelect : function(record, index){
12064 if(this.fireEvent('beforeselect', this, record, index) !== false){
12066 this.setFromData(index > -1 ? record.data : false);
12069 this.fireEvent('select', this, record, index);
12074 * Returns the currently selected field value or empty string if no value is set.
12075 * @return {String} value The selected value
12077 getValue : function(){
12080 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12083 if(this.valueField){
12084 return typeof this.value != 'undefined' ? this.value : '';
12086 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12091 * Clears any text/value currently set in the field
12093 clearValue : function(){
12094 if(this.hiddenField){
12095 this.hiddenField.dom.value = '';
12098 this.setRawValue('');
12099 this.lastSelectionText = '';
12100 this.lastData = false;
12102 var close = this.closeTriggerEl();
12111 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12112 * will be displayed in the field. If the value does not match the data value of an existing item,
12113 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12114 * Otherwise the field will be blank (although the value will still be set).
12115 * @param {String} value The value to match
12117 setValue : function(v){
12124 if(this.valueField){
12125 var r = this.findRecord(this.valueField, v);
12127 text = r.data[this.displayField];
12128 }else if(this.valueNotFoundText !== undefined){
12129 text = this.valueNotFoundText;
12132 this.lastSelectionText = text;
12133 if(this.hiddenField){
12134 this.hiddenField.dom.value = v;
12136 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12139 var close = this.closeTriggerEl();
12142 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
12146 * @property {Object} the last set data for the element
12151 * Sets the value of the field based on a object which is related to the record format for the store.
12152 * @param {Object} value the value to set as. or false on reset?
12154 setFromData : function(o){
12161 var dv = ''; // display value
12162 var vv = ''; // value value..
12164 if (this.displayField) {
12165 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12167 // this is an error condition!!!
12168 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12171 if(this.valueField){
12172 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12175 var close = this.closeTriggerEl();
12178 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12181 if(this.hiddenField){
12182 this.hiddenField.dom.value = vv;
12184 this.lastSelectionText = dv;
12185 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12189 // no hidden field.. - we store the value in 'value', but still display
12190 // display field!!!!
12191 this.lastSelectionText = dv;
12192 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12199 reset : function(){
12200 // overridden so that last data is reset..
12207 this.setValue(this.originalValue);
12208 this.clearInvalid();
12209 this.lastData = false;
12211 this.view.clearSelections();
12215 findRecord : function(prop, value){
12217 if(this.store.getCount() > 0){
12218 this.store.each(function(r){
12219 if(r.data[prop] == value){
12229 getName: function()
12231 // returns hidden if it's set..
12232 if (!this.rendered) {return ''};
12233 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12237 onViewMove : function(e, t){
12238 this.inKeyMode = false;
12242 onViewOver : function(e, t){
12243 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12246 var item = this.view.findItemFromChild(t);
12249 var index = this.view.indexOf(item);
12250 this.select(index, false);
12255 onViewClick : function(view, doFocus, el, e)
12257 var index = this.view.getSelectedIndexes()[0];
12259 var r = this.store.getAt(index);
12263 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12270 Roo.each(this.tickItems, function(v,k){
12272 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12273 _this.tickItems.splice(k, 1);
12275 if(typeof(e) == 'undefined' && view == false){
12276 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12288 this.tickItems.push(r.data);
12290 if(typeof(e) == 'undefined' && view == false){
12291 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12298 this.onSelect(r, index);
12300 if(doFocus !== false && !this.blockFocus){
12301 this.inputEl().focus();
12306 restrictHeight : function(){
12307 //this.innerList.dom.style.height = '';
12308 //var inner = this.innerList.dom;
12309 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12310 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12311 //this.list.beginUpdate();
12312 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12313 this.list.alignTo(this.inputEl(), this.listAlign);
12314 this.list.alignTo(this.inputEl(), this.listAlign);
12315 //this.list.endUpdate();
12319 onEmptyResults : function(){
12321 if(this.tickable && this.editable){
12322 this.restrictHeight();
12330 * Returns true if the dropdown list is expanded, else false.
12332 isExpanded : function(){
12333 return this.list.isVisible();
12337 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12338 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12339 * @param {String} value The data value of the item to select
12340 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12341 * selected item if it is not currently in view (defaults to true)
12342 * @return {Boolean} True if the value matched an item in the list, else false
12344 selectByValue : function(v, scrollIntoView){
12345 if(v !== undefined && v !== null){
12346 var r = this.findRecord(this.valueField || this.displayField, v);
12348 this.select(this.store.indexOf(r), scrollIntoView);
12356 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12357 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12358 * @param {Number} index The zero-based index of the list item to select
12359 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12360 * selected item if it is not currently in view (defaults to true)
12362 select : function(index, scrollIntoView){
12363 this.selectedIndex = index;
12364 this.view.select(index);
12365 if(scrollIntoView !== false){
12366 var el = this.view.getNode(index);
12368 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12371 this.list.scrollChildIntoView(el, false);
12377 selectNext : function(){
12378 var ct = this.store.getCount();
12380 if(this.selectedIndex == -1){
12382 }else if(this.selectedIndex < ct-1){
12383 this.select(this.selectedIndex+1);
12389 selectPrev : function(){
12390 var ct = this.store.getCount();
12392 if(this.selectedIndex == -1){
12394 }else if(this.selectedIndex != 0){
12395 this.select(this.selectedIndex-1);
12401 onKeyUp : function(e){
12402 if(this.editable !== false && !e.isSpecialKey()){
12403 this.lastKey = e.getKey();
12404 this.dqTask.delay(this.queryDelay);
12409 validateBlur : function(){
12410 return !this.list || !this.list.isVisible();
12414 initQuery : function(){
12416 var v = this.getRawValue();
12418 if(this.tickable && this.editable){
12419 v = this.tickableInputEl().getValue();
12426 doForce : function(){
12427 if(this.inputEl().dom.value.length > 0){
12428 this.inputEl().dom.value =
12429 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12435 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12436 * query allowing the query action to be canceled if needed.
12437 * @param {String} query The SQL query to execute
12438 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12439 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12440 * saved in the current store (defaults to false)
12442 doQuery : function(q, forceAll){
12444 if(q === undefined || q === null){
12449 forceAll: forceAll,
12453 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12458 forceAll = qe.forceAll;
12459 if(forceAll === true || (q.length >= this.minChars)){
12461 this.hasQuery = true;
12463 if(this.lastQuery != q || this.alwaysQuery){
12464 this.lastQuery = q;
12465 if(this.mode == 'local'){
12466 this.selectedIndex = -1;
12468 this.store.clearFilter();
12471 if(this.specialFilter){
12472 this.fireEvent('specialfilter', this);
12477 this.store.filter(this.displayField, q);
12480 this.store.fireEvent("datachanged", this.store);
12487 this.store.baseParams[this.queryParam] = q;
12489 var options = {params : this.getParams(q)};
12492 options.add = true;
12493 options.params.start = this.page * this.pageSize;
12496 this.store.load(options);
12499 * this code will make the page width larger, at the beginning, the list not align correctly,
12500 * we should expand the list on onLoad
12501 * so command out it
12506 this.selectedIndex = -1;
12511 this.loadNext = false;
12515 getParams : function(q){
12517 //p[this.queryParam] = q;
12521 p.limit = this.pageSize;
12527 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12529 collapse : function(){
12530 if(!this.isExpanded()){
12537 this.hasFocus = false;
12539 this.cancelBtn.hide();
12540 this.trigger.show();
12543 this.tickableInputEl().dom.value = '';
12544 this.tickableInputEl().blur();
12549 Roo.get(document).un('mousedown', this.collapseIf, this);
12550 Roo.get(document).un('mousewheel', this.collapseIf, this);
12551 if (!this.editable) {
12552 Roo.get(document).un('keydown', this.listKeyPress, this);
12554 this.fireEvent('collapse', this);
12558 collapseIf : function(e){
12559 var in_combo = e.within(this.el);
12560 var in_list = e.within(this.list);
12561 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12563 if (in_combo || in_list || is_list) {
12564 //e.stopPropagation();
12569 this.onTickableFooterButtonClick(e, false, false);
12577 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12579 expand : function(){
12581 if(this.isExpanded() || !this.hasFocus){
12585 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12586 this.list.setWidth(lw);
12593 this.restrictHeight();
12597 this.tickItems = Roo.apply([], this.item);
12600 this.cancelBtn.show();
12601 this.trigger.hide();
12604 this.tickableInputEl().focus();
12609 Roo.get(document).on('mousedown', this.collapseIf, this);
12610 Roo.get(document).on('mousewheel', this.collapseIf, this);
12611 if (!this.editable) {
12612 Roo.get(document).on('keydown', this.listKeyPress, this);
12615 this.fireEvent('expand', this);
12619 // Implements the default empty TriggerField.onTriggerClick function
12620 onTriggerClick : function(e)
12622 Roo.log('trigger click');
12624 if(this.disabled || !this.triggerList){
12629 this.loadNext = false;
12631 if(this.isExpanded()){
12633 if (!this.blockFocus) {
12634 this.inputEl().focus();
12638 this.hasFocus = true;
12639 if(this.triggerAction == 'all') {
12640 this.doQuery(this.allQuery, true);
12642 this.doQuery(this.getRawValue());
12644 if (!this.blockFocus) {
12645 this.inputEl().focus();
12650 onTickableTriggerClick : function(e)
12657 this.loadNext = false;
12658 this.hasFocus = true;
12660 if(this.triggerAction == 'all') {
12661 this.doQuery(this.allQuery, true);
12663 this.doQuery(this.getRawValue());
12667 onSearchFieldClick : function(e)
12669 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12670 this.onTickableFooterButtonClick(e, false, false);
12674 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12679 this.loadNext = false;
12680 this.hasFocus = true;
12682 if(this.triggerAction == 'all') {
12683 this.doQuery(this.allQuery, true);
12685 this.doQuery(this.getRawValue());
12689 listKeyPress : function(e)
12691 //Roo.log('listkeypress');
12692 // scroll to first matching element based on key pres..
12693 if (e.isSpecialKey()) {
12696 var k = String.fromCharCode(e.getKey()).toUpperCase();
12699 var csel = this.view.getSelectedNodes();
12700 var cselitem = false;
12702 var ix = this.view.indexOf(csel[0]);
12703 cselitem = this.store.getAt(ix);
12704 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12710 this.store.each(function(v) {
12712 // start at existing selection.
12713 if (cselitem.id == v.id) {
12719 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12720 match = this.store.indexOf(v);
12726 if (match === false) {
12727 return true; // no more action?
12730 this.view.select(match);
12731 var sn = Roo.get(this.view.getSelectedNodes()[0])
12732 sn.scrollIntoView(sn.dom.parentNode, false);
12735 onViewScroll : function(e, t){
12737 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){
12741 this.hasQuery = true;
12743 this.loading = this.list.select('.loading', true).first();
12745 if(this.loading === null){
12746 this.list.createChild({
12748 cls: 'loading select2-more-results select2-active',
12749 html: 'Loading more results...'
12752 this.loading = this.list.select('.loading', true).first();
12754 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12756 this.loading.hide();
12759 this.loading.show();
12764 this.loadNext = true;
12766 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12771 addItem : function(o)
12773 var dv = ''; // display value
12775 if (this.displayField) {
12776 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12778 // this is an error condition!!!
12779 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12786 var choice = this.choices.createChild({
12788 cls: 'select2-search-choice',
12797 cls: 'select2-search-choice-close',
12802 }, this.searchField);
12804 var close = choice.select('a.select2-search-choice-close', true).first()
12806 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12814 this.inputEl().dom.value = '';
12819 onRemoveItem : function(e, _self, o)
12821 e.preventDefault();
12823 this.lastItem = Roo.apply([], this.item);
12825 var index = this.item.indexOf(o.data) * 1;
12828 Roo.log('not this item?!');
12832 this.item.splice(index, 1);
12837 this.fireEvent('remove', this, e);
12843 syncValue : function()
12845 if(!this.item.length){
12852 Roo.each(this.item, function(i){
12853 if(_this.valueField){
12854 value.push(i[_this.valueField]);
12861 this.value = value.join(',');
12863 if(this.hiddenField){
12864 this.hiddenField.dom.value = this.value;
12867 this.store.fireEvent("datachanged", this.store);
12870 clearItem : function()
12872 if(!this.multiple){
12878 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12887 inputEl: function ()
12889 if(Roo.isTouch && this.mobileTouchView){
12890 return this.el.select('input.form-control',true).first();
12894 return this.searchField;
12897 return this.el.select('input.form-control',true).first();
12901 onTickableFooterButtonClick : function(e, btn, el)
12903 e.preventDefault();
12905 this.lastItem = Roo.apply([], this.item);
12907 if(btn && btn.name == 'cancel'){
12908 this.tickItems = Roo.apply([], this.item);
12917 Roo.each(this.tickItems, function(o){
12925 validate : function()
12927 var v = this.getRawValue();
12930 v = this.getValue();
12933 if(this.disabled || this.allowBlank || v.length){
12938 this.markInvalid();
12942 tickableInputEl : function()
12944 if(!this.tickable || !this.editable){
12945 return this.inputEl();
12948 return this.inputEl().select('.select2-search-field-input', true).first();
12952 getAutoCreateTouchView : function()
12957 cls: 'form-group' //input-group
12963 type : this.inputType,
12964 cls : 'form-control x-combo-noedit',
12965 autocomplete: 'new-password',
12966 placeholder : this.placeholder || '',
12971 input.name = this.name;
12975 input.cls += ' input-' + this.size;
12978 if (this.disabled) {
12979 input.disabled = true;
12990 inputblock.cls += ' input-group';
12992 inputblock.cn.unshift({
12994 cls : 'input-group-addon',
12999 if(this.removable && !this.multiple){
13000 inputblock.cls += ' roo-removable';
13002 inputblock.cn.push({
13005 cls : 'roo-combo-removable-btn close'
13009 if(this.hasFeedback && !this.allowBlank){
13011 inputblock.cls += ' has-feedback';
13013 inputblock.cn.push({
13015 cls: 'glyphicon form-control-feedback'
13022 inputblock.cls += (this.before) ? '' : ' input-group';
13024 inputblock.cn.push({
13026 cls : 'input-group-addon',
13037 cls: 'form-hidden-field'
13051 cls: 'form-hidden-field'
13055 cls: 'select2-choices',
13059 cls: 'select2-search-field',
13072 cls: 'select2-container input-group',
13079 combobox.cls += ' select2-container-multi';
13082 var align = this.labelAlign || this.parentLabelAlign();
13086 if(this.fieldLabel.length){
13088 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13089 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13094 cls : 'control-label ' + lw,
13095 html : this.fieldLabel
13107 var settings = this;
13109 ['xs','sm','md','lg'].map(function(size){
13110 if (settings[size]) {
13111 cfg.cls += ' col-' + size + '-' + settings[size];
13118 initTouchView : function()
13120 this.renderTouchView();
13122 this.inputEl().on("click", this.showTouchView, this);
13123 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13124 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13126 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13128 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13129 this.store.on('load', this.onTouchViewLoad, this);
13130 this.store.on('loadexception', this.onTouchViewLoadException, this);
13132 if(this.hiddenName){
13134 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13136 this.hiddenField.dom.value =
13137 this.hiddenValue !== undefined ? this.hiddenValue :
13138 this.value !== undefined ? this.value : '';
13140 this.el.dom.removeAttribute('name');
13141 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13145 this.choices = this.el.select('ul.select2-choices', true).first();
13146 this.searchField = this.el.select('ul li.select2-search-field', true).first();
13149 if(this.removable && !this.multiple){
13150 var close = this.closeTriggerEl();
13152 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
13153 close.on('click', this.removeBtnClick, this, close);
13162 renderTouchView : function()
13164 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13165 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13167 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13168 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13170 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13171 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13172 this.touchViewBodyEl.setStyle('overflow', 'auto');
13174 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13175 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13177 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13178 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13182 showTouchView : function()
13184 this.touchViewHeaderEl.hide();
13186 if(this.fieldLabel.length){
13187 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
13188 this.touchViewHeaderEl.show();
13191 this.touchViewEl.show();
13193 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
13194 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13196 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
13198 if(this.fieldLabel.length){
13199 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
13202 this.touchViewBodyEl.setHeight(bodyHeight);
13206 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
13208 this.touchViewEl.addClass('in');
13211 this.doTouchViewQuery();
13215 hideTouchView : function()
13217 this.touchViewEl.removeClass('in');
13221 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
13223 this.touchViewEl.setStyle('display', 'none');
13228 setTouchViewValue : function()
13235 Roo.each(this.tickItems, function(o){
13240 this.hideTouchView();
13243 doTouchViewQuery : function()
13252 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
13256 if(!this.alwaysQuery || this.mode == 'local'){
13257 this.onTouchViewLoad();
13264 onTouchViewBeforeLoad : function(combo,opts)
13270 onTouchViewLoad : function()
13272 if(this.store.getCount() < 1){
13273 this.onTouchViewEmptyResults();
13277 this.clearTouchView();
13279 var rawValue = this.getRawValue();
13281 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
13283 this.tickItems = [];
13285 this.store.data.each(function(d, rowIndex){
13286 var row = this.touchViewListGroup.createChild(template);
13288 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
13289 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = d.data[this.displayField];
13292 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
13293 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13296 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
13297 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13298 this.tickItems.push(d.data);
13301 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
13305 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
13308 firstChecked.findParent('li').scrollIntoView(this.touchViewListGroup.dom);
13313 onTouchViewLoadException : function()
13315 this.hideTouchView();
13318 onTouchViewEmptyResults : function()
13320 this.clearTouchView();
13322 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
13324 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
13328 clearTouchView : function()
13330 this.touchViewListGroup.dom.innerHTML = '';
13333 onTouchViewClick : function(e, el, o)
13335 e.preventDefault();
13338 var rowIndex = o.rowIndex;
13340 var r = this.store.getAt(rowIndex);
13342 if(!this.multiple){
13343 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
13344 c.dom.removeAttribute('checked');
13347 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13349 this.setFromData(r.data);
13351 var close = this.closeTriggerEl();
13357 this.hideTouchView();
13362 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
13363 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
13364 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
13368 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13369 this.addItem(r.data);
13370 this.tickItems.push(r.data);
13378 * @cfg {Boolean} grow
13382 * @cfg {Number} growMin
13386 * @cfg {Number} growMax
13395 Roo.apply(Roo.bootstrap.ComboBox, {
13399 cls: 'modal-header',
13421 cls: 'list-group-item',
13425 cls: 'roo-combobox-list-group-item-value'
13429 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
13443 listItemCheckbox : {
13445 cls: 'list-group-item',
13449 cls: 'roo-combobox-list-group-item-value'
13453 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
13469 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
13474 cls: 'modal-footer',
13482 cls: 'col-xs-6 text-left',
13485 cls: 'btn btn-danger roo-touch-view-cancel',
13491 cls: 'col-xs-6 text-right',
13494 cls: 'btn btn-success roo-touch-view-ok',
13505 Roo.apply(Roo.bootstrap.ComboBox, {
13507 touchViewTemplate : {
13509 cls: 'modal fade roo-combobox-touch-view',
13513 cls: 'modal-dialog',
13517 cls: 'modal-content',
13519 Roo.bootstrap.ComboBox.header,
13520 Roo.bootstrap.ComboBox.body,
13521 Roo.bootstrap.ComboBox.footer
13530 * Ext JS Library 1.1.1
13531 * Copyright(c) 2006-2007, Ext JS, LLC.
13533 * Originally Released Under LGPL - original licence link has changed is not relivant.
13536 * <script type="text/javascript">
13541 * @extends Roo.util.Observable
13542 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
13543 * This class also supports single and multi selection modes. <br>
13544 * Create a data model bound view:
13546 var store = new Roo.data.Store(...);
13548 var view = new Roo.View({
13550 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
13552 singleSelect: true,
13553 selectedClass: "ydataview-selected",
13557 // listen for node click?
13558 view.on("click", function(vw, index, node, e){
13559 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
13563 dataModel.load("foobar.xml");
13565 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
13567 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
13568 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
13570 * Note: old style constructor is still suported (container, template, config)
13573 * Create a new View
13574 * @param {Object} config The config object
13577 Roo.View = function(config, depreciated_tpl, depreciated_config){
13579 this.parent = false;
13581 if (typeof(depreciated_tpl) == 'undefined') {
13582 // new way.. - universal constructor.
13583 Roo.apply(this, config);
13584 this.el = Roo.get(this.el);
13587 this.el = Roo.get(config);
13588 this.tpl = depreciated_tpl;
13589 Roo.apply(this, depreciated_config);
13591 this.wrapEl = this.el.wrap().wrap();
13592 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
13595 if(typeof(this.tpl) == "string"){
13596 this.tpl = new Roo.Template(this.tpl);
13598 // support xtype ctors..
13599 this.tpl = new Roo.factory(this.tpl, Roo);
13603 this.tpl.compile();
13608 * @event beforeclick
13609 * Fires before a click is processed. Returns false to cancel the default action.
13610 * @param {Roo.View} this
13611 * @param {Number} index The index of the target node
13612 * @param {HTMLElement} node The target node
13613 * @param {Roo.EventObject} e The raw event object
13615 "beforeclick" : true,
13618 * Fires when a template node is clicked.
13619 * @param {Roo.View} this
13620 * @param {Number} index The index of the target node
13621 * @param {HTMLElement} node The target node
13622 * @param {Roo.EventObject} e The raw event object
13627 * Fires when a template node is double clicked.
13628 * @param {Roo.View} this
13629 * @param {Number} index The index of the target node
13630 * @param {HTMLElement} node The target node
13631 * @param {Roo.EventObject} e The raw event object
13635 * @event contextmenu
13636 * Fires when a template node is right clicked.
13637 * @param {Roo.View} this
13638 * @param {Number} index The index of the target node
13639 * @param {HTMLElement} node The target node
13640 * @param {Roo.EventObject} e The raw event object
13642 "contextmenu" : true,
13644 * @event selectionchange
13645 * Fires when the selected nodes change.
13646 * @param {Roo.View} this
13647 * @param {Array} selections Array of the selected nodes
13649 "selectionchange" : true,
13652 * @event beforeselect
13653 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
13654 * @param {Roo.View} this
13655 * @param {HTMLElement} node The node to be selected
13656 * @param {Array} selections Array of currently selected nodes
13658 "beforeselect" : true,
13660 * @event preparedata
13661 * Fires on every row to render, to allow you to change the data.
13662 * @param {Roo.View} this
13663 * @param {Object} data to be rendered (change this)
13665 "preparedata" : true
13673 "click": this.onClick,
13674 "dblclick": this.onDblClick,
13675 "contextmenu": this.onContextMenu,
13679 this.selections = [];
13681 this.cmp = new Roo.CompositeElementLite([]);
13683 this.store = Roo.factory(this.store, Roo.data);
13684 this.setStore(this.store, true);
13687 if ( this.footer && this.footer.xtype) {
13689 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13691 this.footer.dataSource = this.store
13692 this.footer.container = fctr;
13693 this.footer = Roo.factory(this.footer, Roo);
13694 fctr.insertFirst(this.el);
13696 // this is a bit insane - as the paging toolbar seems to detach the el..
13697 // dom.parentNode.parentNode.parentNode
13698 // they get detached?
13702 Roo.View.superclass.constructor.call(this);
13707 Roo.extend(Roo.View, Roo.util.Observable, {
13710 * @cfg {Roo.data.Store} store Data store to load data from.
13715 * @cfg {String|Roo.Element} el The container element.
13720 * @cfg {String|Roo.Template} tpl The template used by this View
13724 * @cfg {String} dataName the named area of the template to use as the data area
13725 * Works with domtemplates roo-name="name"
13729 * @cfg {String} selectedClass The css class to add to selected nodes
13731 selectedClass : "x-view-selected",
13733 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13738 * @cfg {String} text to display on mask (default Loading)
13742 * @cfg {Boolean} multiSelect Allow multiple selection
13744 multiSelect : false,
13746 * @cfg {Boolean} singleSelect Allow single selection
13748 singleSelect: false,
13751 * @cfg {Boolean} toggleSelect - selecting
13753 toggleSelect : false,
13756 * @cfg {Boolean} tickable - selecting
13761 * Returns the element this view is bound to.
13762 * @return {Roo.Element}
13764 getEl : function(){
13765 return this.wrapEl;
13771 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13773 refresh : function(){
13774 //Roo.log('refresh');
13777 // if we are using something like 'domtemplate', then
13778 // the what gets used is:
13779 // t.applySubtemplate(NAME, data, wrapping data..)
13780 // the outer template then get' applied with
13781 // the store 'extra data'
13782 // and the body get's added to the
13783 // roo-name="data" node?
13784 // <span class='roo-tpl-{name}'></span> ?????
13788 this.clearSelections();
13789 this.el.update("");
13791 var records = this.store.getRange();
13792 if(records.length < 1) {
13794 // is this valid?? = should it render a template??
13796 this.el.update(this.emptyText);
13800 if (this.dataName) {
13801 this.el.update(t.apply(this.store.meta)); //????
13802 el = this.el.child('.roo-tpl-' + this.dataName);
13805 for(var i = 0, len = records.length; i < len; i++){
13806 var data = this.prepareData(records[i].data, i, records[i]);
13807 this.fireEvent("preparedata", this, data, i, records[i]);
13809 var d = Roo.apply({}, data);
13812 Roo.apply(d, {'roo-id' : Roo.id()});
13816 Roo.each(this.parent.item, function(item){
13817 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13820 Roo.apply(d, {'roo-data-checked' : 'checked'});
13824 html[html.length] = Roo.util.Format.trim(
13826 t.applySubtemplate(this.dataName, d, this.store.meta) :
13833 el.update(html.join(""));
13834 this.nodes = el.dom.childNodes;
13835 this.updateIndexes(0);
13840 * Function to override to reformat the data that is sent to
13841 * the template for each node.
13842 * DEPRICATED - use the preparedata event handler.
13843 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13844 * a JSON object for an UpdateManager bound view).
13846 prepareData : function(data, index, record)
13848 this.fireEvent("preparedata", this, data, index, record);
13852 onUpdate : function(ds, record){
13853 // Roo.log('on update');
13854 this.clearSelections();
13855 var index = this.store.indexOf(record);
13856 var n = this.nodes[index];
13857 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13858 n.parentNode.removeChild(n);
13859 this.updateIndexes(index, index);
13865 onAdd : function(ds, records, index)
13867 //Roo.log(['on Add', ds, records, index] );
13868 this.clearSelections();
13869 if(this.nodes.length == 0){
13873 var n = this.nodes[index];
13874 for(var i = 0, len = records.length; i < len; i++){
13875 var d = this.prepareData(records[i].data, i, records[i]);
13877 this.tpl.insertBefore(n, d);
13880 this.tpl.append(this.el, d);
13883 this.updateIndexes(index);
13886 onRemove : function(ds, record, index){
13887 // Roo.log('onRemove');
13888 this.clearSelections();
13889 var el = this.dataName ?
13890 this.el.child('.roo-tpl-' + this.dataName) :
13893 el.dom.removeChild(this.nodes[index]);
13894 this.updateIndexes(index);
13898 * Refresh an individual node.
13899 * @param {Number} index
13901 refreshNode : function(index){
13902 this.onUpdate(this.store, this.store.getAt(index));
13905 updateIndexes : function(startIndex, endIndex){
13906 var ns = this.nodes;
13907 startIndex = startIndex || 0;
13908 endIndex = endIndex || ns.length - 1;
13909 for(var i = startIndex; i <= endIndex; i++){
13910 ns[i].nodeIndex = i;
13915 * Changes the data store this view uses and refresh the view.
13916 * @param {Store} store
13918 setStore : function(store, initial){
13919 if(!initial && this.store){
13920 this.store.un("datachanged", this.refresh);
13921 this.store.un("add", this.onAdd);
13922 this.store.un("remove", this.onRemove);
13923 this.store.un("update", this.onUpdate);
13924 this.store.un("clear", this.refresh);
13925 this.store.un("beforeload", this.onBeforeLoad);
13926 this.store.un("load", this.onLoad);
13927 this.store.un("loadexception", this.onLoad);
13931 store.on("datachanged", this.refresh, this);
13932 store.on("add", this.onAdd, this);
13933 store.on("remove", this.onRemove, this);
13934 store.on("update", this.onUpdate, this);
13935 store.on("clear", this.refresh, this);
13936 store.on("beforeload", this.onBeforeLoad, this);
13937 store.on("load", this.onLoad, this);
13938 store.on("loadexception", this.onLoad, this);
13946 * onbeforeLoad - masks the loading area.
13949 onBeforeLoad : function(store,opts)
13951 //Roo.log('onBeforeLoad');
13953 this.el.update("");
13955 this.el.mask(this.mask ? this.mask : "Loading" );
13957 onLoad : function ()
13964 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13965 * @param {HTMLElement} node
13966 * @return {HTMLElement} The template node
13968 findItemFromChild : function(node){
13969 var el = this.dataName ?
13970 this.el.child('.roo-tpl-' + this.dataName,true) :
13973 if(!node || node.parentNode == el){
13976 var p = node.parentNode;
13977 while(p && p != el){
13978 if(p.parentNode == el){
13987 onClick : function(e){
13988 var item = this.findItemFromChild(e.getTarget());
13990 var index = this.indexOf(item);
13991 if(this.onItemClick(item, index, e) !== false){
13992 this.fireEvent("click", this, index, item, e);
13995 this.clearSelections();
14000 onContextMenu : function(e){
14001 var item = this.findItemFromChild(e.getTarget());
14003 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
14008 onDblClick : function(e){
14009 var item = this.findItemFromChild(e.getTarget());
14011 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
14015 onItemClick : function(item, index, e)
14017 if(this.fireEvent("beforeclick", this, index, item, e) === false){
14020 if (this.toggleSelect) {
14021 var m = this.isSelected(item) ? 'unselect' : 'select';
14024 _t[m](item, true, false);
14027 if(this.multiSelect || this.singleSelect){
14028 if(this.multiSelect && e.shiftKey && this.lastSelection){
14029 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
14031 this.select(item, this.multiSelect && e.ctrlKey);
14032 this.lastSelection = item;
14035 if(!this.tickable){
14036 e.preventDefault();
14044 * Get the number of selected nodes.
14047 getSelectionCount : function(){
14048 return this.selections.length;
14052 * Get the currently selected nodes.
14053 * @return {Array} An array of HTMLElements
14055 getSelectedNodes : function(){
14056 return this.selections;
14060 * Get the indexes of the selected nodes.
14063 getSelectedIndexes : function(){
14064 var indexes = [], s = this.selections;
14065 for(var i = 0, len = s.length; i < len; i++){
14066 indexes.push(s[i].nodeIndex);
14072 * Clear all selections
14073 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
14075 clearSelections : function(suppressEvent){
14076 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
14077 this.cmp.elements = this.selections;
14078 this.cmp.removeClass(this.selectedClass);
14079 this.selections = [];
14080 if(!suppressEvent){
14081 this.fireEvent("selectionchange", this, this.selections);
14087 * Returns true if the passed node is selected
14088 * @param {HTMLElement/Number} node The node or node index
14089 * @return {Boolean}
14091 isSelected : function(node){
14092 var s = this.selections;
14096 node = this.getNode(node);
14097 return s.indexOf(node) !== -1;
14102 * @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
14103 * @param {Boolean} keepExisting (optional) true to keep existing selections
14104 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14106 select : function(nodeInfo, keepExisting, suppressEvent){
14107 if(nodeInfo instanceof Array){
14109 this.clearSelections(true);
14111 for(var i = 0, len = nodeInfo.length; i < len; i++){
14112 this.select(nodeInfo[i], true, true);
14116 var node = this.getNode(nodeInfo);
14117 if(!node || this.isSelected(node)){
14118 return; // already selected.
14121 this.clearSelections(true);
14124 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
14125 Roo.fly(node).addClass(this.selectedClass);
14126 this.selections.push(node);
14127 if(!suppressEvent){
14128 this.fireEvent("selectionchange", this, this.selections);
14136 * @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
14137 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
14138 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14140 unselect : function(nodeInfo, keepExisting, suppressEvent)
14142 if(nodeInfo instanceof Array){
14143 Roo.each(this.selections, function(s) {
14144 this.unselect(s, nodeInfo);
14148 var node = this.getNode(nodeInfo);
14149 if(!node || !this.isSelected(node)){
14150 //Roo.log("not selected");
14151 return; // not selected.
14155 Roo.each(this.selections, function(s) {
14157 Roo.fly(node).removeClass(this.selectedClass);
14164 this.selections= ns;
14165 this.fireEvent("selectionchange", this, this.selections);
14169 * Gets a template node.
14170 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14171 * @return {HTMLElement} The node or null if it wasn't found
14173 getNode : function(nodeInfo){
14174 if(typeof nodeInfo == "string"){
14175 return document.getElementById(nodeInfo);
14176 }else if(typeof nodeInfo == "number"){
14177 return this.nodes[nodeInfo];
14183 * Gets a range template nodes.
14184 * @param {Number} startIndex
14185 * @param {Number} endIndex
14186 * @return {Array} An array of nodes
14188 getNodes : function(start, end){
14189 var ns = this.nodes;
14190 start = start || 0;
14191 end = typeof end == "undefined" ? ns.length - 1 : end;
14194 for(var i = start; i <= end; i++){
14198 for(var i = start; i >= end; i--){
14206 * Finds the index of the passed node
14207 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14208 * @return {Number} The index of the node or -1
14210 indexOf : function(node){
14211 node = this.getNode(node);
14212 if(typeof node.nodeIndex == "number"){
14213 return node.nodeIndex;
14215 var ns = this.nodes;
14216 for(var i = 0, len = ns.length; i < len; i++){
14227 * based on jquery fullcalendar
14231 Roo.bootstrap = Roo.bootstrap || {};
14233 * @class Roo.bootstrap.Calendar
14234 * @extends Roo.bootstrap.Component
14235 * Bootstrap Calendar class
14236 * @cfg {Boolean} loadMask (true|false) default false
14237 * @cfg {Object} header generate the user specific header of the calendar, default false
14240 * Create a new Container
14241 * @param {Object} config The config object
14246 Roo.bootstrap.Calendar = function(config){
14247 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
14251 * Fires when a date is selected
14252 * @param {DatePicker} this
14253 * @param {Date} date The selected date
14257 * @event monthchange
14258 * Fires when the displayed month changes
14259 * @param {DatePicker} this
14260 * @param {Date} date The selected month
14262 'monthchange': true,
14264 * @event evententer
14265 * Fires when mouse over an event
14266 * @param {Calendar} this
14267 * @param {event} Event
14269 'evententer': true,
14271 * @event eventleave
14272 * Fires when the mouse leaves an
14273 * @param {Calendar} this
14276 'eventleave': true,
14278 * @event eventclick
14279 * Fires when the mouse click an
14280 * @param {Calendar} this
14289 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
14292 * @cfg {Number} startDay
14293 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
14301 getAutoCreate : function(){
14304 var fc_button = function(name, corner, style, content ) {
14305 return Roo.apply({},{
14307 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
14309 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
14312 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
14323 style : 'width:100%',
14330 cls : 'fc-header-left',
14332 fc_button('prev', 'left', 'arrow', '‹' ),
14333 fc_button('next', 'right', 'arrow', '›' ),
14334 { tag: 'span', cls: 'fc-header-space' },
14335 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
14343 cls : 'fc-header-center',
14347 cls: 'fc-header-title',
14350 html : 'month / year'
14358 cls : 'fc-header-right',
14360 /* fc_button('month', 'left', '', 'month' ),
14361 fc_button('week', '', '', 'week' ),
14362 fc_button('day', 'right', '', 'day' )
14374 header = this.header;
14377 var cal_heads = function() {
14379 // fixme - handle this.
14381 for (var i =0; i < Date.dayNames.length; i++) {
14382 var d = Date.dayNames[i];
14385 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
14386 html : d.substring(0,3)
14390 ret[0].cls += ' fc-first';
14391 ret[6].cls += ' fc-last';
14394 var cal_cell = function(n) {
14397 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
14402 cls: 'fc-day-number',
14406 cls: 'fc-day-content',
14410 style: 'position: relative;' // height: 17px;
14422 var cal_rows = function() {
14425 for (var r = 0; r < 6; r++) {
14432 for (var i =0; i < Date.dayNames.length; i++) {
14433 var d = Date.dayNames[i];
14434 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
14437 row.cn[0].cls+=' fc-first';
14438 row.cn[0].cn[0].style = 'min-height:90px';
14439 row.cn[6].cls+=' fc-last';
14443 ret[0].cls += ' fc-first';
14444 ret[4].cls += ' fc-prev-last';
14445 ret[5].cls += ' fc-last';
14452 cls: 'fc-border-separate',
14453 style : 'width:100%',
14461 cls : 'fc-first fc-last',
14479 cls : 'fc-content',
14480 style : "position: relative;",
14483 cls : 'fc-view fc-view-month fc-grid',
14484 style : 'position: relative',
14485 unselectable : 'on',
14488 cls : 'fc-event-container',
14489 style : 'position:absolute;z-index:8;top:0;left:0;'
14507 initEvents : function()
14510 throw "can not find store for calendar";
14516 style: "text-align:center",
14520 style: "background-color:white;width:50%;margin:250 auto",
14524 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
14535 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
14537 var size = this.el.select('.fc-content', true).first().getSize();
14538 this.maskEl.setSize(size.width, size.height);
14539 this.maskEl.enableDisplayMode("block");
14540 if(!this.loadMask){
14541 this.maskEl.hide();
14544 this.store = Roo.factory(this.store, Roo.data);
14545 this.store.on('load', this.onLoad, this);
14546 this.store.on('beforeload', this.onBeforeLoad, this);
14550 this.cells = this.el.select('.fc-day',true);
14551 //Roo.log(this.cells);
14552 this.textNodes = this.el.query('.fc-day-number');
14553 this.cells.addClassOnOver('fc-state-hover');
14555 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
14556 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
14557 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
14558 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
14560 this.on('monthchange', this.onMonthChange, this);
14562 this.update(new Date().clearTime());
14565 resize : function() {
14566 var sz = this.el.getSize();
14568 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
14569 this.el.select('.fc-day-content div',true).setHeight(34);
14574 showPrevMonth : function(e){
14575 this.update(this.activeDate.add("mo", -1));
14577 showToday : function(e){
14578 this.update(new Date().clearTime());
14581 showNextMonth : function(e){
14582 this.update(this.activeDate.add("mo", 1));
14586 showPrevYear : function(){
14587 this.update(this.activeDate.add("y", -1));
14591 showNextYear : function(){
14592 this.update(this.activeDate.add("y", 1));
14597 update : function(date)
14599 var vd = this.activeDate;
14600 this.activeDate = date;
14601 // if(vd && this.el){
14602 // var t = date.getTime();
14603 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
14604 // Roo.log('using add remove');
14606 // this.fireEvent('monthchange', this, date);
14608 // this.cells.removeClass("fc-state-highlight");
14609 // this.cells.each(function(c){
14610 // if(c.dateValue == t){
14611 // c.addClass("fc-state-highlight");
14612 // setTimeout(function(){
14613 // try{c.dom.firstChild.focus();}catch(e){}
14623 var days = date.getDaysInMonth();
14625 var firstOfMonth = date.getFirstDateOfMonth();
14626 var startingPos = firstOfMonth.getDay()-this.startDay;
14628 if(startingPos < this.startDay){
14632 var pm = date.add(Date.MONTH, -1);
14633 var prevStart = pm.getDaysInMonth()-startingPos;
14635 this.cells = this.el.select('.fc-day',true);
14636 this.textNodes = this.el.query('.fc-day-number');
14637 this.cells.addClassOnOver('fc-state-hover');
14639 var cells = this.cells.elements;
14640 var textEls = this.textNodes;
14642 Roo.each(cells, function(cell){
14643 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
14646 days += startingPos;
14648 // convert everything to numbers so it's fast
14649 var day = 86400000;
14650 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
14653 //Roo.log(prevStart);
14655 var today = new Date().clearTime().getTime();
14656 var sel = date.clearTime().getTime();
14657 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
14658 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
14659 var ddMatch = this.disabledDatesRE;
14660 var ddText = this.disabledDatesText;
14661 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
14662 var ddaysText = this.disabledDaysText;
14663 var format = this.format;
14665 var setCellClass = function(cal, cell){
14669 //Roo.log('set Cell Class');
14671 var t = d.getTime();
14675 cell.dateValue = t;
14677 cell.className += " fc-today";
14678 cell.className += " fc-state-highlight";
14679 cell.title = cal.todayText;
14682 // disable highlight in other month..
14683 //cell.className += " fc-state-highlight";
14688 cell.className = " fc-state-disabled";
14689 cell.title = cal.minText;
14693 cell.className = " fc-state-disabled";
14694 cell.title = cal.maxText;
14698 if(ddays.indexOf(d.getDay()) != -1){
14699 cell.title = ddaysText;
14700 cell.className = " fc-state-disabled";
14703 if(ddMatch && format){
14704 var fvalue = d.dateFormat(format);
14705 if(ddMatch.test(fvalue)){
14706 cell.title = ddText.replace("%0", fvalue);
14707 cell.className = " fc-state-disabled";
14711 if (!cell.initialClassName) {
14712 cell.initialClassName = cell.dom.className;
14715 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14720 for(; i < startingPos; i++) {
14721 textEls[i].innerHTML = (++prevStart);
14722 d.setDate(d.getDate()+1);
14724 cells[i].className = "fc-past fc-other-month";
14725 setCellClass(this, cells[i]);
14730 for(; i < days; i++){
14731 intDay = i - startingPos + 1;
14732 textEls[i].innerHTML = (intDay);
14733 d.setDate(d.getDate()+1);
14735 cells[i].className = ''; // "x-date-active";
14736 setCellClass(this, cells[i]);
14740 for(; i < 42; i++) {
14741 textEls[i].innerHTML = (++extraDays);
14742 d.setDate(d.getDate()+1);
14744 cells[i].className = "fc-future fc-other-month";
14745 setCellClass(this, cells[i]);
14748 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14750 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14752 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14753 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14755 if(totalRows != 6){
14756 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14757 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14760 this.fireEvent('monthchange', this, date);
14764 if(!this.internalRender){
14765 var main = this.el.dom.firstChild;
14766 var w = main.offsetWidth;
14767 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14768 Roo.fly(main).setWidth(w);
14769 this.internalRender = true;
14770 // opera does not respect the auto grow header center column
14771 // then, after it gets a width opera refuses to recalculate
14772 // without a second pass
14773 if(Roo.isOpera && !this.secondPass){
14774 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14775 this.secondPass = true;
14776 this.update.defer(10, this, [date]);
14783 findCell : function(dt) {
14784 dt = dt.clearTime().getTime();
14786 this.cells.each(function(c){
14787 //Roo.log("check " +c.dateValue + '?=' + dt);
14788 if(c.dateValue == dt){
14798 findCells : function(ev) {
14799 var s = ev.start.clone().clearTime().getTime();
14801 var e= ev.end.clone().clearTime().getTime();
14804 this.cells.each(function(c){
14805 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14807 if(c.dateValue > e){
14810 if(c.dateValue < s){
14819 // findBestRow: function(cells)
14823 // for (var i =0 ; i < cells.length;i++) {
14824 // ret = Math.max(cells[i].rows || 0,ret);
14831 addItem : function(ev)
14833 // look for vertical location slot in
14834 var cells = this.findCells(ev);
14836 // ev.row = this.findBestRow(cells);
14838 // work out the location.
14842 for(var i =0; i < cells.length; i++) {
14844 cells[i].row = cells[0].row;
14847 cells[i].row = cells[i].row + 1;
14857 if (crow.start.getY() == cells[i].getY()) {
14859 crow.end = cells[i];
14876 cells[0].events.push(ev);
14878 this.calevents.push(ev);
14881 clearEvents: function() {
14883 if(!this.calevents){
14887 Roo.each(this.cells.elements, function(c){
14893 Roo.each(this.calevents, function(e) {
14894 Roo.each(e.els, function(el) {
14895 el.un('mouseenter' ,this.onEventEnter, this);
14896 el.un('mouseleave' ,this.onEventLeave, this);
14901 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14907 renderEvents: function()
14911 this.cells.each(function(c) {
14920 if(c.row != c.events.length){
14921 r = 4 - (4 - (c.row - c.events.length));
14924 c.events = ev.slice(0, r);
14925 c.more = ev.slice(r);
14927 if(c.more.length && c.more.length == 1){
14928 c.events.push(c.more.pop());
14931 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14935 this.cells.each(function(c) {
14937 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14940 for (var e = 0; e < c.events.length; e++){
14941 var ev = c.events[e];
14942 var rows = ev.rows;
14944 for(var i = 0; i < rows.length; i++) {
14946 // how many rows should it span..
14949 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14950 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14952 unselectable : "on",
14955 cls: 'fc-event-inner',
14959 // cls: 'fc-event-time',
14960 // html : cells.length > 1 ? '' : ev.time
14964 cls: 'fc-event-title',
14965 html : String.format('{0}', ev.title)
14972 cls: 'ui-resizable-handle ui-resizable-e',
14973 html : '  '
14980 cfg.cls += ' fc-event-start';
14982 if ((i+1) == rows.length) {
14983 cfg.cls += ' fc-event-end';
14986 var ctr = _this.el.select('.fc-event-container',true).first();
14987 var cg = ctr.createChild(cfg);
14989 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14990 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14992 var r = (c.more.length) ? 1 : 0;
14993 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14994 cg.setWidth(ebox.right - sbox.x -2);
14996 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14997 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14998 cg.on('click', _this.onEventClick, _this, ev);
15009 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
15010 style : 'position: absolute',
15011 unselectable : "on",
15014 cls: 'fc-event-inner',
15018 cls: 'fc-event-title',
15026 cls: 'ui-resizable-handle ui-resizable-e',
15027 html : '  '
15033 var ctr = _this.el.select('.fc-event-container',true).first();
15034 var cg = ctr.createChild(cfg);
15036 var sbox = c.select('.fc-day-content',true).first().getBox();
15037 var ebox = c.select('.fc-day-content',true).first().getBox();
15039 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
15040 cg.setWidth(ebox.right - sbox.x -2);
15042 cg.on('click', _this.onMoreEventClick, _this, c.more);
15052 onEventEnter: function (e, el,event,d) {
15053 this.fireEvent('evententer', this, el, event);
15056 onEventLeave: function (e, el,event,d) {
15057 this.fireEvent('eventleave', this, el, event);
15060 onEventClick: function (e, el,event,d) {
15061 this.fireEvent('eventclick', this, el, event);
15064 onMonthChange: function () {
15068 onMoreEventClick: function(e, el, more)
15072 this.calpopover.placement = 'right';
15073 this.calpopover.setTitle('More');
15075 this.calpopover.setContent('');
15077 var ctr = this.calpopover.el.select('.popover-content', true).first();
15079 Roo.each(more, function(m){
15081 cls : 'fc-event-hori fc-event-draggable',
15084 var cg = ctr.createChild(cfg);
15086 cg.on('click', _this.onEventClick, _this, m);
15089 this.calpopover.show(el);
15094 onLoad: function ()
15096 this.calevents = [];
15099 if(this.store.getCount() > 0){
15100 this.store.data.each(function(d){
15103 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
15104 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
15105 time : d.data.start_time,
15106 title : d.data.title,
15107 description : d.data.description,
15108 venue : d.data.venue
15113 this.renderEvents();
15115 if(this.calevents.length && this.loadMask){
15116 this.maskEl.hide();
15120 onBeforeLoad: function()
15122 this.clearEvents();
15124 this.maskEl.show();
15138 * @class Roo.bootstrap.Popover
15139 * @extends Roo.bootstrap.Component
15140 * Bootstrap Popover class
15141 * @cfg {String} html contents of the popover (or false to use children..)
15142 * @cfg {String} title of popover (or false to hide)
15143 * @cfg {String} placement how it is placed
15144 * @cfg {String} trigger click || hover (or false to trigger manually)
15145 * @cfg {String} over what (parent or false to trigger manually.)
15146 * @cfg {Number} delay - delay before showing
15149 * Create a new Popover
15150 * @param {Object} config The config object
15153 Roo.bootstrap.Popover = function(config){
15154 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
15157 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
15159 title: 'Fill in a title',
15162 placement : 'right',
15163 trigger : 'hover', // hover
15169 can_build_overlaid : false,
15171 getChildContainer : function()
15173 return this.el.select('.popover-content',true).first();
15176 getAutoCreate : function(){
15177 Roo.log('make popover?');
15179 cls : 'popover roo-dynamic',
15180 style: 'display:block',
15186 cls : 'popover-inner',
15190 cls: 'popover-title',
15194 cls : 'popover-content',
15205 setTitle: function(str)
15207 this.el.select('.popover-title',true).first().dom.innerHTML = str;
15209 setContent: function(str)
15211 this.el.select('.popover-content',true).first().dom.innerHTML = str;
15213 // as it get's added to the bottom of the page.
15214 onRender : function(ct, position)
15216 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
15218 var cfg = Roo.apply({}, this.getAutoCreate());
15222 cfg.cls += ' ' + this.cls;
15225 cfg.style = this.style;
15227 Roo.log("adding to ")
15228 this.el = Roo.get(document.body).createChild(cfg, position);
15234 initEvents : function()
15236 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
15237 this.el.enableDisplayMode('block');
15239 if (this.over === false) {
15242 if (this.triggers === false) {
15245 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15246 var triggers = this.trigger ? this.trigger.split(' ') : [];
15247 Roo.each(triggers, function(trigger) {
15249 if (trigger == 'click') {
15250 on_el.on('click', this.toggle, this);
15251 } else if (trigger != 'manual') {
15252 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
15253 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
15255 on_el.on(eventIn ,this.enter, this);
15256 on_el.on(eventOut, this.leave, this);
15267 toggle : function () {
15268 this.hoverState == 'in' ? this.leave() : this.enter();
15271 enter : function () {
15274 clearTimeout(this.timeout);
15276 this.hoverState = 'in';
15278 if (!this.delay || !this.delay.show) {
15283 this.timeout = setTimeout(function () {
15284 if (_t.hoverState == 'in') {
15287 }, this.delay.show)
15289 leave : function() {
15290 clearTimeout(this.timeout);
15292 this.hoverState = 'out';
15294 if (!this.delay || !this.delay.hide) {
15299 this.timeout = setTimeout(function () {
15300 if (_t.hoverState == 'out') {
15303 }, this.delay.hide)
15306 show : function (on_el)
15309 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15312 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
15313 if (this.html !== false) {
15314 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
15316 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
15317 if (!this.title.length) {
15318 this.el.select('.popover-title',true).hide();
15321 var placement = typeof this.placement == 'function' ?
15322 this.placement.call(this, this.el, on_el) :
15325 var autoToken = /\s?auto?\s?/i;
15326 var autoPlace = autoToken.test(placement);
15328 placement = placement.replace(autoToken, '') || 'top';
15332 //this.el.setXY([0,0]);
15334 this.el.dom.style.display='block';
15335 this.el.addClass(placement);
15337 //this.el.appendTo(on_el);
15339 var p = this.getPosition();
15340 var box = this.el.getBox();
15345 var align = Roo.bootstrap.Popover.alignment[placement];
15346 this.el.alignTo(on_el, align[0],align[1]);
15347 //var arrow = this.el.select('.arrow',true).first();
15348 //arrow.set(align[2],
15350 this.el.addClass('in');
15351 this.hoverState = null;
15353 if (this.el.hasClass('fade')) {
15360 this.el.setXY([0,0]);
15361 this.el.removeClass('in');
15368 Roo.bootstrap.Popover.alignment = {
15369 'left' : ['r-l', [-10,0], 'right'],
15370 'right' : ['l-r', [10,0], 'left'],
15371 'bottom' : ['t-b', [0,10], 'top'],
15372 'top' : [ 'b-t', [0,-10], 'bottom']
15383 * @class Roo.bootstrap.Progress
15384 * @extends Roo.bootstrap.Component
15385 * Bootstrap Progress class
15386 * @cfg {Boolean} striped striped of the progress bar
15387 * @cfg {Boolean} active animated of the progress bar
15391 * Create a new Progress
15392 * @param {Object} config The config object
15395 Roo.bootstrap.Progress = function(config){
15396 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
15399 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
15404 getAutoCreate : function(){
15412 cfg.cls += ' progress-striped';
15416 cfg.cls += ' active';
15435 * @class Roo.bootstrap.ProgressBar
15436 * @extends Roo.bootstrap.Component
15437 * Bootstrap ProgressBar class
15438 * @cfg {Number} aria_valuenow aria-value now
15439 * @cfg {Number} aria_valuemin aria-value min
15440 * @cfg {Number} aria_valuemax aria-value max
15441 * @cfg {String} label label for the progress bar
15442 * @cfg {String} panel (success | info | warning | danger )
15443 * @cfg {String} role role of the progress bar
15444 * @cfg {String} sr_only text
15448 * Create a new ProgressBar
15449 * @param {Object} config The config object
15452 Roo.bootstrap.ProgressBar = function(config){
15453 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
15456 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
15460 aria_valuemax : 100,
15466 getAutoCreate : function()
15471 cls: 'progress-bar',
15472 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
15484 cfg.role = this.role;
15487 if(this.aria_valuenow){
15488 cfg['aria-valuenow'] = this.aria_valuenow;
15491 if(this.aria_valuemin){
15492 cfg['aria-valuemin'] = this.aria_valuemin;
15495 if(this.aria_valuemax){
15496 cfg['aria-valuemax'] = this.aria_valuemax;
15499 if(this.label && !this.sr_only){
15500 cfg.html = this.label;
15504 cfg.cls += ' progress-bar-' + this.panel;
15510 update : function(aria_valuenow)
15512 this.aria_valuenow = aria_valuenow;
15514 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
15529 * @class Roo.bootstrap.TabGroup
15530 * @extends Roo.bootstrap.Column
15531 * Bootstrap Column class
15532 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
15533 * @cfg {Boolean} carousel true to make the group behave like a carousel
15534 * @cfg {Number} bullets show the panel pointer.. default 0
15535 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
15536 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
15537 * @cfg {Number} timer auto slide timer .. default 0 millisecond
15540 * Create a new TabGroup
15541 * @param {Object} config The config object
15544 Roo.bootstrap.TabGroup = function(config){
15545 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
15547 this.navId = Roo.id();
15550 Roo.bootstrap.TabGroup.register(this);
15554 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
15557 transition : false,
15562 slideOnTouch : false,
15564 getAutoCreate : function()
15566 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
15568 cfg.cls += ' tab-content';
15570 Roo.log('get auto create...............');
15572 if (this.carousel) {
15573 cfg.cls += ' carousel slide';
15576 cls : 'carousel-inner'
15579 if(this.bullets > 0 && !Roo.isTouch){
15582 cls : 'carousel-bullets',
15586 if(this.bullets_cls){
15587 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
15590 for (var i = 0; i < this.bullets; i++){
15592 cls : 'bullet bullet-' + i
15600 cfg.cn[0].cn = bullets;
15607 initEvents: function()
15609 Roo.log('-------- init events on tab group ---------');
15611 if(this.bullets > 0 && !Roo.isTouch){
15617 if(Roo.isTouch && this.slideOnTouch){
15618 this.el.on("touchstart", this.onTouchStart, this);
15621 if(this.autoslide){
15624 this.slideFn = window.setInterval(function() {
15625 _this.showPanelNext();
15631 onTouchStart : function(e, el, o)
15633 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15637 this.showPanelNext();
15640 getChildContainer : function()
15642 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15646 * register a Navigation item
15647 * @param {Roo.bootstrap.NavItem} the navitem to add
15649 register : function(item)
15651 this.tabs.push( item);
15652 item.navId = this.navId; // not really needed..
15656 getActivePanel : function()
15659 Roo.each(this.tabs, function(t) {
15669 getPanelByName : function(n)
15672 Roo.each(this.tabs, function(t) {
15673 if (t.tabId == n) {
15681 indexOfPanel : function(p)
15684 Roo.each(this.tabs, function(t,i) {
15685 if (t.tabId == p.tabId) {
15694 * show a specific panel
15695 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15696 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15698 showPanel : function (pan)
15700 if(this.transition){
15701 Roo.log("waiting for the transitionend");
15705 if (typeof(pan) == 'number') {
15706 pan = this.tabs[pan];
15708 if (typeof(pan) == 'string') {
15709 pan = this.getPanelByName(pan);
15711 if (pan.tabId == this.getActivePanel().tabId) {
15714 var cur = this.getActivePanel();
15716 if (false === cur.fireEvent('beforedeactivate')) {
15720 if(this.bullets > 0 && !Roo.isTouch){
15721 this.setActiveBullet(this.indexOfPanel(pan));
15724 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15726 this.transition = true;
15727 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15728 var lr = dir == 'next' ? 'left' : 'right';
15729 pan.el.addClass(dir); // or prev
15730 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15731 cur.el.addClass(lr); // or right
15732 pan.el.addClass(lr);
15735 cur.el.on('transitionend', function() {
15736 Roo.log("trans end?");
15738 pan.el.removeClass([lr,dir]);
15739 pan.setActive(true);
15741 cur.el.removeClass([lr]);
15742 cur.setActive(false);
15744 _this.transition = false;
15746 }, this, { single: true } );
15751 cur.setActive(false);
15752 pan.setActive(true);
15757 showPanelNext : function()
15759 var i = this.indexOfPanel(this.getActivePanel());
15761 if (i >= this.tabs.length - 1 && !this.autoslide) {
15765 if (i >= this.tabs.length - 1 && this.autoslide) {
15769 this.showPanel(this.tabs[i+1]);
15772 showPanelPrev : function()
15774 var i = this.indexOfPanel(this.getActivePanel());
15776 if (i < 1 && !this.autoslide) {
15780 if (i < 1 && this.autoslide) {
15781 i = this.tabs.length;
15784 this.showPanel(this.tabs[i-1]);
15787 initBullet : function()
15795 for (var i = 0; i < this.bullets; i++){
15796 var bullet = this.el.select('.bullet-' + i, true).first();
15802 bullet.on('click', (function(e, el, o, ii, t){
15804 e.preventDefault();
15806 _this.showPanel(ii);
15808 if(_this.autoslide && _this.slideFn){
15809 clearInterval(_this.slideFn);
15810 _this.slideFn = window.setInterval(function() {
15811 _this.showPanelNext();
15815 }).createDelegate(this, [i, bullet], true));
15819 setActiveBullet : function(i)
15825 Roo.each(this.el.select('.bullet', true).elements, function(el){
15826 el.removeClass('selected');
15829 var bullet = this.el.select('.bullet-' + i, true).first();
15835 bullet.addClass('selected');
15846 Roo.apply(Roo.bootstrap.TabGroup, {
15850 * register a Navigation Group
15851 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15853 register : function(navgrp)
15855 this.groups[navgrp.navId] = navgrp;
15859 * fetch a Navigation Group based on the navigation ID
15860 * if one does not exist , it will get created.
15861 * @param {string} the navgroup to add
15862 * @returns {Roo.bootstrap.NavGroup} the navgroup
15864 get: function(navId) {
15865 if (typeof(this.groups[navId]) == 'undefined') {
15866 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15868 return this.groups[navId] ;
15883 * @class Roo.bootstrap.TabPanel
15884 * @extends Roo.bootstrap.Component
15885 * Bootstrap TabPanel class
15886 * @cfg {Boolean} active panel active
15887 * @cfg {String} html panel content
15888 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15889 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15893 * Create a new TabPanel
15894 * @param {Object} config The config object
15897 Roo.bootstrap.TabPanel = function(config){
15898 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15902 * Fires when the active status changes
15903 * @param {Roo.bootstrap.TabPanel} this
15904 * @param {Boolean} state the new state
15909 * @event beforedeactivate
15910 * Fires before a tab is de-activated - can be used to do validation on a form.
15911 * @param {Roo.bootstrap.TabPanel} this
15912 * @return {Boolean} false if there is an error
15915 'beforedeactivate': true
15918 this.tabId = this.tabId || Roo.id();
15922 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15929 getAutoCreate : function(){
15932 // item is needed for carousel - not sure if it has any effect otherwise
15933 cls: 'tab-pane item',
15934 html: this.html || ''
15938 cfg.cls += ' active';
15942 cfg.tabId = this.tabId;
15949 initEvents: function()
15951 Roo.log('-------- init events on tab panel ---------');
15953 var p = this.parent();
15954 this.navId = this.navId || p.navId;
15956 if (typeof(this.navId) != 'undefined') {
15957 // not really needed.. but just in case.. parent should be a NavGroup.
15958 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15959 Roo.log(['register', tg, this]);
15962 var i = tg.tabs.length - 1;
15964 if(this.active && tg.bullets > 0 && i < tg.bullets){
15965 tg.setActiveBullet(i);
15972 onRender : function(ct, position)
15974 // Roo.log("Call onRender: " + this.xtype);
15976 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15984 setActive: function(state)
15986 Roo.log("panel - set active " + this.tabId + "=" + state);
15988 this.active = state;
15990 this.el.removeClass('active');
15992 } else if (!this.el.hasClass('active')) {
15993 this.el.addClass('active');
15996 this.fireEvent('changed', this, state);
16013 * @class Roo.bootstrap.DateField
16014 * @extends Roo.bootstrap.Input
16015 * Bootstrap DateField class
16016 * @cfg {Number} weekStart default 0
16017 * @cfg {String} viewMode default empty, (months|years)
16018 * @cfg {String} minViewMode default empty, (months|years)
16019 * @cfg {Number} startDate default -Infinity
16020 * @cfg {Number} endDate default Infinity
16021 * @cfg {Boolean} todayHighlight default false
16022 * @cfg {Boolean} todayBtn default false
16023 * @cfg {Boolean} calendarWeeks default false
16024 * @cfg {Object} daysOfWeekDisabled default empty
16025 * @cfg {Boolean} singleMode default false (true | false)
16027 * @cfg {Boolean} keyboardNavigation default true
16028 * @cfg {String} language default en
16031 * Create a new DateField
16032 * @param {Object} config The config object
16035 Roo.bootstrap.DateField = function(config){
16036 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16040 * Fires when this field show.
16041 * @param {Roo.bootstrap.DateField} this
16042 * @param {Mixed} date The date value
16047 * Fires when this field hide.
16048 * @param {Roo.bootstrap.DateField} this
16049 * @param {Mixed} date The date value
16054 * Fires when select a date.
16055 * @param {Roo.bootstrap.DateField} this
16056 * @param {Mixed} date The date value
16062 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16065 * @cfg {String} format
16066 * The default date format string which can be overriden for localization support. The format must be
16067 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16071 * @cfg {String} altFormats
16072 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16073 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16075 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16083 todayHighlight : false,
16089 keyboardNavigation: true,
16091 calendarWeeks: false,
16093 startDate: -Infinity,
16097 daysOfWeekDisabled: [],
16101 singleMode : false,
16103 UTCDate: function()
16105 return new Date(Date.UTC.apply(Date, arguments));
16108 UTCToday: function()
16110 var today = new Date();
16111 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16114 getDate: function() {
16115 var d = this.getUTCDate();
16116 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16119 getUTCDate: function() {
16123 setDate: function(d) {
16124 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
16127 setUTCDate: function(d) {
16129 this.setValue(this.formatDate(this.date));
16132 onRender: function(ct, position)
16135 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
16137 this.language = this.language || 'en';
16138 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
16139 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
16141 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
16142 this.format = this.format || 'm/d/y';
16143 this.isInline = false;
16144 this.isInput = true;
16145 this.component = this.el.select('.add-on', true).first() || false;
16146 this.component = (this.component && this.component.length === 0) ? false : this.component;
16147 this.hasInput = this.component && this.inputEL().length;
16149 if (typeof(this.minViewMode === 'string')) {
16150 switch (this.minViewMode) {
16152 this.minViewMode = 1;
16155 this.minViewMode = 2;
16158 this.minViewMode = 0;
16163 if (typeof(this.viewMode === 'string')) {
16164 switch (this.viewMode) {
16177 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
16179 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
16181 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16183 this.picker().on('mousedown', this.onMousedown, this);
16184 this.picker().on('click', this.onClick, this);
16186 this.picker().addClass('datepicker-dropdown');
16188 this.startViewMode = this.viewMode;
16190 if(this.singleMode){
16191 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
16192 v.setVisibilityMode(Roo.Element.DISPLAY)
16196 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16197 v.setStyle('width', '189px');
16201 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
16202 if(!this.calendarWeeks){
16207 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16208 v.attr('colspan', function(i, val){
16209 return parseInt(val) + 1;
16214 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
16216 this.setStartDate(this.startDate);
16217 this.setEndDate(this.endDate);
16219 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
16226 if(this.isInline) {
16231 picker : function()
16233 return this.pickerEl;
16234 // return this.el.select('.datepicker', true).first();
16237 fillDow: function()
16239 var dowCnt = this.weekStart;
16248 if(this.calendarWeeks){
16256 while (dowCnt < this.weekStart + 7) {
16260 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
16264 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
16267 fillMonths: function()
16270 var months = this.picker().select('>.datepicker-months td', true).first();
16272 months.dom.innerHTML = '';
16278 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
16281 months.createChild(month);
16288 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;
16290 if (this.date < this.startDate) {
16291 this.viewDate = new Date(this.startDate);
16292 } else if (this.date > this.endDate) {
16293 this.viewDate = new Date(this.endDate);
16295 this.viewDate = new Date(this.date);
16303 var d = new Date(this.viewDate),
16304 year = d.getUTCFullYear(),
16305 month = d.getUTCMonth(),
16306 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
16307 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
16308 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
16309 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
16310 currentDate = this.date && this.date.valueOf(),
16311 today = this.UTCToday();
16313 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
16315 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16317 // this.picker.select('>tfoot th.today').
16318 // .text(dates[this.language].today)
16319 // .toggle(this.todayBtn !== false);
16321 this.updateNavArrows();
16324 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
16326 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
16328 prevMonth.setUTCDate(day);
16330 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
16332 var nextMonth = new Date(prevMonth);
16334 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
16336 nextMonth = nextMonth.valueOf();
16338 var fillMonths = false;
16340 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
16342 while(prevMonth.valueOf() < nextMonth) {
16345 if (prevMonth.getUTCDay() === this.weekStart) {
16347 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
16355 if(this.calendarWeeks){
16356 // ISO 8601: First week contains first thursday.
16357 // ISO also states week starts on Monday, but we can be more abstract here.
16359 // Start of current week: based on weekstart/current date
16360 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
16361 // Thursday of this week
16362 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
16363 // First Thursday of year, year from thursday
16364 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
16365 // Calendar week: ms between thursdays, div ms per day, div 7 days
16366 calWeek = (th - yth) / 864e5 / 7 + 1;
16368 fillMonths.cn.push({
16376 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
16378 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
16381 if (this.todayHighlight &&
16382 prevMonth.getUTCFullYear() == today.getFullYear() &&
16383 prevMonth.getUTCMonth() == today.getMonth() &&
16384 prevMonth.getUTCDate() == today.getDate()) {
16385 clsName += ' today';
16388 if (currentDate && prevMonth.valueOf() === currentDate) {
16389 clsName += ' active';
16392 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
16393 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
16394 clsName += ' disabled';
16397 fillMonths.cn.push({
16399 cls: 'day ' + clsName,
16400 html: prevMonth.getDate()
16403 prevMonth.setDate(prevMonth.getDate()+1);
16406 var currentYear = this.date && this.date.getUTCFullYear();
16407 var currentMonth = this.date && this.date.getUTCMonth();
16409 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
16411 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
16412 v.removeClass('active');
16414 if(currentYear === year && k === currentMonth){
16415 v.addClass('active');
16418 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
16419 v.addClass('disabled');
16425 year = parseInt(year/10, 10) * 10;
16427 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
16429 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
16432 for (var i = -1; i < 11; i++) {
16433 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
16435 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
16443 showMode: function(dir)
16446 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
16449 Roo.each(this.picker().select('>div',true).elements, function(v){
16450 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16453 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
16458 if(this.isInline) return;
16460 this.picker().removeClass(['bottom', 'top']);
16462 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16464 * place to the top of element!
16468 this.picker().addClass('top');
16469 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16474 this.picker().addClass('bottom');
16476 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16479 parseDate : function(value)
16481 if(!value || value instanceof Date){
16484 var v = Date.parseDate(value, this.format);
16485 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
16486 v = Date.parseDate(value, 'Y-m-d');
16488 if(!v && this.altFormats){
16489 if(!this.altFormatsArray){
16490 this.altFormatsArray = this.altFormats.split("|");
16492 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
16493 v = Date.parseDate(value, this.altFormatsArray[i]);
16499 formatDate : function(date, fmt)
16501 return (!date || !(date instanceof Date)) ?
16502 date : date.dateFormat(fmt || this.format);
16505 onFocus : function()
16507 Roo.bootstrap.DateField.superclass.onFocus.call(this);
16511 onBlur : function()
16513 Roo.bootstrap.DateField.superclass.onBlur.call(this);
16515 var d = this.inputEl().getValue();
16524 this.picker().show();
16528 this.fireEvent('show', this, this.date);
16533 if(this.isInline) return;
16534 this.picker().hide();
16535 this.viewMode = this.startViewMode;
16538 this.fireEvent('hide', this, this.date);
16542 onMousedown: function(e)
16544 e.stopPropagation();
16545 e.preventDefault();
16550 Roo.bootstrap.DateField.superclass.keyup.call(this);
16554 setValue: function(v)
16557 // v can be a string or a date..
16560 var d = new Date(this.parseDate(v) ).clearTime();
16562 if(isNaN(d.getTime())){
16563 this.date = this.viewDate = '';
16564 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
16568 v = this.formatDate(d);
16570 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
16572 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
16576 this.fireEvent('select', this, this.date);
16580 getValue: function()
16582 return this.formatDate(this.date);
16585 fireKey: function(e)
16587 if (!this.picker().isVisible()){
16588 if (e.keyCode == 27) // allow escape to hide and re-show picker
16593 var dateChanged = false,
16595 newDate, newViewDate;
16600 e.preventDefault();
16604 if (!this.keyboardNavigation) break;
16605 dir = e.keyCode == 37 ? -1 : 1;
16608 newDate = this.moveYear(this.date, dir);
16609 newViewDate = this.moveYear(this.viewDate, dir);
16610 } else if (e.shiftKey){
16611 newDate = this.moveMonth(this.date, dir);
16612 newViewDate = this.moveMonth(this.viewDate, dir);
16614 newDate = new Date(this.date);
16615 newDate.setUTCDate(this.date.getUTCDate() + dir);
16616 newViewDate = new Date(this.viewDate);
16617 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16619 if (this.dateWithinRange(newDate)){
16620 this.date = newDate;
16621 this.viewDate = newViewDate;
16622 this.setValue(this.formatDate(this.date));
16624 e.preventDefault();
16625 dateChanged = true;
16630 if (!this.keyboardNavigation) break;
16631 dir = e.keyCode == 38 ? -1 : 1;
16633 newDate = this.moveYear(this.date, dir);
16634 newViewDate = this.moveYear(this.viewDate, dir);
16635 } else if (e.shiftKey){
16636 newDate = this.moveMonth(this.date, dir);
16637 newViewDate = this.moveMonth(this.viewDate, dir);
16639 newDate = new Date(this.date);
16640 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16641 newViewDate = new Date(this.viewDate);
16642 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16644 if (this.dateWithinRange(newDate)){
16645 this.date = newDate;
16646 this.viewDate = newViewDate;
16647 this.setValue(this.formatDate(this.date));
16649 e.preventDefault();
16650 dateChanged = true;
16654 this.setValue(this.formatDate(this.date));
16656 e.preventDefault();
16659 this.setValue(this.formatDate(this.date));
16673 onClick: function(e)
16675 e.stopPropagation();
16676 e.preventDefault();
16678 var target = e.getTarget();
16680 if(target.nodeName.toLowerCase() === 'i'){
16681 target = Roo.get(target).dom.parentNode;
16684 var nodeName = target.nodeName;
16685 var className = target.className;
16686 var html = target.innerHTML;
16687 //Roo.log(nodeName);
16689 switch(nodeName.toLowerCase()) {
16691 switch(className) {
16697 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16698 switch(this.viewMode){
16700 this.viewDate = this.moveMonth(this.viewDate, dir);
16704 this.viewDate = this.moveYear(this.viewDate, dir);
16710 var date = new Date();
16711 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16713 this.setValue(this.formatDate(this.date));
16720 if (className.indexOf('disabled') < 0) {
16721 this.viewDate.setUTCDate(1);
16722 if (className.indexOf('month') > -1) {
16723 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16725 var year = parseInt(html, 10) || 0;
16726 this.viewDate.setUTCFullYear(year);
16730 if(this.singleMode){
16731 this.setValue(this.formatDate(this.viewDate));
16742 //Roo.log(className);
16743 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16744 var day = parseInt(html, 10) || 1;
16745 var year = this.viewDate.getUTCFullYear(),
16746 month = this.viewDate.getUTCMonth();
16748 if (className.indexOf('old') > -1) {
16755 } else if (className.indexOf('new') > -1) {
16763 //Roo.log([year,month,day]);
16764 this.date = this.UTCDate(year, month, day,0,0,0,0);
16765 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16767 //Roo.log(this.formatDate(this.date));
16768 this.setValue(this.formatDate(this.date));
16775 setStartDate: function(startDate)
16777 this.startDate = startDate || -Infinity;
16778 if (this.startDate !== -Infinity) {
16779 this.startDate = this.parseDate(this.startDate);
16782 this.updateNavArrows();
16785 setEndDate: function(endDate)
16787 this.endDate = endDate || Infinity;
16788 if (this.endDate !== Infinity) {
16789 this.endDate = this.parseDate(this.endDate);
16792 this.updateNavArrows();
16795 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16797 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16798 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16799 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16801 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16802 return parseInt(d, 10);
16805 this.updateNavArrows();
16808 updateNavArrows: function()
16810 if(this.singleMode){
16814 var d = new Date(this.viewDate),
16815 year = d.getUTCFullYear(),
16816 month = d.getUTCMonth();
16818 Roo.each(this.picker().select('.prev', true).elements, function(v){
16820 switch (this.viewMode) {
16823 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16829 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16836 Roo.each(this.picker().select('.next', true).elements, function(v){
16838 switch (this.viewMode) {
16841 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16847 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16855 moveMonth: function(date, dir)
16857 if (!dir) return date;
16858 var new_date = new Date(date.valueOf()),
16859 day = new_date.getUTCDate(),
16860 month = new_date.getUTCMonth(),
16861 mag = Math.abs(dir),
16863 dir = dir > 0 ? 1 : -1;
16866 // If going back one month, make sure month is not current month
16867 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16869 return new_date.getUTCMonth() == month;
16871 // If going forward one month, make sure month is as expected
16872 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16874 return new_date.getUTCMonth() != new_month;
16876 new_month = month + dir;
16877 new_date.setUTCMonth(new_month);
16878 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16879 if (new_month < 0 || new_month > 11)
16880 new_month = (new_month + 12) % 12;
16882 // For magnitudes >1, move one month at a time...
16883 for (var i=0; i<mag; i++)
16884 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16885 new_date = this.moveMonth(new_date, dir);
16886 // ...then reset the day, keeping it in the new month
16887 new_month = new_date.getUTCMonth();
16888 new_date.setUTCDate(day);
16890 return new_month != new_date.getUTCMonth();
16893 // Common date-resetting loop -- if date is beyond end of month, make it
16896 new_date.setUTCDate(--day);
16897 new_date.setUTCMonth(new_month);
16902 moveYear: function(date, dir)
16904 return this.moveMonth(date, dir*12);
16907 dateWithinRange: function(date)
16909 return date >= this.startDate && date <= this.endDate;
16915 this.picker().remove();
16920 Roo.apply(Roo.bootstrap.DateField, {
16931 html: '<i class="fa fa-arrow-left"/>'
16941 html: '<i class="fa fa-arrow-right"/>'
16983 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16984 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16985 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16986 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16987 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17000 navFnc: 'FullYear',
17005 navFnc: 'FullYear',
17010 Roo.apply(Roo.bootstrap.DateField, {
17014 cls: 'datepicker dropdown-menu roo-dynamic',
17018 cls: 'datepicker-days',
17022 cls: 'table-condensed',
17024 Roo.bootstrap.DateField.head,
17028 Roo.bootstrap.DateField.footer
17035 cls: 'datepicker-months',
17039 cls: 'table-condensed',
17041 Roo.bootstrap.DateField.head,
17042 Roo.bootstrap.DateField.content,
17043 Roo.bootstrap.DateField.footer
17050 cls: 'datepicker-years',
17054 cls: 'table-condensed',
17056 Roo.bootstrap.DateField.head,
17057 Roo.bootstrap.DateField.content,
17058 Roo.bootstrap.DateField.footer
17077 * @class Roo.bootstrap.TimeField
17078 * @extends Roo.bootstrap.Input
17079 * Bootstrap DateField class
17083 * Create a new TimeField
17084 * @param {Object} config The config object
17087 Roo.bootstrap.TimeField = function(config){
17088 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17092 * Fires when this field show.
17093 * @param {Roo.bootstrap.DateField} thisthis
17094 * @param {Mixed} date The date value
17099 * Fires when this field hide.
17100 * @param {Roo.bootstrap.DateField} this
17101 * @param {Mixed} date The date value
17106 * Fires when select a date.
17107 * @param {Roo.bootstrap.DateField} this
17108 * @param {Mixed} date The date value
17114 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
17117 * @cfg {String} format
17118 * The default time format string which can be overriden for localization support. The format must be
17119 * valid according to {@link Date#parseDate} (defaults to 'H:i').
17123 onRender: function(ct, position)
17126 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
17128 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
17130 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17132 this.pop = this.picker().select('>.datepicker-time',true).first();
17133 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17135 this.picker().on('mousedown', this.onMousedown, this);
17136 this.picker().on('click', this.onClick, this);
17138 this.picker().addClass('datepicker-dropdown');
17143 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
17144 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
17145 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
17146 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
17147 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
17148 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
17152 fireKey: function(e){
17153 if (!this.picker().isVisible()){
17154 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17160 e.preventDefault();
17168 this.onTogglePeriod();
17171 this.onIncrementMinutes();
17174 this.onDecrementMinutes();
17183 onClick: function(e) {
17184 e.stopPropagation();
17185 e.preventDefault();
17188 picker : function()
17190 return this.el.select('.datepicker', true).first();
17193 fillTime: function()
17195 var time = this.pop.select('tbody', true).first();
17197 time.dom.innerHTML = '';
17212 cls: 'hours-up glyphicon glyphicon-chevron-up'
17232 cls: 'minutes-up glyphicon glyphicon-chevron-up'
17253 cls: 'timepicker-hour',
17268 cls: 'timepicker-minute',
17283 cls: 'btn btn-primary period',
17305 cls: 'hours-down glyphicon glyphicon-chevron-down'
17325 cls: 'minutes-down glyphicon glyphicon-chevron-down'
17343 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
17350 var hours = this.time.getHours();
17351 var minutes = this.time.getMinutes();
17364 hours = hours - 12;
17368 hours = '0' + hours;
17372 minutes = '0' + minutes;
17375 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
17376 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
17377 this.pop.select('button', true).first().dom.innerHTML = period;
17383 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
17385 var cls = ['bottom'];
17387 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
17394 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
17399 this.picker().addClass(cls.join('-'));
17403 Roo.each(cls, function(c){
17405 _this.picker().setTop(_this.inputEl().getHeight());
17409 _this.picker().setTop(0 - _this.picker().getHeight());
17414 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
17418 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
17425 onFocus : function()
17427 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
17431 onBlur : function()
17433 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
17439 this.picker().show();
17444 this.fireEvent('show', this, this.date);
17449 this.picker().hide();
17452 this.fireEvent('hide', this, this.date);
17455 setTime : function()
17458 this.setValue(this.time.format(this.format));
17460 this.fireEvent('select', this, this.date);
17465 onMousedown: function(e){
17466 e.stopPropagation();
17467 e.preventDefault();
17470 onIncrementHours: function()
17472 Roo.log('onIncrementHours');
17473 this.time = this.time.add(Date.HOUR, 1);
17478 onDecrementHours: function()
17480 Roo.log('onDecrementHours');
17481 this.time = this.time.add(Date.HOUR, -1);
17485 onIncrementMinutes: function()
17487 Roo.log('onIncrementMinutes');
17488 this.time = this.time.add(Date.MINUTE, 1);
17492 onDecrementMinutes: function()
17494 Roo.log('onDecrementMinutes');
17495 this.time = this.time.add(Date.MINUTE, -1);
17499 onTogglePeriod: function()
17501 Roo.log('onTogglePeriod');
17502 this.time = this.time.add(Date.HOUR, 12);
17509 Roo.apply(Roo.bootstrap.TimeField, {
17539 cls: 'btn btn-info ok',
17551 Roo.apply(Roo.bootstrap.TimeField, {
17555 cls: 'datepicker dropdown-menu',
17559 cls: 'datepicker-time',
17563 cls: 'table-condensed',
17565 Roo.bootstrap.TimeField.content,
17566 Roo.bootstrap.TimeField.footer
17585 * @class Roo.bootstrap.MonthField
17586 * @extends Roo.bootstrap.Input
17587 * Bootstrap MonthField class
17589 * @cfg {String} language default en
17592 * Create a new MonthField
17593 * @param {Object} config The config object
17596 Roo.bootstrap.MonthField = function(config){
17597 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
17602 * Fires when this field show.
17603 * @param {Roo.bootstrap.MonthField} this
17604 * @param {Mixed} date The date value
17609 * Fires when this field hide.
17610 * @param {Roo.bootstrap.MonthField} this
17611 * @param {Mixed} date The date value
17616 * Fires when select a date.
17617 * @param {Roo.bootstrap.MonthField} this
17618 * @param {String} oldvalue The old value
17619 * @param {String} newvalue The new value
17625 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17627 onRender: function(ct, position)
17630 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17632 this.language = this.language || 'en';
17633 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17634 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17636 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17637 this.isInline = false;
17638 this.isInput = true;
17639 this.component = this.el.select('.add-on', true).first() || false;
17640 this.component = (this.component && this.component.length === 0) ? false : this.component;
17641 this.hasInput = this.component && this.inputEL().length;
17643 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17645 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17647 this.picker().on('mousedown', this.onMousedown, this);
17648 this.picker().on('click', this.onClick, this);
17650 this.picker().addClass('datepicker-dropdown');
17652 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17653 v.setStyle('width', '189px');
17660 if(this.isInline) {
17666 setValue: function(v, suppressEvent)
17668 var o = this.getValue();
17670 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17674 if(suppressEvent !== true){
17675 this.fireEvent('select', this, o, v);
17680 getValue: function()
17685 onClick: function(e)
17687 e.stopPropagation();
17688 e.preventDefault();
17690 var target = e.getTarget();
17692 if(target.nodeName.toLowerCase() === 'i'){
17693 target = Roo.get(target).dom.parentNode;
17696 var nodeName = target.nodeName;
17697 var className = target.className;
17698 var html = target.innerHTML;
17700 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17704 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17706 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17712 picker : function()
17714 return this.pickerEl;
17717 fillMonths: function()
17720 var months = this.picker().select('>.datepicker-months td', true).first();
17722 months.dom.innerHTML = '';
17728 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17731 months.createChild(month);
17740 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17741 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17744 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17745 e.removeClass('active');
17747 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17748 e.addClass('active');
17755 if(this.isInline) return;
17757 this.picker().removeClass(['bottom', 'top']);
17759 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17761 * place to the top of element!
17765 this.picker().addClass('top');
17766 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17771 this.picker().addClass('bottom');
17773 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17776 onFocus : function()
17778 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17782 onBlur : function()
17784 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17786 var d = this.inputEl().getValue();
17795 this.picker().show();
17796 this.picker().select('>.datepicker-months', true).first().show();
17800 this.fireEvent('show', this, this.date);
17805 if(this.isInline) return;
17806 this.picker().hide();
17807 this.fireEvent('hide', this, this.date);
17811 onMousedown: function(e)
17813 e.stopPropagation();
17814 e.preventDefault();
17819 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17823 fireKey: function(e)
17825 if (!this.picker().isVisible()){
17826 if (e.keyCode == 27) // allow escape to hide and re-show picker
17836 e.preventDefault();
17840 dir = e.keyCode == 37 ? -1 : 1;
17842 this.vIndex = this.vIndex + dir;
17844 if(this.vIndex < 0){
17848 if(this.vIndex > 11){
17852 if(isNaN(this.vIndex)){
17856 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17862 dir = e.keyCode == 38 ? -1 : 1;
17864 this.vIndex = this.vIndex + dir * 4;
17866 if(this.vIndex < 0){
17870 if(this.vIndex > 11){
17874 if(isNaN(this.vIndex)){
17878 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17883 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17884 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17888 e.preventDefault();
17891 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17892 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17908 this.picker().remove();
17913 Roo.apply(Roo.bootstrap.MonthField, {
17932 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17933 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17938 Roo.apply(Roo.bootstrap.MonthField, {
17942 cls: 'datepicker dropdown-menu roo-dynamic',
17946 cls: 'datepicker-months',
17950 cls: 'table-condensed',
17952 Roo.bootstrap.DateField.content
17972 * @class Roo.bootstrap.CheckBox
17973 * @extends Roo.bootstrap.Input
17974 * Bootstrap CheckBox class
17976 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17977 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17978 * @cfg {String} boxLabel The text that appears beside the checkbox
17979 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17980 * @cfg {Boolean} checked initnal the element
17981 * @cfg {Boolean} inline inline the element (default false)
17982 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17985 * Create a new CheckBox
17986 * @param {Object} config The config object
17989 Roo.bootstrap.CheckBox = function(config){
17990 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17995 * Fires when the element is checked or unchecked.
17996 * @param {Roo.bootstrap.CheckBox} this This input
17997 * @param {Boolean} checked The new checked value
18004 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18006 inputType: 'checkbox',
18014 getAutoCreate : function()
18016 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18022 cfg.cls = 'form-group ' + this.inputType; //input-group
18025 cfg.cls += ' ' + this.inputType + '-inline';
18031 type : this.inputType,
18032 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18033 cls : 'roo-' + this.inputType, //'form-box',
18034 placeholder : this.placeholder || ''
18038 if (this.weight) { // Validity check?
18039 cfg.cls += " " + this.inputType + "-" + this.weight;
18042 if (this.disabled) {
18043 input.disabled=true;
18047 input.checked = this.checked;
18051 input.name = this.name;
18055 input.cls += ' input-' + this.size;
18060 ['xs','sm','md','lg'].map(function(size){
18061 if (settings[size]) {
18062 cfg.cls += ' col-' + size + '-' + settings[size];
18066 var inputblock = input;
18068 if (this.before || this.after) {
18071 cls : 'input-group',
18076 inputblock.cn.push({
18078 cls : 'input-group-addon',
18083 inputblock.cn.push(input);
18086 inputblock.cn.push({
18088 cls : 'input-group-addon',
18095 if (align ==='left' && this.fieldLabel.length) {
18096 Roo.log("left and has label");
18102 cls : 'control-label col-md-' + this.labelWidth,
18103 html : this.fieldLabel
18107 cls : "col-md-" + (12 - this.labelWidth),
18114 } else if ( this.fieldLabel.length) {
18119 tag: this.boxLabel ? 'span' : 'label',
18121 cls: 'control-label box-input-label',
18122 //cls : 'input-group-addon',
18123 html : this.fieldLabel
18133 Roo.log(" no label && no align");
18134 cfg.cn = [ inputblock ] ;
18139 var boxLabelCfg = {
18141 //'for': id, // box label is handled by onclick - so no for...
18143 html: this.boxLabel
18147 boxLabelCfg.tooltip = this.tooltip;
18150 cfg.cn.push(boxLabelCfg);
18160 * return the real input element.
18162 inputEl: function ()
18164 return this.el.select('input.roo-' + this.inputType,true).first();
18167 labelEl: function()
18169 return this.el.select('label.control-label',true).first();
18171 /* depricated... */
18175 return this.labelEl();
18178 initEvents : function()
18180 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18182 this.inputEl().on('click', this.onClick, this);
18184 if (this.boxLabel) {
18185 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
18188 this.startValue = this.getValue();
18191 Roo.bootstrap.CheckBox.register(this);
18195 onClick : function()
18197 this.setChecked(!this.checked);
18200 setChecked : function(state,suppressEvent)
18202 this.startValue = this.getValue();
18204 if(this.inputType == 'radio'){
18206 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18207 e.dom.checked = false;
18210 this.inputEl().dom.checked = true;
18212 this.inputEl().dom.value = this.inputValue;
18214 if(suppressEvent !== true){
18215 this.fireEvent('check', this, true);
18223 this.checked = state;
18225 this.inputEl().dom.checked = state;
18227 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18229 if(suppressEvent !== true){
18230 this.fireEvent('check', this, state);
18236 getValue : function()
18238 if(this.inputType == 'radio'){
18239 return this.getGroupValue();
18242 return this.inputEl().getValue();
18246 getGroupValue : function()
18248 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
18252 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
18255 setValue : function(v,suppressEvent)
18257 if(this.inputType == 'radio'){
18258 this.setGroupValue(v, suppressEvent);
18262 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
18267 setGroupValue : function(v, suppressEvent)
18269 this.startValue = this.getValue();
18271 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18272 e.dom.checked = false;
18274 if(e.dom.value == v){
18275 e.dom.checked = true;
18279 if(suppressEvent !== true){
18280 this.fireEvent('check', this, true);
18288 validate : function()
18292 (this.inputType == 'radio' && this.validateRadio()) ||
18293 (this.inputType == 'checkbox' && this.validateCheckbox())
18299 this.markInvalid();
18303 validateRadio : function()
18307 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18308 if(!e.dom.checked){
18320 validateCheckbox : function()
18323 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
18326 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18334 for(var i in group){
18339 r = (group[i].getValue() == group[i].inputValue) ? true : false;
18346 * Mark this field as valid
18348 markValid : function()
18350 if(this.allowBlank){
18356 this.fireEvent('valid', this);
18358 if(this.inputType == 'radio'){
18359 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18360 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
18361 e.findParent('.form-group', false, true).addClass(_this.validClass);
18368 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18369 this.el.findParent('.form-group', false, true).addClass(this.validClass);
18373 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18379 for(var i in group){
18380 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18381 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
18386 * Mark this field as invalid
18387 * @param {String} msg The validation message
18389 markInvalid : function(msg)
18391 if(this.allowBlank){
18397 this.fireEvent('invalid', this, msg);
18399 if(this.inputType == 'radio'){
18400 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18401 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
18402 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
18409 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18410 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
18414 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18420 for(var i in group){
18421 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18422 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
18429 Roo.apply(Roo.bootstrap.CheckBox, {
18434 * register a CheckBox Group
18435 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
18437 register : function(checkbox)
18439 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
18440 this.groups[checkbox.groupId] = {};
18443 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
18447 this.groups[checkbox.groupId][checkbox.name] = checkbox;
18451 * fetch a CheckBox Group based on the group ID
18452 * @param {string} the group ID
18453 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
18455 get: function(groupId) {
18456 if (typeof(this.groups[groupId]) == 'undefined') {
18460 return this.groups[groupId] ;
18472 *<div class="radio">
18474 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
18475 Option one is this and that—be sure to include why it's great
18482 *<label class="radio-inline">fieldLabel</label>
18483 *<label class="radio-inline">
18484 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
18492 * @class Roo.bootstrap.Radio
18493 * @extends Roo.bootstrap.CheckBox
18494 * Bootstrap Radio class
18497 * Create a new Radio
18498 * @param {Object} config The config object
18501 Roo.bootstrap.Radio = function(config){
18502 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
18506 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
18508 inputType: 'radio',
18512 getAutoCreate : function()
18514 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18515 align = align || 'left'; // default...
18522 tag : this.inline ? 'span' : 'div',
18527 var inline = this.inline ? ' radio-inline' : '';
18531 // does not need for, as we wrap the input with it..
18533 cls : 'control-label box-label' + inline,
18536 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
18540 //cls : 'control-label' + inline,
18541 html : this.fieldLabel,
18542 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
18551 type : this.inputType,
18552 //value : (!this.checked) ? this.valueOff : this.inputValue,
18553 value : this.inputValue,
18555 placeholder : this.placeholder || '' // ?? needed????
18558 if (this.weight) { // Validity check?
18559 input.cls += " radio-" + this.weight;
18561 if (this.disabled) {
18562 input.disabled=true;
18566 input.checked = this.checked;
18570 input.name = this.name;
18574 input.cls += ' input-' + this.size;
18577 //?? can span's inline have a width??
18580 ['xs','sm','md','lg'].map(function(size){
18581 if (settings[size]) {
18582 cfg.cls += ' col-' + size + '-' + settings[size];
18586 var inputblock = input;
18588 if (this.before || this.after) {
18591 cls : 'input-group',
18596 inputblock.cn.push({
18598 cls : 'input-group-addon',
18602 inputblock.cn.push(input);
18604 inputblock.cn.push({
18606 cls : 'input-group-addon',
18614 if (this.fieldLabel && this.fieldLabel.length) {
18615 cfg.cn.push(fieldLabel);
18618 // normal bootstrap puts the input inside the label.
18619 // however with our styled version - it has to go after the input.
18621 //lbl.cn.push(inputblock);
18625 cls: 'radio' + inline,
18632 cfg.cn.push( lblwrap);
18637 html: this.boxLabel
18646 initEvents : function()
18648 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18650 this.inputEl().on('click', this.onClick, this);
18651 if (this.boxLabel) {
18652 Roo.log('find label')
18653 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18658 inputEl: function ()
18660 return this.el.select('input.roo-radio',true).first();
18662 onClick : function()
18665 this.setChecked(true);
18668 setChecked : function(state,suppressEvent)
18671 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18672 v.dom.checked = false;
18675 Roo.log(this.inputEl().dom);
18676 this.checked = state;
18677 this.inputEl().dom.checked = state;
18679 if(suppressEvent !== true){
18680 this.fireEvent('check', this, state);
18683 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18687 getGroupValue : function()
18690 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18691 if(v.dom.checked == true){
18692 value = v.dom.value;
18700 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18701 * @return {Mixed} value The field value
18703 getValue : function(){
18704 return this.getGroupValue();
18710 //<script type="text/javascript">
18713 * Based Ext JS Library 1.1.1
18714 * Copyright(c) 2006-2007, Ext JS, LLC.
18720 * @class Roo.HtmlEditorCore
18721 * @extends Roo.Component
18722 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18724 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18727 Roo.HtmlEditorCore = function(config){
18730 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18735 * @event initialize
18736 * Fires when the editor is fully initialized (including the iframe)
18737 * @param {Roo.HtmlEditorCore} this
18742 * Fires when the editor is first receives the focus. Any insertion must wait
18743 * until after this event.
18744 * @param {Roo.HtmlEditorCore} this
18748 * @event beforesync
18749 * Fires before the textarea is updated with content from the editor iframe. Return false
18750 * to cancel the sync.
18751 * @param {Roo.HtmlEditorCore} this
18752 * @param {String} html
18756 * @event beforepush
18757 * Fires before the iframe editor is updated with content from the textarea. Return false
18758 * to cancel the push.
18759 * @param {Roo.HtmlEditorCore} this
18760 * @param {String} html
18765 * Fires when the textarea is updated with content from the editor iframe.
18766 * @param {Roo.HtmlEditorCore} this
18767 * @param {String} html
18772 * Fires when the iframe editor is updated with content from the textarea.
18773 * @param {Roo.HtmlEditorCore} this
18774 * @param {String} html
18779 * @event editorevent
18780 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18781 * @param {Roo.HtmlEditorCore} this
18787 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18789 // defaults : white / black...
18790 this.applyBlacklists();
18797 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18801 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18807 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18812 * @cfg {Number} height (in pixels)
18816 * @cfg {Number} width (in pixels)
18821 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18824 stylesheets: false,
18829 // private properties
18830 validationEvent : false,
18832 initialized : false,
18834 sourceEditMode : false,
18835 onFocus : Roo.emptyFn,
18837 hideMode:'offsets',
18841 // blacklist + whitelisted elements..
18848 * Protected method that will not generally be called directly. It
18849 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18850 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18852 getDocMarkup : function(){
18856 // inherit styels from page...??
18857 if (this.stylesheets === false) {
18859 Roo.get(document.head).select('style').each(function(node) {
18860 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18863 Roo.get(document.head).select('link').each(function(node) {
18864 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18867 } else if (!this.stylesheets.length) {
18869 st = '<style type="text/css">' +
18870 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18876 st += '<style type="text/css">' +
18877 'IMG { cursor: pointer } ' +
18881 return '<html><head>' + st +
18882 //<style type="text/css">' +
18883 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18885 ' </head><body class="roo-htmleditor-body"></body></html>';
18889 onRender : function(ct, position)
18892 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18893 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18896 this.el.dom.style.border = '0 none';
18897 this.el.dom.setAttribute('tabIndex', -1);
18898 this.el.addClass('x-hidden hide');
18902 if(Roo.isIE){ // fix IE 1px bogus margin
18903 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18907 this.frameId = Roo.id();
18911 var iframe = this.owner.wrap.createChild({
18913 cls: 'form-control', // bootstrap..
18915 name: this.frameId,
18916 frameBorder : 'no',
18917 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18922 this.iframe = iframe.dom;
18924 this.assignDocWin();
18926 this.doc.designMode = 'on';
18929 this.doc.write(this.getDocMarkup());
18933 var task = { // must defer to wait for browser to be ready
18935 //console.log("run task?" + this.doc.readyState);
18936 this.assignDocWin();
18937 if(this.doc.body || this.doc.readyState == 'complete'){
18939 this.doc.designMode="on";
18943 Roo.TaskMgr.stop(task);
18944 this.initEditor.defer(10, this);
18951 Roo.TaskMgr.start(task);
18956 onResize : function(w, h)
18958 Roo.log('resize: ' +w + ',' + h );
18959 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18963 if(typeof w == 'number'){
18965 this.iframe.style.width = w + 'px';
18967 if(typeof h == 'number'){
18969 this.iframe.style.height = h + 'px';
18971 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18978 * Toggles the editor between standard and source edit mode.
18979 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18981 toggleSourceEdit : function(sourceEditMode){
18983 this.sourceEditMode = sourceEditMode === true;
18985 if(this.sourceEditMode){
18987 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18990 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18991 //this.iframe.className = '';
18994 //this.setSize(this.owner.wrap.getSize());
18995 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19002 * Protected method that will not generally be called directly. If you need/want
19003 * custom HTML cleanup, this is the method you should override.
19004 * @param {String} html The HTML to be cleaned
19005 * return {String} The cleaned HTML
19007 cleanHtml : function(html){
19008 html = String(html);
19009 if(html.length > 5){
19010 if(Roo.isSafari){ // strip safari nonsense
19011 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19014 if(html == ' '){
19021 * HTML Editor -> Textarea
19022 * Protected method that will not generally be called directly. Syncs the contents
19023 * of the editor iframe with the textarea.
19025 syncValue : function(){
19026 if(this.initialized){
19027 var bd = (this.doc.body || this.doc.documentElement);
19028 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19029 var html = bd.innerHTML;
19031 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19032 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19034 html = '<div style="'+m[0]+'">' + html + '</div>';
19037 html = this.cleanHtml(html);
19038 // fix up the special chars.. normaly like back quotes in word...
19039 // however we do not want to do this with chinese..
19040 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19041 var cc = b.charCodeAt();
19043 (cc >= 0x4E00 && cc < 0xA000 ) ||
19044 (cc >= 0x3400 && cc < 0x4E00 ) ||
19045 (cc >= 0xf900 && cc < 0xfb00 )
19051 if(this.owner.fireEvent('beforesync', this, html) !== false){
19052 this.el.dom.value = html;
19053 this.owner.fireEvent('sync', this, html);
19059 * Protected method that will not generally be called directly. Pushes the value of the textarea
19060 * into the iframe editor.
19062 pushValue : function(){
19063 if(this.initialized){
19064 var v = this.el.dom.value.trim();
19066 // if(v.length < 1){
19070 if(this.owner.fireEvent('beforepush', this, v) !== false){
19071 var d = (this.doc.body || this.doc.documentElement);
19073 this.cleanUpPaste();
19074 this.el.dom.value = d.innerHTML;
19075 this.owner.fireEvent('push', this, v);
19081 deferFocus : function(){
19082 this.focus.defer(10, this);
19086 focus : function(){
19087 if(this.win && !this.sourceEditMode){
19094 assignDocWin: function()
19096 var iframe = this.iframe;
19099 this.doc = iframe.contentWindow.document;
19100 this.win = iframe.contentWindow;
19102 // if (!Roo.get(this.frameId)) {
19105 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19106 // this.win = Roo.get(this.frameId).dom.contentWindow;
19108 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
19112 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19113 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
19118 initEditor : function(){
19119 //console.log("INIT EDITOR");
19120 this.assignDocWin();
19124 this.doc.designMode="on";
19126 this.doc.write(this.getDocMarkup());
19129 var dbody = (this.doc.body || this.doc.documentElement);
19130 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
19131 // this copies styles from the containing element into thsi one..
19132 // not sure why we need all of this..
19133 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
19135 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
19136 //ss['background-attachment'] = 'fixed'; // w3c
19137 dbody.bgProperties = 'fixed'; // ie
19138 //Roo.DomHelper.applyStyles(dbody, ss);
19139 Roo.EventManager.on(this.doc, {
19140 //'mousedown': this.onEditorEvent,
19141 'mouseup': this.onEditorEvent,
19142 'dblclick': this.onEditorEvent,
19143 'click': this.onEditorEvent,
19144 'keyup': this.onEditorEvent,
19149 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
19151 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
19152 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
19154 this.initialized = true;
19156 this.owner.fireEvent('initialize', this);
19161 onDestroy : function(){
19167 //for (var i =0; i < this.toolbars.length;i++) {
19168 // // fixme - ask toolbars for heights?
19169 // this.toolbars[i].onDestroy();
19172 //this.wrap.dom.innerHTML = '';
19173 //this.wrap.remove();
19178 onFirstFocus : function(){
19180 this.assignDocWin();
19183 this.activated = true;
19186 if(Roo.isGecko){ // prevent silly gecko errors
19188 var s = this.win.getSelection();
19189 if(!s.focusNode || s.focusNode.nodeType != 3){
19190 var r = s.getRangeAt(0);
19191 r.selectNodeContents((this.doc.body || this.doc.documentElement));
19196 this.execCmd('useCSS', true);
19197 this.execCmd('styleWithCSS', false);
19200 this.owner.fireEvent('activate', this);
19204 adjustFont: function(btn){
19205 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
19206 //if(Roo.isSafari){ // safari
19209 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
19210 if(Roo.isSafari){ // safari
19211 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
19212 v = (v < 10) ? 10 : v;
19213 v = (v > 48) ? 48 : v;
19214 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
19219 v = Math.max(1, v+adjust);
19221 this.execCmd('FontSize', v );
19224 onEditorEvent : function(e)
19226 this.owner.fireEvent('editorevent', this, e);
19227 // this.updateToolbar();
19228 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
19231 insertTag : function(tg)
19233 // could be a bit smarter... -> wrap the current selected tRoo..
19234 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
19236 range = this.createRange(this.getSelection());
19237 var wrappingNode = this.doc.createElement(tg.toLowerCase());
19238 wrappingNode.appendChild(range.extractContents());
19239 range.insertNode(wrappingNode);
19246 this.execCmd("formatblock", tg);
19250 insertText : function(txt)
19254 var range = this.createRange();
19255 range.deleteContents();
19256 //alert(Sender.getAttribute('label'));
19258 range.insertNode(this.doc.createTextNode(txt));
19264 * Executes a Midas editor command on the editor document and performs necessary focus and
19265 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
19266 * @param {String} cmd The Midas command
19267 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
19269 relayCmd : function(cmd, value){
19271 this.execCmd(cmd, value);
19272 this.owner.fireEvent('editorevent', this);
19273 //this.updateToolbar();
19274 this.owner.deferFocus();
19278 * Executes a Midas editor command directly on the editor document.
19279 * For visual commands, you should use {@link #relayCmd} instead.
19280 * <b>This should only be called after the editor is initialized.</b>
19281 * @param {String} cmd The Midas command
19282 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
19284 execCmd : function(cmd, value){
19285 this.doc.execCommand(cmd, false, value === undefined ? null : value);
19292 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
19294 * @param {String} text | dom node..
19296 insertAtCursor : function(text)
19301 if(!this.activated){
19307 var r = this.doc.selection.createRange();
19318 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
19322 // from jquery ui (MIT licenced)
19324 var win = this.win;
19326 if (win.getSelection && win.getSelection().getRangeAt) {
19327 range = win.getSelection().getRangeAt(0);
19328 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
19329 range.insertNode(node);
19330 } else if (win.document.selection && win.document.selection.createRange) {
19331 // no firefox support
19332 var txt = typeof(text) == 'string' ? text : text.outerHTML;
19333 win.document.selection.createRange().pasteHTML(txt);
19335 // no firefox support
19336 var txt = typeof(text) == 'string' ? text : text.outerHTML;
19337 this.execCmd('InsertHTML', txt);
19346 mozKeyPress : function(e){
19348 var c = e.getCharCode(), cmd;
19351 c = String.fromCharCode(c).toLowerCase();
19365 this.cleanUpPaste.defer(100, this);
19373 e.preventDefault();
19381 fixKeys : function(){ // load time branching for fastest keydown performance
19383 return function(e){
19384 var k = e.getKey(), r;
19387 r = this.doc.selection.createRange();
19390 r.pasteHTML('    ');
19397 r = this.doc.selection.createRange();
19399 var target = r.parentElement();
19400 if(!target || target.tagName.toLowerCase() != 'li'){
19402 r.pasteHTML('<br />');
19408 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19409 this.cleanUpPaste.defer(100, this);
19415 }else if(Roo.isOpera){
19416 return function(e){
19417 var k = e.getKey();
19421 this.execCmd('InsertHTML','    ');
19424 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19425 this.cleanUpPaste.defer(100, this);
19430 }else if(Roo.isSafari){
19431 return function(e){
19432 var k = e.getKey();
19436 this.execCmd('InsertText','\t');
19440 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19441 this.cleanUpPaste.defer(100, this);
19449 getAllAncestors: function()
19451 var p = this.getSelectedNode();
19454 a.push(p); // push blank onto stack..
19455 p = this.getParentElement();
19459 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
19463 a.push(this.doc.body);
19467 lastSelNode : false,
19470 getSelection : function()
19472 this.assignDocWin();
19473 return Roo.isIE ? this.doc.selection : this.win.getSelection();
19476 getSelectedNode: function()
19478 // this may only work on Gecko!!!
19480 // should we cache this!!!!
19485 var range = this.createRange(this.getSelection()).cloneRange();
19488 var parent = range.parentElement();
19490 var testRange = range.duplicate();
19491 testRange.moveToElementText(parent);
19492 if (testRange.inRange(range)) {
19495 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
19498 parent = parent.parentElement;
19503 // is ancestor a text element.
19504 var ac = range.commonAncestorContainer;
19505 if (ac.nodeType == 3) {
19506 ac = ac.parentNode;
19509 var ar = ac.childNodes;
19512 var other_nodes = [];
19513 var has_other_nodes = false;
19514 for (var i=0;i<ar.length;i++) {
19515 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
19518 // fullly contained node.
19520 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
19525 // probably selected..
19526 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
19527 other_nodes.push(ar[i]);
19531 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
19536 has_other_nodes = true;
19538 if (!nodes.length && other_nodes.length) {
19539 nodes= other_nodes;
19541 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
19547 createRange: function(sel)
19549 // this has strange effects when using with
19550 // top toolbar - not sure if it's a great idea.
19551 //this.editor.contentWindow.focus();
19552 if (typeof sel != "undefined") {
19554 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
19556 return this.doc.createRange();
19559 return this.doc.createRange();
19562 getParentElement: function()
19565 this.assignDocWin();
19566 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
19568 var range = this.createRange(sel);
19571 var p = range.commonAncestorContainer;
19572 while (p.nodeType == 3) { // text node
19583 * Range intersection.. the hard stuff...
19587 * [ -- selected range --- ]
19591 * if end is before start or hits it. fail.
19592 * if start is after end or hits it fail.
19594 * if either hits (but other is outside. - then it's not
19600 // @see http://www.thismuchiknow.co.uk/?p=64.
19601 rangeIntersectsNode : function(range, node)
19603 var nodeRange = node.ownerDocument.createRange();
19605 nodeRange.selectNode(node);
19607 nodeRange.selectNodeContents(node);
19610 var rangeStartRange = range.cloneRange();
19611 rangeStartRange.collapse(true);
19613 var rangeEndRange = range.cloneRange();
19614 rangeEndRange.collapse(false);
19616 var nodeStartRange = nodeRange.cloneRange();
19617 nodeStartRange.collapse(true);
19619 var nodeEndRange = nodeRange.cloneRange();
19620 nodeEndRange.collapse(false);
19622 return rangeStartRange.compareBoundaryPoints(
19623 Range.START_TO_START, nodeEndRange) == -1 &&
19624 rangeEndRange.compareBoundaryPoints(
19625 Range.START_TO_START, nodeStartRange) == 1;
19629 rangeCompareNode : function(range, node)
19631 var nodeRange = node.ownerDocument.createRange();
19633 nodeRange.selectNode(node);
19635 nodeRange.selectNodeContents(node);
19639 range.collapse(true);
19641 nodeRange.collapse(true);
19643 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19644 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19646 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19648 var nodeIsBefore = ss == 1;
19649 var nodeIsAfter = ee == -1;
19651 if (nodeIsBefore && nodeIsAfter)
19653 if (!nodeIsBefore && nodeIsAfter)
19654 return 1; //right trailed.
19656 if (nodeIsBefore && !nodeIsAfter)
19657 return 2; // left trailed.
19662 // private? - in a new class?
19663 cleanUpPaste : function()
19665 // cleans up the whole document..
19666 Roo.log('cleanuppaste');
19668 this.cleanUpChildren(this.doc.body);
19669 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19670 if (clean != this.doc.body.innerHTML) {
19671 this.doc.body.innerHTML = clean;
19676 cleanWordChars : function(input) {// change the chars to hex code
19677 var he = Roo.HtmlEditorCore;
19679 var output = input;
19680 Roo.each(he.swapCodes, function(sw) {
19681 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19683 output = output.replace(swapper, sw[1]);
19690 cleanUpChildren : function (n)
19692 if (!n.childNodes.length) {
19695 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19696 this.cleanUpChild(n.childNodes[i]);
19703 cleanUpChild : function (node)
19706 //console.log(node);
19707 if (node.nodeName == "#text") {
19708 // clean up silly Windows -- stuff?
19711 if (node.nodeName == "#comment") {
19712 node.parentNode.removeChild(node);
19713 // clean up silly Windows -- stuff?
19716 var lcname = node.tagName.toLowerCase();
19717 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19718 // whitelist of tags..
19720 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19722 node.parentNode.removeChild(node);
19727 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19729 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19730 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19732 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19733 // remove_keep_children = true;
19736 if (remove_keep_children) {
19737 this.cleanUpChildren(node);
19738 // inserts everything just before this node...
19739 while (node.childNodes.length) {
19740 var cn = node.childNodes[0];
19741 node.removeChild(cn);
19742 node.parentNode.insertBefore(cn, node);
19744 node.parentNode.removeChild(node);
19748 if (!node.attributes || !node.attributes.length) {
19749 this.cleanUpChildren(node);
19753 function cleanAttr(n,v)
19756 if (v.match(/^\./) || v.match(/^\//)) {
19759 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19762 if (v.match(/^#/)) {
19765 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19766 node.removeAttribute(n);
19770 var cwhite = this.cwhite;
19771 var cblack = this.cblack;
19773 function cleanStyle(n,v)
19775 if (v.match(/expression/)) { //XSS?? should we even bother..
19776 node.removeAttribute(n);
19780 var parts = v.split(/;/);
19783 Roo.each(parts, function(p) {
19784 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19788 var l = p.split(':').shift().replace(/\s+/g,'');
19789 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19791 if ( cwhite.length && cblack.indexOf(l) > -1) {
19792 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19793 //node.removeAttribute(n);
19797 // only allow 'c whitelisted system attributes'
19798 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19799 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19800 //node.removeAttribute(n);
19810 if (clean.length) {
19811 node.setAttribute(n, clean.join(';'));
19813 node.removeAttribute(n);
19819 for (var i = node.attributes.length-1; i > -1 ; i--) {
19820 var a = node.attributes[i];
19823 if (a.name.toLowerCase().substr(0,2)=='on') {
19824 node.removeAttribute(a.name);
19827 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19828 node.removeAttribute(a.name);
19831 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19832 cleanAttr(a.name,a.value); // fixme..
19835 if (a.name == 'style') {
19836 cleanStyle(a.name,a.value);
19839 /// clean up MS crap..
19840 // tecnically this should be a list of valid class'es..
19843 if (a.name == 'class') {
19844 if (a.value.match(/^Mso/)) {
19845 node.className = '';
19848 if (a.value.match(/body/)) {
19849 node.className = '';
19860 this.cleanUpChildren(node);
19866 * Clean up MS wordisms...
19868 cleanWord : function(node)
19873 this.cleanWord(this.doc.body);
19876 if (node.nodeName == "#text") {
19877 // clean up silly Windows -- stuff?
19880 if (node.nodeName == "#comment") {
19881 node.parentNode.removeChild(node);
19882 // clean up silly Windows -- stuff?
19886 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19887 node.parentNode.removeChild(node);
19891 // remove - but keep children..
19892 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19893 while (node.childNodes.length) {
19894 var cn = node.childNodes[0];
19895 node.removeChild(cn);
19896 node.parentNode.insertBefore(cn, node);
19898 node.parentNode.removeChild(node);
19899 this.iterateChildren(node, this.cleanWord);
19903 if (node.className.length) {
19905 var cn = node.className.split(/\W+/);
19907 Roo.each(cn, function(cls) {
19908 if (cls.match(/Mso[a-zA-Z]+/)) {
19913 node.className = cna.length ? cna.join(' ') : '';
19915 node.removeAttribute("class");
19919 if (node.hasAttribute("lang")) {
19920 node.removeAttribute("lang");
19923 if (node.hasAttribute("style")) {
19925 var styles = node.getAttribute("style").split(";");
19927 Roo.each(styles, function(s) {
19928 if (!s.match(/:/)) {
19931 var kv = s.split(":");
19932 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19935 // what ever is left... we allow.
19938 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19939 if (!nstyle.length) {
19940 node.removeAttribute('style');
19943 this.iterateChildren(node, this.cleanWord);
19949 * iterateChildren of a Node, calling fn each time, using this as the scole..
19950 * @param {DomNode} node node to iterate children of.
19951 * @param {Function} fn method of this class to call on each item.
19953 iterateChildren : function(node, fn)
19955 if (!node.childNodes.length) {
19958 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19959 fn.call(this, node.childNodes[i])
19965 * cleanTableWidths.
19967 * Quite often pasting from word etc.. results in tables with column and widths.
19968 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19971 cleanTableWidths : function(node)
19976 this.cleanTableWidths(this.doc.body);
19981 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19984 Roo.log(node.tagName);
19985 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19986 this.iterateChildren(node, this.cleanTableWidths);
19989 if (node.hasAttribute('width')) {
19990 node.removeAttribute('width');
19994 if (node.hasAttribute("style")) {
19997 var styles = node.getAttribute("style").split(";");
19999 Roo.each(styles, function(s) {
20000 if (!s.match(/:/)) {
20003 var kv = s.split(":");
20004 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20007 // what ever is left... we allow.
20010 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20011 if (!nstyle.length) {
20012 node.removeAttribute('style');
20016 this.iterateChildren(node, this.cleanTableWidths);
20024 domToHTML : function(currentElement, depth, nopadtext) {
20026 depth = depth || 0;
20027 nopadtext = nopadtext || false;
20029 if (!currentElement) {
20030 return this.domToHTML(this.doc.body);
20033 //Roo.log(currentElement);
20035 var allText = false;
20036 var nodeName = currentElement.nodeName;
20037 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20039 if (nodeName == '#text') {
20041 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20046 if (nodeName != 'BODY') {
20049 // Prints the node tagName, such as <A>, <IMG>, etc
20052 for(i = 0; i < currentElement.attributes.length;i++) {
20054 var aname = currentElement.attributes.item(i).name;
20055 if (!currentElement.attributes.item(i).value.length) {
20058 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20061 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20070 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20073 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20078 // Traverse the tree
20080 var currentElementChild = currentElement.childNodes.item(i);
20081 var allText = true;
20082 var innerHTML = '';
20084 while (currentElementChild) {
20085 // Formatting code (indent the tree so it looks nice on the screen)
20086 var nopad = nopadtext;
20087 if (lastnode == 'SPAN') {
20091 if (currentElementChild.nodeName == '#text') {
20092 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
20093 toadd = nopadtext ? toadd : toadd.trim();
20094 if (!nopad && toadd.length > 80) {
20095 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
20097 innerHTML += toadd;
20100 currentElementChild = currentElement.childNodes.item(i);
20106 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
20108 // Recursively traverse the tree structure of the child node
20109 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
20110 lastnode = currentElementChild.nodeName;
20112 currentElementChild=currentElement.childNodes.item(i);
20118 // The remaining code is mostly for formatting the tree
20119 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
20124 ret+= "</"+tagName+">";
20130 applyBlacklists : function()
20132 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
20133 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
20137 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
20138 if (b.indexOf(tag) > -1) {
20141 this.white.push(tag);
20145 Roo.each(w, function(tag) {
20146 if (b.indexOf(tag) > -1) {
20149 if (this.white.indexOf(tag) > -1) {
20152 this.white.push(tag);
20157 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
20158 if (w.indexOf(tag) > -1) {
20161 this.black.push(tag);
20165 Roo.each(b, function(tag) {
20166 if (w.indexOf(tag) > -1) {
20169 if (this.black.indexOf(tag) > -1) {
20172 this.black.push(tag);
20177 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
20178 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
20182 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
20183 if (b.indexOf(tag) > -1) {
20186 this.cwhite.push(tag);
20190 Roo.each(w, function(tag) {
20191 if (b.indexOf(tag) > -1) {
20194 if (this.cwhite.indexOf(tag) > -1) {
20197 this.cwhite.push(tag);
20202 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
20203 if (w.indexOf(tag) > -1) {
20206 this.cblack.push(tag);
20210 Roo.each(b, function(tag) {
20211 if (w.indexOf(tag) > -1) {
20214 if (this.cblack.indexOf(tag) > -1) {
20217 this.cblack.push(tag);
20222 setStylesheets : function(stylesheets)
20224 if(typeof(stylesheets) == 'string'){
20225 Roo.get(this.iframe.contentDocument.head).createChild({
20227 rel : 'stylesheet',
20236 Roo.each(stylesheets, function(s) {
20241 Roo.get(_this.iframe.contentDocument.head).createChild({
20243 rel : 'stylesheet',
20252 removeStylesheets : function()
20256 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
20261 // hide stuff that is not compatible
20275 * @event specialkey
20279 * @cfg {String} fieldClass @hide
20282 * @cfg {String} focusClass @hide
20285 * @cfg {String} autoCreate @hide
20288 * @cfg {String} inputType @hide
20291 * @cfg {String} invalidClass @hide
20294 * @cfg {String} invalidText @hide
20297 * @cfg {String} msgFx @hide
20300 * @cfg {String} validateOnBlur @hide
20304 Roo.HtmlEditorCore.white = [
20305 'area', 'br', 'img', 'input', 'hr', 'wbr',
20307 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
20308 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
20309 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
20310 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
20311 'table', 'ul', 'xmp',
20313 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
20316 'dir', 'menu', 'ol', 'ul', 'dl',
20322 Roo.HtmlEditorCore.black = [
20323 // 'embed', 'object', // enable - backend responsiblity to clean thiese
20325 'base', 'basefont', 'bgsound', 'blink', 'body',
20326 'frame', 'frameset', 'head', 'html', 'ilayer',
20327 'iframe', 'layer', 'link', 'meta', 'object',
20328 'script', 'style' ,'title', 'xml' // clean later..
20330 Roo.HtmlEditorCore.clean = [
20331 'script', 'style', 'title', 'xml'
20333 Roo.HtmlEditorCore.remove = [
20338 Roo.HtmlEditorCore.ablack = [
20342 Roo.HtmlEditorCore.aclean = [
20343 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
20347 Roo.HtmlEditorCore.pwhite= [
20348 'http', 'https', 'mailto'
20351 // white listed style attributes.
20352 Roo.HtmlEditorCore.cwhite= [
20353 // 'text-align', /// default is to allow most things..
20359 // black listed style attributes.
20360 Roo.HtmlEditorCore.cblack= [
20361 // 'font-size' -- this can be set by the project
20365 Roo.HtmlEditorCore.swapCodes =[
20384 * @class Roo.bootstrap.HtmlEditor
20385 * @extends Roo.bootstrap.TextArea
20386 * Bootstrap HtmlEditor class
20389 * Create a new HtmlEditor
20390 * @param {Object} config The config object
20393 Roo.bootstrap.HtmlEditor = function(config){
20394 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
20395 if (!this.toolbars) {
20396 this.toolbars = [];
20398 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
20401 * @event initialize
20402 * Fires when the editor is fully initialized (including the iframe)
20403 * @param {HtmlEditor} this
20408 * Fires when the editor is first receives the focus. Any insertion must wait
20409 * until after this event.
20410 * @param {HtmlEditor} this
20414 * @event beforesync
20415 * Fires before the textarea is updated with content from the editor iframe. Return false
20416 * to cancel the sync.
20417 * @param {HtmlEditor} this
20418 * @param {String} html
20422 * @event beforepush
20423 * Fires before the iframe editor is updated with content from the textarea. Return false
20424 * to cancel the push.
20425 * @param {HtmlEditor} this
20426 * @param {String} html
20431 * Fires when the textarea is updated with content from the editor iframe.
20432 * @param {HtmlEditor} this
20433 * @param {String} html
20438 * Fires when the iframe editor is updated with content from the textarea.
20439 * @param {HtmlEditor} this
20440 * @param {String} html
20444 * @event editmodechange
20445 * Fires when the editor switches edit modes
20446 * @param {HtmlEditor} this
20447 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
20449 editmodechange: true,
20451 * @event editorevent
20452 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20453 * @param {HtmlEditor} this
20457 * @event firstfocus
20458 * Fires when on first focus - needed by toolbars..
20459 * @param {HtmlEditor} this
20464 * Auto save the htmlEditor value as a file into Events
20465 * @param {HtmlEditor} this
20469 * @event savedpreview
20470 * preview the saved version of htmlEditor
20471 * @param {HtmlEditor} this
20478 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
20482 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
20487 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20492 * @cfg {Number} height (in pixels)
20496 * @cfg {Number} width (in pixels)
20501 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20504 stylesheets: false,
20509 // private properties
20510 validationEvent : false,
20512 initialized : false,
20515 onFocus : Roo.emptyFn,
20517 hideMode:'offsets',
20520 tbContainer : false,
20522 toolbarContainer :function() {
20523 return this.wrap.select('.x-html-editor-tb',true).first();
20527 * Protected method that will not generally be called directly. It
20528 * is called when the editor creates its toolbar. Override this method if you need to
20529 * add custom toolbar buttons.
20530 * @param {HtmlEditor} editor
20532 createToolbar : function(){
20534 Roo.log("create toolbars");
20536 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
20537 this.toolbars[0].render(this.toolbarContainer());
20541 // if (!editor.toolbars || !editor.toolbars.length) {
20542 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
20545 // for (var i =0 ; i < editor.toolbars.length;i++) {
20546 // editor.toolbars[i] = Roo.factory(
20547 // typeof(editor.toolbars[i]) == 'string' ?
20548 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
20549 // Roo.bootstrap.HtmlEditor);
20550 // editor.toolbars[i].init(editor);
20556 onRender : function(ct, position)
20558 // Roo.log("Call onRender: " + this.xtype);
20560 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
20562 this.wrap = this.inputEl().wrap({
20563 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
20566 this.editorcore.onRender(ct, position);
20568 if (this.resizable) {
20569 this.resizeEl = new Roo.Resizable(this.wrap, {
20573 minHeight : this.height,
20574 height: this.height,
20575 handles : this.resizable,
20578 resize : function(r, w, h) {
20579 _t.onResize(w,h); // -something
20585 this.createToolbar(this);
20588 if(!this.width && this.resizable){
20589 this.setSize(this.wrap.getSize());
20591 if (this.resizeEl) {
20592 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
20593 // should trigger onReize..
20599 onResize : function(w, h)
20601 Roo.log('resize: ' +w + ',' + h );
20602 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20606 if(this.inputEl() ){
20607 if(typeof w == 'number'){
20608 var aw = w - this.wrap.getFrameWidth('lr');
20609 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20612 if(typeof h == 'number'){
20613 var tbh = -11; // fixme it needs to tool bar size!
20614 for (var i =0; i < this.toolbars.length;i++) {
20615 // fixme - ask toolbars for heights?
20616 tbh += this.toolbars[i].el.getHeight();
20617 //if (this.toolbars[i].footer) {
20618 // tbh += this.toolbars[i].footer.el.getHeight();
20626 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20627 ah -= 5; // knock a few pixes off for look..
20628 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20632 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20633 this.editorcore.onResize(ew,eh);
20638 * Toggles the editor between standard and source edit mode.
20639 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20641 toggleSourceEdit : function(sourceEditMode)
20643 this.editorcore.toggleSourceEdit(sourceEditMode);
20645 if(this.editorcore.sourceEditMode){
20646 Roo.log('editor - showing textarea');
20649 // Roo.log(this.syncValue());
20651 this.inputEl().removeClass(['hide', 'x-hidden']);
20652 this.inputEl().dom.removeAttribute('tabIndex');
20653 this.inputEl().focus();
20655 Roo.log('editor - hiding textarea');
20657 // Roo.log(this.pushValue());
20660 this.inputEl().addClass(['hide', 'x-hidden']);
20661 this.inputEl().dom.setAttribute('tabIndex', -1);
20662 //this.deferFocus();
20665 if(this.resizable){
20666 this.setSize(this.wrap.getSize());
20669 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20672 // private (for BoxComponent)
20673 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20675 // private (for BoxComponent)
20676 getResizeEl : function(){
20680 // private (for BoxComponent)
20681 getPositionEl : function(){
20686 initEvents : function(){
20687 this.originalValue = this.getValue();
20691 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20694 // markInvalid : Roo.emptyFn,
20696 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20699 // clearInvalid : Roo.emptyFn,
20701 setValue : function(v){
20702 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20703 this.editorcore.pushValue();
20708 deferFocus : function(){
20709 this.focus.defer(10, this);
20713 focus : function(){
20714 this.editorcore.focus();
20720 onDestroy : function(){
20726 for (var i =0; i < this.toolbars.length;i++) {
20727 // fixme - ask toolbars for heights?
20728 this.toolbars[i].onDestroy();
20731 this.wrap.dom.innerHTML = '';
20732 this.wrap.remove();
20737 onFirstFocus : function(){
20738 //Roo.log("onFirstFocus");
20739 this.editorcore.onFirstFocus();
20740 for (var i =0; i < this.toolbars.length;i++) {
20741 this.toolbars[i].onFirstFocus();
20747 syncValue : function()
20749 this.editorcore.syncValue();
20752 pushValue : function()
20754 this.editorcore.pushValue();
20758 // hide stuff that is not compatible
20772 * @event specialkey
20776 * @cfg {String} fieldClass @hide
20779 * @cfg {String} focusClass @hide
20782 * @cfg {String} autoCreate @hide
20785 * @cfg {String} inputType @hide
20788 * @cfg {String} invalidClass @hide
20791 * @cfg {String} invalidText @hide
20794 * @cfg {String} msgFx @hide
20797 * @cfg {String} validateOnBlur @hide
20806 Roo.namespace('Roo.bootstrap.htmleditor');
20808 * @class Roo.bootstrap.HtmlEditorToolbar1
20813 new Roo.bootstrap.HtmlEditor({
20816 new Roo.bootstrap.HtmlEditorToolbar1({
20817 disable : { fonts: 1 , format: 1, ..., ... , ...],
20823 * @cfg {Object} disable List of elements to disable..
20824 * @cfg {Array} btns List of additional buttons.
20828 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20831 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20834 Roo.apply(this, config);
20836 // default disabled, based on 'good practice'..
20837 this.disable = this.disable || {};
20838 Roo.applyIf(this.disable, {
20841 specialElements : true
20843 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20845 this.editor = config.editor;
20846 this.editorcore = config.editor.editorcore;
20848 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20850 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20851 // dont call parent... till later.
20853 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20858 editorcore : false,
20863 "h1","h2","h3","h4","h5","h6",
20865 "abbr", "acronym", "address", "cite", "samp", "var",
20869 onRender : function(ct, position)
20871 // Roo.log("Call onRender: " + this.xtype);
20873 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20875 this.el.dom.style.marginBottom = '0';
20877 var editorcore = this.editorcore;
20878 var editor= this.editor;
20881 var btn = function(id,cmd , toggle, handler){
20883 var event = toggle ? 'toggle' : 'click';
20888 xns: Roo.bootstrap,
20891 enableToggle:toggle !== false,
20893 pressed : toggle ? false : null,
20896 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20897 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20906 xns: Roo.bootstrap,
20907 glyphicon : 'font',
20911 xns: Roo.bootstrap,
20915 Roo.each(this.formats, function(f) {
20916 style.menu.items.push({
20918 xns: Roo.bootstrap,
20919 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20924 editorcore.insertTag(this.tagname);
20931 children.push(style);
20934 btn('bold',false,true);
20935 btn('italic',false,true);
20936 btn('align-left', 'justifyleft',true);
20937 btn('align-center', 'justifycenter',true);
20938 btn('align-right' , 'justifyright',true);
20939 btn('link', false, false, function(btn) {
20940 //Roo.log("create link?");
20941 var url = prompt(this.createLinkText, this.defaultLinkValue);
20942 if(url && url != 'http:/'+'/'){
20943 this.editorcore.relayCmd('createlink', url);
20946 btn('list','insertunorderedlist',true);
20947 btn('pencil', false,true, function(btn){
20950 this.toggleSourceEdit(btn.pressed);
20956 xns: Roo.bootstrap,
20961 xns: Roo.bootstrap,
20966 cog.menu.items.push({
20968 xns: Roo.bootstrap,
20969 html : Clean styles,
20974 editorcore.insertTag(this.tagname);
20983 this.xtype = 'NavSimplebar';
20985 for(var i=0;i< children.length;i++) {
20987 this.buttons.add(this.addxtypeChild(children[i]));
20991 editor.on('editorevent', this.updateToolbar, this);
20993 onBtnClick : function(id)
20995 this.editorcore.relayCmd(id);
20996 this.editorcore.focus();
21000 * Protected method that will not generally be called directly. It triggers
21001 * a toolbar update by reading the markup state of the current selection in the editor.
21003 updateToolbar: function(){
21005 if(!this.editorcore.activated){
21006 this.editor.onFirstFocus(); // is this neeed?
21010 var btns = this.buttons;
21011 var doc = this.editorcore.doc;
21012 btns.get('bold').setActive(doc.queryCommandState('bold'));
21013 btns.get('italic').setActive(doc.queryCommandState('italic'));
21014 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21016 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21017 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21018 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21020 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21021 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21024 var ans = this.editorcore.getAllAncestors();
21025 if (this.formatCombo) {
21028 var store = this.formatCombo.store;
21029 this.formatCombo.setValue("");
21030 for (var i =0; i < ans.length;i++) {
21031 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21033 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21041 // hides menus... - so this cant be on a menu...
21042 Roo.bootstrap.MenuMgr.hideAll();
21044 Roo.bootstrap.MenuMgr.hideAll();
21045 //this.editorsyncValue();
21047 onFirstFocus: function() {
21048 this.buttons.each(function(item){
21052 toggleSourceEdit : function(sourceEditMode){
21055 if(sourceEditMode){
21056 Roo.log("disabling buttons");
21057 this.buttons.each( function(item){
21058 if(item.cmd != 'pencil'){
21064 Roo.log("enabling buttons");
21065 if(this.editorcore.initialized){
21066 this.buttons.each( function(item){
21072 Roo.log("calling toggole on editor");
21073 // tell the editor that it's been pressed..
21074 this.editor.toggleSourceEdit(sourceEditMode);
21084 * @class Roo.bootstrap.Table.AbstractSelectionModel
21085 * @extends Roo.util.Observable
21086 * Abstract base class for grid SelectionModels. It provides the interface that should be
21087 * implemented by descendant classes. This class should not be directly instantiated.
21090 Roo.bootstrap.Table.AbstractSelectionModel = function(){
21091 this.locked = false;
21092 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
21096 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
21097 /** @ignore Called by the grid automatically. Do not call directly. */
21098 init : function(grid){
21104 * Locks the selections.
21107 this.locked = true;
21111 * Unlocks the selections.
21113 unlock : function(){
21114 this.locked = false;
21118 * Returns true if the selections are locked.
21119 * @return {Boolean}
21121 isLocked : function(){
21122 return this.locked;
21126 * @extends Roo.bootstrap.Table.AbstractSelectionModel
21127 * @class Roo.bootstrap.Table.RowSelectionModel
21128 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
21129 * It supports multiple selections and keyboard selection/navigation.
21131 * @param {Object} config
21134 Roo.bootstrap.Table.RowSelectionModel = function(config){
21135 Roo.apply(this, config);
21136 this.selections = new Roo.util.MixedCollection(false, function(o){
21141 this.lastActive = false;
21145 * @event selectionchange
21146 * Fires when the selection changes
21147 * @param {SelectionModel} this
21149 "selectionchange" : true,
21151 * @event afterselectionchange
21152 * Fires after the selection changes (eg. by key press or clicking)
21153 * @param {SelectionModel} this
21155 "afterselectionchange" : true,
21157 * @event beforerowselect
21158 * Fires when a row is selected being selected, return false to cancel.
21159 * @param {SelectionModel} this
21160 * @param {Number} rowIndex The selected index
21161 * @param {Boolean} keepExisting False if other selections will be cleared
21163 "beforerowselect" : true,
21166 * Fires when a row is selected.
21167 * @param {SelectionModel} this
21168 * @param {Number} rowIndex The selected index
21169 * @param {Roo.data.Record} r The record
21171 "rowselect" : true,
21173 * @event rowdeselect
21174 * Fires when a row is deselected.
21175 * @param {SelectionModel} this
21176 * @param {Number} rowIndex The selected index
21178 "rowdeselect" : true
21180 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
21181 this.locked = false;
21184 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
21186 * @cfg {Boolean} singleSelect
21187 * True to allow selection of only one row at a time (defaults to false)
21189 singleSelect : false,
21192 initEvents : function(){
21194 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
21195 this.grid.on("mousedown", this.handleMouseDown, this);
21196 }else{ // allow click to work like normal
21197 this.grid.on("rowclick", this.handleDragableRowClick, this);
21200 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
21201 "up" : function(e){
21203 this.selectPrevious(e.shiftKey);
21204 }else if(this.last !== false && this.lastActive !== false){
21205 var last = this.last;
21206 this.selectRange(this.last, this.lastActive-1);
21207 this.grid.getView().focusRow(this.lastActive);
21208 if(last !== false){
21212 this.selectFirstRow();
21214 this.fireEvent("afterselectionchange", this);
21216 "down" : function(e){
21218 this.selectNext(e.shiftKey);
21219 }else if(this.last !== false && this.lastActive !== false){
21220 var last = this.last;
21221 this.selectRange(this.last, this.lastActive+1);
21222 this.grid.getView().focusRow(this.lastActive);
21223 if(last !== false){
21227 this.selectFirstRow();
21229 this.fireEvent("afterselectionchange", this);
21234 var view = this.grid.view;
21235 view.on("refresh", this.onRefresh, this);
21236 view.on("rowupdated", this.onRowUpdated, this);
21237 view.on("rowremoved", this.onRemove, this);
21241 onRefresh : function(){
21242 var ds = this.grid.dataSource, i, v = this.grid.view;
21243 var s = this.selections;
21244 s.each(function(r){
21245 if((i = ds.indexOfId(r.id)) != -1){
21254 onRemove : function(v, index, r){
21255 this.selections.remove(r);
21259 onRowUpdated : function(v, index, r){
21260 if(this.isSelected(r)){
21261 v.onRowSelect(index);
21267 * @param {Array} records The records to select
21268 * @param {Boolean} keepExisting (optional) True to keep existing selections
21270 selectRecords : function(records, keepExisting){
21272 this.clearSelections();
21274 var ds = this.grid.dataSource;
21275 for(var i = 0, len = records.length; i < len; i++){
21276 this.selectRow(ds.indexOf(records[i]), true);
21281 * Gets the number of selected rows.
21284 getCount : function(){
21285 return this.selections.length;
21289 * Selects the first row in the grid.
21291 selectFirstRow : function(){
21296 * Select the last row.
21297 * @param {Boolean} keepExisting (optional) True to keep existing selections
21299 selectLastRow : function(keepExisting){
21300 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
21304 * Selects the row immediately following the last selected row.
21305 * @param {Boolean} keepExisting (optional) True to keep existing selections
21307 selectNext : function(keepExisting){
21308 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
21309 this.selectRow(this.last+1, keepExisting);
21310 this.grid.getView().focusRow(this.last);
21315 * Selects the row that precedes the last selected row.
21316 * @param {Boolean} keepExisting (optional) True to keep existing selections
21318 selectPrevious : function(keepExisting){
21320 this.selectRow(this.last-1, keepExisting);
21321 this.grid.getView().focusRow(this.last);
21326 * Returns the selected records
21327 * @return {Array} Array of selected records
21329 getSelections : function(){
21330 return [].concat(this.selections.items);
21334 * Returns the first selected record.
21337 getSelected : function(){
21338 return this.selections.itemAt(0);
21343 * Clears all selections.
21345 clearSelections : function(fast){
21346 if(this.locked) return;
21348 var ds = this.grid.dataSource;
21349 var s = this.selections;
21350 s.each(function(r){
21351 this.deselectRow(ds.indexOfId(r.id));
21355 this.selections.clear();
21362 * Selects all rows.
21364 selectAll : function(){
21365 if(this.locked) return;
21366 this.selections.clear();
21367 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
21368 this.selectRow(i, true);
21373 * Returns True if there is a selection.
21374 * @return {Boolean}
21376 hasSelection : function(){
21377 return this.selections.length > 0;
21381 * Returns True if the specified row is selected.
21382 * @param {Number/Record} record The record or index of the record to check
21383 * @return {Boolean}
21385 isSelected : function(index){
21386 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
21387 return (r && this.selections.key(r.id) ? true : false);
21391 * Returns True if the specified record id is selected.
21392 * @param {String} id The id of record to check
21393 * @return {Boolean}
21395 isIdSelected : function(id){
21396 return (this.selections.key(id) ? true : false);
21400 handleMouseDown : function(e, t){
21401 var view = this.grid.getView(), rowIndex;
21402 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
21405 if(e.shiftKey && this.last !== false){
21406 var last = this.last;
21407 this.selectRange(last, rowIndex, e.ctrlKey);
21408 this.last = last; // reset the last
21409 view.focusRow(rowIndex);
21411 var isSelected = this.isSelected(rowIndex);
21412 if(e.button !== 0 && isSelected){
21413 view.focusRow(rowIndex);
21414 }else if(e.ctrlKey && isSelected){
21415 this.deselectRow(rowIndex);
21416 }else if(!isSelected){
21417 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
21418 view.focusRow(rowIndex);
21421 this.fireEvent("afterselectionchange", this);
21424 handleDragableRowClick : function(grid, rowIndex, e)
21426 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
21427 this.selectRow(rowIndex, false);
21428 grid.view.focusRow(rowIndex);
21429 this.fireEvent("afterselectionchange", this);
21434 * Selects multiple rows.
21435 * @param {Array} rows Array of the indexes of the row to select
21436 * @param {Boolean} keepExisting (optional) True to keep existing selections
21438 selectRows : function(rows, keepExisting){
21440 this.clearSelections();
21442 for(var i = 0, len = rows.length; i < len; i++){
21443 this.selectRow(rows[i], true);
21448 * Selects a range of rows. All rows in between startRow and endRow are also selected.
21449 * @param {Number} startRow The index of the first row in the range
21450 * @param {Number} endRow The index of the last row in the range
21451 * @param {Boolean} keepExisting (optional) True to retain existing selections
21453 selectRange : function(startRow, endRow, keepExisting){
21454 if(this.locked) return;
21456 this.clearSelections();
21458 if(startRow <= endRow){
21459 for(var i = startRow; i <= endRow; i++){
21460 this.selectRow(i, true);
21463 for(var i = startRow; i >= endRow; i--){
21464 this.selectRow(i, true);
21470 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
21471 * @param {Number} startRow The index of the first row in the range
21472 * @param {Number} endRow The index of the last row in the range
21474 deselectRange : function(startRow, endRow, preventViewNotify){
21475 if(this.locked) return;
21476 for(var i = startRow; i <= endRow; i++){
21477 this.deselectRow(i, preventViewNotify);
21483 * @param {Number} row The index of the row to select
21484 * @param {Boolean} keepExisting (optional) True to keep existing selections
21486 selectRow : function(index, keepExisting, preventViewNotify){
21487 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
21488 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
21489 if(!keepExisting || this.singleSelect){
21490 this.clearSelections();
21492 var r = this.grid.dataSource.getAt(index);
21493 this.selections.add(r);
21494 this.last = this.lastActive = index;
21495 if(!preventViewNotify){
21496 this.grid.getView().onRowSelect(index);
21498 this.fireEvent("rowselect", this, index, r);
21499 this.fireEvent("selectionchange", this);
21505 * @param {Number} row The index of the row to deselect
21507 deselectRow : function(index, preventViewNotify){
21508 if(this.locked) return;
21509 if(this.last == index){
21512 if(this.lastActive == index){
21513 this.lastActive = false;
21515 var r = this.grid.dataSource.getAt(index);
21516 this.selections.remove(r);
21517 if(!preventViewNotify){
21518 this.grid.getView().onRowDeselect(index);
21520 this.fireEvent("rowdeselect", this, index);
21521 this.fireEvent("selectionchange", this);
21525 restoreLast : function(){
21527 this.last = this._last;
21532 acceptsNav : function(row, col, cm){
21533 return !cm.isHidden(col) && cm.isCellEditable(col, row);
21537 onEditorKey : function(field, e){
21538 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
21543 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
21545 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
21547 }else if(k == e.ENTER && !e.ctrlKey){
21551 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
21553 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
21555 }else if(k == e.ESC){
21559 g.startEditing(newCell[0], newCell[1]);
21564 * Ext JS Library 1.1.1
21565 * Copyright(c) 2006-2007, Ext JS, LLC.
21567 * Originally Released Under LGPL - original licence link has changed is not relivant.
21570 * <script type="text/javascript">
21574 * @class Roo.bootstrap.PagingToolbar
21576 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
21578 * Create a new PagingToolbar
21579 * @param {Object} config The config object
21581 Roo.bootstrap.PagingToolbar = function(config)
21583 // old args format still supported... - xtype is prefered..
21584 // created from xtype...
21585 var ds = config.dataSource;
21586 this.toolbarItems = [];
21587 if (config.items) {
21588 this.toolbarItems = config.items;
21589 // config.items = [];
21592 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
21599 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
21603 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21605 * @cfg {Roo.data.Store} dataSource
21606 * The underlying data store providing the paged data
21609 * @cfg {String/HTMLElement/Element} container
21610 * container The id or element that will contain the toolbar
21613 * @cfg {Boolean} displayInfo
21614 * True to display the displayMsg (defaults to false)
21617 * @cfg {Number} pageSize
21618 * The number of records to display per page (defaults to 20)
21622 * @cfg {String} displayMsg
21623 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21625 displayMsg : 'Displaying {0} - {1} of {2}',
21627 * @cfg {String} emptyMsg
21628 * The message to display when no records are found (defaults to "No data to display")
21630 emptyMsg : 'No data to display',
21632 * Customizable piece of the default paging text (defaults to "Page")
21635 beforePageText : "Page",
21637 * Customizable piece of the default paging text (defaults to "of %0")
21640 afterPageText : "of {0}",
21642 * Customizable piece of the default paging text (defaults to "First Page")
21645 firstText : "First Page",
21647 * Customizable piece of the default paging text (defaults to "Previous Page")
21650 prevText : "Previous Page",
21652 * Customizable piece of the default paging text (defaults to "Next Page")
21655 nextText : "Next Page",
21657 * Customizable piece of the default paging text (defaults to "Last Page")
21660 lastText : "Last Page",
21662 * Customizable piece of the default paging text (defaults to "Refresh")
21665 refreshText : "Refresh",
21669 onRender : function(ct, position)
21671 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21672 this.navgroup.parentId = this.id;
21673 this.navgroup.onRender(this.el, null);
21674 // add the buttons to the navgroup
21676 if(this.displayInfo){
21677 Roo.log(this.el.select('ul.navbar-nav',true).first());
21678 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21679 this.displayEl = this.el.select('.x-paging-info', true).first();
21680 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21681 // this.displayEl = navel.el.select('span',true).first();
21687 Roo.each(_this.buttons, function(e){
21688 Roo.factory(e).onRender(_this.el, null);
21692 Roo.each(_this.toolbarItems, function(e) {
21693 _this.navgroup.addItem(e);
21697 this.first = this.navgroup.addItem({
21698 tooltip: this.firstText,
21700 icon : 'fa fa-backward',
21702 preventDefault: true,
21703 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21706 this.prev = this.navgroup.addItem({
21707 tooltip: this.prevText,
21709 icon : 'fa fa-step-backward',
21711 preventDefault: true,
21712 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21714 //this.addSeparator();
21717 var field = this.navgroup.addItem( {
21719 cls : 'x-paging-position',
21721 html : this.beforePageText +
21722 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21723 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21726 this.field = field.el.select('input', true).first();
21727 this.field.on("keydown", this.onPagingKeydown, this);
21728 this.field.on("focus", function(){this.dom.select();});
21731 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21732 //this.field.setHeight(18);
21733 //this.addSeparator();
21734 this.next = this.navgroup.addItem({
21735 tooltip: this.nextText,
21737 html : ' <i class="fa fa-step-forward">',
21739 preventDefault: true,
21740 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21742 this.last = this.navgroup.addItem({
21743 tooltip: this.lastText,
21744 icon : 'fa fa-forward',
21747 preventDefault: true,
21748 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21750 //this.addSeparator();
21751 this.loading = this.navgroup.addItem({
21752 tooltip: this.refreshText,
21753 icon: 'fa fa-refresh',
21754 preventDefault: true,
21755 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21761 updateInfo : function(){
21762 if(this.displayEl){
21763 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21764 var msg = count == 0 ?
21768 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21770 this.displayEl.update(msg);
21775 onLoad : function(ds, r, o){
21776 this.cursor = o.params ? o.params.start : 0;
21777 var d = this.getPageData(),
21781 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21782 this.field.dom.value = ap;
21783 this.first.setDisabled(ap == 1);
21784 this.prev.setDisabled(ap == 1);
21785 this.next.setDisabled(ap == ps);
21786 this.last.setDisabled(ap == ps);
21787 this.loading.enable();
21792 getPageData : function(){
21793 var total = this.ds.getTotalCount();
21796 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21797 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21802 onLoadError : function(){
21803 this.loading.enable();
21807 onPagingKeydown : function(e){
21808 var k = e.getKey();
21809 var d = this.getPageData();
21811 var v = this.field.dom.value, pageNum;
21812 if(!v || isNaN(pageNum = parseInt(v, 10))){
21813 this.field.dom.value = d.activePage;
21816 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21817 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21820 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))
21822 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21823 this.field.dom.value = pageNum;
21824 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21827 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21829 var v = this.field.dom.value, pageNum;
21830 var increment = (e.shiftKey) ? 10 : 1;
21831 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21833 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21834 this.field.dom.value = d.activePage;
21837 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21839 this.field.dom.value = parseInt(v, 10) + increment;
21840 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21841 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21848 beforeLoad : function(){
21850 this.loading.disable();
21855 onClick : function(which){
21864 ds.load({params:{start: 0, limit: this.pageSize}});
21867 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21870 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21873 var total = ds.getTotalCount();
21874 var extra = total % this.pageSize;
21875 var lastStart = extra ? (total - extra) : total-this.pageSize;
21876 ds.load({params:{start: lastStart, limit: this.pageSize}});
21879 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21885 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21886 * @param {Roo.data.Store} store The data store to unbind
21888 unbind : function(ds){
21889 ds.un("beforeload", this.beforeLoad, this);
21890 ds.un("load", this.onLoad, this);
21891 ds.un("loadexception", this.onLoadError, this);
21892 ds.un("remove", this.updateInfo, this);
21893 ds.un("add", this.updateInfo, this);
21894 this.ds = undefined;
21898 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21899 * @param {Roo.data.Store} store The data store to bind
21901 bind : function(ds){
21902 ds.on("beforeload", this.beforeLoad, this);
21903 ds.on("load", this.onLoad, this);
21904 ds.on("loadexception", this.onLoadError, this);
21905 ds.on("remove", this.updateInfo, this);
21906 ds.on("add", this.updateInfo, this);
21917 * @class Roo.bootstrap.MessageBar
21918 * @extends Roo.bootstrap.Component
21919 * Bootstrap MessageBar class
21920 * @cfg {String} html contents of the MessageBar
21921 * @cfg {String} weight (info | success | warning | danger) default info
21922 * @cfg {String} beforeClass insert the bar before the given class
21923 * @cfg {Boolean} closable (true | false) default false
21924 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21927 * Create a new Element
21928 * @param {Object} config The config object
21931 Roo.bootstrap.MessageBar = function(config){
21932 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21935 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21941 beforeClass: 'bootstrap-sticky-wrap',
21943 getAutoCreate : function(){
21947 cls: 'alert alert-dismissable alert-' + this.weight,
21952 html: this.html || ''
21958 cfg.cls += ' alert-messages-fixed';
21972 onRender : function(ct, position)
21974 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21977 var cfg = Roo.apply({}, this.getAutoCreate());
21981 cfg.cls += ' ' + this.cls;
21984 cfg.style = this.style;
21986 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21988 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21991 this.el.select('>button.close').on('click', this.hide, this);
21997 if (!this.rendered) {
22003 this.fireEvent('show', this);
22009 if (!this.rendered) {
22015 this.fireEvent('hide', this);
22018 update : function()
22020 // var e = this.el.dom.firstChild;
22022 // if(this.closable){
22023 // e = e.nextSibling;
22026 // e.data = this.html || '';
22028 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22044 * @class Roo.bootstrap.Graph
22045 * @extends Roo.bootstrap.Component
22046 * Bootstrap Graph class
22050 @cfg {String} graphtype bar | vbar | pie
22051 @cfg {number} g_x coodinator | centre x (pie)
22052 @cfg {number} g_y coodinator | centre y (pie)
22053 @cfg {number} g_r radius (pie)
22054 @cfg {number} g_height height of the chart (respected by all elements in the set)
22055 @cfg {number} g_width width of the chart (respected by all elements in the set)
22056 @cfg {Object} title The title of the chart
22059 -opts (object) options for the chart
22061 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
22062 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
22064 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.
22065 o stacked (boolean) whether or not to tread values as in a stacked bar chart
22067 o stretch (boolean)
22069 -opts (object) options for the pie
22072 o startAngle (number)
22073 o endAngle (number)
22077 * Create a new Input
22078 * @param {Object} config The config object
22081 Roo.bootstrap.Graph = function(config){
22082 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
22088 * The img click event for the img.
22089 * @param {Roo.EventObject} e
22095 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
22106 //g_colors: this.colors,
22113 getAutoCreate : function(){
22124 onRender : function(ct,position){
22125 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
22126 this.raphael = Raphael(this.el.dom);
22128 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22129 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22130 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22131 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
22133 r.text(160, 10, "Single Series Chart").attr(txtattr);
22134 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
22135 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
22136 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
22138 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
22139 r.barchart(330, 10, 300, 220, data1);
22140 r.barchart(10, 250, 300, 220, data2, {stacked: true});
22141 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
22144 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22145 // r.barchart(30, 30, 560, 250, xdata, {
22146 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
22147 // axis : "0 0 1 1",
22148 // axisxlabels : xdata
22149 // //yvalues : cols,
22152 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22154 // this.load(null,xdata,{
22155 // axis : "0 0 1 1",
22156 // axisxlabels : xdata
22161 load : function(graphtype,xdata,opts){
22162 this.raphael.clear();
22164 graphtype = this.graphtype;
22169 var r = this.raphael,
22170 fin = function () {
22171 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
22173 fout = function () {
22174 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
22176 pfin = function() {
22177 this.sector.stop();
22178 this.sector.scale(1.1, 1.1, this.cx, this.cy);
22181 this.label[0].stop();
22182 this.label[0].attr({ r: 7.5 });
22183 this.label[1].attr({ "font-weight": 800 });
22186 pfout = function() {
22187 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
22190 this.label[0].animate({ r: 5 }, 500, "bounce");
22191 this.label[1].attr({ "font-weight": 400 });
22197 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
22200 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
22203 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
22204 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
22206 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
22213 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
22218 setTitle: function(o)
22223 initEvents: function() {
22226 this.el.on('click', this.onClick, this);
22230 onClick : function(e)
22232 Roo.log('img onclick');
22233 this.fireEvent('click', this, e);
22245 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22248 * @class Roo.bootstrap.dash.NumberBox
22249 * @extends Roo.bootstrap.Component
22250 * Bootstrap NumberBox class
22251 * @cfg {String} headline Box headline
22252 * @cfg {String} content Box content
22253 * @cfg {String} icon Box icon
22254 * @cfg {String} footer Footer text
22255 * @cfg {String} fhref Footer href
22258 * Create a new NumberBox
22259 * @param {Object} config The config object
22263 Roo.bootstrap.dash.NumberBox = function(config){
22264 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
22268 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
22277 getAutoCreate : function(){
22281 cls : 'small-box ',
22289 cls : 'roo-headline',
22290 html : this.headline
22294 cls : 'roo-content',
22295 html : this.content
22309 cls : 'ion ' + this.icon
22318 cls : 'small-box-footer',
22319 href : this.fhref || '#',
22323 cfg.cn.push(footer);
22330 onRender : function(ct,position){
22331 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
22338 setHeadline: function (value)
22340 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
22343 setFooter: function (value, href)
22345 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
22348 this.el.select('a.small-box-footer',true).first().attr('href', href);
22353 setContent: function (value)
22355 this.el.select('.roo-content',true).first().dom.innerHTML = value;
22358 initEvents: function()
22372 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22375 * @class Roo.bootstrap.dash.TabBox
22376 * @extends Roo.bootstrap.Component
22377 * Bootstrap TabBox class
22378 * @cfg {String} title Title of the TabBox
22379 * @cfg {String} icon Icon of the TabBox
22380 * @cfg {Boolean} showtabs (true|false) show the tabs default true
22381 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
22384 * Create a new TabBox
22385 * @param {Object} config The config object
22389 Roo.bootstrap.dash.TabBox = function(config){
22390 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
22395 * When a pane is added
22396 * @param {Roo.bootstrap.dash.TabPane} pane
22400 * @event activatepane
22401 * When a pane is activated
22402 * @param {Roo.bootstrap.dash.TabPane} pane
22404 "activatepane" : true
22412 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
22417 tabScrollable : false,
22419 getChildContainer : function()
22421 return this.el.select('.tab-content', true).first();
22424 getAutoCreate : function(){
22428 cls: 'pull-left header',
22436 cls: 'fa ' + this.icon
22442 cls: 'nav nav-tabs pull-right',
22448 if(this.tabScrollable){
22455 cls: 'nav nav-tabs pull-right',
22466 cls: 'nav-tabs-custom',
22471 cls: 'tab-content no-padding',
22479 initEvents : function()
22481 //Roo.log('add add pane handler');
22482 this.on('addpane', this.onAddPane, this);
22485 * Updates the box title
22486 * @param {String} html to set the title to.
22488 setTitle : function(value)
22490 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
22492 onAddPane : function(pane)
22494 this.panes.push(pane);
22495 //Roo.log('addpane');
22497 // tabs are rendere left to right..
22498 if(!this.showtabs){
22502 var ctr = this.el.select('.nav-tabs', true).first();
22505 var existing = ctr.select('.nav-tab',true);
22506 var qty = existing.getCount();;
22509 var tab = ctr.createChild({
22511 cls : 'nav-tab' + (qty ? '' : ' active'),
22519 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
22522 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
22524 pane.el.addClass('active');
22529 onTabClick : function(ev,un,ob,pane)
22531 //Roo.log('tab - prev default');
22532 ev.preventDefault();
22535 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
22536 pane.tab.addClass('active');
22537 //Roo.log(pane.title);
22538 this.getChildContainer().select('.tab-pane',true).removeClass('active');
22539 // technically we should have a deactivate event.. but maybe add later.
22540 // and it should not de-activate the selected tab...
22541 this.fireEvent('activatepane', pane);
22542 pane.el.addClass('active');
22543 pane.fireEvent('activate');
22548 getActivePane : function()
22551 Roo.each(this.panes, function(p) {
22552 if(p.el.hasClass('active')){
22573 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22575 * @class Roo.bootstrap.TabPane
22576 * @extends Roo.bootstrap.Component
22577 * Bootstrap TabPane class
22578 * @cfg {Boolean} active (false | true) Default false
22579 * @cfg {String} title title of panel
22583 * Create a new TabPane
22584 * @param {Object} config The config object
22587 Roo.bootstrap.dash.TabPane = function(config){
22588 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
22594 * When a pane is activated
22595 * @param {Roo.bootstrap.dash.TabPane} pane
22602 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22607 // the tabBox that this is attached to.
22610 getAutoCreate : function()
22618 cfg.cls += ' active';
22623 initEvents : function()
22625 //Roo.log('trigger add pane handler');
22626 this.parent().fireEvent('addpane', this)
22630 * Updates the tab title
22631 * @param {String} html to set the title to.
22633 setTitle: function(str)
22639 this.tab.select('a', true).first().dom.innerHTML = str;
22656 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22659 * @class Roo.bootstrap.menu.Menu
22660 * @extends Roo.bootstrap.Component
22661 * Bootstrap Menu class - container for Menu
22662 * @cfg {String} html Text of the menu
22663 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22664 * @cfg {String} icon Font awesome icon
22665 * @cfg {String} pos Menu align to (top | bottom) default bottom
22669 * Create a new Menu
22670 * @param {Object} config The config object
22674 Roo.bootstrap.menu.Menu = function(config){
22675 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22679 * @event beforeshow
22680 * Fires before this menu is displayed
22681 * @param {Roo.bootstrap.menu.Menu} this
22685 * @event beforehide
22686 * Fires before this menu is hidden
22687 * @param {Roo.bootstrap.menu.Menu} this
22692 * Fires after this menu is displayed
22693 * @param {Roo.bootstrap.menu.Menu} this
22698 * Fires after this menu is hidden
22699 * @param {Roo.bootstrap.menu.Menu} this
22704 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22705 * @param {Roo.bootstrap.menu.Menu} this
22706 * @param {Roo.EventObject} e
22713 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22717 weight : 'default',
22722 getChildContainer : function() {
22723 if(this.isSubMenu){
22727 return this.el.select('ul.dropdown-menu', true).first();
22730 getAutoCreate : function()
22735 cls : 'roo-menu-text',
22743 cls : 'fa ' + this.icon
22754 cls : 'dropdown-button btn btn-' + this.weight,
22759 cls : 'dropdown-toggle btn btn-' + this.weight,
22769 cls : 'dropdown-menu'
22775 if(this.pos == 'top'){
22776 cfg.cls += ' dropup';
22779 if(this.isSubMenu){
22782 cls : 'dropdown-menu'
22789 onRender : function(ct, position)
22791 this.isSubMenu = ct.hasClass('dropdown-submenu');
22793 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22796 initEvents : function()
22798 if(this.isSubMenu){
22802 this.hidden = true;
22804 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22805 this.triggerEl.on('click', this.onTriggerPress, this);
22807 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22808 this.buttonEl.on('click', this.onClick, this);
22814 if(this.isSubMenu){
22818 return this.el.select('ul.dropdown-menu', true).first();
22821 onClick : function(e)
22823 this.fireEvent("click", this, e);
22826 onTriggerPress : function(e)
22828 if (this.isVisible()) {
22835 isVisible : function(){
22836 return !this.hidden;
22841 this.fireEvent("beforeshow", this);
22843 this.hidden = false;
22844 this.el.addClass('open');
22846 Roo.get(document).on("mouseup", this.onMouseUp, this);
22848 this.fireEvent("show", this);
22855 this.fireEvent("beforehide", this);
22857 this.hidden = true;
22858 this.el.removeClass('open');
22860 Roo.get(document).un("mouseup", this.onMouseUp);
22862 this.fireEvent("hide", this);
22865 onMouseUp : function()
22879 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22882 * @class Roo.bootstrap.menu.Item
22883 * @extends Roo.bootstrap.Component
22884 * Bootstrap MenuItem class
22885 * @cfg {Boolean} submenu (true | false) default false
22886 * @cfg {String} html text of the item
22887 * @cfg {String} href the link
22888 * @cfg {Boolean} disable (true | false) default false
22889 * @cfg {Boolean} preventDefault (true | false) default true
22890 * @cfg {String} icon Font awesome icon
22891 * @cfg {String} pos Submenu align to (left | right) default right
22895 * Create a new Item
22896 * @param {Object} config The config object
22900 Roo.bootstrap.menu.Item = function(config){
22901 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22905 * Fires when the mouse is hovering over this menu
22906 * @param {Roo.bootstrap.menu.Item} this
22907 * @param {Roo.EventObject} e
22912 * Fires when the mouse exits this menu
22913 * @param {Roo.bootstrap.menu.Item} this
22914 * @param {Roo.EventObject} e
22920 * The raw click event for the entire grid.
22921 * @param {Roo.EventObject} e
22927 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22932 preventDefault: true,
22937 getAutoCreate : function()
22942 cls : 'roo-menu-item-text',
22950 cls : 'fa ' + this.icon
22959 href : this.href || '#',
22966 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22970 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22972 if(this.pos == 'left'){
22973 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22980 initEvents : function()
22982 this.el.on('mouseover', this.onMouseOver, this);
22983 this.el.on('mouseout', this.onMouseOut, this);
22985 this.el.select('a', true).first().on('click', this.onClick, this);
22989 onClick : function(e)
22991 if(this.preventDefault){
22992 e.preventDefault();
22995 this.fireEvent("click", this, e);
22998 onMouseOver : function(e)
23000 if(this.submenu && this.pos == 'left'){
23001 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23004 this.fireEvent("mouseover", this, e);
23007 onMouseOut : function(e)
23009 this.fireEvent("mouseout", this, e);
23021 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23024 * @class Roo.bootstrap.menu.Separator
23025 * @extends Roo.bootstrap.Component
23026 * Bootstrap Separator class
23029 * Create a new Separator
23030 * @param {Object} config The config object
23034 Roo.bootstrap.menu.Separator = function(config){
23035 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23038 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23040 getAutoCreate : function(){
23061 * @class Roo.bootstrap.Tooltip
23062 * Bootstrap Tooltip class
23063 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
23064 * to determine which dom element triggers the tooltip.
23066 * It needs to add support for additional attributes like tooltip-position
23069 * Create a new Toolti
23070 * @param {Object} config The config object
23073 Roo.bootstrap.Tooltip = function(config){
23074 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
23077 Roo.apply(Roo.bootstrap.Tooltip, {
23079 * @function init initialize tooltip monitoring.
23083 currentTip : false,
23084 currentRegion : false,
23090 Roo.get(document).on('mouseover', this.enter ,this);
23091 Roo.get(document).on('mouseout', this.leave, this);
23094 this.currentTip = new Roo.bootstrap.Tooltip();
23097 enter : function(ev)
23099 var dom = ev.getTarget();
23101 //Roo.log(['enter',dom]);
23102 var el = Roo.fly(dom);
23103 if (this.currentEl) {
23105 //Roo.log(this.currentEl);
23106 //Roo.log(this.currentEl.contains(dom));
23107 if (this.currentEl == el) {
23110 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
23118 if (this.currentTip.el) {
23119 this.currentTip.el.hide(); // force hiding...
23124 // you can not look for children, as if el is the body.. then everythign is the child..
23125 if (!el.attr('tooltip')) { //
23126 if (!el.select("[tooltip]").elements.length) {
23129 // is the mouse over this child...?
23130 bindEl = el.select("[tooltip]").first();
23131 var xy = ev.getXY();
23132 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
23133 //Roo.log("not in region.");
23136 //Roo.log("child element over..");
23139 this.currentEl = bindEl;
23140 this.currentTip.bind(bindEl);
23141 this.currentRegion = Roo.lib.Region.getRegion(dom);
23142 this.currentTip.enter();
23145 leave : function(ev)
23147 var dom = ev.getTarget();
23148 //Roo.log(['leave',dom]);
23149 if (!this.currentEl) {
23154 if (dom != this.currentEl.dom) {
23157 var xy = ev.getXY();
23158 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
23161 // only activate leave if mouse cursor is outside... bounding box..
23166 if (this.currentTip) {
23167 this.currentTip.leave();
23169 //Roo.log('clear currentEl');
23170 this.currentEl = false;
23175 'left' : ['r-l', [-2,0], 'right'],
23176 'right' : ['l-r', [2,0], 'left'],
23177 'bottom' : ['t-b', [0,2], 'top'],
23178 'top' : [ 'b-t', [0,-2], 'bottom']
23184 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
23189 delay : null, // can be { show : 300 , hide: 500}
23193 hoverState : null, //???
23195 placement : 'bottom',
23197 getAutoCreate : function(){
23204 cls : 'tooltip-arrow'
23207 cls : 'tooltip-inner'
23214 bind : function(el)
23220 enter : function () {
23222 if (this.timeout != null) {
23223 clearTimeout(this.timeout);
23226 this.hoverState = 'in';
23227 //Roo.log("enter - show");
23228 if (!this.delay || !this.delay.show) {
23233 this.timeout = setTimeout(function () {
23234 if (_t.hoverState == 'in') {
23237 }, this.delay.show);
23241 clearTimeout(this.timeout);
23243 this.hoverState = 'out';
23244 if (!this.delay || !this.delay.hide) {
23250 this.timeout = setTimeout(function () {
23251 //Roo.log("leave - timeout");
23253 if (_t.hoverState == 'out') {
23255 Roo.bootstrap.Tooltip.currentEl = false;
23263 this.render(document.body);
23266 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
23268 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
23270 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
23272 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
23274 var placement = typeof this.placement == 'function' ?
23275 this.placement.call(this, this.el, on_el) :
23278 var autoToken = /\s?auto?\s?/i;
23279 var autoPlace = autoToken.test(placement);
23281 placement = placement.replace(autoToken, '') || 'top';
23285 //this.el.setXY([0,0]);
23287 //this.el.dom.style.display='block';
23288 this.el.addClass(placement);
23290 //this.el.appendTo(on_el);
23292 var p = this.getPosition();
23293 var box = this.el.getBox();
23298 var align = Roo.bootstrap.Tooltip.alignment[placement];
23299 this.el.alignTo(this.bindEl, align[0],align[1]);
23300 //var arrow = this.el.select('.arrow',true).first();
23301 //arrow.set(align[2],
23303 this.el.addClass('in fade');
23304 this.hoverState = null;
23306 if (this.el.hasClass('fade')) {
23317 //this.el.setXY([0,0]);
23318 this.el.removeClass('in');
23334 * @class Roo.bootstrap.LocationPicker
23335 * @extends Roo.bootstrap.Component
23336 * Bootstrap LocationPicker class
23337 * @cfg {Number} latitude Position when init default 0
23338 * @cfg {Number} longitude Position when init default 0
23339 * @cfg {Number} zoom default 15
23340 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
23341 * @cfg {Boolean} mapTypeControl default false
23342 * @cfg {Boolean} disableDoubleClickZoom default false
23343 * @cfg {Boolean} scrollwheel default true
23344 * @cfg {Boolean} streetViewControl default false
23345 * @cfg {Number} radius default 0
23346 * @cfg {String} locationName
23347 * @cfg {Boolean} draggable default true
23348 * @cfg {Boolean} enableAutocomplete default false
23349 * @cfg {Boolean} enableReverseGeocode default true
23350 * @cfg {String} markerTitle
23353 * Create a new LocationPicker
23354 * @param {Object} config The config object
23358 Roo.bootstrap.LocationPicker = function(config){
23360 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
23365 * Fires when the picker initialized.
23366 * @param {Roo.bootstrap.LocationPicker} this
23367 * @param {Google Location} location
23371 * @event positionchanged
23372 * Fires when the picker position changed.
23373 * @param {Roo.bootstrap.LocationPicker} this
23374 * @param {Google Location} location
23376 positionchanged : true,
23379 * Fires when the map resize.
23380 * @param {Roo.bootstrap.LocationPicker} this
23385 * Fires when the map show.
23386 * @param {Roo.bootstrap.LocationPicker} this
23391 * Fires when the map hide.
23392 * @param {Roo.bootstrap.LocationPicker} this
23397 * Fires when click the map.
23398 * @param {Roo.bootstrap.LocationPicker} this
23399 * @param {Map event} e
23403 * @event mapRightClick
23404 * Fires when right click the map.
23405 * @param {Roo.bootstrap.LocationPicker} this
23406 * @param {Map event} e
23408 mapRightClick : true,
23410 * @event markerClick
23411 * Fires when click the marker.
23412 * @param {Roo.bootstrap.LocationPicker} this
23413 * @param {Map event} e
23415 markerClick : true,
23417 * @event markerRightClick
23418 * Fires when right click the marker.
23419 * @param {Roo.bootstrap.LocationPicker} this
23420 * @param {Map event} e
23422 markerRightClick : true,
23424 * @event OverlayViewDraw
23425 * Fires when OverlayView Draw
23426 * @param {Roo.bootstrap.LocationPicker} this
23428 OverlayViewDraw : true,
23430 * @event OverlayViewOnAdd
23431 * Fires when OverlayView Draw
23432 * @param {Roo.bootstrap.LocationPicker} this
23434 OverlayViewOnAdd : true,
23436 * @event OverlayViewOnRemove
23437 * Fires when OverlayView Draw
23438 * @param {Roo.bootstrap.LocationPicker} this
23440 OverlayViewOnRemove : true,
23442 * @event OverlayViewShow
23443 * Fires when OverlayView Draw
23444 * @param {Roo.bootstrap.LocationPicker} this
23445 * @param {Pixel} cpx
23447 OverlayViewShow : true,
23449 * @event OverlayViewHide
23450 * Fires when OverlayView Draw
23451 * @param {Roo.bootstrap.LocationPicker} this
23453 OverlayViewHide : true
23458 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
23460 gMapContext: false,
23466 mapTypeControl: false,
23467 disableDoubleClickZoom: false,
23469 streetViewControl: false,
23473 enableAutocomplete: false,
23474 enableReverseGeocode: true,
23477 getAutoCreate: function()
23482 cls: 'roo-location-picker'
23488 initEvents: function(ct, position)
23490 if(!this.el.getWidth() || this.isApplied()){
23494 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23499 initial: function()
23501 if(!this.mapTypeId){
23502 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
23505 this.gMapContext = this.GMapContext();
23507 this.initOverlayView();
23509 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
23513 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
23514 _this.setPosition(_this.gMapContext.marker.position);
23517 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
23518 _this.fireEvent('mapClick', this, event);
23522 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
23523 _this.fireEvent('mapRightClick', this, event);
23527 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
23528 _this.fireEvent('markerClick', this, event);
23532 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
23533 _this.fireEvent('markerRightClick', this, event);
23537 this.setPosition(this.gMapContext.location);
23539 this.fireEvent('initial', this, this.gMapContext.location);
23542 initOverlayView: function()
23546 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
23550 _this.fireEvent('OverlayViewDraw', _this);
23555 _this.fireEvent('OverlayViewOnAdd', _this);
23558 onRemove: function()
23560 _this.fireEvent('OverlayViewOnRemove', _this);
23563 show: function(cpx)
23565 _this.fireEvent('OverlayViewShow', _this, cpx);
23570 _this.fireEvent('OverlayViewHide', _this);
23576 fromLatLngToContainerPixel: function(event)
23578 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
23581 isApplied: function()
23583 return this.getGmapContext() == false ? false : true;
23586 getGmapContext: function()
23588 return this.gMapContext
23591 GMapContext: function()
23593 var position = new google.maps.LatLng(this.latitude, this.longitude);
23595 var _map = new google.maps.Map(this.el.dom, {
23598 mapTypeId: this.mapTypeId,
23599 mapTypeControl: this.mapTypeControl,
23600 disableDoubleClickZoom: this.disableDoubleClickZoom,
23601 scrollwheel: this.scrollwheel,
23602 streetViewControl: this.streetViewControl,
23603 locationName: this.locationName,
23604 draggable: this.draggable,
23605 enableAutocomplete: this.enableAutocomplete,
23606 enableReverseGeocode: this.enableReverseGeocode
23609 var _marker = new google.maps.Marker({
23610 position: position,
23612 title: this.markerTitle,
23613 draggable: this.draggable
23620 location: position,
23621 radius: this.radius,
23622 locationName: this.locationName,
23623 addressComponents: {
23624 formatted_address: null,
23625 addressLine1: null,
23626 addressLine2: null,
23628 streetNumber: null,
23632 stateOrProvince: null
23635 domContainer: this.el.dom,
23636 geodecoder: new google.maps.Geocoder()
23640 drawCircle: function(center, radius, options)
23642 if (this.gMapContext.circle != null) {
23643 this.gMapContext.circle.setMap(null);
23647 options = Roo.apply({}, options, {
23648 strokeColor: "#0000FF",
23649 strokeOpacity: .35,
23651 fillColor: "#0000FF",
23655 options.map = this.gMapContext.map;
23656 options.radius = radius;
23657 options.center = center;
23658 this.gMapContext.circle = new google.maps.Circle(options);
23659 return this.gMapContext.circle;
23665 setPosition: function(location)
23667 this.gMapContext.location = location;
23668 this.gMapContext.marker.setPosition(location);
23669 this.gMapContext.map.panTo(location);
23670 this.drawCircle(location, this.gMapContext.radius, {});
23674 if (this.gMapContext.settings.enableReverseGeocode) {
23675 this.gMapContext.geodecoder.geocode({
23676 latLng: this.gMapContext.location
23677 }, function(results, status) {
23679 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23680 _this.gMapContext.locationName = results[0].formatted_address;
23681 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23683 _this.fireEvent('positionchanged', this, location);
23690 this.fireEvent('positionchanged', this, location);
23695 google.maps.event.trigger(this.gMapContext.map, "resize");
23697 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23699 this.fireEvent('resize', this);
23702 setPositionByLatLng: function(latitude, longitude)
23704 this.setPosition(new google.maps.LatLng(latitude, longitude));
23707 getCurrentPosition: function()
23710 latitude: this.gMapContext.location.lat(),
23711 longitude: this.gMapContext.location.lng()
23715 getAddressName: function()
23717 return this.gMapContext.locationName;
23720 getAddressComponents: function()
23722 return this.gMapContext.addressComponents;
23725 address_component_from_google_geocode: function(address_components)
23729 for (var i = 0; i < address_components.length; i++) {
23730 var component = address_components[i];
23731 if (component.types.indexOf("postal_code") >= 0) {
23732 result.postalCode = component.short_name;
23733 } else if (component.types.indexOf("street_number") >= 0) {
23734 result.streetNumber = component.short_name;
23735 } else if (component.types.indexOf("route") >= 0) {
23736 result.streetName = component.short_name;
23737 } else if (component.types.indexOf("neighborhood") >= 0) {
23738 result.city = component.short_name;
23739 } else if (component.types.indexOf("locality") >= 0) {
23740 result.city = component.short_name;
23741 } else if (component.types.indexOf("sublocality") >= 0) {
23742 result.district = component.short_name;
23743 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23744 result.stateOrProvince = component.short_name;
23745 } else if (component.types.indexOf("country") >= 0) {
23746 result.country = component.short_name;
23750 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23751 result.addressLine2 = "";
23755 setZoomLevel: function(zoom)
23757 this.gMapContext.map.setZoom(zoom);
23770 this.fireEvent('show', this);
23781 this.fireEvent('hide', this);
23786 Roo.apply(Roo.bootstrap.LocationPicker, {
23788 OverlayView : function(map, options)
23790 options = options || {};
23804 * @class Roo.bootstrap.Alert
23805 * @extends Roo.bootstrap.Component
23806 * Bootstrap Alert class
23807 * @cfg {String} title The title of alert
23808 * @cfg {String} html The content of alert
23809 * @cfg {String} weight ( success | info | warning | danger )
23810 * @cfg {String} faicon font-awesomeicon
23813 * Create a new alert
23814 * @param {Object} config The config object
23818 Roo.bootstrap.Alert = function(config){
23819 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23823 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23830 getAutoCreate : function()
23839 cls : 'roo-alert-icon'
23844 cls : 'roo-alert-title',
23849 cls : 'roo-alert-text',
23856 cfg.cn[0].cls += ' fa ' + this.faicon;
23860 cfg.cls += ' alert-' + this.weight;
23866 initEvents: function()
23868 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23871 setTitle : function(str)
23873 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23876 setText : function(str)
23878 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23881 setWeight : function(weight)
23884 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23887 this.weight = weight;
23889 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23892 setIcon : function(icon)
23895 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23900 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);