4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
104 cfg.id = this.id || Roo.id();
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
129 this.el = ct.createChild(cfg, position);
132 this.tooltipEl().attr('tooltip', this.tooltip);
135 if(this.tabIndex !== undefined){
136 this.el.dom.setAttribute('tabIndex', this.tabIndex);
143 * Fetch the element to add children to
144 * @return {Roo.Element} defaults to this.el
146 getChildContainer : function()
151 * Fetch the element to display the tooltip on.
152 * @return {Roo.Element} defaults to this.el
154 tooltipEl : function()
159 addxtype : function(tree,cntr)
163 cn = Roo.factory(tree);
165 cn.parentType = this.xtype; //??
166 cn.parentId = this.id;
168 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
169 if (typeof(cn.container_method) == 'string') {
170 cntr = cn.container_method;
174 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
176 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
178 var build_from_html = Roo.XComponent.build_from_html;
180 var is_body = (tree.xtype == 'Body') ;
182 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
184 var self_cntr_el = Roo.get(this[cntr](false));
186 // do not try and build conditional elements
187 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
192 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
193 return this.addxtypeChild(tree,cntr);
196 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202 Roo.log('skipping render');
208 if (!build_from_html) {
212 // this i think handles overlaying multiple children of the same type
213 // with the sam eelement.. - which might be buggy..
215 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
221 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
230 addxtypeChild : function (tree, cntr)
232 Roo.debug && Roo.log('addxtypeChild:' + cntr);
234 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
237 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
238 (typeof(tree['flexy:foreach']) != 'undefined');
242 skip_children = false;
243 // render the element if it's not BODY.
244 if (tree.xtype != 'Body') {
246 cn = Roo.factory(tree);
248 cn.parentType = this.xtype; //??
249 cn.parentId = this.id;
251 var build_from_html = Roo.XComponent.build_from_html;
254 // does the container contain child eleemnts with 'xtype' attributes.
255 // that match this xtype..
256 // note - when we render we create these as well..
257 // so we should check to see if body has xtype set.
258 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
260 var self_cntr_el = Roo.get(this[cntr](false));
261 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
263 //Roo.log(Roo.XComponent.build_from_html);
264 //Roo.log("got echild:");
267 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
268 // and are not displayed -this causes this to use up the wrong element when matching.
269 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
272 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
273 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
279 //echild.dom.removeAttribute('xtype');
281 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
282 Roo.debug && Roo.log(self_cntr_el);
283 Roo.debug && Roo.log(echild);
284 Roo.debug && Roo.log(cn);
290 // if object has flexy:if - then it may or may not be rendered.
291 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
292 // skip a flexy if element.
293 Roo.debug && Roo.log('skipping render');
294 Roo.debug && Roo.log(tree);
296 Roo.debug && Roo.log('skipping all children');
297 skip_children = true;
302 // actually if flexy:foreach is found, we really want to create
303 // multiple copies here...
305 //Roo.log(this[cntr]());
306 cn.render(this[cntr](true));
308 // then add the element..
316 if (typeof (tree.menu) != 'undefined') {
317 tree.menu.parentType = cn.xtype;
318 tree.menu.triggerEl = cn.el;
319 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
323 if (!tree.items || !tree.items.length) {
327 var items = tree.items;
330 //Roo.log(items.length);
332 if (!skip_children) {
333 for(var i =0;i < items.length;i++) {
334 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
340 this.fireEvent('childrenrendered', this);
345 * Show a component - removes 'hidden' class
350 this.el.removeClass('hidden');
354 * Hide a component - adds 'hidden' class
358 if (this.el && !this.el.hasClass('hidden')) {
359 this.el.addClass('hidden');
373 * @class Roo.bootstrap.Body
374 * @extends Roo.bootstrap.Component
375 * Bootstrap Body class
379 * @param {Object} config The config object
382 Roo.bootstrap.Body = function(config){
383 Roo.bootstrap.Body.superclass.constructor.call(this, config);
384 this.el = Roo.get(document.body);
385 if (this.cls && this.cls.length) {
386 Roo.get(document.body).addClass(this.cls);
390 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
395 onRender : function(ct, position)
397 /* Roo.log("Roo.bootstrap.Body - onRender");
398 if (this.cls && this.cls.length) {
399 Roo.get(document.body).addClass(this.cls);
419 * @class Roo.bootstrap.ButtonGroup
420 * @extends Roo.bootstrap.Component
421 * Bootstrap ButtonGroup class
422 * @cfg {String} size lg | sm | xs (default empty normal)
423 * @cfg {String} align vertical | justified (default none)
424 * @cfg {String} direction up | down (default down)
425 * @cfg {Boolean} toolbar false | true
426 * @cfg {Boolean} btn true | false
431 * @param {Object} config The config object
434 Roo.bootstrap.ButtonGroup = function(config){
435 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
438 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
446 getAutoCreate : function(){
452 cfg.html = this.html || cfg.html;
463 if (['vertical','justified'].indexOf(this.align)!==-1) {
464 cfg.cls = 'btn-group-' + this.align;
466 if (this.align == 'justified') {
467 console.log(this.items);
471 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
472 cfg.cls += ' btn-group-' + this.size;
475 if (this.direction == 'up') {
476 cfg.cls += ' dropup' ;
492 * @class Roo.bootstrap.Button
493 * @extends Roo.bootstrap.Component
494 * Bootstrap Button class
495 * @cfg {String} html The button content
496 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
497 * @cfg {String} size ( lg | sm | xs)
498 * @cfg {String} tag ( a | input | submit)
499 * @cfg {String} href empty or href
500 * @cfg {Boolean} disabled default false;
501 * @cfg {Boolean} isClose default false;
502 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
503 * @cfg {String} badge text for badge
504 * @cfg {String} theme default
505 * @cfg {Boolean} inverse
506 * @cfg {Boolean} toggle
507 * @cfg {String} ontext text for on toggle state
508 * @cfg {String} offtext text for off toggle state
509 * @cfg {Boolean} defaulton
510 * @cfg {Boolean} preventDefault default true
511 * @cfg {Boolean} removeClass remove the standard class..
512 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
515 * Create a new button
516 * @param {Object} config The config object
520 Roo.bootstrap.Button = function(config){
521 Roo.bootstrap.Button.superclass.constructor.call(this, config);
526 * When a butotn is pressed
527 * @param {Roo.bootstrap.Button} this
528 * @param {Roo.EventObject} e
533 * After the button has been toggles
534 * @param {Roo.EventObject} e
535 * @param {boolean} pressed (also available as button.pressed)
541 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
559 preventDefault: true,
568 getAutoCreate : function(){
576 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
577 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
582 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
584 if (this.toggle == true) {
587 cls: 'slider-frame roo-button',
592 'data-off-text':'OFF',
593 cls: 'slider-button',
599 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
600 cfg.cls += ' '+this.weight;
609 cfg["aria-hidden"] = true;
611 cfg.html = "×";
617 if (this.theme==='default') {
618 cfg.cls = 'btn roo-button';
620 //if (this.parentType != 'Navbar') {
621 this.weight = this.weight.length ? this.weight : 'default';
623 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
625 cfg.cls += ' btn-' + this.weight;
627 } else if (this.theme==='glow') {
630 cfg.cls = 'btn-glow roo-button';
632 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
634 cfg.cls += ' ' + this.weight;
640 this.cls += ' inverse';
645 cfg.cls += ' active';
649 cfg.disabled = 'disabled';
653 Roo.log('changing to ul' );
655 this.glyphicon = 'caret';
658 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
660 //gsRoo.log(this.parentType);
661 if (this.parentType === 'Navbar' && !this.parent().bar) {
662 Roo.log('changing to li?');
671 href : this.href || '#'
674 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
675 cfg.cls += ' dropdown';
682 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
684 if (this.glyphicon) {
685 cfg.html = ' ' + cfg.html;
690 cls: 'glyphicon glyphicon-' + this.glyphicon
700 // cfg.cls='btn roo-button';
704 var value = cfg.html;
709 cls: 'glyphicon glyphicon-' + this.glyphicon,
728 cfg.cls += ' dropdown';
729 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
732 if (cfg.tag !== 'a' && this.href !== '') {
733 throw "Tag must be a to set href.";
734 } else if (this.href.length > 0) {
735 cfg.href = this.href;
738 if(this.removeClass){
743 cfg.target = this.target;
748 initEvents: function() {
749 // Roo.log('init events?');
750 // Roo.log(this.el.dom);
753 if (typeof (this.menu) != 'undefined') {
754 this.menu.parentType = this.xtype;
755 this.menu.triggerEl = this.el;
756 this.addxtype(Roo.apply({}, this.menu));
760 if (this.el.hasClass('roo-button')) {
761 this.el.on('click', this.onClick, this);
763 this.el.select('.roo-button').on('click', this.onClick, this);
766 if(this.removeClass){
767 this.el.on('click', this.onClick, this);
770 this.el.enableDisplayMode();
773 onClick : function(e)
780 Roo.log('button on click ');
781 if(this.preventDefault){
784 if (this.pressed === true || this.pressed === false) {
785 this.pressed = !this.pressed;
786 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
787 this.fireEvent('toggle', this, e, this.pressed);
791 this.fireEvent('click', this, e);
795 * Enables this button
799 this.disabled = false;
800 this.el.removeClass('disabled');
804 * Disable this button
808 this.disabled = true;
809 this.el.addClass('disabled');
812 * sets the active state on/off,
813 * @param {Boolean} state (optional) Force a particular state
815 setActive : function(v) {
817 this.el[v ? 'addClass' : 'removeClass']('active');
820 * toggles the current active state
822 toggleActive : function()
824 var active = this.el.hasClass('active');
825 this.setActive(!active);
829 setText : function(str)
831 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
835 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
858 * @class Roo.bootstrap.Column
859 * @extends Roo.bootstrap.Component
860 * Bootstrap Column class
861 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
862 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
863 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
864 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
865 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
866 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
867 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
868 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
871 * @cfg {Boolean} hidden (true|false) hide the element
872 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
873 * @cfg {String} fa (ban|check|...) font awesome icon
874 * @cfg {Number} fasize (1|2|....) font awsome size
876 * @cfg {String} icon (info-sign|check|...) glyphicon name
878 * @cfg {String} html content of column.
881 * Create a new Column
882 * @param {Object} config The config object
885 Roo.bootstrap.Column = function(config){
886 Roo.bootstrap.Column.superclass.constructor.call(this, config);
889 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
907 getAutoCreate : function(){
908 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
916 ['xs','sm','md','lg'].map(function(size){
917 //Roo.log( size + ':' + settings[size]);
919 if (settings[size+'off'] !== false) {
920 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
923 if (settings[size] === false) {
926 Roo.log(settings[size]);
927 if (!settings[size]) { // 0 = hidden
928 cfg.cls += ' hidden-' + size;
931 cfg.cls += ' col-' + size + '-' + settings[size];
936 cfg.cls += ' hidden';
939 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
940 cfg.cls +=' alert alert-' + this.alert;
944 if (this.html.length) {
945 cfg.html = this.html;
949 if (this.fasize > 1) {
950 fasize = ' fa-' + this.fasize + 'x';
952 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
957 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
976 * @class Roo.bootstrap.Container
977 * @extends Roo.bootstrap.Component
978 * Bootstrap Container class
979 * @cfg {Boolean} jumbotron is it a jumbotron element
980 * @cfg {String} html content of element
981 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
982 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
983 * @cfg {String} header content of header (for panel)
984 * @cfg {String} footer content of footer (for panel)
985 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
986 * @cfg {String} tag (header|aside|section) type of HTML tag.
987 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
988 * @cfg {String} fa (ban|check|...) font awesome icon
989 * @cfg {String} icon (info-sign|check|...) glyphicon name
990 * @cfg {Boolean} hidden (true|false) hide the element
991 * @cfg {Boolean} expandable (true|false) default false
992 * @cfg {String} rheader contet on the right of header
996 * Create a new Container
997 * @param {Object} config The config object
1000 Roo.bootstrap.Container = function(config){
1001 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1007 * After the panel has been expand
1009 * @param {Roo.bootstrap.Container} this
1014 * After the panel has been collapsed
1016 * @param {Roo.bootstrap.Container} this
1022 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1039 getChildContainer : function() {
1045 if (this.panel.length) {
1046 return this.el.select('.panel-body',true).first();
1053 getAutoCreate : function(){
1056 tag : this.tag || 'div',
1060 if (this.jumbotron) {
1061 cfg.cls = 'jumbotron';
1066 // - this is applied by the parent..
1068 // cfg.cls = this.cls + '';
1071 if (this.sticky.length) {
1073 var bd = Roo.get(document.body);
1074 if (!bd.hasClass('bootstrap-sticky')) {
1075 bd.addClass('bootstrap-sticky');
1076 Roo.select('html',true).setStyle('height', '100%');
1079 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1083 if (this.well.length) {
1084 switch (this.well) {
1087 cfg.cls +=' well well-' +this.well;
1096 cfg.cls += ' hidden';
1100 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1101 cfg.cls +=' alert alert-' + this.alert;
1106 if (this.panel.length) {
1107 cfg.cls += ' panel panel-' + this.panel;
1109 if (this.header.length) {
1113 if(this.expandable){
1115 cfg.cls = cfg.cls + ' expandable';
1126 cls : 'panel-title',
1131 cls: 'panel-header-right',
1137 cls : 'panel-heading',
1150 if (this.footer.length) {
1152 cls : 'panel-footer',
1161 body.html = this.html || cfg.html;
1162 // prefix with the icons..
1164 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1167 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1172 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1173 cfg.cls = 'container';
1179 initEvents: function()
1181 if(!this.expandable){
1185 var headerEl = this.headerEl();
1191 headerEl.on('click', this.onToggleClick, this);
1195 onToggleClick : function()
1197 var headerEl = this.headerEl();
1213 if(this.fireEvent('expand', this)) {
1215 this.expanded = true;
1217 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1219 var toggleEl = this.toggleEl();
1225 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1230 collapse : function()
1232 if(this.fireEvent('collapse', this)) {
1234 this.expanded = false;
1236 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1238 var toggleEl = this.toggleEl();
1244 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1248 toggleEl : function()
1250 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1254 return this.el.select('.panel-heading .fa',true).first();
1257 headerEl : function()
1259 if(!this.el || !this.panel.length || !this.header.length){
1263 return this.el.select('.panel-heading',true).first()
1266 titleEl : function()
1268 if(!this.el || !this.panel.length || !this.header.length){
1272 return this.el.select('.panel-title',true).first();
1275 setTitle : function(v)
1277 var titleEl = this.titleEl();
1283 titleEl.dom.innerHTML = v;
1286 getTitle : function()
1289 var titleEl = this.titleEl();
1295 return titleEl.dom.innerHTML;
1298 setRightTitle : function(v)
1300 var t = this.el.select('.panel-header-right',true).first();
1306 t.dom.innerHTML = v;
1320 * @class Roo.bootstrap.Img
1321 * @extends Roo.bootstrap.Component
1322 * Bootstrap Img class
1323 * @cfg {Boolean} imgResponsive false | true
1324 * @cfg {String} border rounded | circle | thumbnail
1325 * @cfg {String} src image source
1326 * @cfg {String} alt image alternative text
1327 * @cfg {String} href a tag href
1328 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1329 * @cfg {String} xsUrl xs image source
1330 * @cfg {String} smUrl sm image source
1331 * @cfg {String} mdUrl md image source
1332 * @cfg {String} lgUrl lg image source
1335 * Create a new Input
1336 * @param {Object} config The config object
1339 Roo.bootstrap.Img = function(config){
1340 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1346 * The img click event for the img.
1347 * @param {Roo.EventObject} e
1353 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1355 imgResponsive: true,
1365 getAutoCreate : function()
1367 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1368 return this.createSingleImg();
1373 cls: 'roo-image-responsive-group',
1378 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1380 if(!_this[size + 'Url']){
1386 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1387 html: _this.html || cfg.html,
1388 src: _this[size + 'Url']
1391 img.cls += ' roo-image-responsive-' + size;
1393 var s = ['xs', 'sm', 'md', 'lg'];
1395 s.splice(s.indexOf(size), 1);
1397 Roo.each(s, function(ss){
1398 img.cls += ' hidden-' + ss;
1401 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1402 cfg.cls += ' img-' + _this.border;
1406 cfg.alt = _this.alt;
1419 a.target = _this.target;
1423 cfg.cn.push((_this.href) ? a : img);
1430 createSingleImg : function()
1434 cls: (this.imgResponsive) ? 'img-responsive' : '',
1438 cfg.html = this.html || cfg.html;
1440 cfg.src = this.src || cfg.src;
1442 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1443 cfg.cls += ' img-' + this.border;
1460 a.target = this.target;
1465 return (this.href) ? a : cfg;
1468 initEvents: function()
1471 this.el.on('click', this.onClick, this);
1476 onClick : function(e)
1478 Roo.log('img onclick');
1479 this.fireEvent('click', this, e);
1493 * @class Roo.bootstrap.Link
1494 * @extends Roo.bootstrap.Component
1495 * Bootstrap Link Class
1496 * @cfg {String} alt image alternative text
1497 * @cfg {String} href a tag href
1498 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1499 * @cfg {String} html the content of the link.
1500 * @cfg {String} anchor name for the anchor link
1502 * @cfg {Boolean} preventDefault (true | false) default false
1506 * Create a new Input
1507 * @param {Object} config The config object
1510 Roo.bootstrap.Link = function(config){
1511 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1517 * The img click event for the img.
1518 * @param {Roo.EventObject} e
1524 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1528 preventDefault: false,
1532 getAutoCreate : function()
1538 // anchor's do not require html/href...
1539 if (this.anchor === false) {
1540 cfg.html = this.html || '';
1541 cfg.href = this.href || '#';
1543 cfg.name = this.anchor;
1544 if (this.html !== false) {
1545 cfg.html = this.html;
1547 if (this.href !== false) {
1548 cfg.href = this.href;
1552 if(this.alt !== false){
1557 if(this.target !== false) {
1558 cfg.target = this.target;
1564 initEvents: function() {
1566 if(!this.href || this.preventDefault){
1567 this.el.on('click', this.onClick, this);
1571 onClick : function(e)
1573 if(this.preventDefault){
1576 //Roo.log('img onclick');
1577 this.fireEvent('click', this, e);
1590 * @class Roo.bootstrap.Header
1591 * @extends Roo.bootstrap.Component
1592 * Bootstrap Header class
1593 * @cfg {String} html content of header
1594 * @cfg {Number} level (1|2|3|4|5|6) default 1
1597 * Create a new Header
1598 * @param {Object} config The config object
1602 Roo.bootstrap.Header = function(config){
1603 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1606 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1614 getAutoCreate : function(){
1619 tag: 'h' + (1 *this.level),
1620 html: this.html || ''
1632 * Ext JS Library 1.1.1
1633 * Copyright(c) 2006-2007, Ext JS, LLC.
1635 * Originally Released Under LGPL - original licence link has changed is not relivant.
1638 * <script type="text/javascript">
1642 * @class Roo.bootstrap.MenuMgr
1643 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1646 Roo.bootstrap.MenuMgr = function(){
1647 var menus, active, groups = {}, attached = false, lastShow = new Date();
1649 // private - called when first menu is created
1652 active = new Roo.util.MixedCollection();
1653 Roo.get(document).addKeyListener(27, function(){
1654 if(active.length > 0){
1662 if(active && active.length > 0){
1663 var c = active.clone();
1673 if(active.length < 1){
1674 Roo.get(document).un("mouseup", onMouseDown);
1682 var last = active.last();
1683 lastShow = new Date();
1686 Roo.get(document).on("mouseup", onMouseDown);
1691 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1692 m.parentMenu.activeChild = m;
1693 }else if(last && last.isVisible()){
1694 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1699 function onBeforeHide(m){
1701 m.activeChild.hide();
1703 if(m.autoHideTimer){
1704 clearTimeout(m.autoHideTimer);
1705 delete m.autoHideTimer;
1710 function onBeforeShow(m){
1711 var pm = m.parentMenu;
1712 if(!pm && !m.allowOtherMenus){
1714 }else if(pm && pm.activeChild && active != m){
1715 pm.activeChild.hide();
1719 // private this should really trigger on mouseup..
1720 function onMouseDown(e){
1721 Roo.log("on Mouse Up");
1722 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1732 function onBeforeCheck(mi, state){
1734 var g = groups[mi.group];
1735 for(var i = 0, l = g.length; i < l; i++){
1737 g[i].setChecked(false);
1746 * Hides all menus that are currently visible
1748 hideAll : function(){
1753 register : function(menu){
1757 menus[menu.id] = menu;
1758 menu.on("beforehide", onBeforeHide);
1759 menu.on("hide", onHide);
1760 menu.on("beforeshow", onBeforeShow);
1761 menu.on("show", onShow);
1763 if(g && menu.events["checkchange"]){
1767 groups[g].push(menu);
1768 menu.on("checkchange", onCheck);
1773 * Returns a {@link Roo.menu.Menu} object
1774 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1775 * be used to generate and return a new Menu instance.
1777 get : function(menu){
1778 if(typeof menu == "string"){ // menu id
1780 }else if(menu.events){ // menu instance
1783 /*else if(typeof menu.length == 'number'){ // array of menu items?
1784 return new Roo.bootstrap.Menu({items:menu});
1785 }else{ // otherwise, must be a config
1786 return new Roo.bootstrap.Menu(menu);
1793 unregister : function(menu){
1794 delete menus[menu.id];
1795 menu.un("beforehide", onBeforeHide);
1796 menu.un("hide", onHide);
1797 menu.un("beforeshow", onBeforeShow);
1798 menu.un("show", onShow);
1800 if(g && menu.events["checkchange"]){
1801 groups[g].remove(menu);
1802 menu.un("checkchange", onCheck);
1807 registerCheckable : function(menuItem){
1808 var g = menuItem.group;
1813 groups[g].push(menuItem);
1814 menuItem.on("beforecheckchange", onBeforeCheck);
1819 unregisterCheckable : function(menuItem){
1820 var g = menuItem.group;
1822 groups[g].remove(menuItem);
1823 menuItem.un("beforecheckchange", onBeforeCheck);
1835 * @class Roo.bootstrap.Menu
1836 * @extends Roo.bootstrap.Component
1837 * Bootstrap Menu class - container for MenuItems
1838 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1842 * @param {Object} config The config object
1846 Roo.bootstrap.Menu = function(config){
1847 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1848 if (this.registerMenu) {
1849 Roo.bootstrap.MenuMgr.register(this);
1854 * Fires before this menu is displayed
1855 * @param {Roo.menu.Menu} this
1860 * Fires before this menu is hidden
1861 * @param {Roo.menu.Menu} this
1866 * Fires after this menu is displayed
1867 * @param {Roo.menu.Menu} this
1872 * Fires after this menu is hidden
1873 * @param {Roo.menu.Menu} this
1878 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1879 * @param {Roo.menu.Menu} this
1880 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1881 * @param {Roo.EventObject} e
1886 * Fires when the mouse is hovering over this menu
1887 * @param {Roo.menu.Menu} this
1888 * @param {Roo.EventObject} e
1889 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1894 * Fires when the mouse exits this menu
1895 * @param {Roo.menu.Menu} this
1896 * @param {Roo.EventObject} e
1897 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1902 * Fires when a menu item contained in this menu is clicked
1903 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1904 * @param {Roo.EventObject} e
1908 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1911 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1915 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1918 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1920 registerMenu : true,
1922 menuItems :false, // stores the menu items..
1928 getChildContainer : function() {
1932 getAutoCreate : function(){
1934 //if (['right'].indexOf(this.align)!==-1) {
1935 // cfg.cn[1].cls += ' pull-right'
1941 cls : 'dropdown-menu' ,
1942 style : 'z-index:1000'
1946 if (this.type === 'submenu') {
1947 cfg.cls = 'submenu active';
1949 if (this.type === 'treeview') {
1950 cfg.cls = 'treeview-menu';
1955 initEvents : function() {
1957 // Roo.log("ADD event");
1958 // Roo.log(this.triggerEl.dom);
1959 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1961 this.triggerEl.addClass('dropdown-toggle');
1962 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1964 this.el.on("mouseover", this.onMouseOver, this);
1965 this.el.on("mouseout", this.onMouseOut, this);
1969 findTargetItem : function(e){
1970 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1974 //Roo.log(t); Roo.log(t.id);
1976 //Roo.log(this.menuitems);
1977 return this.menuitems.get(t.id);
1979 //return this.items.get(t.menuItemId);
1984 onClick : function(e){
1985 Roo.log("menu.onClick");
1986 var t = this.findTargetItem(e);
1987 if(!t || t.isContainer){
1992 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1993 if(t == this.activeItem && t.shouldDeactivate(e)){
1994 this.activeItem.deactivate();
1995 delete this.activeItem;
1999 this.setActiveItem(t, true);
2007 Roo.log('pass click event');
2011 this.fireEvent("click", this, t, e);
2015 onMouseOver : function(e){
2016 var t = this.findTargetItem(e);
2019 // if(t.canActivate && !t.disabled){
2020 // this.setActiveItem(t, true);
2024 this.fireEvent("mouseover", this, e, t);
2026 isVisible : function(){
2027 return !this.hidden;
2029 onMouseOut : function(e){
2030 var t = this.findTargetItem(e);
2033 // if(t == this.activeItem && t.shouldDeactivate(e)){
2034 // this.activeItem.deactivate();
2035 // delete this.activeItem;
2038 this.fireEvent("mouseout", this, e, t);
2043 * Displays this menu relative to another element
2044 * @param {String/HTMLElement/Roo.Element} element The element to align to
2045 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2046 * the element (defaults to this.defaultAlign)
2047 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2049 show : function(el, pos, parentMenu){
2050 this.parentMenu = parentMenu;
2054 this.fireEvent("beforeshow", this);
2055 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2058 * Displays this menu at a specific xy position
2059 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2060 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2062 showAt : function(xy, parentMenu, /* private: */_e){
2063 this.parentMenu = parentMenu;
2068 this.fireEvent("beforeshow", this);
2069 //xy = this.el.adjustForConstraints(xy);
2073 this.hideMenuItems();
2074 this.hidden = false;
2075 this.triggerEl.addClass('open');
2077 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2078 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2083 this.fireEvent("show", this);
2089 this.doFocus.defer(50, this);
2093 doFocus : function(){
2095 this.focusEl.focus();
2100 * Hides this menu and optionally all parent menus
2101 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2103 hide : function(deep){
2105 this.hideMenuItems();
2106 if(this.el && this.isVisible()){
2107 this.fireEvent("beforehide", this);
2108 if(this.activeItem){
2109 this.activeItem.deactivate();
2110 this.activeItem = null;
2112 this.triggerEl.removeClass('open');;
2114 this.fireEvent("hide", this);
2116 if(deep === true && this.parentMenu){
2117 this.parentMenu.hide(true);
2121 onTriggerPress : function(e)
2124 Roo.log('trigger press');
2125 //Roo.log(e.getTarget());
2126 // Roo.log(this.triggerEl.dom);
2127 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2131 if (this.isVisible()) {
2136 this.show(this.triggerEl, false, false);
2145 hideMenuItems : function()
2147 //$(backdrop).remove()
2148 Roo.select('.open',true).each(function(aa) {
2150 aa.removeClass('open');
2151 //var parent = getParent($(this))
2152 //var relatedTarget = { relatedTarget: this }
2154 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2155 //if (e.isDefaultPrevented()) return
2156 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2159 addxtypeChild : function (tree, cntr) {
2160 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2162 this.menuitems.add(comp);
2183 * @class Roo.bootstrap.MenuItem
2184 * @extends Roo.bootstrap.Component
2185 * Bootstrap MenuItem class
2186 * @cfg {String} html the menu label
2187 * @cfg {String} href the link
2188 * @cfg {Boolean} preventDefault (true | false) default true
2189 * @cfg {Boolean} isContainer (true | false) default false
2193 * Create a new MenuItem
2194 * @param {Object} config The config object
2198 Roo.bootstrap.MenuItem = function(config){
2199 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2204 * The raw click event for the entire grid.
2205 * @param {Roo.bootstrap.MenuItem} this
2206 * @param {Roo.EventObject} e
2212 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2216 preventDefault: true,
2217 isContainer : false,
2219 getAutoCreate : function(){
2221 if(this.isContainer){
2224 cls: 'dropdown-menu-item'
2230 cls: 'dropdown-menu-item',
2239 if (this.parent().type == 'treeview') {
2240 cfg.cls = 'treeview-menu';
2243 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2244 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2248 initEvents: function() {
2250 //this.el.select('a').on('click', this.onClick, this);
2253 onClick : function(e)
2255 Roo.log('item on click ');
2256 //if(this.preventDefault){
2257 // e.preventDefault();
2259 //this.parent().hideMenuItems();
2261 this.fireEvent('click', this, e);
2280 * @class Roo.bootstrap.MenuSeparator
2281 * @extends Roo.bootstrap.Component
2282 * Bootstrap MenuSeparator class
2285 * Create a new MenuItem
2286 * @param {Object} config The config object
2290 Roo.bootstrap.MenuSeparator = function(config){
2291 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2294 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2296 getAutoCreate : function(){
2315 * @class Roo.bootstrap.Modal
2316 * @extends Roo.bootstrap.Component
2317 * Bootstrap Modal class
2318 * @cfg {String} title Title of dialog
2319 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2320 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2321 * @cfg {Boolean} specificTitle default false
2322 * @cfg {Array} buttons Array of buttons or standard button set..
2323 * @cfg {String} buttonPosition (left|right|center) default right
2324 * @cfg {Boolean} animate default true
2325 * @cfg {Boolean} allow_close default true
2328 * Create a new Modal Dialog
2329 * @param {Object} config The config object
2332 Roo.bootstrap.Modal = function(config){
2333 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2338 * The raw btnclick event for the button
2339 * @param {Roo.EventObject} e
2343 this.buttons = this.buttons || [];
2346 this.tmpl = Roo.factory(this.tmpl);
2351 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2353 title : 'test dialog',
2363 specificTitle: false,
2365 buttonPosition: 'right',
2379 onRender : function(ct, position)
2381 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2384 var cfg = Roo.apply({}, this.getAutoCreate());
2387 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2389 //if (!cfg.name.length) {
2393 cfg.cls += ' ' + this.cls;
2396 cfg.style = this.style;
2398 this.el = Roo.get(document.body).createChild(cfg, position);
2400 //var type = this.el.dom.type;
2405 if(this.tabIndex !== undefined){
2406 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2410 this.bodyEl = this.el.select('.modal-body',true).first();
2411 this.closeEl = this.el.select('.modal-header .close', true).first();
2412 this.footerEl = this.el.select('.modal-footer',true).first();
2413 this.titleEl = this.el.select('.modal-title',true).first();
2417 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2418 this.maskEl.enableDisplayMode("block");
2420 //this.el.addClass("x-dlg-modal");
2422 if (this.buttons.length) {
2423 Roo.each(this.buttons, function(bb) {
2424 b = Roo.apply({}, bb);
2425 b.xns = b.xns || Roo.bootstrap;
2426 b.xtype = b.xtype || 'Button';
2427 if (typeof(b.listeners) == 'undefined') {
2428 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2431 var btn = Roo.factory(b);
2433 btn.onRender(this.el.select('.modal-footer div').first());
2437 // render the children.
2440 if(typeof(this.items) != 'undefined'){
2441 var items = this.items;
2444 for(var i =0;i < items.length;i++) {
2445 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2449 this.items = nitems;
2451 // where are these used - they used to be body/close/footer
2455 //this.el.addClass([this.fieldClass, this.cls]);
2458 getAutoCreate : function(){
2463 html : this.html || ''
2468 cls : 'modal-title',
2472 if(this.specificTitle){
2478 if (this.allow_close) {
2489 style : 'display: none',
2492 cls: "modal-dialog",
2495 cls : "modal-content",
2498 cls : 'modal-header',
2503 cls : 'modal-footer',
2507 cls: 'btn-' + this.buttonPosition
2524 modal.cls += ' fade';
2530 getChildContainer : function() {
2535 getButtonContainer : function() {
2536 return this.el.select('.modal-footer div',true).first();
2539 initEvents : function()
2541 if (this.allow_close) {
2542 this.closeEl.on('click', this.hide, this);
2548 if (!this.rendered) {
2552 this.el.setStyle('display', 'block');
2556 (function(){ _this.el.addClass('in'); }).defer(50);
2558 this.el.addClass('in');
2561 // not sure how we can show data in here..
2563 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2566 Roo.get(document.body).addClass("x-body-masked");
2567 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2569 this.el.setStyle('zIndex', '10001');
2571 this.fireEvent('show', this);
2578 Roo.get(document.body).removeClass("x-body-masked");
2579 this.el.removeClass('in');
2583 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2585 this.el.setStyle('display', 'none');
2588 this.fireEvent('hide', this);
2591 addButton : function(str, cb)
2595 var b = Roo.apply({}, { html : str } );
2596 b.xns = b.xns || Roo.bootstrap;
2597 b.xtype = b.xtype || 'Button';
2598 if (typeof(b.listeners) == 'undefined') {
2599 b.listeners = { click : cb.createDelegate(this) };
2602 var btn = Roo.factory(b);
2604 btn.onRender(this.el.select('.modal-footer div').first());
2610 setDefaultButton : function(btn)
2612 //this.el.select('.modal-footer').()
2614 resizeTo: function(w,h)
2618 setContentSize : function(w, h)
2622 onButtonClick: function(btn,e)
2625 this.fireEvent('btnclick', btn.name, e);
2628 * Set the title of the Dialog
2629 * @param {String} str new Title
2631 setTitle: function(str) {
2632 this.titleEl.dom.innerHTML = str;
2635 * Set the body of the Dialog
2636 * @param {String} str new Title
2638 setBody: function(str) {
2639 this.bodyEl.dom.innerHTML = str;
2642 * Set the body of the Dialog using the template
2643 * @param {Obj} data - apply this data to the template and replace the body contents.
2645 applyBody: function(obj)
2648 Roo.log("Error - using apply Body without a template");
2651 this.tmpl.overwrite(this.bodyEl, obj);
2657 Roo.apply(Roo.bootstrap.Modal, {
2659 * Button config that displays a single OK button
2668 * Button config that displays Yes and No buttons
2684 * Button config that displays OK and Cancel buttons
2699 * Button config that displays Yes, No and Cancel buttons
2722 * messagebox - can be used as a replace
2726 * @class Roo.MessageBox
2727 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2731 Roo.Msg.alert('Status', 'Changes saved successfully.');
2733 // Prompt for user data:
2734 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2736 // process text value...
2740 // Show a dialog using config options:
2742 title:'Save Changes?',
2743 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2744 buttons: Roo.Msg.YESNOCANCEL,
2751 Roo.bootstrap.MessageBox = function(){
2752 var dlg, opt, mask, waitTimer;
2753 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2754 var buttons, activeTextEl, bwidth;
2758 var handleButton = function(button){
2760 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2764 var handleHide = function(){
2766 dlg.el.removeClass(opt.cls);
2769 // Roo.TaskMgr.stop(waitTimer);
2770 // waitTimer = null;
2775 var updateButtons = function(b){
2778 buttons["ok"].hide();
2779 buttons["cancel"].hide();
2780 buttons["yes"].hide();
2781 buttons["no"].hide();
2782 //dlg.footer.dom.style.display = 'none';
2785 dlg.footerEl.dom.style.display = '';
2786 for(var k in buttons){
2787 if(typeof buttons[k] != "function"){
2790 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2791 width += buttons[k].el.getWidth()+15;
2801 var handleEsc = function(d, k, e){
2802 if(opt && opt.closable !== false){
2812 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2813 * @return {Roo.BasicDialog} The BasicDialog element
2815 getDialog : function(){
2817 dlg = new Roo.bootstrap.Modal( {
2820 //constraintoviewport:false,
2822 //collapsible : false,
2827 //buttonAlign:"center",
2828 closeClick : function(){
2829 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2832 handleButton("cancel");
2837 dlg.on("hide", handleHide);
2839 //dlg.addKeyListener(27, handleEsc);
2841 this.buttons = buttons;
2842 var bt = this.buttonText;
2843 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2844 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2845 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2846 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2848 bodyEl = dlg.bodyEl.createChild({
2850 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2851 '<textarea class="roo-mb-textarea"></textarea>' +
2852 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2854 msgEl = bodyEl.dom.firstChild;
2855 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2856 textboxEl.enableDisplayMode();
2857 textboxEl.addKeyListener([10,13], function(){
2858 if(dlg.isVisible() && opt && opt.buttons){
2861 }else if(opt.buttons.yes){
2862 handleButton("yes");
2866 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2867 textareaEl.enableDisplayMode();
2868 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2869 progressEl.enableDisplayMode();
2870 var pf = progressEl.dom.firstChild;
2872 pp = Roo.get(pf.firstChild);
2873 pp.setHeight(pf.offsetHeight);
2881 * Updates the message box body text
2882 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2883 * the XHTML-compliant non-breaking space character '&#160;')
2884 * @return {Roo.MessageBox} This message box
2886 updateText : function(text){
2887 if(!dlg.isVisible() && !opt.width){
2888 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2890 msgEl.innerHTML = text || ' ';
2892 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2893 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2895 Math.min(opt.width || cw , this.maxWidth),
2896 Math.max(opt.minWidth || this.minWidth, bwidth)
2899 activeTextEl.setWidth(w);
2901 if(dlg.isVisible()){
2902 dlg.fixedcenter = false;
2904 // to big, make it scroll. = But as usual stupid IE does not support
2907 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2908 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2909 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2911 bodyEl.dom.style.height = '';
2912 bodyEl.dom.style.overflowY = '';
2915 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2917 bodyEl.dom.style.overflowX = '';
2920 dlg.setContentSize(w, bodyEl.getHeight());
2921 if(dlg.isVisible()){
2922 dlg.fixedcenter = true;
2928 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2929 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2930 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2931 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2932 * @return {Roo.MessageBox} This message box
2934 updateProgress : function(value, text){
2936 this.updateText(text);
2938 if (pp) { // weird bug on my firefox - for some reason this is not defined
2939 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2945 * Returns true if the message box is currently displayed
2946 * @return {Boolean} True if the message box is visible, else false
2948 isVisible : function(){
2949 return dlg && dlg.isVisible();
2953 * Hides the message box if it is displayed
2956 if(this.isVisible()){
2962 * Displays a new message box, or reinitializes an existing message box, based on the config options
2963 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2964 * The following config object properties are supported:
2966 Property Type Description
2967 ---------- --------------- ------------------------------------------------------------------------------------
2968 animEl String/Element An id or Element from which the message box should animate as it opens and
2969 closes (defaults to undefined)
2970 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2971 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2972 closable Boolean False to hide the top-right close button (defaults to true). Note that
2973 progress and wait dialogs will ignore this property and always hide the
2974 close button as they can only be closed programmatically.
2975 cls String A custom CSS class to apply to the message box element
2976 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2977 displayed (defaults to 75)
2978 fn Function A callback function to execute after closing the dialog. The arguments to the
2979 function will be btn (the name of the button that was clicked, if applicable,
2980 e.g. "ok"), and text (the value of the active text field, if applicable).
2981 Progress and wait dialogs will ignore this option since they do not respond to
2982 user actions and can only be closed programmatically, so any required function
2983 should be called by the same code after it closes the dialog.
2984 icon String A CSS class that provides a background image to be used as an icon for
2985 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2986 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2987 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2988 modal Boolean False to allow user interaction with the page while the message box is
2989 displayed (defaults to true)
2990 msg String A string that will replace the existing message box body text (defaults
2991 to the XHTML-compliant non-breaking space character ' ')
2992 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2993 progress Boolean True to display a progress bar (defaults to false)
2994 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2995 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2996 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2997 title String The title text
2998 value String The string value to set into the active textbox element if displayed
2999 wait Boolean True to display a progress bar (defaults to false)
3000 width Number The width of the dialog in pixels
3007 msg: 'Please enter your address:',
3009 buttons: Roo.MessageBox.OKCANCEL,
3012 animEl: 'addAddressBtn'
3015 * @param {Object} config Configuration options
3016 * @return {Roo.MessageBox} This message box
3018 show : function(options)
3021 // this causes nightmares if you show one dialog after another
3022 // especially on callbacks..
3024 if(this.isVisible()){
3027 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3028 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3029 Roo.log("New Dialog Message:" + options.msg )
3030 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3031 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3034 var d = this.getDialog();
3036 d.setTitle(opt.title || " ");
3037 d.closeEl.setDisplayed(opt.closable !== false);
3038 activeTextEl = textboxEl;
3039 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3044 textareaEl.setHeight(typeof opt.multiline == "number" ?
3045 opt.multiline : this.defaultTextHeight);
3046 activeTextEl = textareaEl;
3055 progressEl.setDisplayed(opt.progress === true);
3056 this.updateProgress(0);
3057 activeTextEl.dom.value = opt.value || "";
3059 dlg.setDefaultButton(activeTextEl);
3061 var bs = opt.buttons;
3065 }else if(bs && bs.yes){
3066 db = buttons["yes"];
3068 dlg.setDefaultButton(db);
3070 bwidth = updateButtons(opt.buttons);
3071 this.updateText(opt.msg);
3073 d.el.addClass(opt.cls);
3075 d.proxyDrag = opt.proxyDrag === true;
3076 d.modal = opt.modal !== false;
3077 d.mask = opt.modal !== false ? mask : false;
3079 // force it to the end of the z-index stack so it gets a cursor in FF
3080 document.body.appendChild(dlg.el.dom);
3081 d.animateTarget = null;
3082 d.show(options.animEl);
3088 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3089 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3090 * and closing the message box when the process is complete.
3091 * @param {String} title The title bar text
3092 * @param {String} msg The message box body text
3093 * @return {Roo.MessageBox} This message box
3095 progress : function(title, msg){
3102 minWidth: this.minProgressWidth,
3109 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3110 * If a callback function is passed it will be called after the user clicks the button, and the
3111 * id of the button that was clicked will be passed as the only parameter to the callback
3112 * (could also be the top-right close button).
3113 * @param {String} title The title bar text
3114 * @param {String} msg The message box body text
3115 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3116 * @param {Object} scope (optional) The scope of the callback function
3117 * @return {Roo.MessageBox} This message box
3119 alert : function(title, msg, fn, scope){
3132 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3133 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3134 * You are responsible for closing the message box when the process is complete.
3135 * @param {String} msg The message box body text
3136 * @param {String} title (optional) The title bar text
3137 * @return {Roo.MessageBox} This message box
3139 wait : function(msg, title){
3150 waitTimer = Roo.TaskMgr.start({
3152 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3160 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3161 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3162 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3163 * @param {String} title The title bar text
3164 * @param {String} msg The message box body text
3165 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3166 * @param {Object} scope (optional) The scope of the callback function
3167 * @return {Roo.MessageBox} This message box
3169 confirm : function(title, msg, fn, scope){
3173 buttons: this.YESNO,
3182 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3183 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3184 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3185 * (could also be the top-right close button) and the text that was entered will be passed as the two
3186 * parameters to the callback.
3187 * @param {String} title The title bar text
3188 * @param {String} msg The message box body text
3189 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3190 * @param {Object} scope (optional) The scope of the callback function
3191 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3192 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3193 * @return {Roo.MessageBox} This message box
3195 prompt : function(title, msg, fn, scope, multiline){
3199 buttons: this.OKCANCEL,
3204 multiline: multiline,
3211 * Button config that displays a single OK button
3216 * Button config that displays Yes and No buttons
3219 YESNO : {yes:true, no:true},
3221 * Button config that displays OK and Cancel buttons
3224 OKCANCEL : {ok:true, cancel:true},
3226 * Button config that displays Yes, No and Cancel buttons
3229 YESNOCANCEL : {yes:true, no:true, cancel:true},
3232 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3235 defaultTextHeight : 75,
3237 * The maximum width in pixels of the message box (defaults to 600)
3242 * The minimum width in pixels of the message box (defaults to 100)
3247 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3248 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3251 minProgressWidth : 250,
3253 * An object containing the default button text strings that can be overriden for localized language support.
3254 * Supported properties are: ok, cancel, yes and no.
3255 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3268 * Shorthand for {@link Roo.MessageBox}
3270 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3271 Roo.Msg = Roo.Msg || Roo.MessageBox;
3280 * @class Roo.bootstrap.Navbar
3281 * @extends Roo.bootstrap.Component
3282 * Bootstrap Navbar class
3285 * Create a new Navbar
3286 * @param {Object} config The config object
3290 Roo.bootstrap.Navbar = function(config){
3291 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3295 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3304 getAutoCreate : function(){
3307 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3311 initEvents :function ()
3313 //Roo.log(this.el.select('.navbar-toggle',true));
3314 this.el.select('.navbar-toggle',true).on('click', function() {
3315 // Roo.log('click');
3316 this.el.select('.navbar-collapse',true).toggleClass('in');
3324 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3326 var size = this.el.getSize();
3327 this.maskEl.setSize(size.width, size.height);
3328 this.maskEl.enableDisplayMode("block");
3337 getChildContainer : function()
3339 if (this.el.select('.collapse').getCount()) {
3340 return this.el.select('.collapse',true).first();
3373 * @class Roo.bootstrap.NavSimplebar
3374 * @extends Roo.bootstrap.Navbar
3375 * Bootstrap Sidebar class
3377 * @cfg {Boolean} inverse is inverted color
3379 * @cfg {String} type (nav | pills | tabs)
3380 * @cfg {Boolean} arrangement stacked | justified
3381 * @cfg {String} align (left | right) alignment
3383 * @cfg {Boolean} main (true|false) main nav bar? default false
3384 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3386 * @cfg {String} tag (header|footer|nav|div) default is nav
3392 * Create a new Sidebar
3393 * @param {Object} config The config object
3397 Roo.bootstrap.NavSimplebar = function(config){
3398 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3401 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3417 getAutoCreate : function(){
3421 tag : this.tag || 'div',
3434 this.type = this.type || 'nav';
3435 if (['tabs','pills'].indexOf(this.type)!==-1) {
3436 cfg.cn[0].cls += ' nav-' + this.type
3440 if (this.type!=='nav') {
3441 Roo.log('nav type must be nav/tabs/pills')
3443 cfg.cn[0].cls += ' navbar-nav'
3449 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3450 cfg.cn[0].cls += ' nav-' + this.arrangement;
3454 if (this.align === 'right') {
3455 cfg.cn[0].cls += ' navbar-right';
3459 cfg.cls += ' navbar-inverse';
3486 * @class Roo.bootstrap.NavHeaderbar
3487 * @extends Roo.bootstrap.NavSimplebar
3488 * Bootstrap Sidebar class
3490 * @cfg {String} brand what is brand
3491 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3492 * @cfg {String} brand_href href of the brand
3493 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3494 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3495 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3496 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3499 * Create a new Sidebar
3500 * @param {Object} config The config object
3504 Roo.bootstrap.NavHeaderbar = function(config){
3505 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3509 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3516 desktopCenter : false,
3519 getAutoCreate : function(){
3522 tag: this.nav || 'nav',
3529 if (this.desktopCenter) {
3530 cn.push({cls : 'container', cn : []});
3537 cls: 'navbar-header',
3542 cls: 'navbar-toggle',
3543 'data-toggle': 'collapse',
3548 html: 'Toggle navigation'
3570 cls: 'collapse navbar-collapse',
3574 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3576 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3577 cfg.cls += ' navbar-' + this.position;
3579 // tag can override this..
3581 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3584 if (this.brand !== '') {
3587 href: this.brand_href ? this.brand_href : '#',
3588 cls: 'navbar-brand',
3596 cfg.cls += ' main-nav';
3604 getHeaderChildContainer : function()
3606 if (this.el.select('.navbar-header').getCount()) {
3607 return this.el.select('.navbar-header',true).first();
3610 return this.getChildContainer();
3614 initEvents : function()
3616 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3618 if (this.autohide) {
3623 Roo.get(document).on('scroll',function(e) {
3624 var ns = Roo.get(document).getScroll().top;
3625 var os = prevScroll;
3629 ft.removeClass('slideDown');
3630 ft.addClass('slideUp');
3633 ft.removeClass('slideUp');
3634 ft.addClass('slideDown');
3655 * @class Roo.bootstrap.NavSidebar
3656 * @extends Roo.bootstrap.Navbar
3657 * Bootstrap Sidebar class
3660 * Create a new Sidebar
3661 * @param {Object} config The config object
3665 Roo.bootstrap.NavSidebar = function(config){
3666 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3669 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3671 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3673 getAutoCreate : function(){
3678 cls: 'sidebar sidebar-nav'
3700 * @class Roo.bootstrap.NavGroup
3701 * @extends Roo.bootstrap.Component
3702 * Bootstrap NavGroup class
3703 * @cfg {String} align (left|right)
3704 * @cfg {Boolean} inverse
3705 * @cfg {String} type (nav|pills|tab) default nav
3706 * @cfg {String} navId - reference Id for navbar.
3710 * Create a new nav group
3711 * @param {Object} config The config object
3714 Roo.bootstrap.NavGroup = function(config){
3715 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3718 Roo.bootstrap.NavGroup.register(this);
3722 * Fires when the active item changes
3723 * @param {Roo.bootstrap.NavGroup} this
3724 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3725 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3732 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3743 getAutoCreate : function()
3745 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3752 if (['tabs','pills'].indexOf(this.type)!==-1) {
3753 cfg.cls += ' nav-' + this.type
3755 if (this.type!=='nav') {
3756 Roo.log('nav type must be nav/tabs/pills')
3758 cfg.cls += ' navbar-nav'
3761 if (this.parent().sidebar) {
3764 cls: 'dashboard-menu sidebar-menu'
3770 if (this.form === true) {
3776 if (this.align === 'right') {
3777 cfg.cls += ' navbar-right';
3779 cfg.cls += ' navbar-left';
3783 if (this.align === 'right') {
3784 cfg.cls += ' navbar-right';
3788 cfg.cls += ' navbar-inverse';
3796 * sets the active Navigation item
3797 * @param {Roo.bootstrap.NavItem} the new current navitem
3799 setActiveItem : function(item)
3802 Roo.each(this.navItems, function(v){
3807 v.setActive(false, true);
3814 item.setActive(true, true);
3815 this.fireEvent('changed', this, item, prev);
3820 * gets the active Navigation item
3821 * @return {Roo.bootstrap.NavItem} the current navitem
3823 getActive : function()
3827 Roo.each(this.navItems, function(v){
3838 indexOfNav : function()
3842 Roo.each(this.navItems, function(v,i){
3853 * adds a Navigation item
3854 * @param {Roo.bootstrap.NavItem} the navitem to add
3856 addItem : function(cfg)
3858 var cn = new Roo.bootstrap.NavItem(cfg);
3860 cn.parentId = this.id;
3861 cn.onRender(this.el, null);
3865 * register a Navigation item
3866 * @param {Roo.bootstrap.NavItem} the navitem to add
3868 register : function(item)
3870 this.navItems.push( item);
3871 item.navId = this.navId;
3876 * clear all the Navigation item
3879 clearAll : function()
3882 this.el.dom.innerHTML = '';
3885 getNavItem: function(tabId)
3888 Roo.each(this.navItems, function(e) {
3889 if (e.tabId == tabId) {
3899 setActiveNext : function()
3901 var i = this.indexOfNav(this.getActive());
3902 if (i > this.navItems.length) {
3905 this.setActiveItem(this.navItems[i+1]);
3907 setActivePrev : function()
3909 var i = this.indexOfNav(this.getActive());
3913 this.setActiveItem(this.navItems[i-1]);
3915 clearWasActive : function(except) {
3916 Roo.each(this.navItems, function(e) {
3917 if (e.tabId != except.tabId && e.was_active) {
3918 e.was_active = false;
3925 getWasActive : function ()
3928 Roo.each(this.navItems, function(e) {
3943 Roo.apply(Roo.bootstrap.NavGroup, {
3947 * register a Navigation Group
3948 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3950 register : function(navgrp)
3952 this.groups[navgrp.navId] = navgrp;
3956 * fetch a Navigation Group based on the navigation ID
3957 * @param {string} the navgroup to add
3958 * @returns {Roo.bootstrap.NavGroup} the navgroup
3960 get: function(navId) {
3961 if (typeof(this.groups[navId]) == 'undefined') {
3963 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3965 return this.groups[navId] ;
3980 * @class Roo.bootstrap.NavItem
3981 * @extends Roo.bootstrap.Component
3982 * Bootstrap Navbar.NavItem class
3983 * @cfg {String} href link to
3984 * @cfg {String} html content of button
3985 * @cfg {String} badge text inside badge
3986 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3987 * @cfg {String} glyphicon name of glyphicon
3988 * @cfg {String} icon name of font awesome icon
3989 * @cfg {Boolean} active Is item active
3990 * @cfg {Boolean} disabled Is item disabled
3992 * @cfg {Boolean} preventDefault (true | false) default false
3993 * @cfg {String} tabId the tab that this item activates.
3994 * @cfg {String} tagtype (a|span) render as a href or span?
3995 * @cfg {Boolean} animateRef (true|false) link to element default false
3998 * Create a new Navbar Item
3999 * @param {Object} config The config object
4001 Roo.bootstrap.NavItem = function(config){
4002 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4007 * The raw click event for the entire grid.
4008 * @param {Roo.EventObject} e
4013 * Fires when the active item active state changes
4014 * @param {Roo.bootstrap.NavItem} this
4015 * @param {boolean} state the new state
4021 * Fires when scroll to element
4022 * @param {Roo.bootstrap.NavItem} this
4023 * @param {Object} options
4024 * @param {Roo.EventObject} e
4032 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4040 preventDefault : false,
4047 getAutoCreate : function(){
4055 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4057 if (this.disabled) {
4058 cfg.cls += ' disabled';
4061 if (this.href || this.html || this.glyphicon || this.icon) {
4065 href : this.href || "#",
4066 html: this.html || ''
4071 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4074 if(this.glyphicon) {
4075 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4080 cfg.cn[0].html += " <span class='caret'></span>";
4084 if (this.badge !== '') {
4086 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4094 initEvents: function()
4096 if (typeof (this.menu) != 'undefined') {
4097 this.menu.parentType = this.xtype;
4098 this.menu.triggerEl = this.el;
4099 this.menu = this.addxtype(Roo.apply({}, this.menu));
4102 this.el.select('a',true).on('click', this.onClick, this);
4104 if(this.tagtype == 'span'){
4105 this.el.select('span',true).on('click', this.onClick, this);
4108 // at this point parent should be available..
4109 this.parent().register(this);
4112 onClick : function(e)
4115 this.preventDefault ||
4122 if (this.disabled) {
4126 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4127 if (tg && tg.transition) {
4128 Roo.log("waiting for the transitionend");
4134 //Roo.log("fire event clicked");
4135 if(this.fireEvent('click', this, e) === false){
4139 if(this.tagtype == 'span'){
4143 //Roo.log(this.href);
4144 var ael = this.el.select('a',true).first();
4147 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4148 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4149 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4150 return; // ignore... - it's a 'hash' to another page.
4154 this.scrollToElement(e);
4158 var p = this.parent();
4160 if (['tabs','pills'].indexOf(p.type)!==-1) {
4161 if (typeof(p.setActiveItem) !== 'undefined') {
4162 p.setActiveItem(this);
4166 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4167 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4168 // remove the collapsed menu expand...
4169 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4173 isActive: function () {
4176 setActive : function(state, fire, is_was_active)
4178 if (this.active && !state & this.navId) {
4179 this.was_active = true;
4180 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4182 nv.clearWasActive(this);
4186 this.active = state;
4189 this.el.removeClass('active');
4190 } else if (!this.el.hasClass('active')) {
4191 this.el.addClass('active');
4194 this.fireEvent('changed', this, state);
4197 // show a panel if it's registered and related..
4199 if (!this.navId || !this.tabId || !state || is_was_active) {
4203 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4207 var pan = tg.getPanelByName(this.tabId);
4211 // if we can not flip to new panel - go back to old nav highlight..
4212 if (false == tg.showPanel(pan)) {
4213 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4215 var onav = nv.getWasActive();
4217 onav.setActive(true, false, true);
4226 // this should not be here...
4227 setDisabled : function(state)
4229 this.disabled = state;
4231 this.el.removeClass('disabled');
4232 } else if (!this.el.hasClass('disabled')) {
4233 this.el.addClass('disabled');
4239 * Fetch the element to display the tooltip on.
4240 * @return {Roo.Element} defaults to this.el
4242 tooltipEl : function()
4244 return this.el.select('' + this.tagtype + '', true).first();
4247 scrollToElement : function(e)
4249 var c = document.body;
4252 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4254 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4255 c = document.documentElement;
4258 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4264 var o = target.calcOffsetsTo(c);
4271 this.fireEvent('scrollto', this, options, e);
4273 Roo.get(c).scrollTo('top', options.value, true);
4286 * <span> icon </span>
4287 * <span> text </span>
4288 * <span>badge </span>
4292 * @class Roo.bootstrap.NavSidebarItem
4293 * @extends Roo.bootstrap.NavItem
4294 * Bootstrap Navbar.NavSidebarItem class
4296 * Create a new Navbar Button
4297 * @param {Object} config The config object
4299 Roo.bootstrap.NavSidebarItem = function(config){
4300 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4305 * The raw click event for the entire grid.
4306 * @param {Roo.EventObject} e
4311 * Fires when the active item active state changes
4312 * @param {Roo.bootstrap.NavSidebarItem} this
4313 * @param {boolean} state the new state
4321 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4324 getAutoCreate : function(){
4329 href : this.href || '#',
4341 html : this.html || ''
4346 cfg.cls += ' active';
4350 if (this.glyphicon || this.icon) {
4351 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4352 a.cn.push({ tag : 'i', cls : c }) ;
4357 if (this.badge !== '') {
4358 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4362 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4363 a.cls += 'dropdown-toggle treeview' ;
4387 * @class Roo.bootstrap.Row
4388 * @extends Roo.bootstrap.Component
4389 * Bootstrap Row class (contains columns...)
4393 * @param {Object} config The config object
4396 Roo.bootstrap.Row = function(config){
4397 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4400 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4402 getAutoCreate : function(){
4421 * @class Roo.bootstrap.Element
4422 * @extends Roo.bootstrap.Component
4423 * Bootstrap Element class
4424 * @cfg {String} html contents of the element
4425 * @cfg {String} tag tag of the element
4426 * @cfg {String} cls class of the element
4427 * @cfg {Boolean} preventDefault (true|false) default false
4428 * @cfg {Boolean} clickable (true|false) default false
4431 * Create a new Element
4432 * @param {Object} config The config object
4435 Roo.bootstrap.Element = function(config){
4436 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4442 * When a element is chick
4443 * @param {Roo.bootstrap.Element} this
4444 * @param {Roo.EventObject} e
4450 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4455 preventDefault: false,
4458 getAutoCreate : function(){
4469 initEvents: function()
4471 Roo.bootstrap.Element.superclass.initEvents.call(this);
4474 this.el.on('click', this.onClick, this);
4479 onClick : function(e)
4481 if(this.preventDefault){
4485 this.fireEvent('click', this, e);
4488 getValue : function()
4490 return this.el.dom.innerHTML;
4493 setValue : function(value)
4495 this.el.dom.innerHTML = value;
4510 * @class Roo.bootstrap.Pagination
4511 * @extends Roo.bootstrap.Component
4512 * Bootstrap Pagination class
4513 * @cfg {String} size xs | sm | md | lg
4514 * @cfg {Boolean} inverse false | true
4517 * Create a new Pagination
4518 * @param {Object} config The config object
4521 Roo.bootstrap.Pagination = function(config){
4522 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4525 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4531 getAutoCreate : function(){
4537 cfg.cls += ' inverse';
4543 cfg.cls += " " + this.cls;
4561 * @class Roo.bootstrap.PaginationItem
4562 * @extends Roo.bootstrap.Component
4563 * Bootstrap PaginationItem class
4564 * @cfg {String} html text
4565 * @cfg {String} href the link
4566 * @cfg {Boolean} preventDefault (true | false) default true
4567 * @cfg {Boolean} active (true | false) default false
4568 * @cfg {Boolean} disabled default false
4572 * Create a new PaginationItem
4573 * @param {Object} config The config object
4577 Roo.bootstrap.PaginationItem = function(config){
4578 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4583 * The raw click event for the entire grid.
4584 * @param {Roo.EventObject} e
4590 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4594 preventDefault: true,
4599 getAutoCreate : function(){
4605 href : this.href ? this.href : '#',
4606 html : this.html ? this.html : ''
4616 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4620 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4626 initEvents: function() {
4628 this.el.on('click', this.onClick, this);
4631 onClick : function(e)
4633 Roo.log('PaginationItem on click ');
4634 if(this.preventDefault){
4642 this.fireEvent('click', this, e);
4658 * @class Roo.bootstrap.Slider
4659 * @extends Roo.bootstrap.Component
4660 * Bootstrap Slider class
4663 * Create a new Slider
4664 * @param {Object} config The config object
4667 Roo.bootstrap.Slider = function(config){
4668 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4671 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4673 getAutoCreate : function(){
4677 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4681 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4693 * Ext JS Library 1.1.1
4694 * Copyright(c) 2006-2007, Ext JS, LLC.
4696 * Originally Released Under LGPL - original licence link has changed is not relivant.
4699 * <script type="text/javascript">
4704 * @class Roo.grid.ColumnModel
4705 * @extends Roo.util.Observable
4706 * This is the default implementation of a ColumnModel used by the Grid. It defines
4707 * the columns in the grid.
4710 var colModel = new Roo.grid.ColumnModel([
4711 {header: "Ticker", width: 60, sortable: true, locked: true},
4712 {header: "Company Name", width: 150, sortable: true},
4713 {header: "Market Cap.", width: 100, sortable: true},
4714 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4715 {header: "Employees", width: 100, sortable: true, resizable: false}
4720 * The config options listed for this class are options which may appear in each
4721 * individual column definition.
4722 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4724 * @param {Object} config An Array of column config objects. See this class's
4725 * config objects for details.
4727 Roo.grid.ColumnModel = function(config){
4729 * The config passed into the constructor
4731 this.config = config;
4734 // if no id, create one
4735 // if the column does not have a dataIndex mapping,
4736 // map it to the order it is in the config
4737 for(var i = 0, len = config.length; i < len; i++){
4739 if(typeof c.dataIndex == "undefined"){
4742 if(typeof c.renderer == "string"){
4743 c.renderer = Roo.util.Format[c.renderer];
4745 if(typeof c.id == "undefined"){
4748 if(c.editor && c.editor.xtype){
4749 c.editor = Roo.factory(c.editor, Roo.grid);
4751 if(c.editor && c.editor.isFormField){
4752 c.editor = new Roo.grid.GridEditor(c.editor);
4754 this.lookup[c.id] = c;
4758 * The width of columns which have no width specified (defaults to 100)
4761 this.defaultWidth = 100;
4764 * Default sortable of columns which have no sortable specified (defaults to false)
4767 this.defaultSortable = false;
4771 * @event widthchange
4772 * Fires when the width of a column changes.
4773 * @param {ColumnModel} this
4774 * @param {Number} columnIndex The column index
4775 * @param {Number} newWidth The new width
4777 "widthchange": true,
4779 * @event headerchange
4780 * Fires when the text of a header changes.
4781 * @param {ColumnModel} this
4782 * @param {Number} columnIndex The column index
4783 * @param {Number} newText The new header text
4785 "headerchange": true,
4787 * @event hiddenchange
4788 * Fires when a column is hidden or "unhidden".
4789 * @param {ColumnModel} this
4790 * @param {Number} columnIndex The column index
4791 * @param {Boolean} hidden true if hidden, false otherwise
4793 "hiddenchange": true,
4795 * @event columnmoved
4796 * Fires when a column is moved.
4797 * @param {ColumnModel} this
4798 * @param {Number} oldIndex
4799 * @param {Number} newIndex
4801 "columnmoved" : true,
4803 * @event columlockchange
4804 * Fires when a column's locked state is changed
4805 * @param {ColumnModel} this
4806 * @param {Number} colIndex
4807 * @param {Boolean} locked true if locked
4809 "columnlockchange" : true
4811 Roo.grid.ColumnModel.superclass.constructor.call(this);
4813 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4815 * @cfg {String} header The header text to display in the Grid view.
4818 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4819 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4820 * specified, the column's index is used as an index into the Record's data Array.
4823 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4824 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4827 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4828 * Defaults to the value of the {@link #defaultSortable} property.
4829 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4832 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4835 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4838 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4841 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4844 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4845 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4846 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4847 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4850 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4853 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4856 * @cfg {String} cursor (Optional)
4859 * @cfg {String} tooltip (Optional)
4862 * Returns the id of the column at the specified index.
4863 * @param {Number} index The column index
4864 * @return {String} the id
4866 getColumnId : function(index){
4867 return this.config[index].id;
4871 * Returns the column for a specified id.
4872 * @param {String} id The column id
4873 * @return {Object} the column
4875 getColumnById : function(id){
4876 return this.lookup[id];
4881 * Returns the column for a specified dataIndex.
4882 * @param {String} dataIndex The column dataIndex
4883 * @return {Object|Boolean} the column or false if not found
4885 getColumnByDataIndex: function(dataIndex){
4886 var index = this.findColumnIndex(dataIndex);
4887 return index > -1 ? this.config[index] : false;
4891 * Returns the index for a specified column id.
4892 * @param {String} id The column id
4893 * @return {Number} the index, or -1 if not found
4895 getIndexById : function(id){
4896 for(var i = 0, len = this.config.length; i < len; i++){
4897 if(this.config[i].id == id){
4905 * Returns the index for a specified column dataIndex.
4906 * @param {String} dataIndex The column dataIndex
4907 * @return {Number} the index, or -1 if not found
4910 findColumnIndex : function(dataIndex){
4911 for(var i = 0, len = this.config.length; i < len; i++){
4912 if(this.config[i].dataIndex == dataIndex){
4920 moveColumn : function(oldIndex, newIndex){
4921 var c = this.config[oldIndex];
4922 this.config.splice(oldIndex, 1);
4923 this.config.splice(newIndex, 0, c);
4924 this.dataMap = null;
4925 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4928 isLocked : function(colIndex){
4929 return this.config[colIndex].locked === true;
4932 setLocked : function(colIndex, value, suppressEvent){
4933 if(this.isLocked(colIndex) == value){
4936 this.config[colIndex].locked = value;
4938 this.fireEvent("columnlockchange", this, colIndex, value);
4942 getTotalLockedWidth : function(){
4944 for(var i = 0; i < this.config.length; i++){
4945 if(this.isLocked(i) && !this.isHidden(i)){
4946 this.totalWidth += this.getColumnWidth(i);
4952 getLockedCount : function(){
4953 for(var i = 0, len = this.config.length; i < len; i++){
4954 if(!this.isLocked(i)){
4961 * Returns the number of columns.
4964 getColumnCount : function(visibleOnly){
4965 if(visibleOnly === true){
4967 for(var i = 0, len = this.config.length; i < len; i++){
4968 if(!this.isHidden(i)){
4974 return this.config.length;
4978 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4979 * @param {Function} fn
4980 * @param {Object} scope (optional)
4981 * @return {Array} result
4983 getColumnsBy : function(fn, scope){
4985 for(var i = 0, len = this.config.length; i < len; i++){
4986 var c = this.config[i];
4987 if(fn.call(scope||this, c, i) === true){
4995 * Returns true if the specified column is sortable.
4996 * @param {Number} col The column index
4999 isSortable : function(col){
5000 if(typeof this.config[col].sortable == "undefined"){
5001 return this.defaultSortable;
5003 return this.config[col].sortable;
5007 * Returns the rendering (formatting) function defined for the column.
5008 * @param {Number} col The column index.
5009 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5011 getRenderer : function(col){
5012 if(!this.config[col].renderer){
5013 return Roo.grid.ColumnModel.defaultRenderer;
5015 return this.config[col].renderer;
5019 * Sets the rendering (formatting) function for a column.
5020 * @param {Number} col The column index
5021 * @param {Function} fn The function to use to process the cell's raw data
5022 * to return HTML markup for the grid view. The render function is called with
5023 * the following parameters:<ul>
5024 * <li>Data value.</li>
5025 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5026 * <li>css A CSS style string to apply to the table cell.</li>
5027 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5028 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5029 * <li>Row index</li>
5030 * <li>Column index</li>
5031 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5033 setRenderer : function(col, fn){
5034 this.config[col].renderer = fn;
5038 * Returns the width for the specified column.
5039 * @param {Number} col The column index
5042 getColumnWidth : function(col){
5043 return this.config[col].width * 1 || this.defaultWidth;
5047 * Sets the width for a column.
5048 * @param {Number} col The column index
5049 * @param {Number} width The new width
5051 setColumnWidth : function(col, width, suppressEvent){
5052 this.config[col].width = width;
5053 this.totalWidth = null;
5055 this.fireEvent("widthchange", this, col, width);
5060 * Returns the total width of all columns.
5061 * @param {Boolean} includeHidden True to include hidden column widths
5064 getTotalWidth : function(includeHidden){
5065 if(!this.totalWidth){
5066 this.totalWidth = 0;
5067 for(var i = 0, len = this.config.length; i < len; i++){
5068 if(includeHidden || !this.isHidden(i)){
5069 this.totalWidth += this.getColumnWidth(i);
5073 return this.totalWidth;
5077 * Returns the header for the specified column.
5078 * @param {Number} col The column index
5081 getColumnHeader : function(col){
5082 return this.config[col].header;
5086 * Sets the header for a column.
5087 * @param {Number} col The column index
5088 * @param {String} header The new header
5090 setColumnHeader : function(col, header){
5091 this.config[col].header = header;
5092 this.fireEvent("headerchange", this, col, header);
5096 * Returns the tooltip for the specified column.
5097 * @param {Number} col The column index
5100 getColumnTooltip : function(col){
5101 return this.config[col].tooltip;
5104 * Sets the tooltip for a column.
5105 * @param {Number} col The column index
5106 * @param {String} tooltip The new tooltip
5108 setColumnTooltip : function(col, tooltip){
5109 this.config[col].tooltip = tooltip;
5113 * Returns the dataIndex for the specified column.
5114 * @param {Number} col The column index
5117 getDataIndex : function(col){
5118 return this.config[col].dataIndex;
5122 * Sets the dataIndex for a column.
5123 * @param {Number} col The column index
5124 * @param {Number} dataIndex The new dataIndex
5126 setDataIndex : function(col, dataIndex){
5127 this.config[col].dataIndex = dataIndex;
5133 * Returns true if the cell is editable.
5134 * @param {Number} colIndex The column index
5135 * @param {Number} rowIndex The row index
5138 isCellEditable : function(colIndex, rowIndex){
5139 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5143 * Returns the editor defined for the cell/column.
5144 * return false or null to disable editing.
5145 * @param {Number} colIndex The column index
5146 * @param {Number} rowIndex The row index
5149 getCellEditor : function(colIndex, rowIndex){
5150 return this.config[colIndex].editor;
5154 * Sets if a column is editable.
5155 * @param {Number} col The column index
5156 * @param {Boolean} editable True if the column is editable
5158 setEditable : function(col, editable){
5159 this.config[col].editable = editable;
5164 * Returns true if the column is hidden.
5165 * @param {Number} colIndex The column index
5168 isHidden : function(colIndex){
5169 return this.config[colIndex].hidden;
5174 * Returns true if the column width cannot be changed
5176 isFixed : function(colIndex){
5177 return this.config[colIndex].fixed;
5181 * Returns true if the column can be resized
5184 isResizable : function(colIndex){
5185 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5188 * Sets if a column is hidden.
5189 * @param {Number} colIndex The column index
5190 * @param {Boolean} hidden True if the column is hidden
5192 setHidden : function(colIndex, hidden){
5193 this.config[colIndex].hidden = hidden;
5194 this.totalWidth = null;
5195 this.fireEvent("hiddenchange", this, colIndex, hidden);
5199 * Sets the editor for a column.
5200 * @param {Number} col The column index
5201 * @param {Object} editor The editor object
5203 setEditor : function(col, editor){
5204 this.config[col].editor = editor;
5208 Roo.grid.ColumnModel.defaultRenderer = function(value){
5209 if(typeof value == "string" && value.length < 1){
5215 // Alias for backwards compatibility
5216 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5219 * Ext JS Library 1.1.1
5220 * Copyright(c) 2006-2007, Ext JS, LLC.
5222 * Originally Released Under LGPL - original licence link has changed is not relivant.
5225 * <script type="text/javascript">
5229 * @class Roo.LoadMask
5230 * A simple utility class for generically masking elements while loading data. If the element being masked has
5231 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5232 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5233 * element's UpdateManager load indicator and will be destroyed after the initial load.
5235 * Create a new LoadMask
5236 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5237 * @param {Object} config The config object
5239 Roo.LoadMask = function(el, config){
5240 this.el = Roo.get(el);
5241 Roo.apply(this, config);
5243 this.store.on('beforeload', this.onBeforeLoad, this);
5244 this.store.on('load', this.onLoad, this);
5245 this.store.on('loadexception', this.onLoadException, this);
5246 this.removeMask = false;
5248 var um = this.el.getUpdateManager();
5249 um.showLoadIndicator = false; // disable the default indicator
5250 um.on('beforeupdate', this.onBeforeLoad, this);
5251 um.on('update', this.onLoad, this);
5252 um.on('failure', this.onLoad, this);
5253 this.removeMask = true;
5257 Roo.LoadMask.prototype = {
5259 * @cfg {Boolean} removeMask
5260 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5261 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5265 * The text to display in a centered loading message box (defaults to 'Loading...')
5269 * @cfg {String} msgCls
5270 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5272 msgCls : 'x-mask-loading',
5275 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5281 * Disables the mask to prevent it from being displayed
5283 disable : function(){
5284 this.disabled = true;
5288 * Enables the mask so that it can be displayed
5290 enable : function(){
5291 this.disabled = false;
5294 onLoadException : function()
5298 if (typeof(arguments[3]) != 'undefined') {
5299 Roo.MessageBox.alert("Error loading",arguments[3]);
5303 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5304 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5313 this.el.unmask(this.removeMask);
5318 this.el.unmask(this.removeMask);
5322 onBeforeLoad : function(){
5324 this.el.mask(this.msg, this.msgCls);
5329 destroy : function(){
5331 this.store.un('beforeload', this.onBeforeLoad, this);
5332 this.store.un('load', this.onLoad, this);
5333 this.store.un('loadexception', this.onLoadException, this);
5335 var um = this.el.getUpdateManager();
5336 um.un('beforeupdate', this.onBeforeLoad, this);
5337 um.un('update', this.onLoad, this);
5338 um.un('failure', this.onLoad, this);
5349 * @class Roo.bootstrap.Table
5350 * @extends Roo.bootstrap.Component
5351 * Bootstrap Table class
5352 * @cfg {String} cls table class
5353 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5354 * @cfg {String} bgcolor Specifies the background color for a table
5355 * @cfg {Number} border Specifies whether the table cells should have borders or not
5356 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5357 * @cfg {Number} cellspacing Specifies the space between cells
5358 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5359 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5360 * @cfg {String} sortable Specifies that the table should be sortable
5361 * @cfg {String} summary Specifies a summary of the content of a table
5362 * @cfg {Number} width Specifies the width of a table
5363 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5365 * @cfg {boolean} striped Should the rows be alternative striped
5366 * @cfg {boolean} bordered Add borders to the table
5367 * @cfg {boolean} hover Add hover highlighting
5368 * @cfg {boolean} condensed Format condensed
5369 * @cfg {boolean} responsive Format condensed
5370 * @cfg {Boolean} loadMask (true|false) default false
5371 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5372 * @cfg {Boolean} thead (true|false) generate thead, default true
5373 * @cfg {Boolean} RowSelection (true|false) default false
5374 * @cfg {Boolean} CellSelection (true|false) default false
5375 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5379 * Create a new Table
5380 * @param {Object} config The config object
5383 Roo.bootstrap.Table = function(config){
5384 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5387 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5388 this.sm = this.selModel;
5389 this.sm.xmodule = this.xmodule || false;
5391 if (this.cm && typeof(this.cm.config) == 'undefined') {
5392 this.colModel = new Roo.grid.ColumnModel(this.cm);
5393 this.cm = this.colModel;
5394 this.cm.xmodule = this.xmodule || false;
5397 this.store= Roo.factory(this.store, Roo.data);
5398 this.ds = this.store;
5399 this.ds.xmodule = this.xmodule || false;
5402 if (this.footer && this.store) {
5403 this.footer.dataSource = this.ds;
5404 this.footer = Roo.factory(this.footer);
5411 * Fires when a cell is clicked
5412 * @param {Roo.bootstrap.Table} this
5413 * @param {Roo.Element} el
5414 * @param {Number} rowIndex
5415 * @param {Number} columnIndex
5416 * @param {Roo.EventObject} e
5420 * @event celldblclick
5421 * Fires when a cell is double clicked
5422 * @param {Roo.bootstrap.Table} this
5423 * @param {Roo.Element} el
5424 * @param {Number} rowIndex
5425 * @param {Number} columnIndex
5426 * @param {Roo.EventObject} e
5428 "celldblclick" : true,
5431 * Fires when a row is clicked
5432 * @param {Roo.bootstrap.Table} this
5433 * @param {Roo.Element} el
5434 * @param {Number} rowIndex
5435 * @param {Roo.EventObject} e
5439 * @event rowdblclick
5440 * Fires when a row is double clicked
5441 * @param {Roo.bootstrap.Table} this
5442 * @param {Roo.Element} el
5443 * @param {Number} rowIndex
5444 * @param {Roo.EventObject} e
5446 "rowdblclick" : true,
5449 * Fires when a mouseover occur
5450 * @param {Roo.bootstrap.Table} this
5451 * @param {Roo.Element} el
5452 * @param {Number} rowIndex
5453 * @param {Number} columnIndex
5454 * @param {Roo.EventObject} e
5459 * Fires when a mouseout occur
5460 * @param {Roo.bootstrap.Table} this
5461 * @param {Roo.Element} el
5462 * @param {Number} rowIndex
5463 * @param {Number} columnIndex
5464 * @param {Roo.EventObject} e
5469 * Fires when a row is rendered, so you can change add a style to it.
5470 * @param {Roo.bootstrap.Table} this
5471 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5475 * @event rowsrendered
5476 * Fires when all the rows have been rendered
5477 * @param {Roo.bootstrap.Table} this
5479 'rowsrendered' : true
5484 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5508 RowSelection : false,
5509 CellSelection : false,
5512 // Roo.Element - the tbody
5515 getAutoCreate : function(){
5516 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5525 cfg.cls += ' table-striped';
5529 cfg.cls += ' table-hover';
5531 if (this.bordered) {
5532 cfg.cls += ' table-bordered';
5534 if (this.condensed) {
5535 cfg.cls += ' table-condensed';
5537 if (this.responsive) {
5538 cfg.cls += ' table-responsive';
5542 cfg.cls+= ' ' +this.cls;
5545 // this lot should be simplifed...
5548 cfg.align=this.align;
5551 cfg.bgcolor=this.bgcolor;
5554 cfg.border=this.border;
5556 if (this.cellpadding) {
5557 cfg.cellpadding=this.cellpadding;
5559 if (this.cellspacing) {
5560 cfg.cellspacing=this.cellspacing;
5563 cfg.frame=this.frame;
5566 cfg.rules=this.rules;
5568 if (this.sortable) {
5569 cfg.sortable=this.sortable;
5572 cfg.summary=this.summary;
5575 cfg.width=this.width;
5578 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5581 if(this.store || this.cm){
5583 cfg.cn.push(this.renderHeader());
5586 cfg.cn.push(this.renderBody());
5589 cfg.cn.push(this.renderFooter());
5592 cfg.cls+= ' TableGrid';
5595 return { cn : [ cfg ] };
5598 initEvents : function()
5600 if(!this.store || !this.cm){
5604 //Roo.log('initEvents with ds!!!!');
5606 this.mainBody = this.el.select('tbody', true).first();
5611 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5612 e.on('click', _this.sort, _this);
5615 this.el.on("click", this.onClick, this);
5616 this.el.on("dblclick", this.onDblClick, this);
5618 // why is this done????? = it breaks dialogs??
5619 //this.parent().el.setStyle('position', 'relative');
5623 this.footer.parentId = this.id;
5624 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5627 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5629 this.store.on('load', this.onLoad, this);
5630 this.store.on('beforeload', this.onBeforeLoad, this);
5631 this.store.on('update', this.onUpdate, this);
5632 this.store.on('add', this.onAdd, this);
5636 onMouseover : function(e, el)
5638 var cell = Roo.get(el);
5644 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5645 cell = cell.findParent('td', false, true);
5648 var row = cell.findParent('tr', false, true);
5649 var cellIndex = cell.dom.cellIndex;
5650 var rowIndex = row.dom.rowIndex - 1; // start from 0
5652 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5656 onMouseout : function(e, el)
5658 var cell = Roo.get(el);
5664 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5665 cell = cell.findParent('td', false, true);
5668 var row = cell.findParent('tr', false, true);
5669 var cellIndex = cell.dom.cellIndex;
5670 var rowIndex = row.dom.rowIndex - 1; // start from 0
5672 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5676 onClick : function(e, el)
5678 var cell = Roo.get(el);
5680 if(!cell || (!this.CellSelection && !this.RowSelection)){
5684 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5685 cell = cell.findParent('td', false, true);
5688 if(!cell || typeof(cell) == 'undefined'){
5692 var row = cell.findParent('tr', false, true);
5694 if(!row || typeof(row) == 'undefined'){
5698 var cellIndex = cell.dom.cellIndex;
5699 var rowIndex = this.getRowIndex(row);
5701 if(this.CellSelection){
5702 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5705 if(this.RowSelection){
5706 this.fireEvent('rowclick', this, row, rowIndex, e);
5712 onDblClick : function(e,el)
5714 var cell = Roo.get(el);
5716 if(!cell || (!this.CellSelection && !this.RowSelection)){
5720 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5721 cell = cell.findParent('td', false, true);
5724 if(!cell || typeof(cell) == 'undefined'){
5728 var row = cell.findParent('tr', false, true);
5730 if(!row || typeof(row) == 'undefined'){
5734 var cellIndex = cell.dom.cellIndex;
5735 var rowIndex = this.getRowIndex(row);
5737 if(this.CellSelection){
5738 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5741 if(this.RowSelection){
5742 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5746 sort : function(e,el)
5748 var col = Roo.get(el);
5750 if(!col.hasClass('sortable')){
5754 var sort = col.attr('sort');
5757 if(col.hasClass('glyphicon-arrow-up')){
5761 this.store.sortInfo = {field : sort, direction : dir};
5764 Roo.log("calling footer first");
5765 this.footer.onClick('first');
5768 this.store.load({ params : { start : 0 } });
5772 renderHeader : function()
5781 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5783 var config = cm.config[i];
5788 html: cm.getColumnHeader(i)
5791 if(typeof(config.tooltip) != 'undefined'){
5792 c.tooltip = config.tooltip;
5795 if(typeof(config.colspan) != 'undefined'){
5796 c.colspan = config.colspan;
5799 if(typeof(config.hidden) != 'undefined' && config.hidden){
5800 c.style += ' display:none;';
5803 if(typeof(config.dataIndex) != 'undefined'){
5804 c.sort = config.dataIndex;
5807 if(typeof(config.sortable) != 'undefined' && config.sortable){
5811 if(typeof(config.align) != 'undefined' && config.align.length){
5812 c.style += ' text-align:' + config.align + ';';
5815 if(typeof(config.width) != 'undefined'){
5816 c.style += ' width:' + config.width + 'px;';
5819 if(typeof(config.cls) != 'undefined'){
5820 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5829 renderBody : function()
5839 colspan : this.cm.getColumnCount()
5849 renderFooter : function()
5859 colspan : this.cm.getColumnCount()
5873 Roo.log('ds onload');
5878 var ds = this.store;
5880 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5881 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5883 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5884 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5887 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5888 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5892 var tbody = this.mainBody;
5894 if(ds.getCount() > 0){
5895 ds.data.each(function(d,rowIndex){
5896 var row = this.renderRow(cm, ds, rowIndex);
5898 tbody.createChild(row);
5902 if(row.cellObjects.length){
5903 Roo.each(row.cellObjects, function(r){
5904 _this.renderCellObject(r);
5911 Roo.each(this.el.select('tbody td', true).elements, function(e){
5912 e.on('mouseover', _this.onMouseover, _this);
5915 Roo.each(this.el.select('tbody td', true).elements, function(e){
5916 e.on('mouseout', _this.onMouseout, _this);
5918 this.fireEvent('rowsrendered', this);
5919 //if(this.loadMask){
5920 // this.maskEl.hide();
5925 onUpdate : function(ds,record)
5927 this.refreshRow(record);
5930 onRemove : function(ds, record, index, isUpdate){
5931 if(isUpdate !== true){
5932 this.fireEvent("beforerowremoved", this, index, record);
5934 var bt = this.mainBody.dom;
5936 var rows = this.el.select('tbody > tr', true).elements;
5938 if(typeof(rows[index]) != 'undefined'){
5939 bt.removeChild(rows[index].dom);
5942 // if(bt.rows[index]){
5943 // bt.removeChild(bt.rows[index]);
5946 if(isUpdate !== true){
5947 //this.stripeRows(index);
5948 //this.syncRowHeights(index, index);
5950 this.fireEvent("rowremoved", this, index, record);
5954 onAdd : function(ds, records, rowIndex)
5956 //Roo.log('on Add called');
5957 // - note this does not handle multiple adding very well..
5958 var bt = this.mainBody.dom;
5959 for (var i =0 ; i < records.length;i++) {
5960 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5961 //Roo.log(records[i]);
5962 //Roo.log(this.store.getAt(rowIndex+i));
5963 this.insertRow(this.store, rowIndex + i, false);
5970 refreshRow : function(record){
5971 var ds = this.store, index;
5972 if(typeof record == 'number'){
5974 record = ds.getAt(index);
5976 index = ds.indexOf(record);
5978 this.insertRow(ds, index, true);
5979 this.onRemove(ds, record, index+1, true);
5980 //this.syncRowHeights(index, index);
5982 this.fireEvent("rowupdated", this, index, record);
5985 insertRow : function(dm, rowIndex, isUpdate){
5988 this.fireEvent("beforerowsinserted", this, rowIndex);
5990 //var s = this.getScrollState();
5991 var row = this.renderRow(this.cm, this.store, rowIndex);
5992 // insert before rowIndex..
5993 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5997 if(row.cellObjects.length){
5998 Roo.each(row.cellObjects, function(r){
5999 _this.renderCellObject(r);
6004 this.fireEvent("rowsinserted", this, rowIndex);
6005 //this.syncRowHeights(firstRow, lastRow);
6006 //this.stripeRows(firstRow);
6013 getRowDom : function(rowIndex)
6015 var rows = this.el.select('tbody > tr', true).elements;
6017 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6020 // returns the object tree for a tr..
6023 renderRow : function(cm, ds, rowIndex)
6026 var d = ds.getAt(rowIndex);
6033 var cellObjects = [];
6035 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6036 var config = cm.config[i];
6038 var renderer = cm.getRenderer(i);
6042 if(typeof(renderer) !== 'undefined'){
6043 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6045 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6046 // and are rendered into the cells after the row is rendered - using the id for the element.
6048 if(typeof(value) === 'object'){
6058 rowIndex : rowIndex,
6063 this.fireEvent('rowclass', this, rowcfg);
6067 cls : rowcfg.rowClass,
6069 html: (typeof(value) === 'object') ? '' : value
6076 if(typeof(config.colspan) != 'undefined'){
6077 td.colspan = config.colspan;
6080 if(typeof(config.hidden) != 'undefined' && config.hidden){
6081 td.style += ' display:none;';
6084 if(typeof(config.align) != 'undefined' && config.align.length){
6085 td.style += ' text-align:' + config.align + ';';
6088 if(typeof(config.width) != 'undefined'){
6089 td.style += ' width:' + config.width + 'px;';
6092 if(typeof(config.cursor) != 'undefined'){
6093 td.style += ' cursor:' + config.cursor + ';';
6096 if(typeof(config.cls) != 'undefined'){
6097 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6104 row.cellObjects = cellObjects;
6112 onBeforeLoad : function()
6114 //Roo.log('ds onBeforeLoad');
6118 //if(this.loadMask){
6119 // this.maskEl.show();
6127 this.el.select('tbody', true).first().dom.innerHTML = '';
6130 * Show or hide a row.
6131 * @param {Number} rowIndex to show or hide
6132 * @param {Boolean} state hide
6134 setRowVisibility : function(rowIndex, state)
6136 var bt = this.mainBody.dom;
6138 var rows = this.el.select('tbody > tr', true).elements;
6140 if(typeof(rows[rowIndex]) == 'undefined'){
6143 rows[rowIndex].dom.style.display = state ? '' : 'none';
6147 getSelectionModel : function(){
6149 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6151 return this.selModel;
6154 * Render the Roo.bootstrap object from renderder
6156 renderCellObject : function(r)
6160 var t = r.cfg.render(r.container);
6163 Roo.each(r.cfg.cn, function(c){
6165 container: t.getChildContainer(),
6168 _this.renderCellObject(child);
6173 getRowIndex : function(row)
6177 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6200 * @class Roo.bootstrap.TableCell
6201 * @extends Roo.bootstrap.Component
6202 * Bootstrap TableCell class
6203 * @cfg {String} html cell contain text
6204 * @cfg {String} cls cell class
6205 * @cfg {String} tag cell tag (td|th) default td
6206 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6207 * @cfg {String} align Aligns the content in a cell
6208 * @cfg {String} axis Categorizes cells
6209 * @cfg {String} bgcolor Specifies the background color of a cell
6210 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6211 * @cfg {Number} colspan Specifies the number of columns a cell should span
6212 * @cfg {String} headers Specifies one or more header cells a cell is related to
6213 * @cfg {Number} height Sets the height of a cell
6214 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6215 * @cfg {Number} rowspan Sets the number of rows a cell should span
6216 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6217 * @cfg {String} valign Vertical aligns the content in a cell
6218 * @cfg {Number} width Specifies the width of a cell
6221 * Create a new TableCell
6222 * @param {Object} config The config object
6225 Roo.bootstrap.TableCell = function(config){
6226 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6229 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6249 getAutoCreate : function(){
6250 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6270 cfg.align=this.align
6276 cfg.bgcolor=this.bgcolor
6279 cfg.charoff=this.charoff
6282 cfg.colspan=this.colspan
6285 cfg.headers=this.headers
6288 cfg.height=this.height
6291 cfg.nowrap=this.nowrap
6294 cfg.rowspan=this.rowspan
6297 cfg.scope=this.scope
6300 cfg.valign=this.valign
6303 cfg.width=this.width
6322 * @class Roo.bootstrap.TableRow
6323 * @extends Roo.bootstrap.Component
6324 * Bootstrap TableRow class
6325 * @cfg {String} cls row class
6326 * @cfg {String} align Aligns the content in a table row
6327 * @cfg {String} bgcolor Specifies a background color for a table row
6328 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6329 * @cfg {String} valign Vertical aligns the content in a table row
6332 * Create a new TableRow
6333 * @param {Object} config The config object
6336 Roo.bootstrap.TableRow = function(config){
6337 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6340 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6348 getAutoCreate : function(){
6349 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6359 cfg.align = this.align;
6362 cfg.bgcolor = this.bgcolor;
6365 cfg.charoff = this.charoff;
6368 cfg.valign = this.valign;
6386 * @class Roo.bootstrap.TableBody
6387 * @extends Roo.bootstrap.Component
6388 * Bootstrap TableBody class
6389 * @cfg {String} cls element class
6390 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6391 * @cfg {String} align Aligns the content inside the element
6392 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6393 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6396 * Create a new TableBody
6397 * @param {Object} config The config object
6400 Roo.bootstrap.TableBody = function(config){
6401 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6404 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6412 getAutoCreate : function(){
6413 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6427 cfg.align = this.align;
6430 cfg.charoff = this.charoff;
6433 cfg.valign = this.valign;
6440 // initEvents : function()
6447 // this.store = Roo.factory(this.store, Roo.data);
6448 // this.store.on('load', this.onLoad, this);
6450 // this.store.load();
6454 // onLoad: function ()
6456 // this.fireEvent('load', this);
6466 * Ext JS Library 1.1.1
6467 * Copyright(c) 2006-2007, Ext JS, LLC.
6469 * Originally Released Under LGPL - original licence link has changed is not relivant.
6472 * <script type="text/javascript">
6475 // as we use this in bootstrap.
6476 Roo.namespace('Roo.form');
6478 * @class Roo.form.Action
6479 * Internal Class used to handle form actions
6481 * @param {Roo.form.BasicForm} el The form element or its id
6482 * @param {Object} config Configuration options
6487 // define the action interface
6488 Roo.form.Action = function(form, options){
6490 this.options = options || {};
6493 * Client Validation Failed
6496 Roo.form.Action.CLIENT_INVALID = 'client';
6498 * Server Validation Failed
6501 Roo.form.Action.SERVER_INVALID = 'server';
6503 * Connect to Server Failed
6506 Roo.form.Action.CONNECT_FAILURE = 'connect';
6508 * Reading Data from Server Failed
6511 Roo.form.Action.LOAD_FAILURE = 'load';
6513 Roo.form.Action.prototype = {
6515 failureType : undefined,
6516 response : undefined,
6520 run : function(options){
6525 success : function(response){
6530 handleResponse : function(response){
6534 // default connection failure
6535 failure : function(response){
6537 this.response = response;
6538 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6539 this.form.afterAction(this, false);
6542 processResponse : function(response){
6543 this.response = response;
6544 if(!response.responseText){
6547 this.result = this.handleResponse(response);
6551 // utility functions used internally
6552 getUrl : function(appendParams){
6553 var url = this.options.url || this.form.url || this.form.el.dom.action;
6555 var p = this.getParams();
6557 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6563 getMethod : function(){
6564 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6567 getParams : function(){
6568 var bp = this.form.baseParams;
6569 var p = this.options.params;
6571 if(typeof p == "object"){
6572 p = Roo.urlEncode(Roo.applyIf(p, bp));
6573 }else if(typeof p == 'string' && bp){
6574 p += '&' + Roo.urlEncode(bp);
6577 p = Roo.urlEncode(bp);
6582 createCallback : function(){
6584 success: this.success,
6585 failure: this.failure,
6587 timeout: (this.form.timeout*1000),
6588 upload: this.form.fileUpload ? this.success : undefined
6593 Roo.form.Action.Submit = function(form, options){
6594 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6597 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6600 haveProgress : false,
6601 uploadComplete : false,
6603 // uploadProgress indicator.
6604 uploadProgress : function()
6606 if (!this.form.progressUrl) {
6610 if (!this.haveProgress) {
6611 Roo.MessageBox.progress("Uploading", "Uploading");
6613 if (this.uploadComplete) {
6614 Roo.MessageBox.hide();
6618 this.haveProgress = true;
6620 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6622 var c = new Roo.data.Connection();
6624 url : this.form.progressUrl,
6629 success : function(req){
6630 //console.log(data);
6634 rdata = Roo.decode(req.responseText)
6636 Roo.log("Invalid data from server..");
6640 if (!rdata || !rdata.success) {
6642 Roo.MessageBox.alert(Roo.encode(rdata));
6645 var data = rdata.data;
6647 if (this.uploadComplete) {
6648 Roo.MessageBox.hide();
6653 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6654 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6657 this.uploadProgress.defer(2000,this);
6660 failure: function(data) {
6661 Roo.log('progress url failed ');
6672 // run get Values on the form, so it syncs any secondary forms.
6673 this.form.getValues();
6675 var o = this.options;
6676 var method = this.getMethod();
6677 var isPost = method == 'POST';
6678 if(o.clientValidation === false || this.form.isValid()){
6680 if (this.form.progressUrl) {
6681 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6682 (new Date() * 1) + '' + Math.random());
6687 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6688 form:this.form.el.dom,
6689 url:this.getUrl(!isPost),
6691 params:isPost ? this.getParams() : null,
6692 isUpload: this.form.fileUpload
6695 this.uploadProgress();
6697 }else if (o.clientValidation !== false){ // client validation failed
6698 this.failureType = Roo.form.Action.CLIENT_INVALID;
6699 this.form.afterAction(this, false);
6703 success : function(response)
6705 this.uploadComplete= true;
6706 if (this.haveProgress) {
6707 Roo.MessageBox.hide();
6711 var result = this.processResponse(response);
6712 if(result === true || result.success){
6713 this.form.afterAction(this, true);
6717 this.form.markInvalid(result.errors);
6718 this.failureType = Roo.form.Action.SERVER_INVALID;
6720 this.form.afterAction(this, false);
6722 failure : function(response)
6724 this.uploadComplete= true;
6725 if (this.haveProgress) {
6726 Roo.MessageBox.hide();
6729 this.response = response;
6730 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6731 this.form.afterAction(this, false);
6734 handleResponse : function(response){
6735 if(this.form.errorReader){
6736 var rs = this.form.errorReader.read(response);
6739 for(var i = 0, len = rs.records.length; i < len; i++) {
6740 var r = rs.records[i];
6744 if(errors.length < 1){
6748 success : rs.success,
6754 ret = Roo.decode(response.responseText);
6758 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6768 Roo.form.Action.Load = function(form, options){
6769 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6770 this.reader = this.form.reader;
6773 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6778 Roo.Ajax.request(Roo.apply(
6779 this.createCallback(), {
6780 method:this.getMethod(),
6781 url:this.getUrl(false),
6782 params:this.getParams()
6786 success : function(response){
6788 var result = this.processResponse(response);
6789 if(result === true || !result.success || !result.data){
6790 this.failureType = Roo.form.Action.LOAD_FAILURE;
6791 this.form.afterAction(this, false);
6794 this.form.clearInvalid();
6795 this.form.setValues(result.data);
6796 this.form.afterAction(this, true);
6799 handleResponse : function(response){
6800 if(this.form.reader){
6801 var rs = this.form.reader.read(response);
6802 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6804 success : rs.success,
6808 return Roo.decode(response.responseText);
6812 Roo.form.Action.ACTION_TYPES = {
6813 'load' : Roo.form.Action.Load,
6814 'submit' : Roo.form.Action.Submit
6823 * @class Roo.bootstrap.Form
6824 * @extends Roo.bootstrap.Component
6825 * Bootstrap Form class
6826 * @cfg {String} method GET | POST (default POST)
6827 * @cfg {String} labelAlign top | left (default top)
6828 * @cfg {String} align left | right - for navbars
6829 * @cfg {Boolean} loadMask load mask when submit (default true)
6834 * @param {Object} config The config object
6838 Roo.bootstrap.Form = function(config){
6839 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6842 * @event clientvalidation
6843 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6844 * @param {Form} this
6845 * @param {Boolean} valid true if the form has passed client-side validation
6847 clientvalidation: true,
6849 * @event beforeaction
6850 * Fires before any action is performed. Return false to cancel the action.
6851 * @param {Form} this
6852 * @param {Action} action The action to be performed
6856 * @event actionfailed
6857 * Fires when an action fails.
6858 * @param {Form} this
6859 * @param {Action} action The action that failed
6861 actionfailed : true,
6863 * @event actioncomplete
6864 * Fires when an action is completed.
6865 * @param {Form} this
6866 * @param {Action} action The action that completed
6868 actioncomplete : true
6873 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6876 * @cfg {String} method
6877 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6882 * The URL to use for form actions if one isn't supplied in the action options.
6885 * @cfg {Boolean} fileUpload
6886 * Set to true if this form is a file upload.
6890 * @cfg {Object} baseParams
6891 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6895 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6899 * @cfg {Sting} align (left|right) for navbar forms
6904 activeAction : null,
6907 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6908 * element by passing it or its id or mask the form itself by passing in true.
6911 waitMsgTarget : false,
6915 getAutoCreate : function(){
6919 method : this.method || 'POST',
6920 id : this.id || Roo.id(),
6923 if (this.parent().xtype.match(/^Nav/)) {
6924 cfg.cls = 'navbar-form navbar-' + this.align;
6928 if (this.labelAlign == 'left' ) {
6929 cfg.cls += ' form-horizontal';
6935 initEvents : function()
6937 this.el.on('submit', this.onSubmit, this);
6938 // this was added as random key presses on the form where triggering form submit.
6939 this.el.on('keypress', function(e) {
6940 if (e.getCharCode() != 13) {
6943 // we might need to allow it for textareas.. and some other items.
6944 // check e.getTarget().
6946 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6950 Roo.log("keypress blocked");
6958 onSubmit : function(e){
6963 * Returns true if client-side validation on the form is successful.
6966 isValid : function(){
6967 var items = this.getItems();
6969 items.each(function(f){
6978 * Returns true if any fields in this form have changed since their original load.
6981 isDirty : function(){
6983 var items = this.getItems();
6984 items.each(function(f){
6994 * Performs a predefined action (submit or load) or custom actions you define on this form.
6995 * @param {String} actionName The name of the action type
6996 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6997 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6998 * accept other config options):
7000 Property Type Description
7001 ---------------- --------------- ----------------------------------------------------------------------------------
7002 url String The url for the action (defaults to the form's url)
7003 method String The form method to use (defaults to the form's method, or POST if not defined)
7004 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7005 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7006 validate the form on the client (defaults to false)
7008 * @return {BasicForm} this
7010 doAction : function(action, options){
7011 if(typeof action == 'string'){
7012 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7014 if(this.fireEvent('beforeaction', this, action) !== false){
7015 this.beforeAction(action);
7016 action.run.defer(100, action);
7022 beforeAction : function(action){
7023 var o = action.options;
7026 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7028 // not really supported yet.. ??
7030 //if(this.waitMsgTarget === true){
7031 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7032 //}else if(this.waitMsgTarget){
7033 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7034 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7036 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7042 afterAction : function(action, success){
7043 this.activeAction = null;
7044 var o = action.options;
7046 //if(this.waitMsgTarget === true){
7048 //}else if(this.waitMsgTarget){
7049 // this.waitMsgTarget.unmask();
7051 // Roo.MessageBox.updateProgress(1);
7052 // Roo.MessageBox.hide();
7059 Roo.callback(o.success, o.scope, [this, action]);
7060 this.fireEvent('actioncomplete', this, action);
7064 // failure condition..
7065 // we have a scenario where updates need confirming.
7066 // eg. if a locking scenario exists..
7067 // we look for { errors : { needs_confirm : true }} in the response.
7069 (typeof(action.result) != 'undefined') &&
7070 (typeof(action.result.errors) != 'undefined') &&
7071 (typeof(action.result.errors.needs_confirm) != 'undefined')
7074 Roo.log("not supported yet");
7077 Roo.MessageBox.confirm(
7078 "Change requires confirmation",
7079 action.result.errorMsg,
7084 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7094 Roo.callback(o.failure, o.scope, [this, action]);
7095 // show an error message if no failed handler is set..
7096 if (!this.hasListener('actionfailed')) {
7097 Roo.log("need to add dialog support");
7099 Roo.MessageBox.alert("Error",
7100 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7101 action.result.errorMsg :
7102 "Saving Failed, please check your entries or try again"
7107 this.fireEvent('actionfailed', this, action);
7112 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7113 * @param {String} id The value to search for
7116 findField : function(id){
7117 var items = this.getItems();
7118 var field = items.get(id);
7120 items.each(function(f){
7121 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7128 return field || null;
7131 * Mark fields in this form invalid in bulk.
7132 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7133 * @return {BasicForm} this
7135 markInvalid : function(errors){
7136 if(errors instanceof Array){
7137 for(var i = 0, len = errors.length; i < len; i++){
7138 var fieldError = errors[i];
7139 var f = this.findField(fieldError.id);
7141 f.markInvalid(fieldError.msg);
7147 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7148 field.markInvalid(errors[id]);
7152 //Roo.each(this.childForms || [], function (f) {
7153 // f.markInvalid(errors);
7160 * Set values for fields in this form in bulk.
7161 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7162 * @return {BasicForm} this
7164 setValues : function(values){
7165 if(values instanceof Array){ // array of objects
7166 for(var i = 0, len = values.length; i < len; i++){
7168 var f = this.findField(v.id);
7170 f.setValue(v.value);
7171 if(this.trackResetOnLoad){
7172 f.originalValue = f.getValue();
7176 }else{ // object hash
7179 if(typeof values[id] != 'function' && (field = this.findField(id))){
7181 if (field.setFromData &&
7183 field.displayField &&
7184 // combos' with local stores can
7185 // be queried via setValue()
7186 // to set their value..
7187 (field.store && !field.store.isLocal)
7191 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7192 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7193 field.setFromData(sd);
7196 field.setValue(values[id]);
7200 if(this.trackResetOnLoad){
7201 field.originalValue = field.getValue();
7207 //Roo.each(this.childForms || [], function (f) {
7208 // f.setValues(values);
7215 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7216 * they are returned as an array.
7217 * @param {Boolean} asString
7220 getValues : function(asString){
7221 //if (this.childForms) {
7222 // copy values from the child forms
7223 // Roo.each(this.childForms, function (f) {
7224 // this.setValues(f.getValues());
7230 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7231 if(asString === true){
7234 return Roo.urlDecode(fs);
7238 * Returns the fields in this form as an object with key/value pairs.
7239 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7242 getFieldValues : function(with_hidden)
7244 var items = this.getItems();
7246 items.each(function(f){
7250 var v = f.getValue();
7251 if (f.inputType =='radio') {
7252 if (typeof(ret[f.getName()]) == 'undefined') {
7253 ret[f.getName()] = ''; // empty..
7256 if (!f.el.dom.checked) {
7264 // not sure if this supported any more..
7265 if ((typeof(v) == 'object') && f.getRawValue) {
7266 v = f.getRawValue() ; // dates..
7268 // combo boxes where name != hiddenName...
7269 if (f.name != f.getName()) {
7270 ret[f.name] = f.getRawValue();
7272 ret[f.getName()] = v;
7279 * Clears all invalid messages in this form.
7280 * @return {BasicForm} this
7282 clearInvalid : function(){
7283 var items = this.getItems();
7285 items.each(function(f){
7296 * @return {BasicForm} this
7299 var items = this.getItems();
7300 items.each(function(f){
7304 Roo.each(this.childForms || [], function (f) {
7311 getItems : function()
7313 var r=new Roo.util.MixedCollection(false, function(o){
7314 return o.id || (o.id = Roo.id());
7316 var iter = function(el) {
7323 Roo.each(el.items,function(e) {
7343 * Ext JS Library 1.1.1
7344 * Copyright(c) 2006-2007, Ext JS, LLC.
7346 * Originally Released Under LGPL - original licence link has changed is not relivant.
7349 * <script type="text/javascript">
7352 * @class Roo.form.VTypes
7353 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7356 Roo.form.VTypes = function(){
7357 // closure these in so they are only created once.
7358 var alpha = /^[a-zA-Z_]+$/;
7359 var alphanum = /^[a-zA-Z0-9_]+$/;
7360 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7361 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7363 // All these messages and functions are configurable
7366 * The function used to validate email addresses
7367 * @param {String} value The email address
7369 'email' : function(v){
7370 return email.test(v);
7373 * The error text to display when the email validation function returns false
7376 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7378 * The keystroke filter mask to be applied on email input
7381 'emailMask' : /[a-z0-9_\.\-@]/i,
7384 * The function used to validate URLs
7385 * @param {String} value The URL
7387 'url' : function(v){
7391 * The error text to display when the url validation function returns false
7394 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7397 * The function used to validate alpha values
7398 * @param {String} value The value
7400 'alpha' : function(v){
7401 return alpha.test(v);
7404 * The error text to display when the alpha validation function returns false
7407 'alphaText' : 'This field should only contain letters and _',
7409 * The keystroke filter mask to be applied on alpha input
7412 'alphaMask' : /[a-z_]/i,
7415 * The function used to validate alphanumeric values
7416 * @param {String} value The value
7418 'alphanum' : function(v){
7419 return alphanum.test(v);
7422 * The error text to display when the alphanumeric validation function returns false
7425 'alphanumText' : 'This field should only contain letters, numbers and _',
7427 * The keystroke filter mask to be applied on alphanumeric input
7430 'alphanumMask' : /[a-z0-9_]/i
7440 * @class Roo.bootstrap.Input
7441 * @extends Roo.bootstrap.Component
7442 * Bootstrap Input class
7443 * @cfg {Boolean} disabled is it disabled
7444 * @cfg {String} fieldLabel - the label associated
7445 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7446 * @cfg {String} name name of the input
7447 * @cfg {string} fieldLabel - the label associated
7448 * @cfg {string} inputType - input / file submit ...
7449 * @cfg {string} placeholder - placeholder to put in text.
7450 * @cfg {string} before - input group add on before
7451 * @cfg {string} after - input group add on after
7452 * @cfg {string} size - (lg|sm) or leave empty..
7453 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7454 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7455 * @cfg {Number} md colspan out of 12 for computer-sized screens
7456 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7457 * @cfg {string} value default value of the input
7458 * @cfg {Number} labelWidth set the width of label (0-12)
7459 * @cfg {String} labelAlign (top|left)
7460 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7461 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7463 * @cfg {String} align (left|center|right) Default left
7468 * Create a new Input
7469 * @param {Object} config The config object
7472 Roo.bootstrap.Input = function(config){
7473 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7478 * Fires when this field receives input focus.
7479 * @param {Roo.form.Field} this
7484 * Fires when this field loses input focus.
7485 * @param {Roo.form.Field} this
7490 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7491 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7492 * @param {Roo.form.Field} this
7493 * @param {Roo.EventObject} e The event object
7498 * Fires just before the field blurs if the field value has changed.
7499 * @param {Roo.form.Field} this
7500 * @param {Mixed} newValue The new value
7501 * @param {Mixed} oldValue The original value
7506 * Fires after the field has been marked as invalid.
7507 * @param {Roo.form.Field} this
7508 * @param {String} msg The validation message
7513 * Fires after the field has been validated with no errors.
7514 * @param {Roo.form.Field} this
7519 * Fires after the key up
7520 * @param {Roo.form.Field} this
7521 * @param {Roo.EventObject} e The event Object
7527 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7529 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7530 automatic validation (defaults to "keyup").
7532 validationEvent : "keyup",
7534 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7536 validateOnBlur : true,
7538 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7540 validationDelay : 250,
7542 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7544 focusClass : "x-form-focus", // not needed???
7548 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7550 invalidClass : "has-warning",
7553 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7555 validClass : "has-success",
7558 * @cfg {Boolean} hasFeedback (true|false) default true
7563 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7565 invalidFeedbackClass : "glyphicon-warning-sign",
7568 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7570 validFeedbackClass : "glyphicon-ok",
7573 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7575 selectOnFocus : false,
7578 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7582 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7587 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7589 disableKeyFilter : false,
7592 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7596 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7600 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7602 blankText : "This field is required",
7605 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7609 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7611 maxLength : Number.MAX_VALUE,
7613 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7615 minLengthText : "The minimum length for this field is {0}",
7617 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7619 maxLengthText : "The maximum length for this field is {0}",
7623 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7624 * If available, this function will be called only after the basic validators all return true, and will be passed the
7625 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7629 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7630 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7631 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7635 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7639 autocomplete: false,
7658 formatedValue : false,
7660 parentLabelAlign : function()
7663 while (parent.parent()) {
7664 parent = parent.parent();
7665 if (typeof(parent.labelAlign) !='undefined') {
7666 return parent.labelAlign;
7673 getAutoCreate : function(){
7675 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7681 if(this.inputType != 'hidden'){
7682 cfg.cls = 'form-group' //input-group
7688 type : this.inputType,
7690 cls : 'form-control',
7691 placeholder : this.placeholder || '',
7692 autocomplete : this.autocomplete || 'new-password'
7697 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7700 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7701 input.maxLength = this.maxLength;
7704 if (this.disabled) {
7705 input.disabled=true;
7708 if (this.readOnly) {
7709 input.readonly=true;
7713 input.name = this.name;
7716 input.cls += ' input-' + this.size;
7719 ['xs','sm','md','lg'].map(function(size){
7720 if (settings[size]) {
7721 cfg.cls += ' col-' + size + '-' + settings[size];
7725 var inputblock = input;
7729 cls: 'glyphicon form-control-feedback'
7732 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7735 cls : 'has-feedback',
7743 if (this.before || this.after) {
7746 cls : 'input-group',
7750 if (this.before && typeof(this.before) == 'string') {
7752 inputblock.cn.push({
7754 cls : 'roo-input-before input-group-addon',
7758 if (this.before && typeof(this.before) == 'object') {
7759 this.before = Roo.factory(this.before);
7760 Roo.log(this.before);
7761 inputblock.cn.push({
7763 cls : 'roo-input-before input-group-' +
7764 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7768 inputblock.cn.push(input);
7770 if (this.after && typeof(this.after) == 'string') {
7771 inputblock.cn.push({
7773 cls : 'roo-input-after input-group-addon',
7777 if (this.after && typeof(this.after) == 'object') {
7778 this.after = Roo.factory(this.after);
7779 Roo.log(this.after);
7780 inputblock.cn.push({
7782 cls : 'roo-input-after input-group-' +
7783 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7787 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7788 inputblock.cls += ' has-feedback';
7789 inputblock.cn.push(feedback);
7793 if (align ==='left' && this.fieldLabel.length) {
7794 Roo.log("left and has label");
7800 cls : 'control-label col-sm-' + this.labelWidth,
7801 html : this.fieldLabel
7805 cls : "col-sm-" + (12 - this.labelWidth),
7812 } else if ( this.fieldLabel.length) {
7818 //cls : 'input-group-addon',
7819 html : this.fieldLabel
7829 Roo.log(" no label && no align");
7838 Roo.log('input-parentType: ' + this.parentType);
7840 if (this.parentType === 'Navbar' && this.parent().bar) {
7841 cfg.cls += ' navbar-form';
7849 * return the real input element.
7851 inputEl: function ()
7853 return this.el.select('input.form-control',true).first();
7856 tooltipEl : function()
7858 return this.inputEl();
7861 setDisabled : function(v)
7863 var i = this.inputEl().dom;
7865 i.removeAttribute('disabled');
7869 i.setAttribute('disabled','true');
7871 initEvents : function()
7874 this.inputEl().on("keydown" , this.fireKey, this);
7875 this.inputEl().on("focus", this.onFocus, this);
7876 this.inputEl().on("blur", this.onBlur, this);
7878 this.inputEl().relayEvent('keyup', this);
7880 // reference to original value for reset
7881 this.originalValue = this.getValue();
7882 //Roo.form.TextField.superclass.initEvents.call(this);
7883 if(this.validationEvent == 'keyup'){
7884 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7885 this.inputEl().on('keyup', this.filterValidation, this);
7887 else if(this.validationEvent !== false){
7888 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7891 if(this.selectOnFocus){
7892 this.on("focus", this.preFocus, this);
7895 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7896 this.inputEl().on("keypress", this.filterKeys, this);
7899 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7900 this.el.on("click", this.autoSize, this);
7903 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7904 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7907 if (typeof(this.before) == 'object') {
7908 this.before.render(this.el.select('.roo-input-before',true).first());
7910 if (typeof(this.after) == 'object') {
7911 this.after.render(this.el.select('.roo-input-after',true).first());
7916 filterValidation : function(e){
7917 if(!e.isNavKeyPress()){
7918 this.validationTask.delay(this.validationDelay);
7922 * Validates the field value
7923 * @return {Boolean} True if the value is valid, else false
7925 validate : function(){
7926 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7927 if(this.disabled || this.validateValue(this.getRawValue())){
7938 * Validates a value according to the field's validation rules and marks the field as invalid
7939 * if the validation fails
7940 * @param {Mixed} value The value to validate
7941 * @return {Boolean} True if the value is valid, else false
7943 validateValue : function(value){
7944 if(value.length < 1) { // if it's blank
7945 if(this.allowBlank){
7951 if(value.length < this.minLength){
7954 if(value.length > this.maxLength){
7958 var vt = Roo.form.VTypes;
7959 if(!vt[this.vtype](value, this)){
7963 if(typeof this.validator == "function"){
7964 var msg = this.validator(value);
7970 if(this.regex && !this.regex.test(value)){
7980 fireKey : function(e){
7981 //Roo.log('field ' + e.getKey());
7982 if(e.isNavKeyPress()){
7983 this.fireEvent("specialkey", this, e);
7986 focus : function (selectText){
7988 this.inputEl().focus();
7989 if(selectText === true){
7990 this.inputEl().dom.select();
7996 onFocus : function(){
7997 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7998 // this.el.addClass(this.focusClass);
8001 this.hasFocus = true;
8002 this.startValue = this.getValue();
8003 this.fireEvent("focus", this);
8007 beforeBlur : Roo.emptyFn,
8011 onBlur : function(){
8013 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8014 //this.el.removeClass(this.focusClass);
8016 this.hasFocus = false;
8017 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8020 var v = this.getValue();
8021 if(String(v) !== String(this.startValue)){
8022 this.fireEvent('change', this, v, this.startValue);
8024 this.fireEvent("blur", this);
8028 * Resets the current field value to the originally loaded value and clears any validation messages
8031 this.setValue(this.originalValue);
8035 * Returns the name of the field
8036 * @return {Mixed} name The name field
8038 getName: function(){
8042 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8043 * @return {Mixed} value The field value
8045 getValue : function(){
8047 var v = this.inputEl().getValue();
8052 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8053 * @return {Mixed} value The field value
8055 getRawValue : function(){
8056 var v = this.inputEl().getValue();
8062 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8063 * @param {Mixed} value The value to set
8065 setRawValue : function(v){
8066 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8069 selectText : function(start, end){
8070 var v = this.getRawValue();
8072 start = start === undefined ? 0 : start;
8073 end = end === undefined ? v.length : end;
8074 var d = this.inputEl().dom;
8075 if(d.setSelectionRange){
8076 d.setSelectionRange(start, end);
8077 }else if(d.createTextRange){
8078 var range = d.createTextRange();
8079 range.moveStart("character", start);
8080 range.moveEnd("character", v.length-end);
8087 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8088 * @param {Mixed} value The value to set
8090 setValue : function(v){
8093 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8099 processValue : function(value){
8100 if(this.stripCharsRe){
8101 var newValue = value.replace(this.stripCharsRe, '');
8102 if(newValue !== value){
8103 this.setRawValue(newValue);
8110 preFocus : function(){
8112 if(this.selectOnFocus){
8113 this.inputEl().dom.select();
8116 filterKeys : function(e){
8118 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8121 var c = e.getCharCode(), cc = String.fromCharCode(c);
8122 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8125 if(!this.maskRe.test(cc)){
8130 * Clear any invalid styles/messages for this field
8132 clearInvalid : function(){
8134 if(!this.el || this.preventMark){ // not rendered
8137 this.el.removeClass(this.invalidClass);
8139 this.fireEvent('valid', this);
8143 * Mark this field as valid
8145 markValid : function(){
8146 if(!this.el || this.preventMark){ // not rendered
8150 this.el.removeClass([this.invalidClass, this.validClass]);
8152 if(this.disabled || this.allowBlank){
8156 this.el.addClass(this.validClass);
8158 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8160 var feedback = this.el.select('.form-control-feedback', true).first();
8163 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8164 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8169 this.fireEvent('valid', this);
8173 * Mark this field as invalid
8174 * @param {String} msg The validation message
8176 markInvalid : function(msg){
8177 if(!this.el || this.preventMark){ // not rendered
8181 this.el.removeClass([this.invalidClass, this.validClass]);
8183 if(this.disabled || this.allowBlank){
8187 this.el.addClass(this.invalidClass);
8189 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8191 var feedback = this.el.select('.form-control-feedback', true).first();
8194 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8196 if(this.getValue().length){
8197 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8204 this.fireEvent('invalid', this, msg);
8207 SafariOnKeyDown : function(event)
8209 // this is a workaround for a password hang bug on chrome/ webkit.
8211 var isSelectAll = false;
8213 if(this.inputEl().dom.selectionEnd > 0){
8214 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8216 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8217 event.preventDefault();
8222 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8224 event.preventDefault();
8225 // this is very hacky as keydown always get's upper case.
8227 var cc = String.fromCharCode(event.getCharCode());
8228 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8232 adjustWidth : function(tag, w){
8233 tag = tag.toLowerCase();
8234 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8235 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8239 if(tag == 'textarea'){
8242 }else if(Roo.isOpera){
8246 if(tag == 'textarea'){
8265 * @class Roo.bootstrap.TextArea
8266 * @extends Roo.bootstrap.Input
8267 * Bootstrap TextArea class
8268 * @cfg {Number} cols Specifies the visible width of a text area
8269 * @cfg {Number} rows Specifies the visible number of lines in a text area
8270 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8271 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8272 * @cfg {string} html text
8275 * Create a new TextArea
8276 * @param {Object} config The config object
8279 Roo.bootstrap.TextArea = function(config){
8280 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8284 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8294 getAutoCreate : function(){
8296 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8307 value : this.value || '',
8308 html: this.html || '',
8309 cls : 'form-control',
8310 placeholder : this.placeholder || ''
8314 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8315 input.maxLength = this.maxLength;
8319 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8323 input.cols = this.cols;
8326 if (this.readOnly) {
8327 input.readonly = true;
8331 input.name = this.name;
8335 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8339 ['xs','sm','md','lg'].map(function(size){
8340 if (settings[size]) {
8341 cfg.cls += ' col-' + size + '-' + settings[size];
8345 var inputblock = input;
8347 if(this.hasFeedback && !this.allowBlank){
8351 cls: 'glyphicon form-control-feedback'
8355 cls : 'has-feedback',
8364 if (this.before || this.after) {
8367 cls : 'input-group',
8371 inputblock.cn.push({
8373 cls : 'input-group-addon',
8378 inputblock.cn.push(input);
8380 if(this.hasFeedback && !this.allowBlank){
8381 inputblock.cls += ' has-feedback';
8382 inputblock.cn.push(feedback);
8386 inputblock.cn.push({
8388 cls : 'input-group-addon',
8395 if (align ==='left' && this.fieldLabel.length) {
8396 Roo.log("left and has label");
8402 cls : 'control-label col-sm-' + this.labelWidth,
8403 html : this.fieldLabel
8407 cls : "col-sm-" + (12 - this.labelWidth),
8414 } else if ( this.fieldLabel.length) {
8420 //cls : 'input-group-addon',
8421 html : this.fieldLabel
8431 Roo.log(" no label && no align");
8441 if (this.disabled) {
8442 input.disabled=true;
8449 * return the real textarea element.
8451 inputEl: function ()
8453 return this.el.select('textarea.form-control',true).first();
8461 * trigger field - base class for combo..
8466 * @class Roo.bootstrap.TriggerField
8467 * @extends Roo.bootstrap.Input
8468 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8469 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8470 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8471 * for which you can provide a custom implementation. For example:
8473 var trigger = new Roo.bootstrap.TriggerField();
8474 trigger.onTriggerClick = myTriggerFn;
8475 trigger.applyTo('my-field');
8478 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8479 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8480 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8481 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8482 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8485 * Create a new TriggerField.
8486 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8487 * to the base TextField)
8489 Roo.bootstrap.TriggerField = function(config){
8490 this.mimicing = false;
8491 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8494 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8496 * @cfg {String} triggerClass A CSS class to apply to the trigger
8499 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8504 * @cfg {Boolean} removable (true|false) special filter default false
8508 /** @cfg {Boolean} grow @hide */
8509 /** @cfg {Number} growMin @hide */
8510 /** @cfg {Number} growMax @hide */
8516 autoSize: Roo.emptyFn,
8523 actionMode : 'wrap',
8528 getAutoCreate : function(){
8530 var align = this.labelAlign || this.parentLabelAlign();
8535 cls: 'form-group' //input-group
8542 type : this.inputType,
8543 cls : 'form-control',
8544 autocomplete: 'new-password',
8545 placeholder : this.placeholder || ''
8549 input.name = this.name;
8552 input.cls += ' input-' + this.size;
8555 if (this.disabled) {
8556 input.disabled=true;
8559 var inputblock = input;
8561 if(this.hasFeedback && !this.allowBlank){
8565 cls: 'glyphicon form-control-feedback'
8568 if(this.removable && !this.editable && !this.tickable){
8570 cls : 'has-feedback',
8576 cls : 'roo-combo-removable-btn close'
8583 cls : 'has-feedback',
8592 if(this.removable && !this.editable && !this.tickable){
8594 cls : 'roo-removable',
8600 cls : 'roo-combo-removable-btn close'
8607 if (this.before || this.after) {
8610 cls : 'input-group',
8614 inputblock.cn.push({
8616 cls : 'input-group-addon',
8621 inputblock.cn.push(input);
8623 if(this.hasFeedback && !this.allowBlank){
8624 inputblock.cls += ' has-feedback';
8625 inputblock.cn.push(feedback);
8629 inputblock.cn.push({
8631 cls : 'input-group-addon',
8644 cls: 'form-hidden-field'
8652 Roo.log('multiple');
8660 cls: 'form-hidden-field'
8664 cls: 'select2-choices',
8668 cls: 'select2-search-field',
8681 cls: 'select2-container input-group',
8686 // cls: 'typeahead typeahead-long dropdown-menu',
8687 // style: 'display:none'
8692 if(!this.multiple && this.showToggleBtn){
8698 if (this.caret != false) {
8701 cls: 'fa fa-' + this.caret
8708 cls : 'input-group-addon btn dropdown-toggle',
8713 cls: 'combobox-clear',
8727 combobox.cls += ' select2-container-multi';
8730 if (align ==='left' && this.fieldLabel.length) {
8732 Roo.log("left and has label");
8738 cls : 'control-label col-sm-' + this.labelWidth,
8739 html : this.fieldLabel
8743 cls : "col-sm-" + (12 - this.labelWidth),
8750 } else if ( this.fieldLabel.length) {
8756 //cls : 'input-group-addon',
8757 html : this.fieldLabel
8767 Roo.log(" no label && no align");
8774 ['xs','sm','md','lg'].map(function(size){
8775 if (settings[size]) {
8776 cfg.cls += ' col-' + size + '-' + settings[size];
8787 onResize : function(w, h){
8788 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8789 // if(typeof w == 'number'){
8790 // var x = w - this.trigger.getWidth();
8791 // this.inputEl().setWidth(this.adjustWidth('input', x));
8792 // this.trigger.setStyle('left', x+'px');
8797 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8800 getResizeEl : function(){
8801 return this.inputEl();
8805 getPositionEl : function(){
8806 return this.inputEl();
8810 alignErrorIcon : function(){
8811 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8815 initEvents : function(){
8819 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8820 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8821 if(!this.multiple && this.showToggleBtn){
8822 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8823 if(this.hideTrigger){
8824 this.trigger.setDisplayed(false);
8826 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8830 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8833 if(this.removable && !this.editable && !this.tickable){
8834 var close = this.closeTriggerEl();
8837 close.setVisibilityMode(Roo.Element.DISPALY).hide();
8838 close.on('click', this.removeBtnClick, this, close);
8842 //this.trigger.addClassOnOver('x-form-trigger-over');
8843 //this.trigger.addClassOnClick('x-form-trigger-click');
8846 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8850 closeTriggerEl : function()
8852 var close = this.el.select('.roo-combo-removable-btn', true).first();
8853 return close ? close : false;
8856 removeBtnClick : function(e, h, el)
8860 if(this.fireEvent("remove", this) !== false){
8865 createList : function()
8867 this.list = Roo.get(document.body).createChild({
8869 cls: 'typeahead typeahead-long dropdown-menu',
8870 style: 'display:none'
8873 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8878 initTrigger : function(){
8883 onDestroy : function(){
8885 this.trigger.removeAllListeners();
8886 // this.trigger.remove();
8889 // this.wrap.remove();
8891 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8895 onFocus : function(){
8896 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8899 this.wrap.addClass('x-trigger-wrap-focus');
8900 this.mimicing = true;
8901 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8902 if(this.monitorTab){
8903 this.el.on("keydown", this.checkTab, this);
8910 checkTab : function(e){
8911 if(e.getKey() == e.TAB){
8917 onBlur : function(){
8922 mimicBlur : function(e, t){
8924 if(!this.wrap.contains(t) && this.validateBlur()){
8931 triggerBlur : function(){
8932 this.mimicing = false;
8933 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8934 if(this.monitorTab){
8935 this.el.un("keydown", this.checkTab, this);
8937 //this.wrap.removeClass('x-trigger-wrap-focus');
8938 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8942 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8943 validateBlur : function(e, t){
8948 onDisable : function(){
8949 this.inputEl().dom.disabled = true;
8950 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8952 // this.wrap.addClass('x-item-disabled');
8957 onEnable : function(){
8958 this.inputEl().dom.disabled = false;
8959 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8961 // this.el.removeClass('x-item-disabled');
8966 onShow : function(){
8967 var ae = this.getActionEl();
8970 ae.dom.style.display = '';
8971 ae.dom.style.visibility = 'visible';
8977 onHide : function(){
8978 var ae = this.getActionEl();
8979 ae.dom.style.display = 'none';
8983 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8984 * by an implementing function.
8986 * @param {EventObject} e
8988 onTriggerClick : Roo.emptyFn
8992 * Ext JS Library 1.1.1
8993 * Copyright(c) 2006-2007, Ext JS, LLC.
8995 * Originally Released Under LGPL - original licence link has changed is not relivant.
8998 * <script type="text/javascript">
9003 * @class Roo.data.SortTypes
9005 * Defines the default sorting (casting?) comparison functions used when sorting data.
9007 Roo.data.SortTypes = {
9009 * Default sort that does nothing
9010 * @param {Mixed} s The value being converted
9011 * @return {Mixed} The comparison value
9018 * The regular expression used to strip tags
9022 stripTagsRE : /<\/?[^>]+>/gi,
9025 * Strips all HTML tags to sort on text only
9026 * @param {Mixed} s The value being converted
9027 * @return {String} The comparison value
9029 asText : function(s){
9030 return String(s).replace(this.stripTagsRE, "");
9034 * Strips all HTML tags to sort on text only - Case insensitive
9035 * @param {Mixed} s The value being converted
9036 * @return {String} The comparison value
9038 asUCText : function(s){
9039 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9043 * Case insensitive string
9044 * @param {Mixed} s The value being converted
9045 * @return {String} The comparison value
9047 asUCString : function(s) {
9048 return String(s).toUpperCase();
9053 * @param {Mixed} s The value being converted
9054 * @return {Number} The comparison value
9056 asDate : function(s) {
9060 if(s instanceof Date){
9063 return Date.parse(String(s));
9068 * @param {Mixed} s The value being converted
9069 * @return {Float} The comparison value
9071 asFloat : function(s) {
9072 var val = parseFloat(String(s).replace(/,/g, ""));
9073 if(isNaN(val)) val = 0;
9079 * @param {Mixed} s The value being converted
9080 * @return {Number} The comparison value
9082 asInt : function(s) {
9083 var val = parseInt(String(s).replace(/,/g, ""));
9084 if(isNaN(val)) val = 0;
9089 * Ext JS Library 1.1.1
9090 * Copyright(c) 2006-2007, Ext JS, LLC.
9092 * Originally Released Under LGPL - original licence link has changed is not relivant.
9095 * <script type="text/javascript">
9099 * @class Roo.data.Record
9100 * Instances of this class encapsulate both record <em>definition</em> information, and record
9101 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9102 * to access Records cached in an {@link Roo.data.Store} object.<br>
9104 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9105 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9108 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9110 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9111 * {@link #create}. The parameters are the same.
9112 * @param {Array} data An associative Array of data values keyed by the field name.
9113 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9114 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9115 * not specified an integer id is generated.
9117 Roo.data.Record = function(data, id){
9118 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9123 * Generate a constructor for a specific record layout.
9124 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9125 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9126 * Each field definition object may contain the following properties: <ul>
9127 * <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,
9128 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9129 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9130 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9131 * is being used, then this is a string containing the javascript expression to reference the data relative to
9132 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9133 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9134 * this may be omitted.</p></li>
9135 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9136 * <ul><li>auto (Default, implies no conversion)</li>
9141 * <li>date</li></ul></p></li>
9142 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9143 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9144 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9145 * by the Reader into an object that will be stored in the Record. It is passed the
9146 * following parameters:<ul>
9147 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9149 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9151 * <br>usage:<br><pre><code>
9152 var TopicRecord = Roo.data.Record.create(
9153 {name: 'title', mapping: 'topic_title'},
9154 {name: 'author', mapping: 'username'},
9155 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9156 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9157 {name: 'lastPoster', mapping: 'user2'},
9158 {name: 'excerpt', mapping: 'post_text'}
9161 var myNewRecord = new TopicRecord({
9162 title: 'Do my job please',
9165 lastPost: new Date(),
9166 lastPoster: 'Animal',
9167 excerpt: 'No way dude!'
9169 myStore.add(myNewRecord);
9174 Roo.data.Record.create = function(o){
9176 f.superclass.constructor.apply(this, arguments);
9178 Roo.extend(f, Roo.data.Record);
9179 var p = f.prototype;
9180 p.fields = new Roo.util.MixedCollection(false, function(field){
9183 for(var i = 0, len = o.length; i < len; i++){
9184 p.fields.add(new Roo.data.Field(o[i]));
9186 f.getField = function(name){
9187 return p.fields.get(name);
9192 Roo.data.Record.AUTO_ID = 1000;
9193 Roo.data.Record.EDIT = 'edit';
9194 Roo.data.Record.REJECT = 'reject';
9195 Roo.data.Record.COMMIT = 'commit';
9197 Roo.data.Record.prototype = {
9199 * Readonly flag - true if this record has been modified.
9208 join : function(store){
9213 * Set the named field to the specified value.
9214 * @param {String} name The name of the field to set.
9215 * @param {Object} value The value to set the field to.
9217 set : function(name, value){
9218 if(this.data[name] == value){
9225 if(typeof this.modified[name] == 'undefined'){
9226 this.modified[name] = this.data[name];
9228 this.data[name] = value;
9229 if(!this.editing && this.store){
9230 this.store.afterEdit(this);
9235 * Get the value of the named field.
9236 * @param {String} name The name of the field to get the value of.
9237 * @return {Object} The value of the field.
9239 get : function(name){
9240 return this.data[name];
9244 beginEdit : function(){
9245 this.editing = true;
9250 cancelEdit : function(){
9251 this.editing = false;
9252 delete this.modified;
9256 endEdit : function(){
9257 this.editing = false;
9258 if(this.dirty && this.store){
9259 this.store.afterEdit(this);
9264 * Usually called by the {@link Roo.data.Store} which owns the Record.
9265 * Rejects all changes made to the Record since either creation, or the last commit operation.
9266 * Modified fields are reverted to their original values.
9268 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9269 * of reject operations.
9271 reject : function(){
9272 var m = this.modified;
9274 if(typeof m[n] != "function"){
9275 this.data[n] = m[n];
9279 delete this.modified;
9280 this.editing = false;
9282 this.store.afterReject(this);
9287 * Usually called by the {@link Roo.data.Store} which owns the Record.
9288 * Commits all changes made to the Record since either creation, or the last commit operation.
9290 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9291 * of commit operations.
9293 commit : function(){
9295 delete this.modified;
9296 this.editing = false;
9298 this.store.afterCommit(this);
9303 hasError : function(){
9304 return this.error != null;
9308 clearError : function(){
9313 * Creates a copy of this record.
9314 * @param {String} id (optional) A new record id if you don't want to use this record's id
9317 copy : function(newId) {
9318 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9322 * Ext JS Library 1.1.1
9323 * Copyright(c) 2006-2007, Ext JS, LLC.
9325 * Originally Released Under LGPL - original licence link has changed is not relivant.
9328 * <script type="text/javascript">
9334 * @class Roo.data.Store
9335 * @extends Roo.util.Observable
9336 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9337 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9339 * 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
9340 * has no knowledge of the format of the data returned by the Proxy.<br>
9342 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9343 * instances from the data object. These records are cached and made available through accessor functions.
9345 * Creates a new Store.
9346 * @param {Object} config A config object containing the objects needed for the Store to access data,
9347 * and read the data into Records.
9349 Roo.data.Store = function(config){
9350 this.data = new Roo.util.MixedCollection(false);
9351 this.data.getKey = function(o){
9354 this.baseParams = {};
9361 "multisort" : "_multisort"
9364 if(config && config.data){
9365 this.inlineData = config.data;
9369 Roo.apply(this, config);
9371 if(this.reader){ // reader passed
9372 this.reader = Roo.factory(this.reader, Roo.data);
9373 this.reader.xmodule = this.xmodule || false;
9374 if(!this.recordType){
9375 this.recordType = this.reader.recordType;
9377 if(this.reader.onMetaChange){
9378 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9382 if(this.recordType){
9383 this.fields = this.recordType.prototype.fields;
9389 * @event datachanged
9390 * Fires when the data cache has changed, and a widget which is using this Store
9391 * as a Record cache should refresh its view.
9392 * @param {Store} this
9397 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9398 * @param {Store} this
9399 * @param {Object} meta The JSON metadata
9404 * Fires when Records have been added to the Store
9405 * @param {Store} this
9406 * @param {Roo.data.Record[]} records The array of Records added
9407 * @param {Number} index The index at which the record(s) were added
9412 * Fires when a Record has been removed from the Store
9413 * @param {Store} this
9414 * @param {Roo.data.Record} record The Record that was removed
9415 * @param {Number} index The index at which the record was removed
9420 * Fires when a Record has been updated
9421 * @param {Store} this
9422 * @param {Roo.data.Record} record The Record that was updated
9423 * @param {String} operation The update operation being performed. Value may be one of:
9425 Roo.data.Record.EDIT
9426 Roo.data.Record.REJECT
9427 Roo.data.Record.COMMIT
9433 * Fires when the data cache has been cleared.
9434 * @param {Store} this
9439 * Fires before a request is made for a new data object. If the beforeload handler returns false
9440 * the load action will be canceled.
9441 * @param {Store} this
9442 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9446 * @event beforeloadadd
9447 * Fires after a new set of Records has been loaded.
9448 * @param {Store} this
9449 * @param {Roo.data.Record[]} records The Records that were loaded
9450 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9452 beforeloadadd : true,
9455 * Fires after a new set of Records has been loaded, before they are added to the store.
9456 * @param {Store} this
9457 * @param {Roo.data.Record[]} records The Records that were loaded
9458 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9459 * @params {Object} return from reader
9463 * @event loadexception
9464 * Fires if an exception occurs in the Proxy during loading.
9465 * Called with the signature of the Proxy's "loadexception" event.
9466 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9469 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9470 * @param {Object} load options
9471 * @param {Object} jsonData from your request (normally this contains the Exception)
9473 loadexception : true
9477 this.proxy = Roo.factory(this.proxy, Roo.data);
9478 this.proxy.xmodule = this.xmodule || false;
9479 this.relayEvents(this.proxy, ["loadexception"]);
9481 this.sortToggle = {};
9482 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9484 Roo.data.Store.superclass.constructor.call(this);
9486 if(this.inlineData){
9487 this.loadData(this.inlineData);
9488 delete this.inlineData;
9492 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9494 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9495 * without a remote query - used by combo/forms at present.
9499 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9502 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9505 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9506 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9509 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9510 * on any HTTP request
9513 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9516 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9520 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9521 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9526 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9527 * loaded or when a record is removed. (defaults to false).
9529 pruneModifiedRecords : false,
9535 * Add Records to the Store and fires the add event.
9536 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9538 add : function(records){
9539 records = [].concat(records);
9540 for(var i = 0, len = records.length; i < len; i++){
9541 records[i].join(this);
9543 var index = this.data.length;
9544 this.data.addAll(records);
9545 this.fireEvent("add", this, records, index);
9549 * Remove a Record from the Store and fires the remove event.
9550 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9552 remove : function(record){
9553 var index = this.data.indexOf(record);
9554 this.data.removeAt(index);
9555 if(this.pruneModifiedRecords){
9556 this.modified.remove(record);
9558 this.fireEvent("remove", this, record, index);
9562 * Remove all Records from the Store and fires the clear event.
9564 removeAll : function(){
9566 if(this.pruneModifiedRecords){
9569 this.fireEvent("clear", this);
9573 * Inserts Records to the Store at the given index and fires the add event.
9574 * @param {Number} index The start index at which to insert the passed Records.
9575 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9577 insert : function(index, records){
9578 records = [].concat(records);
9579 for(var i = 0, len = records.length; i < len; i++){
9580 this.data.insert(index, records[i]);
9581 records[i].join(this);
9583 this.fireEvent("add", this, records, index);
9587 * Get the index within the cache of the passed Record.
9588 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9589 * @return {Number} The index of the passed Record. Returns -1 if not found.
9591 indexOf : function(record){
9592 return this.data.indexOf(record);
9596 * Get the index within the cache of the Record with the passed id.
9597 * @param {String} id The id of the Record to find.
9598 * @return {Number} The index of the Record. Returns -1 if not found.
9600 indexOfId : function(id){
9601 return this.data.indexOfKey(id);
9605 * Get the Record with the specified id.
9606 * @param {String} id The id of the Record to find.
9607 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9609 getById : function(id){
9610 return this.data.key(id);
9614 * Get the Record at the specified index.
9615 * @param {Number} index The index of the Record to find.
9616 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9618 getAt : function(index){
9619 return this.data.itemAt(index);
9623 * Returns a range of Records between specified indices.
9624 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9625 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9626 * @return {Roo.data.Record[]} An array of Records
9628 getRange : function(start, end){
9629 return this.data.getRange(start, end);
9633 storeOptions : function(o){
9634 o = Roo.apply({}, o);
9637 this.lastOptions = o;
9641 * Loads the Record cache from the configured Proxy using the configured Reader.
9643 * If using remote paging, then the first load call must specify the <em>start</em>
9644 * and <em>limit</em> properties in the options.params property to establish the initial
9645 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9647 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9648 * and this call will return before the new data has been loaded. Perform any post-processing
9649 * in a callback function, or in a "load" event handler.</strong>
9651 * @param {Object} options An object containing properties which control loading options:<ul>
9652 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9653 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9654 * passed the following arguments:<ul>
9655 * <li>r : Roo.data.Record[]</li>
9656 * <li>options: Options object from the load call</li>
9657 * <li>success: Boolean success indicator</li></ul></li>
9658 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9659 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9662 load : function(options){
9663 options = options || {};
9664 if(this.fireEvent("beforeload", this, options) !== false){
9665 this.storeOptions(options);
9666 var p = Roo.apply(options.params || {}, this.baseParams);
9667 // if meta was not loaded from remote source.. try requesting it.
9668 if (!this.reader.metaFromRemote) {
9671 if(this.sortInfo && this.remoteSort){
9672 var pn = this.paramNames;
9673 p[pn["sort"]] = this.sortInfo.field;
9674 p[pn["dir"]] = this.sortInfo.direction;
9676 if (this.multiSort) {
9677 var pn = this.paramNames;
9678 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9681 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9686 * Reloads the Record cache from the configured Proxy using the configured Reader and
9687 * the options from the last load operation performed.
9688 * @param {Object} options (optional) An object containing properties which may override the options
9689 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9690 * the most recently used options are reused).
9692 reload : function(options){
9693 this.load(Roo.applyIf(options||{}, this.lastOptions));
9697 // Called as a callback by the Reader during a load operation.
9698 loadRecords : function(o, options, success){
9699 if(!o || success === false){
9700 if(success !== false){
9701 this.fireEvent("load", this, [], options, o);
9703 if(options.callback){
9704 options.callback.call(options.scope || this, [], options, false);
9708 // if data returned failure - throw an exception.
9709 if (o.success === false) {
9710 // show a message if no listener is registered.
9711 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9712 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9714 // loadmask wil be hooked into this..
9715 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9718 var r = o.records, t = o.totalRecords || r.length;
9720 this.fireEvent("beforeloadadd", this, r, options, o);
9722 if(!options || options.add !== true){
9723 if(this.pruneModifiedRecords){
9726 for(var i = 0, len = r.length; i < len; i++){
9730 this.data = this.snapshot;
9731 delete this.snapshot;
9734 this.data.addAll(r);
9735 this.totalLength = t;
9737 this.fireEvent("datachanged", this);
9739 this.totalLength = Math.max(t, this.data.length+r.length);
9742 this.fireEvent("load", this, r, options, o);
9743 if(options.callback){
9744 options.callback.call(options.scope || this, r, options, true);
9750 * Loads data from a passed data block. A Reader which understands the format of the data
9751 * must have been configured in the constructor.
9752 * @param {Object} data The data block from which to read the Records. The format of the data expected
9753 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9754 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9756 loadData : function(o, append){
9757 var r = this.reader.readRecords(o);
9758 this.loadRecords(r, {add: append}, true);
9762 * Gets the number of cached records.
9764 * <em>If using paging, this may not be the total size of the dataset. If the data object
9765 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9766 * the data set size</em>
9768 getCount : function(){
9769 return this.data.length || 0;
9773 * Gets the total number of records in the dataset as returned by the server.
9775 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9776 * the dataset size</em>
9778 getTotalCount : function(){
9779 return this.totalLength || 0;
9783 * Returns the sort state of the Store as an object with two properties:
9785 field {String} The name of the field by which the Records are sorted
9786 direction {String} The sort order, "ASC" or "DESC"
9789 getSortState : function(){
9790 return this.sortInfo;
9794 applySort : function(){
9795 if(this.sortInfo && !this.remoteSort){
9796 var s = this.sortInfo, f = s.field;
9797 var st = this.fields.get(f).sortType;
9798 var fn = function(r1, r2){
9799 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9800 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9802 this.data.sort(s.direction, fn);
9803 if(this.snapshot && this.snapshot != this.data){
9804 this.snapshot.sort(s.direction, fn);
9810 * Sets the default sort column and order to be used by the next load operation.
9811 * @param {String} fieldName The name of the field to sort by.
9812 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9814 setDefaultSort : function(field, dir){
9815 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9820 * If remote sorting is used, the sort is performed on the server, and the cache is
9821 * reloaded. If local sorting is used, the cache is sorted internally.
9822 * @param {String} fieldName The name of the field to sort by.
9823 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9825 sort : function(fieldName, dir){
9826 var f = this.fields.get(fieldName);
9828 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9830 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9831 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9836 this.sortToggle[f.name] = dir;
9837 this.sortInfo = {field: f.name, direction: dir};
9838 if(!this.remoteSort){
9840 this.fireEvent("datachanged", this);
9842 this.load(this.lastOptions);
9847 * Calls the specified function for each of the Records in the cache.
9848 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9849 * Returning <em>false</em> aborts and exits the iteration.
9850 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9852 each : function(fn, scope){
9853 this.data.each(fn, scope);
9857 * Gets all records modified since the last commit. Modified records are persisted across load operations
9858 * (e.g., during paging).
9859 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9861 getModifiedRecords : function(){
9862 return this.modified;
9866 createFilterFn : function(property, value, anyMatch){
9867 if(!value.exec){ // not a regex
9868 value = String(value);
9869 if(value.length == 0){
9872 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9875 return value.test(r.data[property]);
9880 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9881 * @param {String} property A field on your records
9882 * @param {Number} start The record index to start at (defaults to 0)
9883 * @param {Number} end The last record index to include (defaults to length - 1)
9884 * @return {Number} The sum
9886 sum : function(property, start, end){
9887 var rs = this.data.items, v = 0;
9889 end = (end || end === 0) ? end : rs.length-1;
9891 for(var i = start; i <= end; i++){
9892 v += (rs[i].data[property] || 0);
9898 * Filter the records by a specified property.
9899 * @param {String} field A field on your records
9900 * @param {String/RegExp} value Either a string that the field
9901 * should start with or a RegExp to test against the field
9902 * @param {Boolean} anyMatch True to match any part not just the beginning
9904 filter : function(property, value, anyMatch){
9905 var fn = this.createFilterFn(property, value, anyMatch);
9906 return fn ? this.filterBy(fn) : this.clearFilter();
9910 * Filter by a function. The specified function will be called with each
9911 * record in this data source. If the function returns true the record is included,
9912 * otherwise it is filtered.
9913 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9914 * @param {Object} scope (optional) The scope of the function (defaults to this)
9916 filterBy : function(fn, scope){
9917 this.snapshot = this.snapshot || this.data;
9918 this.data = this.queryBy(fn, scope||this);
9919 this.fireEvent("datachanged", this);
9923 * Query the records by a specified property.
9924 * @param {String} field A field on your records
9925 * @param {String/RegExp} value Either a string that the field
9926 * should start with or a RegExp to test against the field
9927 * @param {Boolean} anyMatch True to match any part not just the beginning
9928 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9930 query : function(property, value, anyMatch){
9931 var fn = this.createFilterFn(property, value, anyMatch);
9932 return fn ? this.queryBy(fn) : this.data.clone();
9936 * Query by a function. The specified function will be called with each
9937 * record in this data source. If the function returns true the record is included
9939 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9940 * @param {Object} scope (optional) The scope of the function (defaults to this)
9941 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9943 queryBy : function(fn, scope){
9944 var data = this.snapshot || this.data;
9945 return data.filterBy(fn, scope||this);
9949 * Collects unique values for a particular dataIndex from this store.
9950 * @param {String} dataIndex The property to collect
9951 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9952 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9953 * @return {Array} An array of the unique values
9955 collect : function(dataIndex, allowNull, bypassFilter){
9956 var d = (bypassFilter === true && this.snapshot) ?
9957 this.snapshot.items : this.data.items;
9958 var v, sv, r = [], l = {};
9959 for(var i = 0, len = d.length; i < len; i++){
9960 v = d[i].data[dataIndex];
9962 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9971 * Revert to a view of the Record cache with no filtering applied.
9972 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9974 clearFilter : function(suppressEvent){
9975 if(this.snapshot && this.snapshot != this.data){
9976 this.data = this.snapshot;
9977 delete this.snapshot;
9978 if(suppressEvent !== true){
9979 this.fireEvent("datachanged", this);
9985 afterEdit : function(record){
9986 if(this.modified.indexOf(record) == -1){
9987 this.modified.push(record);
9989 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9993 afterReject : function(record){
9994 this.modified.remove(record);
9995 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9999 afterCommit : function(record){
10000 this.modified.remove(record);
10001 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10005 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10006 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10008 commitChanges : function(){
10009 var m = this.modified.slice(0);
10010 this.modified = [];
10011 for(var i = 0, len = m.length; i < len; i++){
10017 * Cancel outstanding changes on all changed records.
10019 rejectChanges : function(){
10020 var m = this.modified.slice(0);
10021 this.modified = [];
10022 for(var i = 0, len = m.length; i < len; i++){
10027 onMetaChange : function(meta, rtype, o){
10028 this.recordType = rtype;
10029 this.fields = rtype.prototype.fields;
10030 delete this.snapshot;
10031 this.sortInfo = meta.sortInfo || this.sortInfo;
10032 this.modified = [];
10033 this.fireEvent('metachange', this, this.reader.meta);
10036 moveIndex : function(data, type)
10038 var index = this.indexOf(data);
10040 var newIndex = index + type;
10044 this.insert(newIndex, data);
10049 * Ext JS Library 1.1.1
10050 * Copyright(c) 2006-2007, Ext JS, LLC.
10052 * Originally Released Under LGPL - original licence link has changed is not relivant.
10055 * <script type="text/javascript">
10059 * @class Roo.data.SimpleStore
10060 * @extends Roo.data.Store
10061 * Small helper class to make creating Stores from Array data easier.
10062 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10063 * @cfg {Array} fields An array of field definition objects, or field name strings.
10064 * @cfg {Array} data The multi-dimensional array of data
10066 * @param {Object} config
10068 Roo.data.SimpleStore = function(config){
10069 Roo.data.SimpleStore.superclass.constructor.call(this, {
10071 reader: new Roo.data.ArrayReader({
10074 Roo.data.Record.create(config.fields)
10076 proxy : new Roo.data.MemoryProxy(config.data)
10080 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10082 * Ext JS Library 1.1.1
10083 * Copyright(c) 2006-2007, Ext JS, LLC.
10085 * Originally Released Under LGPL - original licence link has changed is not relivant.
10088 * <script type="text/javascript">
10093 * @extends Roo.data.Store
10094 * @class Roo.data.JsonStore
10095 * Small helper class to make creating Stores for JSON data easier. <br/>
10097 var store = new Roo.data.JsonStore({
10098 url: 'get-images.php',
10100 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10103 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10104 * JsonReader and HttpProxy (unless inline data is provided).</b>
10105 * @cfg {Array} fields An array of field definition objects, or field name strings.
10107 * @param {Object} config
10109 Roo.data.JsonStore = function(c){
10110 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10111 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10112 reader: new Roo.data.JsonReader(c, c.fields)
10115 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10117 * Ext JS Library 1.1.1
10118 * Copyright(c) 2006-2007, Ext JS, LLC.
10120 * Originally Released Under LGPL - original licence link has changed is not relivant.
10123 * <script type="text/javascript">
10127 Roo.data.Field = function(config){
10128 if(typeof config == "string"){
10129 config = {name: config};
10131 Roo.apply(this, config);
10134 this.type = "auto";
10137 var st = Roo.data.SortTypes;
10138 // named sortTypes are supported, here we look them up
10139 if(typeof this.sortType == "string"){
10140 this.sortType = st[this.sortType];
10143 // set default sortType for strings and dates
10144 if(!this.sortType){
10147 this.sortType = st.asUCString;
10150 this.sortType = st.asDate;
10153 this.sortType = st.none;
10158 var stripRe = /[\$,%]/g;
10160 // prebuilt conversion function for this field, instead of
10161 // switching every time we're reading a value
10163 var cv, dateFormat = this.dateFormat;
10168 cv = function(v){ return v; };
10171 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10175 return v !== undefined && v !== null && v !== '' ?
10176 parseInt(String(v).replace(stripRe, ""), 10) : '';
10181 return v !== undefined && v !== null && v !== '' ?
10182 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10187 cv = function(v){ return v === true || v === "true" || v == 1; };
10194 if(v instanceof Date){
10198 if(dateFormat == "timestamp"){
10199 return new Date(v*1000);
10201 return Date.parseDate(v, dateFormat);
10203 var parsed = Date.parse(v);
10204 return parsed ? new Date(parsed) : null;
10213 Roo.data.Field.prototype = {
10221 * Ext JS Library 1.1.1
10222 * Copyright(c) 2006-2007, Ext JS, LLC.
10224 * Originally Released Under LGPL - original licence link has changed is not relivant.
10227 * <script type="text/javascript">
10230 // Base class for reading structured data from a data source. This class is intended to be
10231 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10234 * @class Roo.data.DataReader
10235 * Base class for reading structured data from a data source. This class is intended to be
10236 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10239 Roo.data.DataReader = function(meta, recordType){
10243 this.recordType = recordType instanceof Array ?
10244 Roo.data.Record.create(recordType) : recordType;
10247 Roo.data.DataReader.prototype = {
10249 * Create an empty record
10250 * @param {Object} data (optional) - overlay some values
10251 * @return {Roo.data.Record} record created.
10253 newRow : function(d) {
10255 this.recordType.prototype.fields.each(function(c) {
10257 case 'int' : da[c.name] = 0; break;
10258 case 'date' : da[c.name] = new Date(); break;
10259 case 'float' : da[c.name] = 0.0; break;
10260 case 'boolean' : da[c.name] = false; break;
10261 default : da[c.name] = ""; break;
10265 return new this.recordType(Roo.apply(da, d));
10270 * Ext JS Library 1.1.1
10271 * Copyright(c) 2006-2007, Ext JS, LLC.
10273 * Originally Released Under LGPL - original licence link has changed is not relivant.
10276 * <script type="text/javascript">
10280 * @class Roo.data.DataProxy
10281 * @extends Roo.data.Observable
10282 * This class is an abstract base class for implementations which provide retrieval of
10283 * unformatted data objects.<br>
10285 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10286 * (of the appropriate type which knows how to parse the data object) to provide a block of
10287 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10289 * Custom implementations must implement the load method as described in
10290 * {@link Roo.data.HttpProxy#load}.
10292 Roo.data.DataProxy = function(){
10295 * @event beforeload
10296 * Fires before a network request is made to retrieve a data object.
10297 * @param {Object} This DataProxy object.
10298 * @param {Object} params The params parameter to the load function.
10303 * Fires before the load method's callback is called.
10304 * @param {Object} This DataProxy object.
10305 * @param {Object} o The data object.
10306 * @param {Object} arg The callback argument object passed to the load function.
10310 * @event loadexception
10311 * Fires if an Exception occurs during data retrieval.
10312 * @param {Object} This DataProxy object.
10313 * @param {Object} o The data object.
10314 * @param {Object} arg The callback argument object passed to the load function.
10315 * @param {Object} e The Exception.
10317 loadexception : true
10319 Roo.data.DataProxy.superclass.constructor.call(this);
10322 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10325 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10329 * Ext JS Library 1.1.1
10330 * Copyright(c) 2006-2007, Ext JS, LLC.
10332 * Originally Released Under LGPL - original licence link has changed is not relivant.
10335 * <script type="text/javascript">
10338 * @class Roo.data.MemoryProxy
10339 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10340 * to the Reader when its load method is called.
10342 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10344 Roo.data.MemoryProxy = function(data){
10348 Roo.data.MemoryProxy.superclass.constructor.call(this);
10352 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10354 * Load data from the requested source (in this case an in-memory
10355 * data object passed to the constructor), read the data object into
10356 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10357 * process that block using the passed callback.
10358 * @param {Object} params This parameter is not used by the MemoryProxy class.
10359 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10360 * object into a block of Roo.data.Records.
10361 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10362 * The function must be passed <ul>
10363 * <li>The Record block object</li>
10364 * <li>The "arg" argument from the load function</li>
10365 * <li>A boolean success indicator</li>
10367 * @param {Object} scope The scope in which to call the callback
10368 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10370 load : function(params, reader, callback, scope, arg){
10371 params = params || {};
10374 result = reader.readRecords(this.data);
10376 this.fireEvent("loadexception", this, arg, null, e);
10377 callback.call(scope, null, arg, false);
10380 callback.call(scope, result, arg, true);
10384 update : function(params, records){
10389 * Ext JS Library 1.1.1
10390 * Copyright(c) 2006-2007, Ext JS, LLC.
10392 * Originally Released Under LGPL - original licence link has changed is not relivant.
10395 * <script type="text/javascript">
10398 * @class Roo.data.HttpProxy
10399 * @extends Roo.data.DataProxy
10400 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10401 * configured to reference a certain URL.<br><br>
10403 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10404 * from which the running page was served.<br><br>
10406 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10408 * Be aware that to enable the browser to parse an XML document, the server must set
10409 * the Content-Type header in the HTTP response to "text/xml".
10411 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10412 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10413 * will be used to make the request.
10415 Roo.data.HttpProxy = function(conn){
10416 Roo.data.HttpProxy.superclass.constructor.call(this);
10417 // is conn a conn config or a real conn?
10419 this.useAjax = !conn || !conn.events;
10423 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10424 // thse are take from connection...
10427 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10430 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10431 * extra parameters to each request made by this object. (defaults to undefined)
10434 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10435 * to each request made by this object. (defaults to undefined)
10438 * @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)
10441 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10444 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10450 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10454 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10455 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10456 * a finer-grained basis than the DataProxy events.
10458 getConnection : function(){
10459 return this.useAjax ? Roo.Ajax : this.conn;
10463 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10464 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10465 * process that block using the passed callback.
10466 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10467 * for the request to the remote server.
10468 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10469 * object into a block of Roo.data.Records.
10470 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10471 * The function must be passed <ul>
10472 * <li>The Record block object</li>
10473 * <li>The "arg" argument from the load function</li>
10474 * <li>A boolean success indicator</li>
10476 * @param {Object} scope The scope in which to call the callback
10477 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10479 load : function(params, reader, callback, scope, arg){
10480 if(this.fireEvent("beforeload", this, params) !== false){
10482 params : params || {},
10484 callback : callback,
10489 callback : this.loadResponse,
10493 Roo.applyIf(o, this.conn);
10494 if(this.activeRequest){
10495 Roo.Ajax.abort(this.activeRequest);
10497 this.activeRequest = Roo.Ajax.request(o);
10499 this.conn.request(o);
10502 callback.call(scope||this, null, arg, false);
10507 loadResponse : function(o, success, response){
10508 delete this.activeRequest;
10510 this.fireEvent("loadexception", this, o, response);
10511 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10516 result = o.reader.read(response);
10518 this.fireEvent("loadexception", this, o, response, e);
10519 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10523 this.fireEvent("load", this, o, o.request.arg);
10524 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10528 update : function(dataSet){
10533 updateResponse : function(dataSet){
10538 * Ext JS Library 1.1.1
10539 * Copyright(c) 2006-2007, Ext JS, LLC.
10541 * Originally Released Under LGPL - original licence link has changed is not relivant.
10544 * <script type="text/javascript">
10548 * @class Roo.data.ScriptTagProxy
10549 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10550 * other than the originating domain of the running page.<br><br>
10552 * <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
10553 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10555 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10556 * source code that is used as the source inside a <script> tag.<br><br>
10558 * In order for the browser to process the returned data, the server must wrap the data object
10559 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10560 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10561 * depending on whether the callback name was passed:
10564 boolean scriptTag = false;
10565 String cb = request.getParameter("callback");
10568 response.setContentType("text/javascript");
10570 response.setContentType("application/x-json");
10572 Writer out = response.getWriter();
10574 out.write(cb + "(");
10576 out.print(dataBlock.toJsonString());
10583 * @param {Object} config A configuration object.
10585 Roo.data.ScriptTagProxy = function(config){
10586 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10587 Roo.apply(this, config);
10588 this.head = document.getElementsByTagName("head")[0];
10591 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10593 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10595 * @cfg {String} url The URL from which to request the data object.
10598 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10602 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10603 * the server the name of the callback function set up by the load call to process the returned data object.
10604 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10605 * javascript output which calls this named function passing the data object as its only parameter.
10607 callbackParam : "callback",
10609 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10610 * name to the request.
10615 * Load data from the configured URL, read the data object into
10616 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10617 * process that block using the passed callback.
10618 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10619 * for the request to the remote server.
10620 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10621 * object into a block of Roo.data.Records.
10622 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10623 * The function must be passed <ul>
10624 * <li>The Record block object</li>
10625 * <li>The "arg" argument from the load function</li>
10626 * <li>A boolean success indicator</li>
10628 * @param {Object} scope The scope in which to call the callback
10629 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10631 load : function(params, reader, callback, scope, arg){
10632 if(this.fireEvent("beforeload", this, params) !== false){
10634 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10636 var url = this.url;
10637 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10639 url += "&_dc=" + (new Date().getTime());
10641 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10644 cb : "stcCallback"+transId,
10645 scriptId : "stcScript"+transId,
10649 callback : callback,
10655 window[trans.cb] = function(o){
10656 conn.handleResponse(o, trans);
10659 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10661 if(this.autoAbort !== false){
10665 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10667 var script = document.createElement("script");
10668 script.setAttribute("src", url);
10669 script.setAttribute("type", "text/javascript");
10670 script.setAttribute("id", trans.scriptId);
10671 this.head.appendChild(script);
10673 this.trans = trans;
10675 callback.call(scope||this, null, arg, false);
10680 isLoading : function(){
10681 return this.trans ? true : false;
10685 * Abort the current server request.
10687 abort : function(){
10688 if(this.isLoading()){
10689 this.destroyTrans(this.trans);
10694 destroyTrans : function(trans, isLoaded){
10695 this.head.removeChild(document.getElementById(trans.scriptId));
10696 clearTimeout(trans.timeoutId);
10698 window[trans.cb] = undefined;
10700 delete window[trans.cb];
10703 // if hasn't been loaded, wait for load to remove it to prevent script error
10704 window[trans.cb] = function(){
10705 window[trans.cb] = undefined;
10707 delete window[trans.cb];
10714 handleResponse : function(o, trans){
10715 this.trans = false;
10716 this.destroyTrans(trans, true);
10719 result = trans.reader.readRecords(o);
10721 this.fireEvent("loadexception", this, o, trans.arg, e);
10722 trans.callback.call(trans.scope||window, null, trans.arg, false);
10725 this.fireEvent("load", this, o, trans.arg);
10726 trans.callback.call(trans.scope||window, result, trans.arg, true);
10730 handleFailure : function(trans){
10731 this.trans = false;
10732 this.destroyTrans(trans, false);
10733 this.fireEvent("loadexception", this, null, trans.arg);
10734 trans.callback.call(trans.scope||window, null, trans.arg, false);
10738 * Ext JS Library 1.1.1
10739 * Copyright(c) 2006-2007, Ext JS, LLC.
10741 * Originally Released Under LGPL - original licence link has changed is not relivant.
10744 * <script type="text/javascript">
10748 * @class Roo.data.JsonReader
10749 * @extends Roo.data.DataReader
10750 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10751 * based on mappings in a provided Roo.data.Record constructor.
10753 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10754 * in the reply previously.
10759 var RecordDef = Roo.data.Record.create([
10760 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10761 {name: 'occupation'} // This field will use "occupation" as the mapping.
10763 var myReader = new Roo.data.JsonReader({
10764 totalProperty: "results", // The property which contains the total dataset size (optional)
10765 root: "rows", // The property which contains an Array of row objects
10766 id: "id" // The property within each row object that provides an ID for the record (optional)
10770 * This would consume a JSON file like this:
10772 { 'results': 2, 'rows': [
10773 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10774 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10777 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10778 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10779 * paged from the remote server.
10780 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10781 * @cfg {String} root name of the property which contains the Array of row objects.
10782 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10783 * @cfg {Array} fields Array of field definition objects
10785 * Create a new JsonReader
10786 * @param {Object} meta Metadata configuration options
10787 * @param {Object} recordType Either an Array of field definition objects,
10788 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10790 Roo.data.JsonReader = function(meta, recordType){
10793 // set some defaults:
10794 Roo.applyIf(meta, {
10795 totalProperty: 'total',
10796 successProperty : 'success',
10801 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10803 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10806 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10807 * Used by Store query builder to append _requestMeta to params.
10810 metaFromRemote : false,
10812 * This method is only used by a DataProxy which has retrieved data from a remote server.
10813 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10814 * @return {Object} data A data block which is used by an Roo.data.Store object as
10815 * a cache of Roo.data.Records.
10817 read : function(response){
10818 var json = response.responseText;
10820 var o = /* eval:var:o */ eval("("+json+")");
10822 throw {message: "JsonReader.read: Json object not found"};
10828 this.metaFromRemote = true;
10829 this.meta = o.metaData;
10830 this.recordType = Roo.data.Record.create(o.metaData.fields);
10831 this.onMetaChange(this.meta, this.recordType, o);
10833 return this.readRecords(o);
10836 // private function a store will implement
10837 onMetaChange : function(meta, recordType, o){
10844 simpleAccess: function(obj, subsc) {
10851 getJsonAccessor: function(){
10853 return function(expr) {
10855 return(re.test(expr))
10856 ? new Function("obj", "return obj." + expr)
10861 return Roo.emptyFn;
10866 * Create a data block containing Roo.data.Records from an XML document.
10867 * @param {Object} o An object which contains an Array of row objects in the property specified
10868 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10869 * which contains the total size of the dataset.
10870 * @return {Object} data A data block which is used by an Roo.data.Store object as
10871 * a cache of Roo.data.Records.
10873 readRecords : function(o){
10875 * After any data loads, the raw JSON data is available for further custom processing.
10879 var s = this.meta, Record = this.recordType,
10880 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10882 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10884 if(s.totalProperty) {
10885 this.getTotal = this.getJsonAccessor(s.totalProperty);
10887 if(s.successProperty) {
10888 this.getSuccess = this.getJsonAccessor(s.successProperty);
10890 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10892 var g = this.getJsonAccessor(s.id);
10893 this.getId = function(rec) {
10895 return (r === undefined || r === "") ? null : r;
10898 this.getId = function(){return null;};
10901 for(var jj = 0; jj < fl; jj++){
10903 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10904 this.ef[jj] = this.getJsonAccessor(map);
10908 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10909 if(s.totalProperty){
10910 var vt = parseInt(this.getTotal(o), 10);
10915 if(s.successProperty){
10916 var vs = this.getSuccess(o);
10917 if(vs === false || vs === 'false'){
10922 for(var i = 0; i < c; i++){
10925 var id = this.getId(n);
10926 for(var j = 0; j < fl; j++){
10928 var v = this.ef[j](n);
10930 Roo.log('missing convert for ' + f.name);
10934 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10936 var record = new Record(values, id);
10938 records[i] = record;
10944 totalRecords : totalRecords
10949 * Ext JS Library 1.1.1
10950 * Copyright(c) 2006-2007, Ext JS, LLC.
10952 * Originally Released Under LGPL - original licence link has changed is not relivant.
10955 * <script type="text/javascript">
10959 * @class Roo.data.ArrayReader
10960 * @extends Roo.data.DataReader
10961 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10962 * Each element of that Array represents a row of data fields. The
10963 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10964 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10968 var RecordDef = Roo.data.Record.create([
10969 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10970 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10972 var myReader = new Roo.data.ArrayReader({
10973 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10977 * This would consume an Array like this:
10979 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10981 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10983 * Create a new JsonReader
10984 * @param {Object} meta Metadata configuration options.
10985 * @param {Object} recordType Either an Array of field definition objects
10986 * as specified to {@link Roo.data.Record#create},
10987 * or an {@link Roo.data.Record} object
10988 * created using {@link Roo.data.Record#create}.
10990 Roo.data.ArrayReader = function(meta, recordType){
10991 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10994 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10996 * Create a data block containing Roo.data.Records from an XML document.
10997 * @param {Object} o An Array of row objects which represents the dataset.
10998 * @return {Object} data A data block which is used by an Roo.data.Store object as
10999 * a cache of Roo.data.Records.
11001 readRecords : function(o){
11002 var sid = this.meta ? this.meta.id : null;
11003 var recordType = this.recordType, fields = recordType.prototype.fields;
11006 for(var i = 0; i < root.length; i++){
11009 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11010 for(var j = 0, jlen = fields.length; j < jlen; j++){
11011 var f = fields.items[j];
11012 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11013 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11015 values[f.name] = v;
11017 var record = new recordType(values, id);
11019 records[records.length] = record;
11023 totalRecords : records.length
11032 * @class Roo.bootstrap.ComboBox
11033 * @extends Roo.bootstrap.TriggerField
11034 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11035 * @cfg {Boolean} append (true|false) default false
11036 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11037 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11038 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11039 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11040 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11041 * @cfg {Boolean} animate default true
11042 * @cfg {Boolean} emptyResultText only for touch device
11044 * Create a new ComboBox.
11045 * @param {Object} config Configuration options
11047 Roo.bootstrap.ComboBox = function(config){
11048 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11052 * Fires when the dropdown list is expanded
11053 * @param {Roo.bootstrap.ComboBox} combo This combo box
11058 * Fires when the dropdown list is collapsed
11059 * @param {Roo.bootstrap.ComboBox} combo This combo box
11063 * @event beforeselect
11064 * Fires before a list item is selected. Return false to cancel the selection.
11065 * @param {Roo.bootstrap.ComboBox} combo This combo box
11066 * @param {Roo.data.Record} record The data record returned from the underlying store
11067 * @param {Number} index The index of the selected item in the dropdown list
11069 'beforeselect' : true,
11072 * Fires when a list item is selected
11073 * @param {Roo.bootstrap.ComboBox} combo This combo box
11074 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11075 * @param {Number} index The index of the selected item in the dropdown list
11079 * @event beforequery
11080 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11081 * The event object passed has these properties:
11082 * @param {Roo.bootstrap.ComboBox} combo This combo box
11083 * @param {String} query The query
11084 * @param {Boolean} forceAll true to force "all" query
11085 * @param {Boolean} cancel true to cancel the query
11086 * @param {Object} e The query event object
11088 'beforequery': true,
11091 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11092 * @param {Roo.bootstrap.ComboBox} combo This combo box
11097 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11098 * @param {Roo.bootstrap.ComboBox} combo This combo box
11099 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11104 * Fires when the remove value from the combobox array
11105 * @param {Roo.bootstrap.ComboBox} combo This combo box
11109 * @event specialfilter
11110 * Fires when specialfilter
11111 * @param {Roo.bootstrap.ComboBox} combo This combo box
11113 'specialfilter' : true
11118 this.tickItems = [];
11120 this.selectedIndex = -1;
11121 if(this.mode == 'local'){
11122 if(config.queryDelay === undefined){
11123 this.queryDelay = 10;
11125 if(config.minChars === undefined){
11131 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11134 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11135 * rendering into an Roo.Editor, defaults to false)
11138 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11139 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11142 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11145 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11146 * the dropdown list (defaults to undefined, with no header element)
11150 * @cfg {String/Roo.Template} tpl The template to use to render the output
11154 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11156 listWidth: undefined,
11158 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11159 * mode = 'remote' or 'text' if mode = 'local')
11161 displayField: undefined,
11164 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11165 * mode = 'remote' or 'value' if mode = 'local').
11166 * Note: use of a valueField requires the user make a selection
11167 * in order for a value to be mapped.
11169 valueField: undefined,
11173 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11174 * field's data value (defaults to the underlying DOM element's name)
11176 hiddenName: undefined,
11178 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11182 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11184 selectedClass: 'active',
11187 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11191 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11192 * anchor positions (defaults to 'tl-bl')
11194 listAlign: 'tl-bl?',
11196 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11200 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11201 * query specified by the allQuery config option (defaults to 'query')
11203 triggerAction: 'query',
11205 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11206 * (defaults to 4, does not apply if editable = false)
11210 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11211 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11215 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11216 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11220 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11221 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11225 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11226 * when editable = true (defaults to false)
11228 selectOnFocus:false,
11230 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11232 queryParam: 'query',
11234 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11235 * when mode = 'remote' (defaults to 'Loading...')
11237 loadingText: 'Loading...',
11239 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11243 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11247 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11248 * traditional select (defaults to true)
11252 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11256 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11260 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11261 * listWidth has a higher value)
11265 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11266 * allow the user to set arbitrary text into the field (defaults to false)
11268 forceSelection:false,
11270 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11271 * if typeAhead = true (defaults to 250)
11273 typeAheadDelay : 250,
11275 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11276 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11278 valueNotFoundText : undefined,
11280 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11282 blockFocus : false,
11285 * @cfg {Boolean} disableClear Disable showing of clear button.
11287 disableClear : false,
11289 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11291 alwaysQuery : false,
11294 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11299 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11301 invalidClass : "has-warning",
11304 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11306 validClass : "has-success",
11309 * @cfg {Boolean} specialFilter (true|false) special filter default false
11311 specialFilter : false,
11323 btnPosition : 'right',
11324 triggerList : true,
11325 showToggleBtn : true,
11327 emptyResultText: 'Empty',
11328 // element that contains real text value.. (when hidden is used..)
11330 getAutoCreate : function()
11339 cfg = this.getAutoCreateTouchView();
11346 if(!this.tickable){
11347 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11352 * ComboBox with tickable selections
11355 var align = this.labelAlign || this.parentLabelAlign();
11358 cls : 'form-group roo-combobox-tickable' //input-group
11363 cls : 'tickable-buttons',
11368 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11375 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11382 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11389 buttons.cn.unshift({
11391 cls: 'select2-search-field-input'
11397 Roo.each(buttons.cn, function(c){
11399 c.cls += ' btn-' + _this.size;
11402 if (_this.disabled) {
11413 cls: 'form-hidden-field'
11417 cls: 'select2-choices',
11421 cls: 'select2-search-field',
11433 cls: 'select2-container input-group select2-container-multi',
11438 // cls: 'typeahead typeahead-long dropdown-menu',
11439 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11444 if(this.hasFeedback && !this.allowBlank){
11448 cls: 'glyphicon form-control-feedback'
11451 combobox.cn.push(feedback);
11454 if (align ==='left' && this.fieldLabel.length) {
11456 Roo.log("left and has label");
11462 cls : 'control-label col-sm-' + this.labelWidth,
11463 html : this.fieldLabel
11467 cls : "col-sm-" + (12 - this.labelWidth),
11474 } else if ( this.fieldLabel.length) {
11480 //cls : 'input-group-addon',
11481 html : this.fieldLabel
11491 Roo.log(" no label && no align");
11498 ['xs','sm','md','lg'].map(function(size){
11499 if (settings[size]) {
11500 cfg.cls += ' col-' + size + '-' + settings[size];
11509 initEvents: function()
11513 throw "can not find store for combo";
11516 this.store = Roo.factory(this.store, Roo.data);
11523 this.initTouchView();
11528 this.initTickableEvents();
11532 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11534 if(this.hiddenName){
11536 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11538 this.hiddenField.dom.value =
11539 this.hiddenValue !== undefined ? this.hiddenValue :
11540 this.value !== undefined ? this.value : '';
11542 // prevent input submission
11543 this.el.dom.removeAttribute('name');
11544 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11549 // this.el.dom.setAttribute('autocomplete', 'off');
11552 var cls = 'x-combo-list';
11554 //this.list = new Roo.Layer({
11555 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11561 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11562 _this.list.setWidth(lw);
11565 this.list.on('mouseover', this.onViewOver, this);
11566 this.list.on('mousemove', this.onViewMove, this);
11568 this.list.on('scroll', this.onViewScroll, this);
11571 this.list.swallowEvent('mousewheel');
11572 this.assetHeight = 0;
11575 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11576 this.assetHeight += this.header.getHeight();
11579 this.innerList = this.list.createChild({cls:cls+'-inner'});
11580 this.innerList.on('mouseover', this.onViewOver, this);
11581 this.innerList.on('mousemove', this.onViewMove, this);
11582 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11584 if(this.allowBlank && !this.pageSize && !this.disableClear){
11585 this.footer = this.list.createChild({cls:cls+'-ft'});
11586 this.pageTb = new Roo.Toolbar(this.footer);
11590 this.footer = this.list.createChild({cls:cls+'-ft'});
11591 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11592 {pageSize: this.pageSize});
11596 if (this.pageTb && this.allowBlank && !this.disableClear) {
11598 this.pageTb.add(new Roo.Toolbar.Fill(), {
11599 cls: 'x-btn-icon x-btn-clear',
11601 handler: function()
11604 _this.clearValue();
11605 _this.onSelect(false, -1);
11610 this.assetHeight += this.footer.getHeight();
11615 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11618 this.view = new Roo.View(this.list, this.tpl, {
11619 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11621 //this.view.wrapEl.setDisplayed(false);
11622 this.view.on('click', this.onViewClick, this);
11626 this.store.on('beforeload', this.onBeforeLoad, this);
11627 this.store.on('load', this.onLoad, this);
11628 this.store.on('loadexception', this.onLoadException, this);
11630 if(this.resizable){
11631 this.resizer = new Roo.Resizable(this.list, {
11632 pinned:true, handles:'se'
11634 this.resizer.on('resize', function(r, w, h){
11635 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11636 this.listWidth = w;
11637 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11638 this.restrictHeight();
11640 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11643 if(!this.editable){
11644 this.editable = true;
11645 this.setEditable(false);
11650 if (typeof(this.events.add.listeners) != 'undefined') {
11652 this.addicon = this.wrap.createChild(
11653 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11655 this.addicon.on('click', function(e) {
11656 this.fireEvent('add', this);
11659 if (typeof(this.events.edit.listeners) != 'undefined') {
11661 this.editicon = this.wrap.createChild(
11662 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11663 if (this.addicon) {
11664 this.editicon.setStyle('margin-left', '40px');
11666 this.editicon.on('click', function(e) {
11668 // we fire even if inothing is selected..
11669 this.fireEvent('edit', this, this.lastData );
11675 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11676 "up" : function(e){
11677 this.inKeyMode = true;
11681 "down" : function(e){
11682 if(!this.isExpanded()){
11683 this.onTriggerClick();
11685 this.inKeyMode = true;
11690 "enter" : function(e){
11691 // this.onViewClick();
11695 if(this.fireEvent("specialkey", this, e)){
11696 this.onViewClick(false);
11702 "esc" : function(e){
11706 "tab" : function(e){
11709 if(this.fireEvent("specialkey", this, e)){
11710 this.onViewClick(false);
11718 doRelay : function(foo, bar, hname){
11719 if(hname == 'down' || this.scope.isExpanded()){
11720 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11729 this.queryDelay = Math.max(this.queryDelay || 10,
11730 this.mode == 'local' ? 10 : 250);
11733 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11735 if(this.typeAhead){
11736 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11738 if(this.editable !== false){
11739 this.inputEl().on("keyup", this.onKeyUp, this);
11741 if(this.forceSelection){
11742 this.inputEl().on('blur', this.doForce, this);
11746 this.choices = this.el.select('ul.select2-choices', true).first();
11747 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11751 initTickableEvents: function()
11755 if(this.hiddenName){
11757 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11759 this.hiddenField.dom.value =
11760 this.hiddenValue !== undefined ? this.hiddenValue :
11761 this.value !== undefined ? this.value : '';
11763 // prevent input submission
11764 this.el.dom.removeAttribute('name');
11765 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11770 // this.list = this.el.select('ul.dropdown-menu',true).first();
11772 this.choices = this.el.select('ul.select2-choices', true).first();
11773 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11774 if(this.triggerList){
11775 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11778 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11779 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11781 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11782 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11784 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11785 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11787 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11788 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11789 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11792 this.cancelBtn.hide();
11797 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11798 _this.list.setWidth(lw);
11801 this.list.on('mouseover', this.onViewOver, this);
11802 this.list.on('mousemove', this.onViewMove, this);
11804 this.list.on('scroll', this.onViewScroll, this);
11807 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>';
11810 this.view = new Roo.View(this.list, this.tpl, {
11811 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11814 //this.view.wrapEl.setDisplayed(false);
11815 this.view.on('click', this.onViewClick, this);
11819 this.store.on('beforeload', this.onBeforeLoad, this);
11820 this.store.on('load', this.onLoad, this);
11821 this.store.on('loadexception', this.onLoadException, this);
11824 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11825 "up" : function(e){
11826 this.inKeyMode = true;
11830 "down" : function(e){
11831 this.inKeyMode = true;
11835 "enter" : function(e){
11836 if(this.fireEvent("specialkey", this, e)){
11837 this.onViewClick(false);
11843 "esc" : function(e){
11844 this.onTickableFooterButtonClick(e, false, false);
11847 "tab" : function(e){
11848 this.fireEvent("specialkey", this, e);
11850 this.onTickableFooterButtonClick(e, false, false);
11857 doRelay : function(e, fn, key){
11858 if(this.scope.isExpanded()){
11859 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11868 this.queryDelay = Math.max(this.queryDelay || 10,
11869 this.mode == 'local' ? 10 : 250);
11872 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11874 if(this.typeAhead){
11875 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11878 if(this.editable !== false){
11879 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11884 onDestroy : function(){
11886 this.view.setStore(null);
11887 this.view.el.removeAllListeners();
11888 this.view.el.remove();
11889 this.view.purgeListeners();
11892 this.list.dom.innerHTML = '';
11896 this.store.un('beforeload', this.onBeforeLoad, this);
11897 this.store.un('load', this.onLoad, this);
11898 this.store.un('loadexception', this.onLoadException, this);
11900 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11904 fireKey : function(e){
11905 if(e.isNavKeyPress() && !this.list.isVisible()){
11906 this.fireEvent("specialkey", this, e);
11911 onResize: function(w, h){
11912 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11914 // if(typeof w != 'number'){
11915 // // we do not handle it!?!?
11918 // var tw = this.trigger.getWidth();
11919 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11920 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11922 // this.inputEl().setWidth( this.adjustWidth('input', x));
11924 // //this.trigger.setStyle('left', x+'px');
11926 // if(this.list && this.listWidth === undefined){
11927 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11928 // this.list.setWidth(lw);
11929 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11937 * Allow or prevent the user from directly editing the field text. If false is passed,
11938 * the user will only be able to select from the items defined in the dropdown list. This method
11939 * is the runtime equivalent of setting the 'editable' config option at config time.
11940 * @param {Boolean} value True to allow the user to directly edit the field text
11942 setEditable : function(value){
11943 if(value == this.editable){
11946 this.editable = value;
11948 this.inputEl().dom.setAttribute('readOnly', true);
11949 this.inputEl().on('mousedown', this.onTriggerClick, this);
11950 this.inputEl().addClass('x-combo-noedit');
11952 this.inputEl().dom.setAttribute('readOnly', false);
11953 this.inputEl().un('mousedown', this.onTriggerClick, this);
11954 this.inputEl().removeClass('x-combo-noedit');
11960 onBeforeLoad : function(combo,opts){
11961 if(!this.hasFocus){
11965 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11967 this.restrictHeight();
11968 this.selectedIndex = -1;
11972 onLoad : function(){
11974 this.hasQuery = false;
11976 if(!this.hasFocus){
11980 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11981 this.loading.hide();
11984 if(this.store.getCount() > 0){
11986 this.restrictHeight();
11987 if(this.lastQuery == this.allQuery){
11988 if(this.editable && !this.tickable){
11989 this.inputEl().dom.select();
11993 !this.selectByValue(this.value, true) &&
11996 !this.store.lastOptions ||
11997 typeof(this.store.lastOptions.add) == 'undefined' ||
11998 this.store.lastOptions.add != true
12001 this.select(0, true);
12004 if(this.autoFocus){
12007 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12008 this.taTask.delay(this.typeAheadDelay);
12012 this.onEmptyResults();
12018 onLoadException : function()
12020 this.hasQuery = false;
12022 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12023 this.loading.hide();
12026 if(this.tickable && this.editable){
12032 Roo.log(this.store.reader.jsonData);
12033 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12035 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12041 onTypeAhead : function(){
12042 if(this.store.getCount() > 0){
12043 var r = this.store.getAt(0);
12044 var newValue = r.data[this.displayField];
12045 var len = newValue.length;
12046 var selStart = this.getRawValue().length;
12048 if(selStart != len){
12049 this.setRawValue(newValue);
12050 this.selectText(selStart, newValue.length);
12056 onSelect : function(record, index){
12058 if(this.fireEvent('beforeselect', this, record, index) !== false){
12060 this.setFromData(index > -1 ? record.data : false);
12063 this.fireEvent('select', this, record, index);
12068 * Returns the currently selected field value or empty string if no value is set.
12069 * @return {String} value The selected value
12071 getValue : function(){
12074 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12077 if(this.valueField){
12078 return typeof this.value != 'undefined' ? this.value : '';
12080 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12085 * Clears any text/value currently set in the field
12087 clearValue : function(){
12088 if(this.hiddenField){
12089 this.hiddenField.dom.value = '';
12092 this.setRawValue('');
12093 this.lastSelectionText = '';
12094 this.lastData = false;
12096 var close = this.closeTriggerEl();
12105 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12106 * will be displayed in the field. If the value does not match the data value of an existing item,
12107 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12108 * Otherwise the field will be blank (although the value will still be set).
12109 * @param {String} value The value to match
12111 setValue : function(v){
12118 if(this.valueField){
12119 var r = this.findRecord(this.valueField, v);
12121 text = r.data[this.displayField];
12122 }else if(this.valueNotFoundText !== undefined){
12123 text = this.valueNotFoundText;
12126 this.lastSelectionText = text;
12127 if(this.hiddenField){
12128 this.hiddenField.dom.value = v;
12130 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12133 var close = this.closeTriggerEl();
12136 (v.length || v * 1 > 0) ? close.show() : close.hide();
12140 * @property {Object} the last set data for the element
12145 * Sets the value of the field based on a object which is related to the record format for the store.
12146 * @param {Object} value the value to set as. or false on reset?
12148 setFromData : function(o){
12155 var dv = ''; // display value
12156 var vv = ''; // value value..
12158 if (this.displayField) {
12159 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12161 // this is an error condition!!!
12162 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12165 if(this.valueField){
12166 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12169 var close = this.closeTriggerEl();
12172 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12175 if(this.hiddenField){
12176 this.hiddenField.dom.value = vv;
12178 this.lastSelectionText = dv;
12179 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12183 // no hidden field.. - we store the value in 'value', but still display
12184 // display field!!!!
12185 this.lastSelectionText = dv;
12186 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12193 reset : function(){
12194 // overridden so that last data is reset..
12201 this.setValue(this.originalValue);
12202 this.clearInvalid();
12203 this.lastData = false;
12205 this.view.clearSelections();
12209 findRecord : function(prop, value){
12211 if(this.store.getCount() > 0){
12212 this.store.each(function(r){
12213 if(r.data[prop] == value){
12223 getName: function()
12225 // returns hidden if it's set..
12226 if (!this.rendered) {return ''};
12227 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12231 onViewMove : function(e, t){
12232 this.inKeyMode = false;
12236 onViewOver : function(e, t){
12237 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12240 var item = this.view.findItemFromChild(t);
12243 var index = this.view.indexOf(item);
12244 this.select(index, false);
12249 onViewClick : function(view, doFocus, el, e)
12251 var index = this.view.getSelectedIndexes()[0];
12253 var r = this.store.getAt(index);
12257 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12264 Roo.each(this.tickItems, function(v,k){
12266 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12267 _this.tickItems.splice(k, 1);
12269 if(typeof(e) == 'undefined' && view == false){
12270 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12282 this.tickItems.push(r.data);
12284 if(typeof(e) == 'undefined' && view == false){
12285 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12292 this.onSelect(r, index);
12294 if(doFocus !== false && !this.blockFocus){
12295 this.inputEl().focus();
12300 restrictHeight : function(){
12301 //this.innerList.dom.style.height = '';
12302 //var inner = this.innerList.dom;
12303 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12304 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12305 //this.list.beginUpdate();
12306 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12307 this.list.alignTo(this.inputEl(), this.listAlign);
12308 this.list.alignTo(this.inputEl(), this.listAlign);
12309 //this.list.endUpdate();
12313 onEmptyResults : function(){
12315 if(this.tickable && this.editable){
12316 this.restrictHeight();
12324 * Returns true if the dropdown list is expanded, else false.
12326 isExpanded : function(){
12327 return this.list.isVisible();
12331 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12332 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12333 * @param {String} value The data value of the item to select
12334 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12335 * selected item if it is not currently in view (defaults to true)
12336 * @return {Boolean} True if the value matched an item in the list, else false
12338 selectByValue : function(v, scrollIntoView){
12339 if(v !== undefined && v !== null){
12340 var r = this.findRecord(this.valueField || this.displayField, v);
12342 this.select(this.store.indexOf(r), scrollIntoView);
12350 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12351 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12352 * @param {Number} index The zero-based index of the list item to select
12353 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12354 * selected item if it is not currently in view (defaults to true)
12356 select : function(index, scrollIntoView){
12357 this.selectedIndex = index;
12358 this.view.select(index);
12359 if(scrollIntoView !== false){
12360 var el = this.view.getNode(index);
12362 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12365 this.list.scrollChildIntoView(el, false);
12371 selectNext : function(){
12372 var ct = this.store.getCount();
12374 if(this.selectedIndex == -1){
12376 }else if(this.selectedIndex < ct-1){
12377 this.select(this.selectedIndex+1);
12383 selectPrev : function(){
12384 var ct = this.store.getCount();
12386 if(this.selectedIndex == -1){
12388 }else if(this.selectedIndex != 0){
12389 this.select(this.selectedIndex-1);
12395 onKeyUp : function(e){
12396 if(this.editable !== false && !e.isSpecialKey()){
12397 this.lastKey = e.getKey();
12398 this.dqTask.delay(this.queryDelay);
12403 validateBlur : function(){
12404 return !this.list || !this.list.isVisible();
12408 initQuery : function(){
12410 var v = this.getRawValue();
12412 if(this.tickable && this.editable){
12413 v = this.tickableInputEl().getValue();
12420 doForce : function(){
12421 if(this.inputEl().dom.value.length > 0){
12422 this.inputEl().dom.value =
12423 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12429 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12430 * query allowing the query action to be canceled if needed.
12431 * @param {String} query The SQL query to execute
12432 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12433 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12434 * saved in the current store (defaults to false)
12436 doQuery : function(q, forceAll){
12438 if(q === undefined || q === null){
12443 forceAll: forceAll,
12447 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12452 forceAll = qe.forceAll;
12453 if(forceAll === true || (q.length >= this.minChars)){
12455 this.hasQuery = true;
12457 if(this.lastQuery != q || this.alwaysQuery){
12458 this.lastQuery = q;
12459 if(this.mode == 'local'){
12460 this.selectedIndex = -1;
12462 this.store.clearFilter();
12465 if(this.specialFilter){
12466 this.fireEvent('specialfilter', this);
12471 this.store.filter(this.displayField, q);
12474 this.store.fireEvent("datachanged", this.store);
12481 this.store.baseParams[this.queryParam] = q;
12483 var options = {params : this.getParams(q)};
12486 options.add = true;
12487 options.params.start = this.page * this.pageSize;
12490 this.store.load(options);
12493 * this code will make the page width larger, at the beginning, the list not align correctly,
12494 * we should expand the list on onLoad
12495 * so command out it
12500 this.selectedIndex = -1;
12505 this.loadNext = false;
12509 getParams : function(q){
12511 //p[this.queryParam] = q;
12515 p.limit = this.pageSize;
12521 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12523 collapse : function(){
12524 if(!this.isExpanded()){
12531 this.hasFocus = false;
12533 this.cancelBtn.hide();
12534 this.trigger.show();
12537 this.tickableInputEl().dom.value = '';
12538 this.tickableInputEl().blur();
12543 Roo.get(document).un('mousedown', this.collapseIf, this);
12544 Roo.get(document).un('mousewheel', this.collapseIf, this);
12545 if (!this.editable) {
12546 Roo.get(document).un('keydown', this.listKeyPress, this);
12548 this.fireEvent('collapse', this);
12552 collapseIf : function(e){
12553 var in_combo = e.within(this.el);
12554 var in_list = e.within(this.list);
12555 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12557 if (in_combo || in_list || is_list) {
12558 //e.stopPropagation();
12563 this.onTickableFooterButtonClick(e, false, false);
12571 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12573 expand : function(){
12575 if(this.isExpanded() || !this.hasFocus){
12579 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12580 this.list.setWidth(lw);
12587 this.restrictHeight();
12591 this.tickItems = Roo.apply([], this.item);
12594 this.cancelBtn.show();
12595 this.trigger.hide();
12598 this.tickableInputEl().focus();
12603 Roo.get(document).on('mousedown', this.collapseIf, this);
12604 Roo.get(document).on('mousewheel', this.collapseIf, this);
12605 if (!this.editable) {
12606 Roo.get(document).on('keydown', this.listKeyPress, this);
12609 this.fireEvent('expand', this);
12613 // Implements the default empty TriggerField.onTriggerClick function
12614 onTriggerClick : function(e)
12616 Roo.log('trigger click');
12618 if(this.disabled || !this.triggerList){
12623 this.loadNext = false;
12625 if(this.isExpanded()){
12627 if (!this.blockFocus) {
12628 this.inputEl().focus();
12632 this.hasFocus = true;
12633 if(this.triggerAction == 'all') {
12634 this.doQuery(this.allQuery, true);
12636 this.doQuery(this.getRawValue());
12638 if (!this.blockFocus) {
12639 this.inputEl().focus();
12644 onTickableTriggerClick : function(e)
12651 this.loadNext = false;
12652 this.hasFocus = true;
12654 if(this.triggerAction == 'all') {
12655 this.doQuery(this.allQuery, true);
12657 this.doQuery(this.getRawValue());
12661 onSearchFieldClick : function(e)
12663 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12664 this.onTickableFooterButtonClick(e, false, false);
12668 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12673 this.loadNext = false;
12674 this.hasFocus = true;
12676 if(this.triggerAction == 'all') {
12677 this.doQuery(this.allQuery, true);
12679 this.doQuery(this.getRawValue());
12683 listKeyPress : function(e)
12685 //Roo.log('listkeypress');
12686 // scroll to first matching element based on key pres..
12687 if (e.isSpecialKey()) {
12690 var k = String.fromCharCode(e.getKey()).toUpperCase();
12693 var csel = this.view.getSelectedNodes();
12694 var cselitem = false;
12696 var ix = this.view.indexOf(csel[0]);
12697 cselitem = this.store.getAt(ix);
12698 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12704 this.store.each(function(v) {
12706 // start at existing selection.
12707 if (cselitem.id == v.id) {
12713 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12714 match = this.store.indexOf(v);
12720 if (match === false) {
12721 return true; // no more action?
12724 this.view.select(match);
12725 var sn = Roo.get(this.view.getSelectedNodes()[0])
12726 sn.scrollIntoView(sn.dom.parentNode, false);
12729 onViewScroll : function(e, t){
12731 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){
12735 this.hasQuery = true;
12737 this.loading = this.list.select('.loading', true).first();
12739 if(this.loading === null){
12740 this.list.createChild({
12742 cls: 'loading select2-more-results select2-active',
12743 html: 'Loading more results...'
12746 this.loading = this.list.select('.loading', true).first();
12748 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12750 this.loading.hide();
12753 this.loading.show();
12758 this.loadNext = true;
12760 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12765 addItem : function(o)
12767 var dv = ''; // display value
12769 if (this.displayField) {
12770 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12772 // this is an error condition!!!
12773 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12780 var choice = this.choices.createChild({
12782 cls: 'select2-search-choice',
12791 cls: 'select2-search-choice-close',
12796 }, this.searchField);
12798 var close = choice.select('a.select2-search-choice-close', true).first()
12800 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12808 this.inputEl().dom.value = '';
12813 onRemoveItem : function(e, _self, o)
12815 e.preventDefault();
12817 this.lastItem = Roo.apply([], this.item);
12819 var index = this.item.indexOf(o.data) * 1;
12822 Roo.log('not this item?!');
12826 this.item.splice(index, 1);
12831 this.fireEvent('remove', this, e);
12837 syncValue : function()
12839 if(!this.item.length){
12846 Roo.each(this.item, function(i){
12847 if(_this.valueField){
12848 value.push(i[_this.valueField]);
12855 this.value = value.join(',');
12857 if(this.hiddenField){
12858 this.hiddenField.dom.value = this.value;
12861 this.store.fireEvent("datachanged", this.store);
12864 clearItem : function()
12866 if(!this.multiple){
12872 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12881 inputEl: function ()
12883 if(this.tickable && !Roo.isTouch){
12884 return this.searchField;
12886 return this.el.select('input.form-control',true).first();
12890 onTickableFooterButtonClick : function(e, btn, el)
12892 e.preventDefault();
12894 this.lastItem = Roo.apply([], this.item);
12896 if(btn && btn.name == 'cancel'){
12897 this.tickItems = Roo.apply([], this.item);
12906 Roo.each(this.tickItems, function(o){
12914 validate : function()
12916 var v = this.getRawValue();
12919 v = this.getValue();
12922 if(this.disabled || this.allowBlank || v.length){
12927 this.markInvalid();
12931 tickableInputEl : function()
12933 if(!this.tickable || !this.editable){
12934 return this.inputEl();
12937 return this.inputEl().select('.select2-search-field-input', true).first();
12941 getAutoCreateTouchView : function()
12946 cls: 'form-group' //input-group
12952 type : this.inputType,
12953 cls : 'form-control x-combo-noedit',
12954 autocomplete: 'new-password',
12955 placeholder : this.placeholder || '',
12960 input.name = this.name;
12964 input.cls += ' input-' + this.size;
12967 if (this.disabled) {
12968 input.disabled = true;
12979 inputblock.cls += ' input-group';
12981 inputblock.cn.unshift({
12983 cls : 'input-group-addon',
12988 if(this.removable && !this.multiple){
12989 inputblock.cls += ' roo-removable';
12991 inputblock.cn.push({
12994 cls : 'roo-combo-removable-btn close'
12998 if(this.hasFeedback && !this.allowBlank){
13000 inputblock.cls += ' has-feedback';
13002 inputblock.cn.push({
13004 cls: 'glyphicon form-control-feedback'
13011 inputblock.cls += (this.before) ? '' : ' input-group';
13013 inputblock.cn.push({
13015 cls : 'input-group-addon',
13026 cls: 'form-hidden-field'
13040 cls: 'form-hidden-field'
13044 cls: 'select2-choices',
13048 cls: 'select2-search-field',
13061 cls: 'select2-container input-group',
13068 combobox.cls += ' select2-container-multi';
13071 var align = this.labelAlign || this.parentLabelAlign();
13075 if(this.fieldLabel.length){
13077 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13078 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13083 cls : 'control-label ' + lw,
13084 html : this.fieldLabel
13096 var settings = this;
13098 ['xs','sm','md','lg'].map(function(size){
13099 if (settings[size]) {
13100 cfg.cls += ' col-' + size + '-' + settings[size];
13107 initTouchView : function()
13109 this.renderTouchView();
13111 this.inputEl().on("click", this.showTouchView, this);
13112 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13113 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13115 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13117 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13118 this.store.on('load', this.onTouchViewLoad, this);
13119 this.store.on('loadexception', this.onTouchViewLoadException, this);
13121 if(this.hiddenName){
13123 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13125 this.hiddenField.dom.value =
13126 this.hiddenValue !== undefined ? this.hiddenValue :
13127 this.value !== undefined ? this.value : '';
13129 this.el.dom.removeAttribute('name');
13130 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13134 this.choices = this.el.select('ul.select2-choices', true).first();
13135 this.searchField = this.el.select('ul li.select2-search-field', true).first();
13138 if(this.removable && !this.multiple){
13139 var close = this.closeTriggerEl();
13142 close.setVisibilityMode(Roo.Element.DISPALY).hide();
13143 close.on('click', this.removeBtnClick, this, close);
13152 renderTouchView : function()
13154 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13155 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13157 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13158 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13160 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13161 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13162 this.touchViewBodyEl.setStyle('overflow', 'auto');
13164 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13165 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13167 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13168 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13172 showTouchView : function()
13174 this.touchViewHeaderEl.hide();
13176 if(this.fieldLabel.length){
13177 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
13178 this.touchViewHeaderEl.show();
13181 this.touchViewEl.show();
13183 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
13184 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13186 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
13188 if(this.fieldLabel.length){
13189 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
13192 this.touchViewBodyEl.setHeight(bodyHeight);
13196 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
13198 this.touchViewEl.addClass('in');
13201 this.doTouchViewQuery();
13205 hideTouchView : function()
13207 this.touchViewEl.removeClass('in');
13211 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
13213 this.touchViewEl.setStyle('display', 'none');
13218 setTouchViewValue : function()
13225 Roo.each(this.tickItems, function(o){
13230 this.hideTouchView();
13233 doTouchViewQuery : function()
13235 Roo.log('doTouchViewQuery');
13244 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
13248 if(!this.alwaysQuery || this.mode == 'local'){
13249 this.onTouchViewLoad();
13256 onTouchViewBeforeLoad : function(combo,opts)
13258 Roo.log('onTouchViewBeforeLoad');
13264 onTouchViewLoad : function()
13266 Roo.log('onTouchViewLoad');
13268 if(this.store.getCount() < 1){
13269 this.onTouchViewEmptyResults();
13273 this.clearTouchView();
13275 var rawValue = this.getRawValue();
13277 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
13279 this.tickItems = [];
13281 this.store.data.each(function(d, rowIndex){
13282 var row = this.touchViewListGroup.createChild(template);
13284 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
13285 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = d.data[this.displayField];
13288 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
13289 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13292 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
13293 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13294 this.tickItems.push(d.data);
13297 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
13301 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
13304 firstChecked.findParent('li').scrollIntoView(this.touchViewListGroup.dom);
13309 onTouchViewLoadException : function()
13311 Roo.log('onTouchViewLoadException');
13313 this.hideTouchView();
13316 onTouchViewEmptyResults : function()
13318 Roo.log('onTouchViewEmptyResults');
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]);