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
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
192 skip_children = false;
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
223 Roo.log(self_cntr_el);
231 // if object has flexy:if - then it may or may not be rendered.
232 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
233 // skip a flexy if element.
234 Roo.log('skipping render');
237 Roo.log('skipping all children');
238 skip_children = true;
243 // actually if flexy:foreach is found, we really want to create
244 // multiple copies here...
246 //Roo.log(this[cntr]());
247 cn.render(this[cntr](true));
249 // then add the element..
257 if (typeof (tree.menu) != 'undefined') {
258 tree.menu.parentType = cn.xtype;
259 tree.menu.triggerEl = cn.el;
260 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
264 if (!tree.items || !tree.items.length) {
268 var items = tree.items;
271 //Roo.log(items.length);
273 if (!skip_children) {
274 for(var i =0;i < items.length;i++) {
275 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
297 * @class Roo.bootstrap.Body
298 * @extends Roo.bootstrap.Component
299 * Bootstrap Body class
303 * @param {Object} config The config object
306 Roo.bootstrap.Body = function(config){
307 Roo.bootstrap.Body.superclass.constructor.call(this, config);
308 this.el = Roo.get(document.body);
309 if (this.cls && this.cls.length) {
310 Roo.get(document.body).addClass(this.cls);
314 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
319 onRender : function(ct, position)
321 /* Roo.log("Roo.bootstrap.Body - onRender");
322 if (this.cls && this.cls.length) {
323 Roo.get(document.body).addClass(this.cls);
343 * @class Roo.bootstrap.ButtonGroup
344 * @extends Roo.bootstrap.Component
345 * Bootstrap ButtonGroup class
346 * @cfg {String} size lg | sm | xs (default empty normal)
347 * @cfg {String} align vertical | justified (default none)
348 * @cfg {String} direction up | down (default down)
349 * @cfg {Boolean} toolbar false | true
350 * @cfg {Boolean} btn true | false
355 * @param {Object} config The config object
358 Roo.bootstrap.ButtonGroup = function(config){
359 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
362 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
370 getAutoCreate : function(){
376 cfg.html = this.html || cfg.html;
387 if (['vertical','justified'].indexOf(this.align)!==-1) {
388 cfg.cls = 'btn-group-' + this.align;
390 if (this.align == 'justified') {
391 console.log(this.items);
395 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
396 cfg.cls += ' btn-group-' + this.size;
399 if (this.direction == 'up') {
400 cfg.cls += ' dropup' ;
416 * @class Roo.bootstrap.Button
417 * @extends Roo.bootstrap.Component
418 * Bootstrap Button class
419 * @cfg {String} html The button content
420 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
421 * @cfg {String} size empty | lg | sm | xs
422 * @cfg {String} tag empty | a | input | submit
423 * @cfg {String} href empty or href
424 * @cfg {Boolean} disabled false | true
425 * @cfg {Boolean} isClose false | true
426 * @cfg {String} glyphicon empty | 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
427 * @cfg {String} badge text for badge
428 * @cfg {String} theme default (or empty) | glow
429 * @cfg {Boolean} inverse false | true
430 * @cfg {Boolean} toggle false | true
431 * @cfg {String} ontext text for on toggle state
432 * @cfg {String} offtext text for off toggle state
433 * @cfg {Boolean} defaulton true | false
434 * @cfg {Boolean} preventDefault (true | false) default true
435 * @cfg {Boolean} removeClass true | false remove the standard class..
436 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
439 * Create a new button
440 * @param {Object} config The config object
444 Roo.bootstrap.Button = function(config){
445 Roo.bootstrap.Button.superclass.constructor.call(this, config);
450 * When a butotn is pressed
451 * @param {Roo.EventObject} e
456 * After the button has been toggles
457 * @param {Roo.EventObject} e
458 * @param {boolean} pressed (also available as button.pressed)
464 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
482 preventDefault: true,
491 getAutoCreate : function(){
499 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
500 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
505 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
507 if (this.toggle == true) {
510 cls: 'slider-frame roo-button',
515 'data-off-text':'OFF',
516 cls: 'slider-button',
522 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
523 cfg.cls += ' '+this.weight;
532 cfg["aria-hidden"] = true;
534 cfg.html = "×";
540 if (this.theme==='default') {
541 cfg.cls = 'btn roo-button';
543 //if (this.parentType != 'Navbar') {
544 this.weight = this.weight.length ? this.weight : 'default';
546 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
548 cfg.cls += ' btn-' + this.weight;
550 } else if (this.theme==='glow') {
553 cfg.cls = 'btn-glow roo-button';
555 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
557 cfg.cls += ' ' + this.weight;
563 this.cls += ' inverse';
568 cfg.cls += ' active';
572 cfg.disabled = 'disabled';
576 Roo.log('changing to ul' );
578 this.glyphicon = 'caret';
581 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
583 //gsRoo.log(this.parentType);
584 if (this.parentType === 'Navbar' && !this.parent().bar) {
585 Roo.log('changing to li?');
594 href : this.href || '#'
597 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
598 cfg.cls += ' dropdown';
605 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
607 if (this.glyphicon) {
608 cfg.html = ' ' + cfg.html;
613 cls: 'glyphicon glyphicon-' + this.glyphicon
623 // cfg.cls='btn roo-button';
627 var value = cfg.html;
632 cls: 'glyphicon glyphicon-' + this.glyphicon,
651 cfg.cls += ' dropdown';
652 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
655 if (cfg.tag !== 'a' && this.href !== '') {
656 throw "Tag must be a to set href.";
657 } else if (this.href.length > 0) {
658 cfg.href = this.href;
661 if(this.removeClass){
666 cfg.target = this.target;
671 initEvents: function() {
672 // Roo.log('init events?');
673 // Roo.log(this.el.dom);
676 if (typeof (this.menu) != 'undefined') {
677 this.menu.parentType = this.xtype;
678 this.menu.triggerEl = this.el;
679 this.addxtype(Roo.apply({}, this.menu));
683 if (this.el.hasClass('roo-button')) {
684 this.el.on('click', this.onClick, this);
686 this.el.select('.roo-button').on('click', this.onClick, this);
689 if(this.removeClass){
690 this.el.on('click', this.onClick, this);
693 this.el.enableDisplayMode();
696 onClick : function(e)
702 Roo.log('button on click ');
703 if(this.preventDefault){
706 if (this.pressed === true || this.pressed === false) {
707 this.pressed = !this.pressed;
708 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
709 this.fireEvent('toggle', this, e, this.pressed);
713 this.fireEvent('click', this, e);
717 * Enables this button
721 this.disabled = false;
722 this.el.removeClass('disabled');
726 * Disable this button
730 this.disabled = true;
731 this.el.addClass('disabled');
734 * sets the active state on/off,
735 * @param {Boolean} state (optional) Force a particular state
737 setActive : function(v) {
739 this.el[v ? 'addClass' : 'removeClass']('active');
742 * toggles the current active state
744 toggleActive : function()
746 var active = this.el.hasClass('active');
747 this.setActive(!active);
751 setText : function(str)
753 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
757 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
780 * @class Roo.bootstrap.Column
781 * @extends Roo.bootstrap.Component
782 * Bootstrap Column class
783 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
784 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
785 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
786 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
787 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
788 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
789 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
790 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
793 * @cfg {Boolean} hidden (true|false) hide the element
794 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
795 * @cfg {String} fa (ban|check|...) font awesome icon
796 * @cfg {Number} fasize (1|2|....) font awsome size
798 * @cfg {String} icon (info-sign|check|...) glyphicon name
800 * @cfg {String} html content of column.
803 * Create a new Column
804 * @param {Object} config The config object
807 Roo.bootstrap.Column = function(config){
808 Roo.bootstrap.Column.superclass.constructor.call(this, config);
811 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
829 getAutoCreate : function(){
830 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
838 ['xs','sm','md','lg'].map(function(size){
839 //Roo.log( size + ':' + settings[size]);
841 if (settings[size+'off'] !== false) {
842 cfg.cls += ' col-' + settings[size+'off'] + '-offset';
845 if (settings[size] === false) {
848 Roo.log(settings[size]);
849 if (!settings[size]) { // 0 = hidden
850 cfg.cls += ' hidden-' + size;
853 cfg.cls += ' col-' + size + '-' + settings[size];
858 cfg.cls += ' hidden';
861 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
862 cfg.cls +=' alert alert-' + this.alert;
866 if (this.html.length) {
867 cfg.html = this.html;
871 if (this.fasize > 1) {
872 fasize = ' fa-' + this.fasize + 'x';
874 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
879 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
898 * @class Roo.bootstrap.Container
899 * @extends Roo.bootstrap.Component
900 * Bootstrap Container class
901 * @cfg {Boolean} jumbotron is it a jumbotron element
902 * @cfg {String} html content of element
903 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
904 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
905 * @cfg {String} header content of header (for panel)
906 * @cfg {String} footer content of footer (for panel)
907 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
908 * @cfg {String} tag (header|aside|section) type of HTML tag.
909 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
910 * @cfg {String} fa (ban|check|...) font awesome icon
911 * @cfg {String} icon (info-sign|check|...) glyphicon name
912 * @cfg {Boolean} hidden (true|false) hide the element
916 * Create a new Container
917 * @param {Object} config The config object
920 Roo.bootstrap.Container = function(config){
921 Roo.bootstrap.Container.superclass.constructor.call(this, config);
924 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
938 getChildContainer : function() {
944 if (this.panel.length) {
945 return this.el.select('.panel-body',true).first();
952 getAutoCreate : function(){
955 tag : this.tag || 'div',
959 if (this.jumbotron) {
960 cfg.cls = 'jumbotron';
965 // - this is applied by the parent..
967 // cfg.cls = this.cls + '';
970 if (this.sticky.length) {
972 var bd = Roo.get(document.body);
973 if (!bd.hasClass('bootstrap-sticky')) {
974 bd.addClass('bootstrap-sticky');
975 Roo.select('html',true).setStyle('height', '100%');
978 cfg.cls += 'bootstrap-sticky-' + this.sticky;
982 if (this.well.length) {
986 cfg.cls +=' well well-' +this.well;
995 cfg.cls += ' hidden';
999 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1000 cfg.cls +=' alert alert-' + this.alert;
1005 if (this.panel.length) {
1006 cfg.cls += ' panel panel-' + this.panel;
1008 if (this.header.length) {
1011 cls : 'panel-heading',
1014 cls : 'panel-title',
1027 if (this.footer.length) {
1029 cls : 'panel-footer',
1038 body.html = this.html || cfg.html;
1039 // prefix with the icons..
1041 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1044 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1049 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1050 cfg.cls = 'container';
1056 titleEl : function()
1058 if(!this.el || !this.panel.length || !this.header.length){
1062 return this.el.select('.panel-title',true).first();
1065 setTitle : function(v)
1067 var titleEl = this.titleEl();
1073 titleEl.dom.innerHTML = v;
1076 getTitle : function()
1079 var titleEl = this.titleEl();
1085 return titleEl.dom.innerHTML;
1099 * @class Roo.bootstrap.Img
1100 * @extends Roo.bootstrap.Component
1101 * Bootstrap Img class
1102 * @cfg {Boolean} imgResponsive false | true
1103 * @cfg {String} border rounded | circle | thumbnail
1104 * @cfg {String} src image source
1105 * @cfg {String} alt image alternative text
1106 * @cfg {String} href a tag href
1107 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1110 * Create a new Input
1111 * @param {Object} config The config object
1114 Roo.bootstrap.Img = function(config){
1115 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1121 * The img click event for the img.
1122 * @param {Roo.EventObject} e
1128 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1130 imgResponsive: true,
1136 getAutoCreate : function(){
1140 cls: (this.imgResponsive) ? 'img-responsive' : '',
1144 cfg.html = this.html || cfg.html;
1146 cfg.src = this.src || cfg.src;
1148 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1149 cfg.cls += ' img-' + this.border;
1166 a.target = this.target;
1172 return (this.href) ? a : cfg;
1175 initEvents: function() {
1178 this.el.on('click', this.onClick, this);
1182 onClick : function(e)
1184 Roo.log('img onclick');
1185 this.fireEvent('click', this, e);
1199 * @class Roo.bootstrap.Link
1200 * @extends Roo.bootstrap.Component
1201 * Bootstrap Link Class
1202 * @cfg {String} alt image alternative text
1203 * @cfg {String} href a tag href
1204 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1205 * @cfg {String} html the content of the link.
1206 * @cfg {String} anchor name for the anchor link
1208 * @cfg {Boolean} preventDefault (true | false) default false
1212 * Create a new Input
1213 * @param {Object} config The config object
1216 Roo.bootstrap.Link = function(config){
1217 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1223 * The img click event for the img.
1224 * @param {Roo.EventObject} e
1230 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1234 preventDefault: false,
1238 getAutoCreate : function()
1244 // anchor's do not require html/href...
1245 if (this.anchor === false) {
1246 cfg.html = this.html || 'html-missing';
1247 cfg.href = this.href || '#';
1249 cfg.name = this.anchor;
1250 if (this.html !== false) {
1251 cfg.html = this.html;
1253 if (this.href !== false) {
1254 cfg.href = this.href;
1258 if(this.alt !== false){
1263 if(this.target !== false) {
1264 cfg.target = this.target;
1270 initEvents: function() {
1272 if(!this.href || this.preventDefault){
1273 this.el.on('click', this.onClick, this);
1277 onClick : function(e)
1279 if(this.preventDefault){
1282 //Roo.log('img onclick');
1283 this.fireEvent('click', this, e);
1296 * @class Roo.bootstrap.Header
1297 * @extends Roo.bootstrap.Component
1298 * Bootstrap Header class
1299 * @cfg {String} html content of header
1300 * @cfg {Number} level (1|2|3|4|5|6) default 1
1303 * Create a new Header
1304 * @param {Object} config The config object
1308 Roo.bootstrap.Header = function(config){
1309 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1312 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1320 getAutoCreate : function(){
1323 tag: 'h' + (1 *this.level),
1324 html: this.html || 'fill in html'
1336 * Ext JS Library 1.1.1
1337 * Copyright(c) 2006-2007, Ext JS, LLC.
1339 * Originally Released Under LGPL - original licence link has changed is not relivant.
1342 * <script type="text/javascript">
1346 * @class Roo.bootstrap.MenuMgr
1347 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1350 Roo.bootstrap.MenuMgr = function(){
1351 var menus, active, groups = {}, attached = false, lastShow = new Date();
1353 // private - called when first menu is created
1356 active = new Roo.util.MixedCollection();
1357 Roo.get(document).addKeyListener(27, function(){
1358 if(active.length > 0){
1366 if(active && active.length > 0){
1367 var c = active.clone();
1377 if(active.length < 1){
1378 Roo.get(document).un("mouseup", onMouseDown);
1386 var last = active.last();
1387 lastShow = new Date();
1390 Roo.get(document).on("mouseup", onMouseDown);
1395 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1396 m.parentMenu.activeChild = m;
1397 }else if(last && last.isVisible()){
1398 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1403 function onBeforeHide(m){
1405 m.activeChild.hide();
1407 if(m.autoHideTimer){
1408 clearTimeout(m.autoHideTimer);
1409 delete m.autoHideTimer;
1414 function onBeforeShow(m){
1415 var pm = m.parentMenu;
1416 if(!pm && !m.allowOtherMenus){
1418 }else if(pm && pm.activeChild && active != m){
1419 pm.activeChild.hide();
1424 function onMouseDown(e){
1425 Roo.log("on MouseDown");
1426 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1434 function onBeforeCheck(mi, state){
1436 var g = groups[mi.group];
1437 for(var i = 0, l = g.length; i < l; i++){
1439 g[i].setChecked(false);
1448 * Hides all menus that are currently visible
1450 hideAll : function(){
1455 register : function(menu){
1459 menus[menu.id] = menu;
1460 menu.on("beforehide", onBeforeHide);
1461 menu.on("hide", onHide);
1462 menu.on("beforeshow", onBeforeShow);
1463 menu.on("show", onShow);
1465 if(g && menu.events["checkchange"]){
1469 groups[g].push(menu);
1470 menu.on("checkchange", onCheck);
1475 * Returns a {@link Roo.menu.Menu} object
1476 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1477 * be used to generate and return a new Menu instance.
1479 get : function(menu){
1480 if(typeof menu == "string"){ // menu id
1482 }else if(menu.events){ // menu instance
1485 /*else if(typeof menu.length == 'number'){ // array of menu items?
1486 return new Roo.bootstrap.Menu({items:menu});
1487 }else{ // otherwise, must be a config
1488 return new Roo.bootstrap.Menu(menu);
1495 unregister : function(menu){
1496 delete menus[menu.id];
1497 menu.un("beforehide", onBeforeHide);
1498 menu.un("hide", onHide);
1499 menu.un("beforeshow", onBeforeShow);
1500 menu.un("show", onShow);
1502 if(g && menu.events["checkchange"]){
1503 groups[g].remove(menu);
1504 menu.un("checkchange", onCheck);
1509 registerCheckable : function(menuItem){
1510 var g = menuItem.group;
1515 groups[g].push(menuItem);
1516 menuItem.on("beforecheckchange", onBeforeCheck);
1521 unregisterCheckable : function(menuItem){
1522 var g = menuItem.group;
1524 groups[g].remove(menuItem);
1525 menuItem.un("beforecheckchange", onBeforeCheck);
1537 * @class Roo.bootstrap.Menu
1538 * @extends Roo.bootstrap.Component
1539 * Bootstrap Menu class - container for MenuItems
1540 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1544 * @param {Object} config The config object
1548 Roo.bootstrap.Menu = function(config){
1549 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1550 if (this.registerMenu) {
1551 Roo.bootstrap.MenuMgr.register(this);
1556 * Fires before this menu is displayed
1557 * @param {Roo.menu.Menu} this
1562 * Fires before this menu is hidden
1563 * @param {Roo.menu.Menu} this
1568 * Fires after this menu is displayed
1569 * @param {Roo.menu.Menu} this
1574 * Fires after this menu is hidden
1575 * @param {Roo.menu.Menu} this
1580 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1581 * @param {Roo.menu.Menu} this
1582 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1583 * @param {Roo.EventObject} e
1588 * Fires when the mouse is hovering over this menu
1589 * @param {Roo.menu.Menu} this
1590 * @param {Roo.EventObject} e
1591 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1596 * Fires when the mouse exits this menu
1597 * @param {Roo.menu.Menu} this
1598 * @param {Roo.EventObject} e
1599 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1604 * Fires when a menu item contained in this menu is clicked
1605 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1606 * @param {Roo.EventObject} e
1610 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1613 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1617 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1620 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1622 registerMenu : true,
1624 menuItems :false, // stores the menu items..
1630 getChildContainer : function() {
1634 getAutoCreate : function(){
1636 //if (['right'].indexOf(this.align)!==-1) {
1637 // cfg.cn[1].cls += ' pull-right'
1643 cls : 'dropdown-menu' ,
1644 style : 'z-index:1000'
1648 if (this.type === 'submenu') {
1649 cfg.cls = 'submenu active';
1651 if (this.type === 'treeview') {
1652 cfg.cls = 'treeview-menu';
1657 initEvents : function() {
1659 // Roo.log("ADD event");
1660 // Roo.log(this.triggerEl.dom);
1661 this.triggerEl.on('click', this.onTriggerPress, this);
1662 this.triggerEl.addClass('dropdown-toggle');
1663 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1665 this.el.on("mouseover", this.onMouseOver, this);
1666 this.el.on("mouseout", this.onMouseOut, this);
1670 findTargetItem : function(e){
1671 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1675 //Roo.log(t); Roo.log(t.id);
1677 //Roo.log(this.menuitems);
1678 return this.menuitems.get(t.id);
1680 //return this.items.get(t.menuItemId);
1685 onClick : function(e){
1686 Roo.log("menu.onClick");
1687 var t = this.findTargetItem(e);
1693 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1694 if(t == this.activeItem && t.shouldDeactivate(e)){
1695 this.activeItem.deactivate();
1696 delete this.activeItem;
1700 this.setActiveItem(t, true);
1707 Roo.log('pass click event');
1711 this.fireEvent("click", this, t, e);
1715 onMouseOver : function(e){
1716 var t = this.findTargetItem(e);
1719 // if(t.canActivate && !t.disabled){
1720 // this.setActiveItem(t, true);
1724 this.fireEvent("mouseover", this, e, t);
1726 isVisible : function(){
1727 return !this.hidden;
1729 onMouseOut : function(e){
1730 var t = this.findTargetItem(e);
1733 // if(t == this.activeItem && t.shouldDeactivate(e)){
1734 // this.activeItem.deactivate();
1735 // delete this.activeItem;
1738 this.fireEvent("mouseout", this, e, t);
1743 * Displays this menu relative to another element
1744 * @param {String/HTMLElement/Roo.Element} element The element to align to
1745 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1746 * the element (defaults to this.defaultAlign)
1747 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1749 show : function(el, pos, parentMenu){
1750 this.parentMenu = parentMenu;
1754 this.fireEvent("beforeshow", this);
1755 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1758 * Displays this menu at a specific xy position
1759 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1760 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1762 showAt : function(xy, parentMenu, /* private: */_e){
1763 this.parentMenu = parentMenu;
1768 this.fireEvent("beforeshow", this);
1770 //xy = this.el.adjustForConstraints(xy);
1772 //this.el.setXY(xy);
1774 this.hideMenuItems();
1775 this.hidden = false;
1776 this.triggerEl.addClass('open');
1778 this.fireEvent("show", this);
1784 this.doFocus.defer(50, this);
1788 doFocus : function(){
1790 this.focusEl.focus();
1795 * Hides this menu and optionally all parent menus
1796 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1798 hide : function(deep){
1800 this.hideMenuItems();
1801 if(this.el && this.isVisible()){
1802 this.fireEvent("beforehide", this);
1803 if(this.activeItem){
1804 this.activeItem.deactivate();
1805 this.activeItem = null;
1807 this.triggerEl.removeClass('open');;
1809 this.fireEvent("hide", this);
1811 if(deep === true && this.parentMenu){
1812 this.parentMenu.hide(true);
1816 onTriggerPress : function(e)
1819 Roo.log('trigger press');
1820 //Roo.log(e.getTarget());
1821 // Roo.log(this.triggerEl.dom);
1822 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1825 if (this.isVisible()) {
1829 this.show(this.triggerEl, false, false);
1838 hideMenuItems : function()
1840 //$(backdrop).remove()
1841 Roo.select('.open',true).each(function(aa) {
1843 aa.removeClass('open');
1844 //var parent = getParent($(this))
1845 //var relatedTarget = { relatedTarget: this }
1847 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1848 //if (e.isDefaultPrevented()) return
1849 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1852 addxtypeChild : function (tree, cntr) {
1853 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1855 this.menuitems.add(comp);
1876 * @class Roo.bootstrap.MenuItem
1877 * @extends Roo.bootstrap.Component
1878 * Bootstrap MenuItem class
1879 * @cfg {String} html the menu label
1880 * @cfg {String} href the link
1881 * @cfg {Boolean} preventDefault (true | false) default true
1885 * Create a new MenuItem
1886 * @param {Object} config The config object
1890 Roo.bootstrap.MenuItem = function(config){
1891 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1896 * The raw click event for the entire grid.
1897 * @param {Roo.EventObject} e
1903 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1907 preventDefault: true,
1909 getAutoCreate : function(){
1912 cls: 'dropdown-menu-item',
1921 if (this.parent().type == 'treeview') {
1922 cfg.cls = 'treeview-menu';
1925 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1926 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1930 initEvents: function() {
1932 //this.el.select('a').on('click', this.onClick, this);
1935 onClick : function(e)
1937 Roo.log('item on click ');
1938 //if(this.preventDefault){
1939 // e.preventDefault();
1941 //this.parent().hideMenuItems();
1943 this.fireEvent('click', this, e);
1962 * @class Roo.bootstrap.MenuSeparator
1963 * @extends Roo.bootstrap.Component
1964 * Bootstrap MenuSeparator class
1967 * Create a new MenuItem
1968 * @param {Object} config The config object
1972 Roo.bootstrap.MenuSeparator = function(config){
1973 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1976 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1978 getAutoCreate : function(){
1993 <div class="modal fade">
1994 <div class="modal-dialog">
1995 <div class="modal-content">
1996 <div class="modal-header">
1997 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1998 <h4 class="modal-title">Modal title</h4>
2000 <div class="modal-body">
2001 <p>One fine body…</p>
2003 <div class="modal-footer">
2004 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2005 <button type="button" class="btn btn-primary">Save changes</button>
2007 </div><!-- /.modal-content -->
2008 </div><!-- /.modal-dialog -->
2009 </div><!-- /.modal -->
2019 * @class Roo.bootstrap.Modal
2020 * @extends Roo.bootstrap.Component
2021 * Bootstrap Modal class
2022 * @cfg {String} title Title of dialog
2023 * @cfg {Boolean} specificTitle (true|false) default false
2024 * @cfg {Array} buttons Array of buttons or standard button set..
2025 * @cfg {String} buttonPosition (left|right|center) default right
2028 * Create a new Modal Dialog
2029 * @param {Object} config The config object
2032 Roo.bootstrap.Modal = function(config){
2033 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2038 * The raw btnclick event for the button
2039 * @param {Roo.EventObject} e
2043 this.buttons = this.buttons || [];
2046 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2048 title : 'test dialog',
2055 specificTitle: false,
2057 buttonPosition: 'right',
2059 onRender : function(ct, position)
2061 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2064 var cfg = Roo.apply({}, this.getAutoCreate());
2067 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2069 //if (!cfg.name.length) {
2073 cfg.cls += ' ' + this.cls;
2076 cfg.style = this.style;
2078 this.el = Roo.get(document.body).createChild(cfg, position);
2080 //var type = this.el.dom.type;
2082 if(this.tabIndex !== undefined){
2083 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2088 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2089 this.maskEl.enableDisplayMode("block");
2091 //this.el.addClass("x-dlg-modal");
2093 if (this.buttons.length) {
2094 Roo.each(this.buttons, function(bb) {
2095 b = Roo.apply({}, bb);
2096 b.xns = b.xns || Roo.bootstrap;
2097 b.xtype = b.xtype || 'Button';
2098 if (typeof(b.listeners) == 'undefined') {
2099 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2102 var btn = Roo.factory(b);
2104 btn.onRender(this.el.select('.modal-footer div').first());
2108 // render the children.
2111 if(typeof(this.items) != 'undefined'){
2112 var items = this.items;
2115 for(var i =0;i < items.length;i++) {
2116 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2120 this.items = nitems;
2122 this.body = this.el.select('.modal-body',true).first();
2123 this.close = this.el.select('.modal-header .close', true).first();
2124 this.footer = this.el.select('.modal-footer',true).first();
2126 //this.el.addClass([this.fieldClass, this.cls]);
2129 getAutoCreate : function(){
2134 html : this.html || ''
2139 cls : 'modal-title',
2143 if(this.specificTitle){
2149 style : 'display: none',
2152 cls: "modal-dialog",
2155 cls : "modal-content",
2158 cls : 'modal-header',
2170 cls : 'modal-footer',
2174 cls: 'btn-' + this.buttonPosition
2193 getChildContainer : function() {
2195 return this.el.select('.modal-body',true).first();
2198 getButtonContainer : function() {
2199 return this.el.select('.modal-footer div',true).first();
2202 initEvents : function()
2204 this.el.select('.modal-header .close').on('click', this.hide, this);
2206 // this.addxtype(this);
2210 if (!this.rendered) {
2214 this.el.addClass('on');
2215 this.el.removeClass('fade');
2216 this.el.setStyle('display', 'block');
2217 Roo.get(document.body).addClass("x-body-masked");
2218 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2220 this.el.setStyle('zIndex', '10001');
2221 this.fireEvent('show', this);
2227 Roo.log('Modal hide?!');
2229 Roo.get(document.body).removeClass("x-body-masked");
2230 this.el.removeClass('on');
2231 this.el.addClass('fade');
2232 this.el.setStyle('display', 'none');
2233 this.fireEvent('hide', this);
2236 addButton : function(str, cb)
2240 var b = Roo.apply({}, { html : str } );
2241 b.xns = b.xns || Roo.bootstrap;
2242 b.xtype = b.xtype || 'Button';
2243 if (typeof(b.listeners) == 'undefined') {
2244 b.listeners = { click : cb.createDelegate(this) };
2247 var btn = Roo.factory(b);
2249 btn.onRender(this.el.select('.modal-footer div').first());
2255 setDefaultButton : function(btn)
2257 //this.el.select('.modal-footer').()
2259 resizeTo: function(w,h)
2263 setContentSize : function(w, h)
2267 onButtonClick: function(btn,e)
2270 this.fireEvent('btnclick', btn.name, e);
2272 setTitle: function(str) {
2273 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2279 Roo.apply(Roo.bootstrap.Modal, {
2281 * Button config that displays a single OK button
2290 * Button config that displays Yes and No buttons
2306 * Button config that displays OK and Cancel buttons
2321 * Button config that displays Yes, No and Cancel buttons
2343 * messagebox - can be used as a replace
2347 * @class Roo.MessageBox
2348 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2352 Roo.Msg.alert('Status', 'Changes saved successfully.');
2354 // Prompt for user data:
2355 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2357 // process text value...
2361 // Show a dialog using config options:
2363 title:'Save Changes?',
2364 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2365 buttons: Roo.Msg.YESNOCANCEL,
2372 Roo.bootstrap.MessageBox = function(){
2373 var dlg, opt, mask, waitTimer;
2374 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2375 var buttons, activeTextEl, bwidth;
2379 var handleButton = function(button){
2381 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2385 var handleHide = function(){
2387 dlg.el.removeClass(opt.cls);
2390 // Roo.TaskMgr.stop(waitTimer);
2391 // waitTimer = null;
2396 var updateButtons = function(b){
2399 buttons["ok"].hide();
2400 buttons["cancel"].hide();
2401 buttons["yes"].hide();
2402 buttons["no"].hide();
2403 //dlg.footer.dom.style.display = 'none';
2406 dlg.footer.dom.style.display = '';
2407 for(var k in buttons){
2408 if(typeof buttons[k] != "function"){
2411 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2412 width += buttons[k].el.getWidth()+15;
2422 var handleEsc = function(d, k, e){
2423 if(opt && opt.closable !== false){
2433 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2434 * @return {Roo.BasicDialog} The BasicDialog element
2436 getDialog : function(){
2438 dlg = new Roo.bootstrap.Modal( {
2441 //constraintoviewport:false,
2443 //collapsible : false,
2448 //buttonAlign:"center",
2449 closeClick : function(){
2450 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2453 handleButton("cancel");
2458 dlg.on("hide", handleHide);
2460 //dlg.addKeyListener(27, handleEsc);
2462 this.buttons = buttons;
2463 var bt = this.buttonText;
2464 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2465 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2466 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2467 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2469 bodyEl = dlg.body.createChild({
2471 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2472 '<textarea class="roo-mb-textarea"></textarea>' +
2473 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2475 msgEl = bodyEl.dom.firstChild;
2476 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2477 textboxEl.enableDisplayMode();
2478 textboxEl.addKeyListener([10,13], function(){
2479 if(dlg.isVisible() && opt && opt.buttons){
2482 }else if(opt.buttons.yes){
2483 handleButton("yes");
2487 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2488 textareaEl.enableDisplayMode();
2489 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2490 progressEl.enableDisplayMode();
2491 var pf = progressEl.dom.firstChild;
2493 pp = Roo.get(pf.firstChild);
2494 pp.setHeight(pf.offsetHeight);
2502 * Updates the message box body text
2503 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2504 * the XHTML-compliant non-breaking space character '&#160;')
2505 * @return {Roo.MessageBox} This message box
2507 updateText : function(text){
2508 if(!dlg.isVisible() && !opt.width){
2509 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2511 msgEl.innerHTML = text || ' ';
2513 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2514 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2516 Math.min(opt.width || cw , this.maxWidth),
2517 Math.max(opt.minWidth || this.minWidth, bwidth)
2520 activeTextEl.setWidth(w);
2522 if(dlg.isVisible()){
2523 dlg.fixedcenter = false;
2525 // to big, make it scroll. = But as usual stupid IE does not support
2528 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2529 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2530 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2532 bodyEl.dom.style.height = '';
2533 bodyEl.dom.style.overflowY = '';
2536 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2538 bodyEl.dom.style.overflowX = '';
2541 dlg.setContentSize(w, bodyEl.getHeight());
2542 if(dlg.isVisible()){
2543 dlg.fixedcenter = true;
2549 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2550 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2551 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2552 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2553 * @return {Roo.MessageBox} This message box
2555 updateProgress : function(value, text){
2557 this.updateText(text);
2559 if (pp) { // weird bug on my firefox - for some reason this is not defined
2560 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2566 * Returns true if the message box is currently displayed
2567 * @return {Boolean} True if the message box is visible, else false
2569 isVisible : function(){
2570 return dlg && dlg.isVisible();
2574 * Hides the message box if it is displayed
2577 if(this.isVisible()){
2583 * Displays a new message box, or reinitializes an existing message box, based on the config options
2584 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2585 * The following config object properties are supported:
2587 Property Type Description
2588 ---------- --------------- ------------------------------------------------------------------------------------
2589 animEl String/Element An id or Element from which the message box should animate as it opens and
2590 closes (defaults to undefined)
2591 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2592 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2593 closable Boolean False to hide the top-right close button (defaults to true). Note that
2594 progress and wait dialogs will ignore this property and always hide the
2595 close button as they can only be closed programmatically.
2596 cls String A custom CSS class to apply to the message box element
2597 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2598 displayed (defaults to 75)
2599 fn Function A callback function to execute after closing the dialog. The arguments to the
2600 function will be btn (the name of the button that was clicked, if applicable,
2601 e.g. "ok"), and text (the value of the active text field, if applicable).
2602 Progress and wait dialogs will ignore this option since they do not respond to
2603 user actions and can only be closed programmatically, so any required function
2604 should be called by the same code after it closes the dialog.
2605 icon String A CSS class that provides a background image to be used as an icon for
2606 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2607 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2608 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2609 modal Boolean False to allow user interaction with the page while the message box is
2610 displayed (defaults to true)
2611 msg String A string that will replace the existing message box body text (defaults
2612 to the XHTML-compliant non-breaking space character ' ')
2613 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2614 progress Boolean True to display a progress bar (defaults to false)
2615 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2616 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2617 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2618 title String The title text
2619 value String The string value to set into the active textbox element if displayed
2620 wait Boolean True to display a progress bar (defaults to false)
2621 width Number The width of the dialog in pixels
2628 msg: 'Please enter your address:',
2630 buttons: Roo.MessageBox.OKCANCEL,
2633 animEl: 'addAddressBtn'
2636 * @param {Object} config Configuration options
2637 * @return {Roo.MessageBox} This message box
2639 show : function(options)
2642 // this causes nightmares if you show one dialog after another
2643 // especially on callbacks..
2645 if(this.isVisible()){
2648 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2649 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2650 Roo.log("New Dialog Message:" + options.msg )
2651 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2652 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2655 var d = this.getDialog();
2657 d.setTitle(opt.title || " ");
2658 d.close.setDisplayed(opt.closable !== false);
2659 activeTextEl = textboxEl;
2660 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2665 textareaEl.setHeight(typeof opt.multiline == "number" ?
2666 opt.multiline : this.defaultTextHeight);
2667 activeTextEl = textareaEl;
2676 progressEl.setDisplayed(opt.progress === true);
2677 this.updateProgress(0);
2678 activeTextEl.dom.value = opt.value || "";
2680 dlg.setDefaultButton(activeTextEl);
2682 var bs = opt.buttons;
2686 }else if(bs && bs.yes){
2687 db = buttons["yes"];
2689 dlg.setDefaultButton(db);
2691 bwidth = updateButtons(opt.buttons);
2692 this.updateText(opt.msg);
2694 d.el.addClass(opt.cls);
2696 d.proxyDrag = opt.proxyDrag === true;
2697 d.modal = opt.modal !== false;
2698 d.mask = opt.modal !== false ? mask : false;
2700 // force it to the end of the z-index stack so it gets a cursor in FF
2701 document.body.appendChild(dlg.el.dom);
2702 d.animateTarget = null;
2703 d.show(options.animEl);
2709 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2710 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2711 * and closing the message box when the process is complete.
2712 * @param {String} title The title bar text
2713 * @param {String} msg The message box body text
2714 * @return {Roo.MessageBox} This message box
2716 progress : function(title, msg){
2723 minWidth: this.minProgressWidth,
2730 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2731 * If a callback function is passed it will be called after the user clicks the button, and the
2732 * id of the button that was clicked will be passed as the only parameter to the callback
2733 * (could also be the top-right close button).
2734 * @param {String} title The title bar text
2735 * @param {String} msg The message box body text
2736 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2737 * @param {Object} scope (optional) The scope of the callback function
2738 * @return {Roo.MessageBox} This message box
2740 alert : function(title, msg, fn, scope){
2753 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2754 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2755 * You are responsible for closing the message box when the process is complete.
2756 * @param {String} msg The message box body text
2757 * @param {String} title (optional) The title bar text
2758 * @return {Roo.MessageBox} This message box
2760 wait : function(msg, title){
2771 waitTimer = Roo.TaskMgr.start({
2773 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2781 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2782 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2783 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2784 * @param {String} title The title bar text
2785 * @param {String} msg The message box body text
2786 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2787 * @param {Object} scope (optional) The scope of the callback function
2788 * @return {Roo.MessageBox} This message box
2790 confirm : function(title, msg, fn, scope){
2794 buttons: this.YESNO,
2803 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2804 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2805 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2806 * (could also be the top-right close button) and the text that was entered will be passed as the two
2807 * parameters to the callback.
2808 * @param {String} title The title bar text
2809 * @param {String} msg The message box body text
2810 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2811 * @param {Object} scope (optional) The scope of the callback function
2812 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2813 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2814 * @return {Roo.MessageBox} This message box
2816 prompt : function(title, msg, fn, scope, multiline){
2820 buttons: this.OKCANCEL,
2825 multiline: multiline,
2832 * Button config that displays a single OK button
2837 * Button config that displays Yes and No buttons
2840 YESNO : {yes:true, no:true},
2842 * Button config that displays OK and Cancel buttons
2845 OKCANCEL : {ok:true, cancel:true},
2847 * Button config that displays Yes, No and Cancel buttons
2850 YESNOCANCEL : {yes:true, no:true, cancel:true},
2853 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2856 defaultTextHeight : 75,
2858 * The maximum width in pixels of the message box (defaults to 600)
2863 * The minimum width in pixels of the message box (defaults to 100)
2868 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2869 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2872 minProgressWidth : 250,
2874 * An object containing the default button text strings that can be overriden for localized language support.
2875 * Supported properties are: ok, cancel, yes and no.
2876 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2889 * Shorthand for {@link Roo.MessageBox}
2891 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2892 Roo.Msg = Roo.Msg || Roo.MessageBox;
2901 * @class Roo.bootstrap.Navbar
2902 * @extends Roo.bootstrap.Component
2903 * Bootstrap Navbar class
2906 * Create a new Navbar
2907 * @param {Object} config The config object
2911 Roo.bootstrap.Navbar = function(config){
2912 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2916 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2925 getAutoCreate : function(){
2928 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2932 initEvents :function ()
2934 //Roo.log(this.el.select('.navbar-toggle',true));
2935 this.el.select('.navbar-toggle',true).on('click', function() {
2936 // Roo.log('click');
2937 this.el.select('.navbar-collapse',true).toggleClass('in');
2945 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2947 var size = this.el.getSize();
2948 this.maskEl.setSize(size.width, size.height);
2949 this.maskEl.enableDisplayMode("block");
2958 getChildContainer : function()
2960 if (this.el.select('.collapse').getCount()) {
2961 return this.el.select('.collapse',true).first();
2994 * @class Roo.bootstrap.NavSimplebar
2995 * @extends Roo.bootstrap.Navbar
2996 * Bootstrap Sidebar class
2998 * @cfg {Boolean} inverse is inverted color
3000 * @cfg {String} type (nav | pills | tabs)
3001 * @cfg {Boolean} arrangement stacked | justified
3002 * @cfg {String} align (left | right) alignment
3004 * @cfg {Boolean} main (true|false) main nav bar? default false
3005 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3007 * @cfg {String} tag (header|footer|nav|div) default is nav
3013 * Create a new Sidebar
3014 * @param {Object} config The config object
3018 Roo.bootstrap.NavSimplebar = function(config){
3019 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3022 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3038 getAutoCreate : function(){
3042 tag : this.tag || 'div',
3055 this.type = this.type || 'nav';
3056 if (['tabs','pills'].indexOf(this.type)!==-1) {
3057 cfg.cn[0].cls += ' nav-' + this.type
3061 if (this.type!=='nav') {
3062 Roo.log('nav type must be nav/tabs/pills')
3064 cfg.cn[0].cls += ' navbar-nav'
3070 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3071 cfg.cn[0].cls += ' nav-' + this.arrangement;
3075 if (this.align === 'right') {
3076 cfg.cn[0].cls += ' navbar-right';
3080 cfg.cls += ' navbar-inverse';
3107 * @class Roo.bootstrap.NavHeaderbar
3108 * @extends Roo.bootstrap.NavSimplebar
3109 * Bootstrap Sidebar class
3111 * @cfg {String} brand what is brand
3112 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3113 * @cfg {String} brand_href href of the brand
3114 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3115 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3118 * Create a new Sidebar
3119 * @param {Object} config The config object
3123 Roo.bootstrap.NavHeaderbar = function(config){
3124 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3127 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3135 getAutoCreate : function(){
3138 tag: this.nav || 'nav',
3147 cls: 'navbar-header',
3152 cls: 'navbar-toggle',
3153 'data-toggle': 'collapse',
3158 html: 'Toggle navigation'
3180 cls: 'collapse navbar-collapse',
3184 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3186 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3187 cfg.cls += ' navbar-' + this.position;
3189 // tag can override this..
3191 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3194 if (this.brand !== '') {
3197 href: this.brand_href ? this.brand_href : '#',
3198 cls: 'navbar-brand',
3206 cfg.cls += ' main-nav';
3214 initEvents : function()
3216 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3218 if (this.autohide) {
3223 Roo.get(document).on('scroll',function(e) {
3224 var ns = Roo.get(document).getScroll().top;
3225 var os = prevScroll;
3229 ft.removeClass('slideDown');
3230 ft.addClass('slideUp');
3233 ft.removeClass('slideUp');
3234 ft.addClass('slideDown');
3258 * @class Roo.bootstrap.NavSidebar
3259 * @extends Roo.bootstrap.Navbar
3260 * Bootstrap Sidebar class
3263 * Create a new Sidebar
3264 * @param {Object} config The config object
3268 Roo.bootstrap.NavSidebar = function(config){
3269 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3272 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3274 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3276 getAutoCreate : function(){
3281 cls: 'sidebar sidebar-nav'
3303 * @class Roo.bootstrap.NavGroup
3304 * @extends Roo.bootstrap.Component
3305 * Bootstrap NavGroup class
3306 * @cfg {String} align left | right
3307 * @cfg {Boolean} inverse false | true
3308 * @cfg {String} type (nav|pills|tab) default nav
3309 * @cfg {String} navId - reference Id for navbar.
3313 * Create a new nav group
3314 * @param {Object} config The config object
3317 Roo.bootstrap.NavGroup = function(config){
3318 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3321 Roo.bootstrap.NavGroup.register(this);
3325 * Fires when the active item changes
3326 * @param {Roo.bootstrap.NavGroup} this
3327 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3328 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3335 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3346 getAutoCreate : function()
3348 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3355 if (['tabs','pills'].indexOf(this.type)!==-1) {
3356 cfg.cls += ' nav-' + this.type
3358 if (this.type!=='nav') {
3359 Roo.log('nav type must be nav/tabs/pills')
3361 cfg.cls += ' navbar-nav'
3364 if (this.parent().sidebar) {
3367 cls: 'dashboard-menu sidebar-menu'
3373 if (this.form === true) {
3379 if (this.align === 'right') {
3380 cfg.cls += ' navbar-right';
3382 cfg.cls += ' navbar-left';
3386 if (this.align === 'right') {
3387 cfg.cls += ' navbar-right';
3391 cfg.cls += ' navbar-inverse';
3399 * sets the active Navigation item
3400 * @param {Roo.bootstrap.NavItem} the new current navitem
3402 setActiveItem : function(item)
3405 Roo.each(this.navItems, function(v){
3410 v.setActive(false, true);
3417 item.setActive(true, true);
3418 this.fireEvent('changed', this, item, prev);
3423 * gets the active Navigation item
3424 * @return {Roo.bootstrap.NavItem} the current navitem
3426 getActive : function()
3430 Roo.each(this.navItems, function(v){
3441 indexOfNav : function()
3445 Roo.each(this.navItems, function(v,i){
3456 * adds a Navigation item
3457 * @param {Roo.bootstrap.NavItem} the navitem to add
3459 addItem : function(cfg)
3461 var cn = new Roo.bootstrap.NavItem(cfg);
3463 cn.parentId = this.id;
3464 cn.onRender(this.el, null);
3468 * register a Navigation item
3469 * @param {Roo.bootstrap.NavItem} the navitem to add
3471 register : function(item)
3473 this.navItems.push( item);
3474 item.navId = this.navId;
3479 getNavItem: function(tabId)
3482 Roo.each(this.navItems, function(e) {
3483 if (e.tabId == tabId) {
3493 setActiveNext : function()
3495 var i = this.indexOfNav(this.getActive());
3496 if (i > this.navItems.length) {
3499 this.setActiveItem(this.navItems[i+1]);
3501 setActivePrev : function()
3503 var i = this.indexOfNav(this.getActive());
3507 this.setActiveItem(this.navItems[i-1]);
3509 clearWasActive : function(except) {
3510 Roo.each(this.navItems, function(e) {
3511 if (e.tabId != except.tabId && e.was_active) {
3512 e.was_active = false;
3519 getWasActive : function ()
3522 Roo.each(this.navItems, function(e) {
3537 Roo.apply(Roo.bootstrap.NavGroup, {
3541 * register a Navigation Group
3542 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3544 register : function(navgrp)
3546 this.groups[navgrp.navId] = navgrp;
3550 * fetch a Navigation Group based on the navigation ID
3551 * @param {string} the navgroup to add
3552 * @returns {Roo.bootstrap.NavGroup} the navgroup
3554 get: function(navId) {
3555 if (typeof(this.groups[navId]) == 'undefined') {
3557 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3559 return this.groups[navId] ;
3574 * @class Roo.bootstrap.NavItem
3575 * @extends Roo.bootstrap.Component
3576 * Bootstrap Navbar.NavItem class
3577 * @cfg {String} href link to
3578 * @cfg {String} html content of button
3579 * @cfg {String} badge text inside badge
3580 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3581 * @cfg {String} glyphicon name of glyphicon
3582 * @cfg {String} icon name of font awesome icon
3583 * @cfg {Boolean} active Is item active
3584 * @cfg {Boolean} disabled Is item disabled
3586 * @cfg {Boolean} preventDefault (true | false) default false
3587 * @cfg {String} tabId the tab that this item activates.
3588 * @cfg {String} tagtype (a|span) render as a href or span?
3591 * Create a new Navbar Item
3592 * @param {Object} config The config object
3594 Roo.bootstrap.NavItem = function(config){
3595 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3600 * The raw click event for the entire grid.
3601 * @param {Roo.EventObject} e
3606 * Fires when the active item active state changes
3607 * @param {Roo.bootstrap.NavItem} this
3608 * @param {boolean} state the new state
3616 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3624 preventDefault : false,
3631 getAutoCreate : function(){
3639 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3641 if (this.disabled) {
3642 cfg.cls += ' disabled';
3645 if (this.href || this.html || this.glyphicon || this.icon) {
3649 href : this.href || "#",
3650 html: this.html || ''
3655 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3658 if(this.glyphicon) {
3659 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3664 cfg.cn[0].html += " <span class='caret'></span>";
3668 if (this.badge !== '') {
3670 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3678 initEvents: function() {
3679 // Roo.log('init events?');
3680 // Roo.log(this.el.dom);
3681 if (typeof (this.menu) != 'undefined') {
3682 this.menu.parentType = this.xtype;
3683 this.menu.triggerEl = this.el;
3684 this.addxtype(Roo.apply({}, this.menu));
3688 this.el.select('a',true).on('click', this.onClick, this);
3689 // at this point parent should be available..
3690 this.parent().register(this);
3693 onClick : function(e)
3696 if(this.preventDefault){
3699 if (this.disabled) {
3703 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3704 if (tg && tg.transition) {
3705 Roo.log("waiting for the transitionend");
3709 Roo.log("fire event clicked");
3710 if(this.fireEvent('click', this, e) === false){
3713 var p = this.parent();
3714 if (['tabs','pills'].indexOf(p.type)!==-1) {
3715 if (typeof(p.setActiveItem) !== 'undefined') {
3716 p.setActiveItem(this);
3719 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3720 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3721 // remove the collapsed menu expand...
3722 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3727 isActive: function () {
3730 setActive : function(state, fire, is_was_active)
3732 if (this.active && !state & this.navId) {
3733 this.was_active = true;
3734 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3736 nv.clearWasActive(this);
3740 this.active = state;
3743 this.el.removeClass('active');
3744 } else if (!this.el.hasClass('active')) {
3745 this.el.addClass('active');
3748 this.fireEvent('changed', this, state);
3751 // show a panel if it's registered and related..
3753 if (!this.navId || !this.tabId || !state || is_was_active) {
3757 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3761 var pan = tg.getPanelByName(this.tabId);
3765 // if we can not flip to new panel - go back to old nav highlight..
3766 if (false == tg.showPanel(pan)) {
3767 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3769 var onav = nv.getWasActive();
3771 onav.setActive(true, false, true);
3780 // this should not be here...
3781 setDisabled : function(state)
3783 this.disabled = state;
3785 this.el.removeClass('disabled');
3786 } else if (!this.el.hasClass('disabled')) {
3787 this.el.addClass('disabled');
3800 * <span> icon </span>
3801 * <span> text </span>
3802 * <span>badge </span>
3806 * @class Roo.bootstrap.NavSidebarItem
3807 * @extends Roo.bootstrap.NavItem
3808 * Bootstrap Navbar.NavSidebarItem class
3810 * Create a new Navbar Button
3811 * @param {Object} config The config object
3813 Roo.bootstrap.NavSidebarItem = function(config){
3814 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3819 * The raw click event for the entire grid.
3820 * @param {Roo.EventObject} e
3825 * Fires when the active item active state changes
3826 * @param {Roo.bootstrap.NavSidebarItem} this
3827 * @param {boolean} state the new state
3835 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3838 getAutoCreate : function(){
3843 href : this.href || '#',
3855 html : this.html || ''
3860 cfg.cls += ' active';
3864 if (this.glyphicon || this.icon) {
3865 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3866 a.cn.push({ tag : 'i', cls : c }) ;
3871 if (this.badge !== '') {
3872 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3876 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3877 a.cls += 'dropdown-toggle treeview' ;
3901 * @class Roo.bootstrap.Row
3902 * @extends Roo.bootstrap.Component
3903 * Bootstrap Row class (contains columns...)
3907 * @param {Object} config The config object
3910 Roo.bootstrap.Row = function(config){
3911 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3914 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3916 getAutoCreate : function(){
3935 * @class Roo.bootstrap.Element
3936 * @extends Roo.bootstrap.Component
3937 * Bootstrap Element class
3938 * @cfg {String} html contents of the element
3939 * @cfg {String} tag tag of the element
3940 * @cfg {String} cls class of the element
3943 * Create a new Element
3944 * @param {Object} config The config object
3947 Roo.bootstrap.Element = function(config){
3948 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3951 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3958 getAutoCreate : function(){
3983 * @class Roo.bootstrap.Pagination
3984 * @extends Roo.bootstrap.Component
3985 * Bootstrap Pagination class
3986 * @cfg {String} size xs | sm | md | lg
3987 * @cfg {Boolean} inverse false | true
3990 * Create a new Pagination
3991 * @param {Object} config The config object
3994 Roo.bootstrap.Pagination = function(config){
3995 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3998 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4004 getAutoCreate : function(){
4010 cfg.cls += ' inverse';
4016 cfg.cls += " " + this.cls;
4034 * @class Roo.bootstrap.PaginationItem
4035 * @extends Roo.bootstrap.Component
4036 * Bootstrap PaginationItem class
4037 * @cfg {String} html text
4038 * @cfg {String} href the link
4039 * @cfg {Boolean} preventDefault (true | false) default true
4040 * @cfg {Boolean} active (true | false) default false
4044 * Create a new PaginationItem
4045 * @param {Object} config The config object
4049 Roo.bootstrap.PaginationItem = function(config){
4050 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4055 * The raw click event for the entire grid.
4056 * @param {Roo.EventObject} e
4062 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4066 preventDefault: true,
4070 getAutoCreate : function(){
4076 href : this.href ? this.href : '#',
4077 html : this.html ? this.html : ''
4087 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4093 initEvents: function() {
4095 this.el.on('click', this.onClick, this);
4098 onClick : function(e)
4100 Roo.log('PaginationItem on click ');
4101 if(this.preventDefault){
4105 this.fireEvent('click', this, e);
4121 * @class Roo.bootstrap.Slider
4122 * @extends Roo.bootstrap.Component
4123 * Bootstrap Slider class
4126 * Create a new Slider
4127 * @param {Object} config The config object
4130 Roo.bootstrap.Slider = function(config){
4131 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4134 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4136 getAutoCreate : function(){
4140 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4144 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4156 * Ext JS Library 1.1.1
4157 * Copyright(c) 2006-2007, Ext JS, LLC.
4159 * Originally Released Under LGPL - original licence link has changed is not relivant.
4162 * <script type="text/javascript">
4167 * @class Roo.grid.ColumnModel
4168 * @extends Roo.util.Observable
4169 * This is the default implementation of a ColumnModel used by the Grid. It defines
4170 * the columns in the grid.
4173 var colModel = new Roo.grid.ColumnModel([
4174 {header: "Ticker", width: 60, sortable: true, locked: true},
4175 {header: "Company Name", width: 150, sortable: true},
4176 {header: "Market Cap.", width: 100, sortable: true},
4177 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4178 {header: "Employees", width: 100, sortable: true, resizable: false}
4183 * The config options listed for this class are options which may appear in each
4184 * individual column definition.
4185 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4187 * @param {Object} config An Array of column config objects. See this class's
4188 * config objects for details.
4190 Roo.grid.ColumnModel = function(config){
4192 * The config passed into the constructor
4194 this.config = config;
4197 // if no id, create one
4198 // if the column does not have a dataIndex mapping,
4199 // map it to the order it is in the config
4200 for(var i = 0, len = config.length; i < len; i++){
4202 if(typeof c.dataIndex == "undefined"){
4205 if(typeof c.renderer == "string"){
4206 c.renderer = Roo.util.Format[c.renderer];
4208 if(typeof c.id == "undefined"){
4211 if(c.editor && c.editor.xtype){
4212 c.editor = Roo.factory(c.editor, Roo.grid);
4214 if(c.editor && c.editor.isFormField){
4215 c.editor = new Roo.grid.GridEditor(c.editor);
4217 this.lookup[c.id] = c;
4221 * The width of columns which have no width specified (defaults to 100)
4224 this.defaultWidth = 100;
4227 * Default sortable of columns which have no sortable specified (defaults to false)
4230 this.defaultSortable = false;
4234 * @event widthchange
4235 * Fires when the width of a column changes.
4236 * @param {ColumnModel} this
4237 * @param {Number} columnIndex The column index
4238 * @param {Number} newWidth The new width
4240 "widthchange": true,
4242 * @event headerchange
4243 * Fires when the text of a header changes.
4244 * @param {ColumnModel} this
4245 * @param {Number} columnIndex The column index
4246 * @param {Number} newText The new header text
4248 "headerchange": true,
4250 * @event hiddenchange
4251 * Fires when a column is hidden or "unhidden".
4252 * @param {ColumnModel} this
4253 * @param {Number} columnIndex The column index
4254 * @param {Boolean} hidden true if hidden, false otherwise
4256 "hiddenchange": true,
4258 * @event columnmoved
4259 * Fires when a column is moved.
4260 * @param {ColumnModel} this
4261 * @param {Number} oldIndex
4262 * @param {Number} newIndex
4264 "columnmoved" : true,
4266 * @event columlockchange
4267 * Fires when a column's locked state is changed
4268 * @param {ColumnModel} this
4269 * @param {Number} colIndex
4270 * @param {Boolean} locked true if locked
4272 "columnlockchange" : true
4274 Roo.grid.ColumnModel.superclass.constructor.call(this);
4276 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4278 * @cfg {String} header The header text to display in the Grid view.
4281 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4282 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4283 * specified, the column's index is used as an index into the Record's data Array.
4286 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4287 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4290 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4291 * Defaults to the value of the {@link #defaultSortable} property.
4292 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4295 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4298 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4301 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4304 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4307 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4308 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4309 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4310 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4313 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4316 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4320 * Returns the id of the column at the specified index.
4321 * @param {Number} index The column index
4322 * @return {String} the id
4324 getColumnId : function(index){
4325 return this.config[index].id;
4329 * Returns the column for a specified id.
4330 * @param {String} id The column id
4331 * @return {Object} the column
4333 getColumnById : function(id){
4334 return this.lookup[id];
4339 * Returns the column for a specified dataIndex.
4340 * @param {String} dataIndex The column dataIndex
4341 * @return {Object|Boolean} the column or false if not found
4343 getColumnByDataIndex: function(dataIndex){
4344 var index = this.findColumnIndex(dataIndex);
4345 return index > -1 ? this.config[index] : false;
4349 * Returns the index for a specified column id.
4350 * @param {String} id The column id
4351 * @return {Number} the index, or -1 if not found
4353 getIndexById : function(id){
4354 for(var i = 0, len = this.config.length; i < len; i++){
4355 if(this.config[i].id == id){
4363 * Returns the index for a specified column dataIndex.
4364 * @param {String} dataIndex The column dataIndex
4365 * @return {Number} the index, or -1 if not found
4368 findColumnIndex : function(dataIndex){
4369 for(var i = 0, len = this.config.length; i < len; i++){
4370 if(this.config[i].dataIndex == dataIndex){
4378 moveColumn : function(oldIndex, newIndex){
4379 var c = this.config[oldIndex];
4380 this.config.splice(oldIndex, 1);
4381 this.config.splice(newIndex, 0, c);
4382 this.dataMap = null;
4383 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4386 isLocked : function(colIndex){
4387 return this.config[colIndex].locked === true;
4390 setLocked : function(colIndex, value, suppressEvent){
4391 if(this.isLocked(colIndex) == value){
4394 this.config[colIndex].locked = value;
4396 this.fireEvent("columnlockchange", this, colIndex, value);
4400 getTotalLockedWidth : function(){
4402 for(var i = 0; i < this.config.length; i++){
4403 if(this.isLocked(i) && !this.isHidden(i)){
4404 this.totalWidth += this.getColumnWidth(i);
4410 getLockedCount : function(){
4411 for(var i = 0, len = this.config.length; i < len; i++){
4412 if(!this.isLocked(i)){
4419 * Returns the number of columns.
4422 getColumnCount : function(visibleOnly){
4423 if(visibleOnly === true){
4425 for(var i = 0, len = this.config.length; i < len; i++){
4426 if(!this.isHidden(i)){
4432 return this.config.length;
4436 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4437 * @param {Function} fn
4438 * @param {Object} scope (optional)
4439 * @return {Array} result
4441 getColumnsBy : function(fn, scope){
4443 for(var i = 0, len = this.config.length; i < len; i++){
4444 var c = this.config[i];
4445 if(fn.call(scope||this, c, i) === true){
4453 * Returns true if the specified column is sortable.
4454 * @param {Number} col The column index
4457 isSortable : function(col){
4458 if(typeof this.config[col].sortable == "undefined"){
4459 return this.defaultSortable;
4461 return this.config[col].sortable;
4465 * Returns the rendering (formatting) function defined for the column.
4466 * @param {Number} col The column index.
4467 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4469 getRenderer : function(col){
4470 if(!this.config[col].renderer){
4471 return Roo.grid.ColumnModel.defaultRenderer;
4473 return this.config[col].renderer;
4477 * Sets the rendering (formatting) function for a column.
4478 * @param {Number} col The column index
4479 * @param {Function} fn The function to use to process the cell's raw data
4480 * to return HTML markup for the grid view. The render function is called with
4481 * the following parameters:<ul>
4482 * <li>Data value.</li>
4483 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4484 * <li>css A CSS style string to apply to the table cell.</li>
4485 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4486 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4487 * <li>Row index</li>
4488 * <li>Column index</li>
4489 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4491 setRenderer : function(col, fn){
4492 this.config[col].renderer = fn;
4496 * Returns the width for the specified column.
4497 * @param {Number} col The column index
4500 getColumnWidth : function(col){
4501 return this.config[col].width * 1 || this.defaultWidth;
4505 * Sets the width for a column.
4506 * @param {Number} col The column index
4507 * @param {Number} width The new width
4509 setColumnWidth : function(col, width, suppressEvent){
4510 this.config[col].width = width;
4511 this.totalWidth = null;
4513 this.fireEvent("widthchange", this, col, width);
4518 * Returns the total width of all columns.
4519 * @param {Boolean} includeHidden True to include hidden column widths
4522 getTotalWidth : function(includeHidden){
4523 if(!this.totalWidth){
4524 this.totalWidth = 0;
4525 for(var i = 0, len = this.config.length; i < len; i++){
4526 if(includeHidden || !this.isHidden(i)){
4527 this.totalWidth += this.getColumnWidth(i);
4531 return this.totalWidth;
4535 * Returns the header for the specified column.
4536 * @param {Number} col The column index
4539 getColumnHeader : function(col){
4540 return this.config[col].header;
4544 * Sets the header for a column.
4545 * @param {Number} col The column index
4546 * @param {String} header The new header
4548 setColumnHeader : function(col, header){
4549 this.config[col].header = header;
4550 this.fireEvent("headerchange", this, col, header);
4554 * Returns the tooltip for the specified column.
4555 * @param {Number} col The column index
4558 getColumnTooltip : function(col){
4559 return this.config[col].tooltip;
4562 * Sets the tooltip for a column.
4563 * @param {Number} col The column index
4564 * @param {String} tooltip The new tooltip
4566 setColumnTooltip : function(col, tooltip){
4567 this.config[col].tooltip = tooltip;
4571 * Returns the dataIndex for the specified column.
4572 * @param {Number} col The column index
4575 getDataIndex : function(col){
4576 return this.config[col].dataIndex;
4580 * Sets the dataIndex for a column.
4581 * @param {Number} col The column index
4582 * @param {Number} dataIndex The new dataIndex
4584 setDataIndex : function(col, dataIndex){
4585 this.config[col].dataIndex = dataIndex;
4591 * Returns true if the cell is editable.
4592 * @param {Number} colIndex The column index
4593 * @param {Number} rowIndex The row index
4596 isCellEditable : function(colIndex, rowIndex){
4597 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4601 * Returns the editor defined for the cell/column.
4602 * return false or null to disable editing.
4603 * @param {Number} colIndex The column index
4604 * @param {Number} rowIndex The row index
4607 getCellEditor : function(colIndex, rowIndex){
4608 return this.config[colIndex].editor;
4612 * Sets if a column is editable.
4613 * @param {Number} col The column index
4614 * @param {Boolean} editable True if the column is editable
4616 setEditable : function(col, editable){
4617 this.config[col].editable = editable;
4622 * Returns true if the column is hidden.
4623 * @param {Number} colIndex The column index
4626 isHidden : function(colIndex){
4627 return this.config[colIndex].hidden;
4632 * Returns true if the column width cannot be changed
4634 isFixed : function(colIndex){
4635 return this.config[colIndex].fixed;
4639 * Returns true if the column can be resized
4642 isResizable : function(colIndex){
4643 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4646 * Sets if a column is hidden.
4647 * @param {Number} colIndex The column index
4648 * @param {Boolean} hidden True if the column is hidden
4650 setHidden : function(colIndex, hidden){
4651 this.config[colIndex].hidden = hidden;
4652 this.totalWidth = null;
4653 this.fireEvent("hiddenchange", this, colIndex, hidden);
4657 * Sets the editor for a column.
4658 * @param {Number} col The column index
4659 * @param {Object} editor The editor object
4661 setEditor : function(col, editor){
4662 this.config[col].editor = editor;
4666 Roo.grid.ColumnModel.defaultRenderer = function(value){
4667 if(typeof value == "string" && value.length < 1){
4673 // Alias for backwards compatibility
4674 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4677 * Ext JS Library 1.1.1
4678 * Copyright(c) 2006-2007, Ext JS, LLC.
4680 * Originally Released Under LGPL - original licence link has changed is not relivant.
4683 * <script type="text/javascript">
4687 * @class Roo.LoadMask
4688 * A simple utility class for generically masking elements while loading data. If the element being masked has
4689 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4690 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4691 * element's UpdateManager load indicator and will be destroyed after the initial load.
4693 * Create a new LoadMask
4694 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4695 * @param {Object} config The config object
4697 Roo.LoadMask = function(el, config){
4698 this.el = Roo.get(el);
4699 Roo.apply(this, config);
4701 this.store.on('beforeload', this.onBeforeLoad, this);
4702 this.store.on('load', this.onLoad, this);
4703 this.store.on('loadexception', this.onLoadException, this);
4704 this.removeMask = false;
4706 var um = this.el.getUpdateManager();
4707 um.showLoadIndicator = false; // disable the default indicator
4708 um.on('beforeupdate', this.onBeforeLoad, this);
4709 um.on('update', this.onLoad, this);
4710 um.on('failure', this.onLoad, this);
4711 this.removeMask = true;
4715 Roo.LoadMask.prototype = {
4717 * @cfg {Boolean} removeMask
4718 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4719 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4723 * The text to display in a centered loading message box (defaults to 'Loading...')
4727 * @cfg {String} msgCls
4728 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4730 msgCls : 'x-mask-loading',
4733 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4739 * Disables the mask to prevent it from being displayed
4741 disable : function(){
4742 this.disabled = true;
4746 * Enables the mask so that it can be displayed
4748 enable : function(){
4749 this.disabled = false;
4752 onLoadException : function()
4756 if (typeof(arguments[3]) != 'undefined') {
4757 Roo.MessageBox.alert("Error loading",arguments[3]);
4761 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4762 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4771 this.el.unmask(this.removeMask);
4776 this.el.unmask(this.removeMask);
4780 onBeforeLoad : function(){
4782 this.el.mask(this.msg, this.msgCls);
4787 destroy : function(){
4789 this.store.un('beforeload', this.onBeforeLoad, this);
4790 this.store.un('load', this.onLoad, this);
4791 this.store.un('loadexception', this.onLoadException, this);
4793 var um = this.el.getUpdateManager();
4794 um.un('beforeupdate', this.onBeforeLoad, this);
4795 um.un('update', this.onLoad, this);
4796 um.un('failure', this.onLoad, this);
4807 * @class Roo.bootstrap.Table
4808 * @extends Roo.bootstrap.Component
4809 * Bootstrap Table class
4810 * @cfg {String} cls table class
4811 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4812 * @cfg {String} bgcolor Specifies the background color for a table
4813 * @cfg {Number} border Specifies whether the table cells should have borders or not
4814 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4815 * @cfg {Number} cellspacing Specifies the space between cells
4816 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4817 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4818 * @cfg {String} sortable Specifies that the table should be sortable
4819 * @cfg {String} summary Specifies a summary of the content of a table
4820 * @cfg {Number} width Specifies the width of a table
4821 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4823 * @cfg {boolean} striped Should the rows be alternative striped
4824 * @cfg {boolean} bordered Add borders to the table
4825 * @cfg {boolean} hover Add hover highlighting
4826 * @cfg {boolean} condensed Format condensed
4827 * @cfg {boolean} responsive Format condensed
4828 * @cfg {Boolean} loadMask (true|false) default false
4829 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4830 * @cfg {Boolean} thead (true|false) generate thead, default true
4831 * @cfg {Boolean} RowSelection (true|false) default false
4832 * @cfg {Boolean} CellSelection (true|false) default false
4834 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4838 * Create a new Table
4839 * @param {Object} config The config object
4842 Roo.bootstrap.Table = function(config){
4843 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4846 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4847 this.sm = this.selModel;
4848 this.sm.xmodule = this.xmodule || false;
4850 if (this.cm && typeof(this.cm.config) == 'undefined') {
4851 this.colModel = new Roo.grid.ColumnModel(this.cm);
4852 this.cm = this.colModel;
4853 this.cm.xmodule = this.xmodule || false;
4856 this.store= Roo.factory(this.store, Roo.data);
4857 this.ds = this.store;
4858 this.ds.xmodule = this.xmodule || false;
4861 if (this.footer && this.store) {
4862 this.footer.dataSource = this.ds;
4863 this.footer = Roo.factory(this.footer);
4870 * Fires when a cell is clicked
4871 * @param {Roo.bootstrap.Table} this
4872 * @param {Roo.Element} el
4873 * @param {Number} rowIndex
4874 * @param {Number} columnIndex
4875 * @param {Roo.EventObject} e
4879 * @event celldblclick
4880 * Fires when a cell is double clicked
4881 * @param {Roo.bootstrap.Table} this
4882 * @param {Roo.Element} el
4883 * @param {Number} rowIndex
4884 * @param {Number} columnIndex
4885 * @param {Roo.EventObject} e
4887 "celldblclick" : true,
4890 * Fires when a row is clicked
4891 * @param {Roo.bootstrap.Table} this
4892 * @param {Roo.Element} el
4893 * @param {Number} rowIndex
4894 * @param {Roo.EventObject} e
4898 * @event rowdblclick
4899 * Fires when a row is double clicked
4900 * @param {Roo.bootstrap.Table} this
4901 * @param {Roo.Element} el
4902 * @param {Number} rowIndex
4903 * @param {Roo.EventObject} e
4905 "rowdblclick" : true,
4908 * Fires when a mouseover occur
4909 * @param {Roo.bootstrap.Table} this
4910 * @param {Roo.Element} el
4911 * @param {Number} rowIndex
4912 * @param {Number} columnIndex
4913 * @param {Roo.EventObject} e
4918 * Fires when a mouseout occur
4919 * @param {Roo.bootstrap.Table} this
4920 * @param {Roo.Element} el
4921 * @param {Number} rowIndex
4922 * @param {Number} columnIndex
4923 * @param {Roo.EventObject} e
4928 * Fires when a row is rendered, so you can change add a style to it.
4929 * @param {Roo.bootstrap.Table} this
4930 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4937 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4961 RowSelection : false,
4962 CellSelection : false,
4965 // Roo.Element - the tbody
4968 getAutoCreate : function(){
4969 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4978 cfg.cls += ' table-striped';
4982 cfg.cls += ' table-hover';
4984 if (this.bordered) {
4985 cfg.cls += ' table-bordered';
4987 if (this.condensed) {
4988 cfg.cls += ' table-condensed';
4990 if (this.responsive) {
4991 cfg.cls += ' table-responsive';
4995 cfg.cls+= ' ' +this.cls;
4998 // this lot should be simplifed...
5001 cfg.align=this.align;
5004 cfg.bgcolor=this.bgcolor;
5007 cfg.border=this.border;
5009 if (this.cellpadding) {
5010 cfg.cellpadding=this.cellpadding;
5012 if (this.cellspacing) {
5013 cfg.cellspacing=this.cellspacing;
5016 cfg.frame=this.frame;
5019 cfg.rules=this.rules;
5021 if (this.sortable) {
5022 cfg.sortable=this.sortable;
5025 cfg.summary=this.summary;
5028 cfg.width=this.width;
5031 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5034 if(this.store || this.cm){
5036 cfg.cn.push(this.renderHeader());
5039 cfg.cn.push(this.renderBody());
5042 cfg.cn.push(this.renderFooter());
5045 cfg.cls+= ' TableGrid';
5048 return { cn : [ cfg ] };
5051 initEvents : function()
5053 if(!this.store || !this.cm){
5057 //Roo.log('initEvents with ds!!!!');
5059 this.mainBody = this.el.select('tbody', true).first();
5064 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5065 e.on('click', _this.sort, _this);
5068 this.el.on("click", this.onClick, this);
5069 this.el.on("dblclick", this.onDblClick, this);
5071 this.parent().el.setStyle('position', 'relative');
5073 this.footer.parentId = this.id;
5074 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5077 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5079 this.store.on('load', this.onLoad, this);
5080 this.store.on('beforeload', this.onBeforeLoad, this);
5081 this.store.on('update', this.onUpdate, this);
5085 onMouseover : function(e, el)
5087 var cell = Roo.get(el);
5093 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5094 cell = cell.findParent('td', false, true);
5097 var row = cell.findParent('tr', false, true);
5098 var cellIndex = cell.dom.cellIndex;
5099 var rowIndex = row.dom.rowIndex - 1; // start from 0
5101 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5105 onMouseout : function(e, el)
5107 var cell = Roo.get(el);
5113 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5114 cell = cell.findParent('td', false, true);
5117 var row = cell.findParent('tr', false, true);
5118 var cellIndex = cell.dom.cellIndex;
5119 var rowIndex = row.dom.rowIndex - 1; // start from 0
5121 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5125 onClick : function(e, el)
5127 var cell = Roo.get(el);
5129 if(!cell || (!this.CellSelection && !this.RowSelection)){
5134 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5135 cell = cell.findParent('td', false, true);
5138 var row = cell.findParent('tr', false, true);
5139 var cellIndex = cell.dom.cellIndex;
5140 var rowIndex = row.dom.rowIndex - 1;
5142 if(this.CellSelection){
5143 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5146 if(this.RowSelection){
5147 this.fireEvent('rowclick', this, row, rowIndex, e);
5153 onDblClick : function(e,el)
5155 var cell = Roo.get(el);
5157 if(!cell || (!this.CellSelection && !this.RowSelection)){
5161 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5162 cell = cell.findParent('td', false, true);
5165 var row = cell.findParent('tr', false, true);
5166 var cellIndex = cell.dom.cellIndex;
5167 var rowIndex = row.dom.rowIndex - 1;
5169 if(this.CellSelection){
5170 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5173 if(this.RowSelection){
5174 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5178 sort : function(e,el)
5180 var col = Roo.get(el)
5182 if(!col.hasClass('sortable')){
5186 var sort = col.attr('sort');
5189 if(col.hasClass('glyphicon-arrow-up')){
5193 this.store.sortInfo = {field : sort, direction : dir};
5196 Roo.log("calling footer first");
5197 this.footer.onClick('first');
5200 this.store.load({ params : { start : 0 } });
5204 renderHeader : function()
5213 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5215 var config = cm.config[i];
5220 html: cm.getColumnHeader(i)
5223 if(typeof(config.hidden) != 'undefined' && config.hidden){
5224 c.style += ' display:none;';
5227 if(typeof(config.dataIndex) != 'undefined'){
5228 c.sort = config.dataIndex;
5231 if(typeof(config.sortable) != 'undefined' && config.sortable){
5235 if(typeof(config.align) != 'undefined' && config.align.length){
5236 c.style += ' text-align:' + config.align + ';';
5239 if(typeof(config.width) != 'undefined'){
5240 c.style += ' width:' + config.width + 'px;';
5249 renderBody : function()
5259 colspan : this.cm.getColumnCount()
5269 renderFooter : function()
5279 colspan : this.cm.getColumnCount()
5293 Roo.log('ds onload');
5298 var ds = this.store;
5300 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5301 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5303 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5304 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5307 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5308 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5312 var tbody = this.mainBody;
5314 if(ds.getCount() > 0){
5315 ds.data.each(function(d,rowIndex){
5316 var row = this.renderRow(cm, ds, rowIndex);
5318 tbody.createChild(row);
5322 if(row.cellObjects.length){
5323 Roo.each(row.cellObjects, function(r){
5324 _this.renderCellObject(r);
5331 Roo.each(this.el.select('tbody td', true).elements, function(e){
5332 e.on('mouseover', _this.onMouseover, _this);
5335 Roo.each(this.el.select('tbody td', true).elements, function(e){
5336 e.on('mouseout', _this.onMouseout, _this);
5339 //if(this.loadMask){
5340 // this.maskEl.hide();
5345 onUpdate : function(ds,record)
5347 this.refreshRow(record);
5349 onRemove : function(ds, record, index, isUpdate){
5350 if(isUpdate !== true){
5351 this.fireEvent("beforerowremoved", this, index, record);
5353 var bt = this.mainBody.dom;
5355 bt.removeChild(bt.rows[index]);
5358 if(isUpdate !== true){
5359 //this.stripeRows(index);
5360 //this.syncRowHeights(index, index);
5362 this.fireEvent("rowremoved", this, index, record);
5367 refreshRow : function(record){
5368 var ds = this.store, index;
5369 if(typeof record == 'number'){
5371 record = ds.getAt(index);
5373 index = ds.indexOf(record);
5375 this.insertRow(ds, index, true);
5376 this.onRemove(ds, record, index+1, true);
5377 //this.syncRowHeights(index, index);
5379 this.fireEvent("rowupdated", this, index, record);
5382 insertRow : function(dm, rowIndex, isUpdate){
5385 this.fireEvent("beforerowsinserted", this, rowIndex);
5387 //var s = this.getScrollState();
5388 var row = this.renderRow(this.cm, this.store, rowIndex);
5389 // insert before rowIndex..
5390 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5394 if(row.cellObjects.length){
5395 Roo.each(row.cellObjects, function(r){
5396 _this.renderCellObject(r);
5401 this.fireEvent("rowsinserted", this, rowIndex);
5402 //this.syncRowHeights(firstRow, lastRow);
5403 //this.stripeRows(firstRow);
5410 getRowDom : function(rowIndex)
5412 // not sure if I need to check this.. but let's do it anyway..
5413 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5414 this.mainBody.dom.rows[rowIndex] : false
5416 // returns the object tree for a tr..
5419 renderRow : function(cm, ds, rowIndex) {
5421 var d = ds.getAt(rowIndex);
5428 var cellObjects = [];
5430 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5431 var config = cm.config[i];
5433 var renderer = cm.getRenderer(i);
5437 if(typeof(renderer) !== 'undefined'){
5438 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5440 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5441 // and are rendered into the cells after the row is rendered - using the id for the element.
5443 if(typeof(value) === 'object'){
5453 rowIndex : rowIndex,
5458 this.fireEvent('rowclass', this, rowcfg);
5462 cls : rowcfg.rowClass,
5464 html: (typeof(value) === 'object') ? '' : value
5471 if(typeof(config.hidden) != 'undefined' && config.hidden){
5472 td.style += ' display:none;';
5475 if(typeof(config.align) != 'undefined' && config.align.length){
5476 td.style += ' text-align:' + config.align + ';';
5479 if(typeof(config.width) != 'undefined'){
5480 td.style += ' width:' + config.width + 'px;';
5487 row.cellObjects = cellObjects;
5495 onBeforeLoad : function()
5497 //Roo.log('ds onBeforeLoad');
5501 //if(this.loadMask){
5502 // this.maskEl.show();
5508 this.el.select('tbody', true).first().dom.innerHTML = '';
5511 getSelectionModel : function(){
5513 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5515 return this.selModel;
5518 * Render the Roo.bootstrap object from renderder
5520 renderCellObject : function(r)
5524 var t = r.cfg.render(r.container);
5527 Roo.each(r.cfg.cn, function(c){
5529 container: t.getChildContainer(),
5532 _this.renderCellObject(child);
5549 * @class Roo.bootstrap.TableCell
5550 * @extends Roo.bootstrap.Component
5551 * Bootstrap TableCell class
5552 * @cfg {String} html cell contain text
5553 * @cfg {String} cls cell class
5554 * @cfg {String} tag cell tag (td|th) default td
5555 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5556 * @cfg {String} align Aligns the content in a cell
5557 * @cfg {String} axis Categorizes cells
5558 * @cfg {String} bgcolor Specifies the background color of a cell
5559 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5560 * @cfg {Number} colspan Specifies the number of columns a cell should span
5561 * @cfg {String} headers Specifies one or more header cells a cell is related to
5562 * @cfg {Number} height Sets the height of a cell
5563 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5564 * @cfg {Number} rowspan Sets the number of rows a cell should span
5565 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5566 * @cfg {String} valign Vertical aligns the content in a cell
5567 * @cfg {Number} width Specifies the width of a cell
5570 * Create a new TableCell
5571 * @param {Object} config The config object
5574 Roo.bootstrap.TableCell = function(config){
5575 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5578 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5598 getAutoCreate : function(){
5599 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5619 cfg.align=this.align
5625 cfg.bgcolor=this.bgcolor
5628 cfg.charoff=this.charoff
5631 cfg.colspan=this.colspan
5634 cfg.headers=this.headers
5637 cfg.height=this.height
5640 cfg.nowrap=this.nowrap
5643 cfg.rowspan=this.rowspan
5646 cfg.scope=this.scope
5649 cfg.valign=this.valign
5652 cfg.width=this.width
5671 * @class Roo.bootstrap.TableRow
5672 * @extends Roo.bootstrap.Component
5673 * Bootstrap TableRow class
5674 * @cfg {String} cls row class
5675 * @cfg {String} align Aligns the content in a table row
5676 * @cfg {String} bgcolor Specifies a background color for a table row
5677 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5678 * @cfg {String} valign Vertical aligns the content in a table row
5681 * Create a new TableRow
5682 * @param {Object} config The config object
5685 Roo.bootstrap.TableRow = function(config){
5686 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5689 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5697 getAutoCreate : function(){
5698 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5708 cfg.align = this.align;
5711 cfg.bgcolor = this.bgcolor;
5714 cfg.charoff = this.charoff;
5717 cfg.valign = this.valign;
5735 * @class Roo.bootstrap.TableBody
5736 * @extends Roo.bootstrap.Component
5737 * Bootstrap TableBody class
5738 * @cfg {String} cls element class
5739 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5740 * @cfg {String} align Aligns the content inside the element
5741 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5742 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5745 * Create a new TableBody
5746 * @param {Object} config The config object
5749 Roo.bootstrap.TableBody = function(config){
5750 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5753 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5761 getAutoCreate : function(){
5762 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5776 cfg.align = this.align;
5779 cfg.charoff = this.charoff;
5782 cfg.valign = this.valign;
5789 // initEvents : function()
5796 // this.store = Roo.factory(this.store, Roo.data);
5797 // this.store.on('load', this.onLoad, this);
5799 // this.store.load();
5803 // onLoad: function ()
5805 // this.fireEvent('load', this);
5815 * Ext JS Library 1.1.1
5816 * Copyright(c) 2006-2007, Ext JS, LLC.
5818 * Originally Released Under LGPL - original licence link has changed is not relivant.
5821 * <script type="text/javascript">
5824 // as we use this in bootstrap.
5825 Roo.namespace('Roo.form');
5827 * @class Roo.form.Action
5828 * Internal Class used to handle form actions
5830 * @param {Roo.form.BasicForm} el The form element or its id
5831 * @param {Object} config Configuration options
5836 // define the action interface
5837 Roo.form.Action = function(form, options){
5839 this.options = options || {};
5842 * Client Validation Failed
5845 Roo.form.Action.CLIENT_INVALID = 'client';
5847 * Server Validation Failed
5850 Roo.form.Action.SERVER_INVALID = 'server';
5852 * Connect to Server Failed
5855 Roo.form.Action.CONNECT_FAILURE = 'connect';
5857 * Reading Data from Server Failed
5860 Roo.form.Action.LOAD_FAILURE = 'load';
5862 Roo.form.Action.prototype = {
5864 failureType : undefined,
5865 response : undefined,
5869 run : function(options){
5874 success : function(response){
5879 handleResponse : function(response){
5883 // default connection failure
5884 failure : function(response){
5886 this.response = response;
5887 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5888 this.form.afterAction(this, false);
5891 processResponse : function(response){
5892 this.response = response;
5893 if(!response.responseText){
5896 this.result = this.handleResponse(response);
5900 // utility functions used internally
5901 getUrl : function(appendParams){
5902 var url = this.options.url || this.form.url || this.form.el.dom.action;
5904 var p = this.getParams();
5906 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5912 getMethod : function(){
5913 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5916 getParams : function(){
5917 var bp = this.form.baseParams;
5918 var p = this.options.params;
5920 if(typeof p == "object"){
5921 p = Roo.urlEncode(Roo.applyIf(p, bp));
5922 }else if(typeof p == 'string' && bp){
5923 p += '&' + Roo.urlEncode(bp);
5926 p = Roo.urlEncode(bp);
5931 createCallback : function(){
5933 success: this.success,
5934 failure: this.failure,
5936 timeout: (this.form.timeout*1000),
5937 upload: this.form.fileUpload ? this.success : undefined
5942 Roo.form.Action.Submit = function(form, options){
5943 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5946 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5949 haveProgress : false,
5950 uploadComplete : false,
5952 // uploadProgress indicator.
5953 uploadProgress : function()
5955 if (!this.form.progressUrl) {
5959 if (!this.haveProgress) {
5960 Roo.MessageBox.progress("Uploading", "Uploading");
5962 if (this.uploadComplete) {
5963 Roo.MessageBox.hide();
5967 this.haveProgress = true;
5969 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5971 var c = new Roo.data.Connection();
5973 url : this.form.progressUrl,
5978 success : function(req){
5979 //console.log(data);
5983 rdata = Roo.decode(req.responseText)
5985 Roo.log("Invalid data from server..");
5989 if (!rdata || !rdata.success) {
5991 Roo.MessageBox.alert(Roo.encode(rdata));
5994 var data = rdata.data;
5996 if (this.uploadComplete) {
5997 Roo.MessageBox.hide();
6002 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6003 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6006 this.uploadProgress.defer(2000,this);
6009 failure: function(data) {
6010 Roo.log('progress url failed ');
6021 // run get Values on the form, so it syncs any secondary forms.
6022 this.form.getValues();
6024 var o = this.options;
6025 var method = this.getMethod();
6026 var isPost = method == 'POST';
6027 if(o.clientValidation === false || this.form.isValid()){
6029 if (this.form.progressUrl) {
6030 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6031 (new Date() * 1) + '' + Math.random());
6036 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6037 form:this.form.el.dom,
6038 url:this.getUrl(!isPost),
6040 params:isPost ? this.getParams() : null,
6041 isUpload: this.form.fileUpload
6044 this.uploadProgress();
6046 }else if (o.clientValidation !== false){ // client validation failed
6047 this.failureType = Roo.form.Action.CLIENT_INVALID;
6048 this.form.afterAction(this, false);
6052 success : function(response)
6054 this.uploadComplete= true;
6055 if (this.haveProgress) {
6056 Roo.MessageBox.hide();
6060 var result = this.processResponse(response);
6061 if(result === true || result.success){
6062 this.form.afterAction(this, true);
6066 this.form.markInvalid(result.errors);
6067 this.failureType = Roo.form.Action.SERVER_INVALID;
6069 this.form.afterAction(this, false);
6071 failure : function(response)
6073 this.uploadComplete= true;
6074 if (this.haveProgress) {
6075 Roo.MessageBox.hide();
6078 this.response = response;
6079 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6080 this.form.afterAction(this, false);
6083 handleResponse : function(response){
6084 if(this.form.errorReader){
6085 var rs = this.form.errorReader.read(response);
6088 for(var i = 0, len = rs.records.length; i < len; i++) {
6089 var r = rs.records[i];
6093 if(errors.length < 1){
6097 success : rs.success,
6103 ret = Roo.decode(response.responseText);
6107 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6117 Roo.form.Action.Load = function(form, options){
6118 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6119 this.reader = this.form.reader;
6122 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6127 Roo.Ajax.request(Roo.apply(
6128 this.createCallback(), {
6129 method:this.getMethod(),
6130 url:this.getUrl(false),
6131 params:this.getParams()
6135 success : function(response){
6137 var result = this.processResponse(response);
6138 if(result === true || !result.success || !result.data){
6139 this.failureType = Roo.form.Action.LOAD_FAILURE;
6140 this.form.afterAction(this, false);
6143 this.form.clearInvalid();
6144 this.form.setValues(result.data);
6145 this.form.afterAction(this, true);
6148 handleResponse : function(response){
6149 if(this.form.reader){
6150 var rs = this.form.reader.read(response);
6151 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6153 success : rs.success,
6157 return Roo.decode(response.responseText);
6161 Roo.form.Action.ACTION_TYPES = {
6162 'load' : Roo.form.Action.Load,
6163 'submit' : Roo.form.Action.Submit
6172 * @class Roo.bootstrap.Form
6173 * @extends Roo.bootstrap.Component
6174 * Bootstrap Form class
6175 * @cfg {String} method GET | POST (default POST)
6176 * @cfg {String} labelAlign top | left (default top)
6177 * @cfg {String} align left | right - for navbars
6178 * @cfg {Boolean} loadMask load mask when submit (default true)
6183 * @param {Object} config The config object
6187 Roo.bootstrap.Form = function(config){
6188 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6191 * @event clientvalidation
6192 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6193 * @param {Form} this
6194 * @param {Boolean} valid true if the form has passed client-side validation
6196 clientvalidation: true,
6198 * @event beforeaction
6199 * Fires before any action is performed. Return false to cancel the action.
6200 * @param {Form} this
6201 * @param {Action} action The action to be performed
6205 * @event actionfailed
6206 * Fires when an action fails.
6207 * @param {Form} this
6208 * @param {Action} action The action that failed
6210 actionfailed : true,
6212 * @event actioncomplete
6213 * Fires when an action is completed.
6214 * @param {Form} this
6215 * @param {Action} action The action that completed
6217 actioncomplete : true
6222 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6225 * @cfg {String} method
6226 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6231 * The URL to use for form actions if one isn't supplied in the action options.
6234 * @cfg {Boolean} fileUpload
6235 * Set to true if this form is a file upload.
6239 * @cfg {Object} baseParams
6240 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6244 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6248 * @cfg {Sting} align (left|right) for navbar forms
6253 activeAction : null,
6256 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6257 * element by passing it or its id or mask the form itself by passing in true.
6260 waitMsgTarget : false,
6264 getAutoCreate : function(){
6268 method : this.method || 'POST',
6269 id : this.id || Roo.id(),
6272 if (this.parent().xtype.match(/^Nav/)) {
6273 cfg.cls = 'navbar-form navbar-' + this.align;
6277 if (this.labelAlign == 'left' ) {
6278 cfg.cls += ' form-horizontal';
6284 initEvents : function()
6286 this.el.on('submit', this.onSubmit, this);
6287 // this was added as random key presses on the form where triggering form submit.
6288 this.el.on('keypress', function(e) {
6289 if (e.getCharCode() != 13) {
6292 // we might need to allow it for textareas.. and some other items.
6293 // check e.getTarget().
6295 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6299 Roo.log("keypress blocked");
6307 onSubmit : function(e){
6312 * Returns true if client-side validation on the form is successful.
6315 isValid : function(){
6316 var items = this.getItems();
6318 items.each(function(f){
6327 * Returns true if any fields in this form have changed since their original load.
6330 isDirty : function(){
6332 var items = this.getItems();
6333 items.each(function(f){
6343 * Performs a predefined action (submit or load) or custom actions you define on this form.
6344 * @param {String} actionName The name of the action type
6345 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6346 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6347 * accept other config options):
6349 Property Type Description
6350 ---------------- --------------- ----------------------------------------------------------------------------------
6351 url String The url for the action (defaults to the form's url)
6352 method String The form method to use (defaults to the form's method, or POST if not defined)
6353 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6354 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6355 validate the form on the client (defaults to false)
6357 * @return {BasicForm} this
6359 doAction : function(action, options){
6360 if(typeof action == 'string'){
6361 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6363 if(this.fireEvent('beforeaction', this, action) !== false){
6364 this.beforeAction(action);
6365 action.run.defer(100, action);
6371 beforeAction : function(action){
6372 var o = action.options;
6375 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6377 // not really supported yet.. ??
6379 //if(this.waitMsgTarget === true){
6380 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6381 //}else if(this.waitMsgTarget){
6382 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6383 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6385 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6391 afterAction : function(action, success){
6392 this.activeAction = null;
6393 var o = action.options;
6395 //if(this.waitMsgTarget === true){
6397 //}else if(this.waitMsgTarget){
6398 // this.waitMsgTarget.unmask();
6400 // Roo.MessageBox.updateProgress(1);
6401 // Roo.MessageBox.hide();
6408 Roo.callback(o.success, o.scope, [this, action]);
6409 this.fireEvent('actioncomplete', this, action);
6413 // failure condition..
6414 // we have a scenario where updates need confirming.
6415 // eg. if a locking scenario exists..
6416 // we look for { errors : { needs_confirm : true }} in the response.
6418 (typeof(action.result) != 'undefined') &&
6419 (typeof(action.result.errors) != 'undefined') &&
6420 (typeof(action.result.errors.needs_confirm) != 'undefined')
6423 Roo.log("not supported yet");
6426 Roo.MessageBox.confirm(
6427 "Change requires confirmation",
6428 action.result.errorMsg,
6433 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6443 Roo.callback(o.failure, o.scope, [this, action]);
6444 // show an error message if no failed handler is set..
6445 if (!this.hasListener('actionfailed')) {
6446 Roo.log("need to add dialog support");
6448 Roo.MessageBox.alert("Error",
6449 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6450 action.result.errorMsg :
6451 "Saving Failed, please check your entries or try again"
6456 this.fireEvent('actionfailed', this, action);
6461 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6462 * @param {String} id The value to search for
6465 findField : function(id){
6466 var items = this.getItems();
6467 var field = items.get(id);
6469 items.each(function(f){
6470 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6477 return field || null;
6480 * Mark fields in this form invalid in bulk.
6481 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6482 * @return {BasicForm} this
6484 markInvalid : function(errors){
6485 if(errors instanceof Array){
6486 for(var i = 0, len = errors.length; i < len; i++){
6487 var fieldError = errors[i];
6488 var f = this.findField(fieldError.id);
6490 f.markInvalid(fieldError.msg);
6496 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6497 field.markInvalid(errors[id]);
6501 //Roo.each(this.childForms || [], function (f) {
6502 // f.markInvalid(errors);
6509 * Set values for fields in this form in bulk.
6510 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6511 * @return {BasicForm} this
6513 setValues : function(values){
6514 if(values instanceof Array){ // array of objects
6515 for(var i = 0, len = values.length; i < len; i++){
6517 var f = this.findField(v.id);
6519 f.setValue(v.value);
6520 if(this.trackResetOnLoad){
6521 f.originalValue = f.getValue();
6525 }else{ // object hash
6528 if(typeof values[id] != 'function' && (field = this.findField(id))){
6530 if (field.setFromData &&
6532 field.displayField &&
6533 // combos' with local stores can
6534 // be queried via setValue()
6535 // to set their value..
6536 (field.store && !field.store.isLocal)
6540 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6541 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6542 field.setFromData(sd);
6545 field.setValue(values[id]);
6549 if(this.trackResetOnLoad){
6550 field.originalValue = field.getValue();
6556 //Roo.each(this.childForms || [], function (f) {
6557 // f.setValues(values);
6564 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6565 * they are returned as an array.
6566 * @param {Boolean} asString
6569 getValues : function(asString){
6570 //if (this.childForms) {
6571 // copy values from the child forms
6572 // Roo.each(this.childForms, function (f) {
6573 // this.setValues(f.getValues());
6579 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6580 if(asString === true){
6583 return Roo.urlDecode(fs);
6587 * Returns the fields in this form as an object with key/value pairs.
6588 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6591 getFieldValues : function(with_hidden)
6593 var items = this.getItems();
6595 items.each(function(f){
6599 var v = f.getValue();
6600 if (f.inputType =='radio') {
6601 if (typeof(ret[f.getName()]) == 'undefined') {
6602 ret[f.getName()] = ''; // empty..
6605 if (!f.el.dom.checked) {
6613 // not sure if this supported any more..
6614 if ((typeof(v) == 'object') && f.getRawValue) {
6615 v = f.getRawValue() ; // dates..
6617 // combo boxes where name != hiddenName...
6618 if (f.name != f.getName()) {
6619 ret[f.name] = f.getRawValue();
6621 ret[f.getName()] = v;
6628 * Clears all invalid messages in this form.
6629 * @return {BasicForm} this
6631 clearInvalid : function(){
6632 var items = this.getItems();
6634 items.each(function(f){
6645 * @return {BasicForm} this
6648 var items = this.getItems();
6649 items.each(function(f){
6653 Roo.each(this.childForms || [], function (f) {
6660 getItems : function()
6662 var r=new Roo.util.MixedCollection(false, function(o){
6663 return o.id || (o.id = Roo.id());
6665 var iter = function(el) {
6672 Roo.each(el.items,function(e) {
6691 * Ext JS Library 1.1.1
6692 * Copyright(c) 2006-2007, Ext JS, LLC.
6694 * Originally Released Under LGPL - original licence link has changed is not relivant.
6697 * <script type="text/javascript">
6700 * @class Roo.form.VTypes
6701 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6704 Roo.form.VTypes = function(){
6705 // closure these in so they are only created once.
6706 var alpha = /^[a-zA-Z_]+$/;
6707 var alphanum = /^[a-zA-Z0-9_]+$/;
6708 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6709 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6711 // All these messages and functions are configurable
6714 * The function used to validate email addresses
6715 * @param {String} value The email address
6717 'email' : function(v){
6718 return email.test(v);
6721 * The error text to display when the email validation function returns false
6724 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6726 * The keystroke filter mask to be applied on email input
6729 'emailMask' : /[a-z0-9_\.\-@]/i,
6732 * The function used to validate URLs
6733 * @param {String} value The URL
6735 'url' : function(v){
6739 * The error text to display when the url validation function returns false
6742 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6745 * The function used to validate alpha values
6746 * @param {String} value The value
6748 'alpha' : function(v){
6749 return alpha.test(v);
6752 * The error text to display when the alpha validation function returns false
6755 'alphaText' : 'This field should only contain letters and _',
6757 * The keystroke filter mask to be applied on alpha input
6760 'alphaMask' : /[a-z_]/i,
6763 * The function used to validate alphanumeric values
6764 * @param {String} value The value
6766 'alphanum' : function(v){
6767 return alphanum.test(v);
6770 * The error text to display when the alphanumeric validation function returns false
6773 'alphanumText' : 'This field should only contain letters, numbers and _',
6775 * The keystroke filter mask to be applied on alphanumeric input
6778 'alphanumMask' : /[a-z0-9_]/i
6788 * @class Roo.bootstrap.Input
6789 * @extends Roo.bootstrap.Component
6790 * Bootstrap Input class
6791 * @cfg {Boolean} disabled is it disabled
6792 * @cfg {String} fieldLabel - the label associated
6793 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6794 * @cfg {String} name name of the input
6795 * @cfg {string} fieldLabel - the label associated
6796 * @cfg {string} inputType - input / file submit ...
6797 * @cfg {string} placeholder - placeholder to put in text.
6798 * @cfg {string} before - input group add on before
6799 * @cfg {string} after - input group add on after
6800 * @cfg {string} size - (lg|sm) or leave empty..
6801 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6802 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6803 * @cfg {Number} md colspan out of 12 for computer-sized screens
6804 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6805 * @cfg {string} value default value of the input
6806 * @cfg {Number} labelWidth set the width of label (0-12)
6807 * @cfg {String} labelAlign (top|left)
6808 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6809 * @cfg {String} align (left|center|right) Default left
6813 * Create a new Input
6814 * @param {Object} config The config object
6817 Roo.bootstrap.Input = function(config){
6818 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6823 * Fires when this field receives input focus.
6824 * @param {Roo.form.Field} this
6829 * Fires when this field loses input focus.
6830 * @param {Roo.form.Field} this
6835 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6836 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6837 * @param {Roo.form.Field} this
6838 * @param {Roo.EventObject} e The event object
6843 * Fires just before the field blurs if the field value has changed.
6844 * @param {Roo.form.Field} this
6845 * @param {Mixed} newValue The new value
6846 * @param {Mixed} oldValue The original value
6851 * Fires after the field has been marked as invalid.
6852 * @param {Roo.form.Field} this
6853 * @param {String} msg The validation message
6858 * Fires after the field has been validated with no errors.
6859 * @param {Roo.form.Field} this
6864 * Fires after the key up
6865 * @param {Roo.form.Field} this
6866 * @param {Roo.EventObject} e The event Object
6872 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6874 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6875 automatic validation (defaults to "keyup").
6877 validationEvent : "keyup",
6879 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6881 validateOnBlur : true,
6883 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6885 validationDelay : 250,
6887 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6889 focusClass : "x-form-focus", // not needed???
6893 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6895 invalidClass : "has-error",
6898 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6900 selectOnFocus : false,
6903 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6907 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6912 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6914 disableKeyFilter : false,
6917 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6921 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6925 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6927 blankText : "This field is required",
6930 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6934 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6936 maxLength : Number.MAX_VALUE,
6938 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6940 minLengthText : "The minimum length for this field is {0}",
6942 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6944 maxLengthText : "The maximum length for this field is {0}",
6948 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6949 * If available, this function will be called only after the basic validators all return true, and will be passed the
6950 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6954 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6955 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6956 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6960 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6983 formatedValue : false,
6985 parentLabelAlign : function()
6988 while (parent.parent()) {
6989 parent = parent.parent();
6990 if (typeof(parent.labelAlign) !='undefined') {
6991 return parent.labelAlign;
6998 getAutoCreate : function(){
7000 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7006 if(this.inputType != 'hidden'){
7007 cfg.cls = 'form-group' //input-group
7013 type : this.inputType,
7015 cls : 'form-control',
7016 placeholder : this.placeholder || ''
7021 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7024 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7025 input.maxLength = this.maxLength;
7028 if (this.disabled) {
7029 input.disabled=true;
7032 if (this.readOnly) {
7033 input.readonly=true;
7037 input.name = this.name;
7040 input.cls += ' input-' + this.size;
7043 ['xs','sm','md','lg'].map(function(size){
7044 if (settings[size]) {
7045 cfg.cls += ' col-' + size + '-' + settings[size];
7049 var inputblock = input;
7051 if (this.before || this.after) {
7054 cls : 'input-group',
7057 if (this.before && typeof(this.before) == 'string') {
7059 inputblock.cn.push({
7061 cls : 'roo-input-before input-group-addon',
7065 if (this.before && typeof(this.before) == 'object') {
7066 this.before = Roo.factory(this.before);
7067 Roo.log(this.before);
7068 inputblock.cn.push({
7070 cls : 'roo-input-before input-group-' +
7071 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7075 inputblock.cn.push(input);
7077 if (this.after && typeof(this.after) == 'string') {
7078 inputblock.cn.push({
7080 cls : 'roo-input-after input-group-addon',
7084 if (this.after && typeof(this.after) == 'object') {
7085 this.after = Roo.factory(this.after);
7086 Roo.log(this.after);
7087 inputblock.cn.push({
7089 cls : 'roo-input-after input-group-' +
7090 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7095 if (align ==='left' && this.fieldLabel.length) {
7096 Roo.log("left and has label");
7102 cls : 'control-label col-sm-' + this.labelWidth,
7103 html : this.fieldLabel
7107 cls : "col-sm-" + (12 - this.labelWidth),
7114 } else if ( this.fieldLabel.length) {
7120 //cls : 'input-group-addon',
7121 html : this.fieldLabel
7131 Roo.log(" no label && no align");
7140 Roo.log('input-parentType: ' + this.parentType);
7142 if (this.parentType === 'Navbar' && this.parent().bar) {
7143 cfg.cls += ' navbar-form';
7151 * return the real input element.
7153 inputEl: function ()
7155 return this.el.select('input.form-control',true).first();
7157 setDisabled : function(v)
7159 var i = this.inputEl().dom;
7161 i.removeAttribute('disabled');
7165 i.setAttribute('disabled','true');
7167 initEvents : function()
7170 this.inputEl().on("keydown" , this.fireKey, this);
7171 this.inputEl().on("focus", this.onFocus, this);
7172 this.inputEl().on("blur", this.onBlur, this);
7174 this.inputEl().relayEvent('keyup', this);
7176 // reference to original value for reset
7177 this.originalValue = this.getValue();
7178 //Roo.form.TextField.superclass.initEvents.call(this);
7179 if(this.validationEvent == 'keyup'){
7180 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7181 this.inputEl().on('keyup', this.filterValidation, this);
7183 else if(this.validationEvent !== false){
7184 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7187 if(this.selectOnFocus){
7188 this.on("focus", this.preFocus, this);
7191 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7192 this.inputEl().on("keypress", this.filterKeys, this);
7195 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7196 this.el.on("click", this.autoSize, this);
7199 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7200 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7203 if (typeof(this.before) == 'object') {
7204 this.before.render(this.el.select('.roo-input-before',true).first());
7206 if (typeof(this.after) == 'object') {
7207 this.after.render(this.el.select('.roo-input-after',true).first());
7212 filterValidation : function(e){
7213 if(!e.isNavKeyPress()){
7214 this.validationTask.delay(this.validationDelay);
7218 * Validates the field value
7219 * @return {Boolean} True if the value is valid, else false
7221 validate : function(){
7222 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7223 if(this.disabled || this.validateValue(this.getRawValue())){
7224 this.clearInvalid();
7232 * Validates a value according to the field's validation rules and marks the field as invalid
7233 * if the validation fails
7234 * @param {Mixed} value The value to validate
7235 * @return {Boolean} True if the value is valid, else false
7237 validateValue : function(value){
7238 if(value.length < 1) { // if it's blank
7239 if(this.allowBlank){
7240 this.clearInvalid();
7243 this.markInvalid(this.blankText);
7247 if(value.length < this.minLength){
7248 this.markInvalid(String.format(this.minLengthText, this.minLength));
7251 if(value.length > this.maxLength){
7252 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7256 var vt = Roo.form.VTypes;
7257 if(!vt[this.vtype](value, this)){
7258 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7262 if(typeof this.validator == "function"){
7263 var msg = this.validator(value);
7265 this.markInvalid(msg);
7269 if(this.regex && !this.regex.test(value)){
7270 this.markInvalid(this.regexText);
7279 fireKey : function(e){
7280 //Roo.log('field ' + e.getKey());
7281 if(e.isNavKeyPress()){
7282 this.fireEvent("specialkey", this, e);
7285 focus : function (selectText){
7287 this.inputEl().focus();
7288 if(selectText === true){
7289 this.inputEl().dom.select();
7295 onFocus : function(){
7296 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7297 // this.el.addClass(this.focusClass);
7300 this.hasFocus = true;
7301 this.startValue = this.getValue();
7302 this.fireEvent("focus", this);
7306 beforeBlur : Roo.emptyFn,
7310 onBlur : function(){
7312 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7313 //this.el.removeClass(this.focusClass);
7315 this.hasFocus = false;
7316 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7319 var v = this.getValue();
7320 if(String(v) !== String(this.startValue)){
7321 this.fireEvent('change', this, v, this.startValue);
7323 this.fireEvent("blur", this);
7327 * Resets the current field value to the originally loaded value and clears any validation messages
7330 this.setValue(this.originalValue);
7331 this.clearInvalid();
7334 * Returns the name of the field
7335 * @return {Mixed} name The name field
7337 getName: function(){
7341 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7342 * @return {Mixed} value The field value
7344 getValue : function(){
7346 var v = this.inputEl().getValue();
7351 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7352 * @return {Mixed} value The field value
7354 getRawValue : function(){
7355 var v = this.inputEl().getValue();
7361 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7362 * @param {Mixed} value The value to set
7364 setRawValue : function(v){
7365 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7368 selectText : function(start, end){
7369 var v = this.getRawValue();
7371 start = start === undefined ? 0 : start;
7372 end = end === undefined ? v.length : end;
7373 var d = this.inputEl().dom;
7374 if(d.setSelectionRange){
7375 d.setSelectionRange(start, end);
7376 }else if(d.createTextRange){
7377 var range = d.createTextRange();
7378 range.moveStart("character", start);
7379 range.moveEnd("character", v.length-end);
7386 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7387 * @param {Mixed} value The value to set
7389 setValue : function(v){
7392 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7398 processValue : function(value){
7399 if(this.stripCharsRe){
7400 var newValue = value.replace(this.stripCharsRe, '');
7401 if(newValue !== value){
7402 this.setRawValue(newValue);
7409 preFocus : function(){
7411 if(this.selectOnFocus){
7412 this.inputEl().dom.select();
7415 filterKeys : function(e){
7417 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7420 var c = e.getCharCode(), cc = String.fromCharCode(c);
7421 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7424 if(!this.maskRe.test(cc)){
7429 * Clear any invalid styles/messages for this field
7431 clearInvalid : function(){
7433 if(!this.el || this.preventMark){ // not rendered
7436 this.el.removeClass(this.invalidClass);
7438 switch(this.msgTarget){
7440 this.el.dom.qtip = '';
7443 this.el.dom.title = '';
7447 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7452 this.errorIcon.dom.qtip = '';
7453 this.errorIcon.hide();
7454 this.un('resize', this.alignErrorIcon, this);
7458 var t = Roo.getDom(this.msgTarget);
7460 t.style.display = 'none';
7464 this.fireEvent('valid', this);
7467 * Mark this field as invalid
7468 * @param {String} msg The validation message
7470 markInvalid : function(msg){
7471 if(!this.el || this.preventMark){ // not rendered
7474 this.el.addClass(this.invalidClass);
7476 msg = msg || this.invalidText;
7477 switch(this.msgTarget){
7479 this.el.dom.qtip = msg;
7480 this.el.dom.qclass = 'x-form-invalid-tip';
7481 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7482 Roo.QuickTips.enable();
7486 this.el.dom.title = msg;
7490 var elp = this.el.findParent('.x-form-element', 5, true);
7491 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7492 this.errorEl.setWidth(elp.getWidth(true)-20);
7494 this.errorEl.update(msg);
7495 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7498 if(!this.errorIcon){
7499 var elp = this.el.findParent('.x-form-element', 5, true);
7500 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7502 this.alignErrorIcon();
7503 this.errorIcon.dom.qtip = msg;
7504 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7505 this.errorIcon.show();
7506 this.on('resize', this.alignErrorIcon, this);
7509 var t = Roo.getDom(this.msgTarget);
7511 t.style.display = this.msgDisplay;
7515 this.fireEvent('invalid', this, msg);
7518 SafariOnKeyDown : function(event)
7520 // this is a workaround for a password hang bug on chrome/ webkit.
7522 var isSelectAll = false;
7524 if(this.inputEl().dom.selectionEnd > 0){
7525 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7527 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7528 event.preventDefault();
7533 if(isSelectAll){ // backspace and delete key
7535 event.preventDefault();
7536 // this is very hacky as keydown always get's upper case.
7538 var cc = String.fromCharCode(event.getCharCode());
7539 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7543 adjustWidth : function(tag, w){
7544 tag = tag.toLowerCase();
7545 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7546 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7550 if(tag == 'textarea'){
7553 }else if(Roo.isOpera){
7557 if(tag == 'textarea'){
7576 * @class Roo.bootstrap.TextArea
7577 * @extends Roo.bootstrap.Input
7578 * Bootstrap TextArea class
7579 * @cfg {Number} cols Specifies the visible width of a text area
7580 * @cfg {Number} rows Specifies the visible number of lines in a text area
7581 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7582 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7583 * @cfg {string} html text
7586 * Create a new TextArea
7587 * @param {Object} config The config object
7590 Roo.bootstrap.TextArea = function(config){
7591 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7595 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7605 getAutoCreate : function(){
7607 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7618 value : this.value || '',
7619 html: this.html || '',
7620 cls : 'form-control',
7621 placeholder : this.placeholder || ''
7625 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7626 input.maxLength = this.maxLength;
7630 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7634 input.cols = this.cols;
7637 if (this.readOnly) {
7638 input.readonly = true;
7642 input.name = this.name;
7646 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7650 ['xs','sm','md','lg'].map(function(size){
7651 if (settings[size]) {
7652 cfg.cls += ' col-' + size + '-' + settings[size];
7656 var inputblock = input;
7658 if (this.before || this.after) {
7661 cls : 'input-group',
7665 inputblock.cn.push({
7667 cls : 'input-group-addon',
7671 inputblock.cn.push(input);
7673 inputblock.cn.push({
7675 cls : 'input-group-addon',
7682 if (align ==='left' && this.fieldLabel.length) {
7683 Roo.log("left and has label");
7689 cls : 'control-label col-sm-' + this.labelWidth,
7690 html : this.fieldLabel
7694 cls : "col-sm-" + (12 - this.labelWidth),
7701 } else if ( this.fieldLabel.length) {
7707 //cls : 'input-group-addon',
7708 html : this.fieldLabel
7718 Roo.log(" no label && no align");
7728 if (this.disabled) {
7729 input.disabled=true;
7736 * return the real textarea element.
7738 inputEl: function ()
7740 return this.el.select('textarea.form-control',true).first();
7748 * trigger field - base class for combo..
7753 * @class Roo.bootstrap.TriggerField
7754 * @extends Roo.bootstrap.Input
7755 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7756 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7757 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7758 * for which you can provide a custom implementation. For example:
7760 var trigger = new Roo.bootstrap.TriggerField();
7761 trigger.onTriggerClick = myTriggerFn;
7762 trigger.applyTo('my-field');
7765 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7766 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7767 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7768 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7770 * Create a new TriggerField.
7771 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7772 * to the base TextField)
7774 Roo.bootstrap.TriggerField = function(config){
7775 this.mimicing = false;
7776 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7779 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7781 * @cfg {String} triggerClass A CSS class to apply to the trigger
7784 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7788 /** @cfg {Boolean} grow @hide */
7789 /** @cfg {Number} growMin @hide */
7790 /** @cfg {Number} growMax @hide */
7796 autoSize: Roo.emptyFn,
7803 actionMode : 'wrap',
7807 getAutoCreate : function(){
7809 var align = this.labelAlign || this.parentLabelAlign();
7814 cls: 'form-group' //input-group
7821 type : this.inputType,
7822 cls : 'form-control',
7823 autocomplete: 'off',
7824 placeholder : this.placeholder || ''
7828 input.name = this.name;
7831 input.cls += ' input-' + this.size;
7834 if (this.disabled) {
7835 input.disabled=true;
7838 var inputblock = input;
7840 if (this.before || this.after) {
7843 cls : 'input-group',
7847 inputblock.cn.push({
7849 cls : 'input-group-addon',
7853 inputblock.cn.push(input);
7855 inputblock.cn.push({
7857 cls : 'input-group-addon',
7870 cls: 'form-hidden-field'
7878 Roo.log('multiple');
7886 cls: 'form-hidden-field'
7890 cls: 'select2-choices',
7894 cls: 'select2-search-field',
7907 cls: 'select2-container input-group',
7912 // cls: 'typeahead typeahead-long dropdown-menu',
7913 // style: 'display:none'
7918 if(!this.multiple && this.showToggleBtn){
7921 cls : 'input-group-addon btn dropdown-toggle',
7929 cls: 'combobox-clear',
7943 combobox.cls += ' select2-container-multi';
7946 if (align ==='left' && this.fieldLabel.length) {
7948 Roo.log("left and has label");
7954 cls : 'control-label col-sm-' + this.labelWidth,
7955 html : this.fieldLabel
7959 cls : "col-sm-" + (12 - this.labelWidth),
7966 } else if ( this.fieldLabel.length) {
7972 //cls : 'input-group-addon',
7973 html : this.fieldLabel
7983 Roo.log(" no label && no align");
7990 ['xs','sm','md','lg'].map(function(size){
7991 if (settings[size]) {
7992 cfg.cls += ' col-' + size + '-' + settings[size];
8003 onResize : function(w, h){
8004 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8005 // if(typeof w == 'number'){
8006 // var x = w - this.trigger.getWidth();
8007 // this.inputEl().setWidth(this.adjustWidth('input', x));
8008 // this.trigger.setStyle('left', x+'px');
8013 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8016 getResizeEl : function(){
8017 return this.inputEl();
8021 getPositionEl : function(){
8022 return this.inputEl();
8026 alignErrorIcon : function(){
8027 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8031 initEvents : function(){
8035 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8036 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8037 if(!this.multiple && this.showToggleBtn){
8038 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8039 if(this.hideTrigger){
8040 this.trigger.setDisplayed(false);
8042 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8046 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8049 //this.trigger.addClassOnOver('x-form-trigger-over');
8050 //this.trigger.addClassOnClick('x-form-trigger-click');
8053 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8057 createList : function()
8059 this.list = Roo.get(document.body).createChild({
8061 cls: 'typeahead typeahead-long dropdown-menu',
8062 style: 'display:none'
8065 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8070 initTrigger : function(){
8075 onDestroy : function(){
8077 this.trigger.removeAllListeners();
8078 // this.trigger.remove();
8081 // this.wrap.remove();
8083 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8087 onFocus : function(){
8088 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8091 this.wrap.addClass('x-trigger-wrap-focus');
8092 this.mimicing = true;
8093 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8094 if(this.monitorTab){
8095 this.el.on("keydown", this.checkTab, this);
8102 checkTab : function(e){
8103 if(e.getKey() == e.TAB){
8109 onBlur : function(){
8114 mimicBlur : function(e, t){
8116 if(!this.wrap.contains(t) && this.validateBlur()){
8123 triggerBlur : function(){
8124 this.mimicing = false;
8125 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8126 if(this.monitorTab){
8127 this.el.un("keydown", this.checkTab, this);
8129 //this.wrap.removeClass('x-trigger-wrap-focus');
8130 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8134 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8135 validateBlur : function(e, t){
8140 onDisable : function(){
8141 this.inputEl().dom.disabled = true;
8142 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8144 // this.wrap.addClass('x-item-disabled');
8149 onEnable : function(){
8150 this.inputEl().dom.disabled = false;
8151 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8153 // this.el.removeClass('x-item-disabled');
8158 onShow : function(){
8159 var ae = this.getActionEl();
8162 ae.dom.style.display = '';
8163 ae.dom.style.visibility = 'visible';
8169 onHide : function(){
8170 var ae = this.getActionEl();
8171 ae.dom.style.display = 'none';
8175 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8176 * by an implementing function.
8178 * @param {EventObject} e
8180 onTriggerClick : Roo.emptyFn
8184 * Ext JS Library 1.1.1
8185 * Copyright(c) 2006-2007, Ext JS, LLC.
8187 * Originally Released Under LGPL - original licence link has changed is not relivant.
8190 * <script type="text/javascript">
8195 * @class Roo.data.SortTypes
8197 * Defines the default sorting (casting?) comparison functions used when sorting data.
8199 Roo.data.SortTypes = {
8201 * Default sort that does nothing
8202 * @param {Mixed} s The value being converted
8203 * @return {Mixed} The comparison value
8210 * The regular expression used to strip tags
8214 stripTagsRE : /<\/?[^>]+>/gi,
8217 * Strips all HTML tags to sort on text only
8218 * @param {Mixed} s The value being converted
8219 * @return {String} The comparison value
8221 asText : function(s){
8222 return String(s).replace(this.stripTagsRE, "");
8226 * Strips all HTML tags to sort on text only - Case insensitive
8227 * @param {Mixed} s The value being converted
8228 * @return {String} The comparison value
8230 asUCText : function(s){
8231 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8235 * Case insensitive string
8236 * @param {Mixed} s The value being converted
8237 * @return {String} The comparison value
8239 asUCString : function(s) {
8240 return String(s).toUpperCase();
8245 * @param {Mixed} s The value being converted
8246 * @return {Number} The comparison value
8248 asDate : function(s) {
8252 if(s instanceof Date){
8255 return Date.parse(String(s));
8260 * @param {Mixed} s The value being converted
8261 * @return {Float} The comparison value
8263 asFloat : function(s) {
8264 var val = parseFloat(String(s).replace(/,/g, ""));
8265 if(isNaN(val)) val = 0;
8271 * @param {Mixed} s The value being converted
8272 * @return {Number} The comparison value
8274 asInt : function(s) {
8275 var val = parseInt(String(s).replace(/,/g, ""));
8276 if(isNaN(val)) val = 0;
8281 * Ext JS Library 1.1.1
8282 * Copyright(c) 2006-2007, Ext JS, LLC.
8284 * Originally Released Under LGPL - original licence link has changed is not relivant.
8287 * <script type="text/javascript">
8291 * @class Roo.data.Record
8292 * Instances of this class encapsulate both record <em>definition</em> information, and record
8293 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8294 * to access Records cached in an {@link Roo.data.Store} object.<br>
8296 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8297 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8300 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8302 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8303 * {@link #create}. The parameters are the same.
8304 * @param {Array} data An associative Array of data values keyed by the field name.
8305 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8306 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8307 * not specified an integer id is generated.
8309 Roo.data.Record = function(data, id){
8310 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8315 * Generate a constructor for a specific record layout.
8316 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8317 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8318 * Each field definition object may contain the following properties: <ul>
8319 * <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,
8320 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8321 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8322 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8323 * is being used, then this is a string containing the javascript expression to reference the data relative to
8324 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8325 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8326 * this may be omitted.</p></li>
8327 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8328 * <ul><li>auto (Default, implies no conversion)</li>
8333 * <li>date</li></ul></p></li>
8334 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8335 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8336 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8337 * by the Reader into an object that will be stored in the Record. It is passed the
8338 * following parameters:<ul>
8339 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8341 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8343 * <br>usage:<br><pre><code>
8344 var TopicRecord = Roo.data.Record.create(
8345 {name: 'title', mapping: 'topic_title'},
8346 {name: 'author', mapping: 'username'},
8347 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8348 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8349 {name: 'lastPoster', mapping: 'user2'},
8350 {name: 'excerpt', mapping: 'post_text'}
8353 var myNewRecord = new TopicRecord({
8354 title: 'Do my job please',
8357 lastPost: new Date(),
8358 lastPoster: 'Animal',
8359 excerpt: 'No way dude!'
8361 myStore.add(myNewRecord);
8366 Roo.data.Record.create = function(o){
8368 f.superclass.constructor.apply(this, arguments);
8370 Roo.extend(f, Roo.data.Record);
8371 var p = f.prototype;
8372 p.fields = new Roo.util.MixedCollection(false, function(field){
8375 for(var i = 0, len = o.length; i < len; i++){
8376 p.fields.add(new Roo.data.Field(o[i]));
8378 f.getField = function(name){
8379 return p.fields.get(name);
8384 Roo.data.Record.AUTO_ID = 1000;
8385 Roo.data.Record.EDIT = 'edit';
8386 Roo.data.Record.REJECT = 'reject';
8387 Roo.data.Record.COMMIT = 'commit';
8389 Roo.data.Record.prototype = {
8391 * Readonly flag - true if this record has been modified.
8400 join : function(store){
8405 * Set the named field to the specified value.
8406 * @param {String} name The name of the field to set.
8407 * @param {Object} value The value to set the field to.
8409 set : function(name, value){
8410 if(this.data[name] == value){
8417 if(typeof this.modified[name] == 'undefined'){
8418 this.modified[name] = this.data[name];
8420 this.data[name] = value;
8421 if(!this.editing && this.store){
8422 this.store.afterEdit(this);
8427 * Get the value of the named field.
8428 * @param {String} name The name of the field to get the value of.
8429 * @return {Object} The value of the field.
8431 get : function(name){
8432 return this.data[name];
8436 beginEdit : function(){
8437 this.editing = true;
8442 cancelEdit : function(){
8443 this.editing = false;
8444 delete this.modified;
8448 endEdit : function(){
8449 this.editing = false;
8450 if(this.dirty && this.store){
8451 this.store.afterEdit(this);
8456 * Usually called by the {@link Roo.data.Store} which owns the Record.
8457 * Rejects all changes made to the Record since either creation, or the last commit operation.
8458 * Modified fields are reverted to their original values.
8460 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8461 * of reject operations.
8463 reject : function(){
8464 var m = this.modified;
8466 if(typeof m[n] != "function"){
8467 this.data[n] = m[n];
8471 delete this.modified;
8472 this.editing = false;
8474 this.store.afterReject(this);
8479 * Usually called by the {@link Roo.data.Store} which owns the Record.
8480 * Commits all changes made to the Record since either creation, or the last commit operation.
8482 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8483 * of commit operations.
8485 commit : function(){
8487 delete this.modified;
8488 this.editing = false;
8490 this.store.afterCommit(this);
8495 hasError : function(){
8496 return this.error != null;
8500 clearError : function(){
8505 * Creates a copy of this record.
8506 * @param {String} id (optional) A new record id if you don't want to use this record's id
8509 copy : function(newId) {
8510 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8514 * Ext JS Library 1.1.1
8515 * Copyright(c) 2006-2007, Ext JS, LLC.
8517 * Originally Released Under LGPL - original licence link has changed is not relivant.
8520 * <script type="text/javascript">
8526 * @class Roo.data.Store
8527 * @extends Roo.util.Observable
8528 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8529 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8531 * 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
8532 * has no knowledge of the format of the data returned by the Proxy.<br>
8534 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8535 * instances from the data object. These records are cached and made available through accessor functions.
8537 * Creates a new Store.
8538 * @param {Object} config A config object containing the objects needed for the Store to access data,
8539 * and read the data into Records.
8541 Roo.data.Store = function(config){
8542 this.data = new Roo.util.MixedCollection(false);
8543 this.data.getKey = function(o){
8546 this.baseParams = {};
8553 "multisort" : "_multisort"
8556 if(config && config.data){
8557 this.inlineData = config.data;
8561 Roo.apply(this, config);
8563 if(this.reader){ // reader passed
8564 this.reader = Roo.factory(this.reader, Roo.data);
8565 this.reader.xmodule = this.xmodule || false;
8566 if(!this.recordType){
8567 this.recordType = this.reader.recordType;
8569 if(this.reader.onMetaChange){
8570 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8574 if(this.recordType){
8575 this.fields = this.recordType.prototype.fields;
8581 * @event datachanged
8582 * Fires when the data cache has changed, and a widget which is using this Store
8583 * as a Record cache should refresh its view.
8584 * @param {Store} this
8589 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8590 * @param {Store} this
8591 * @param {Object} meta The JSON metadata
8596 * Fires when Records have been added to the Store
8597 * @param {Store} this
8598 * @param {Roo.data.Record[]} records The array of Records added
8599 * @param {Number} index The index at which the record(s) were added
8604 * Fires when a Record has been removed from the Store
8605 * @param {Store} this
8606 * @param {Roo.data.Record} record The Record that was removed
8607 * @param {Number} index The index at which the record was removed
8612 * Fires when a Record has been updated
8613 * @param {Store} this
8614 * @param {Roo.data.Record} record The Record that was updated
8615 * @param {String} operation The update operation being performed. Value may be one of:
8617 Roo.data.Record.EDIT
8618 Roo.data.Record.REJECT
8619 Roo.data.Record.COMMIT
8625 * Fires when the data cache has been cleared.
8626 * @param {Store} this
8631 * Fires before a request is made for a new data object. If the beforeload handler returns false
8632 * the load action will be canceled.
8633 * @param {Store} this
8634 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8638 * @event beforeloadadd
8639 * Fires after a new set of Records has been loaded.
8640 * @param {Store} this
8641 * @param {Roo.data.Record[]} records The Records that were loaded
8642 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8644 beforeloadadd : true,
8647 * Fires after a new set of Records has been loaded, before they are added to the store.
8648 * @param {Store} this
8649 * @param {Roo.data.Record[]} records The Records that were loaded
8650 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8651 * @params {Object} return from reader
8655 * @event loadexception
8656 * Fires if an exception occurs in the Proxy during loading.
8657 * Called with the signature of the Proxy's "loadexception" event.
8658 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8661 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8662 * @param {Object} load options
8663 * @param {Object} jsonData from your request (normally this contains the Exception)
8665 loadexception : true
8669 this.proxy = Roo.factory(this.proxy, Roo.data);
8670 this.proxy.xmodule = this.xmodule || false;
8671 this.relayEvents(this.proxy, ["loadexception"]);
8673 this.sortToggle = {};
8674 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8676 Roo.data.Store.superclass.constructor.call(this);
8678 if(this.inlineData){
8679 this.loadData(this.inlineData);
8680 delete this.inlineData;
8684 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8686 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8687 * without a remote query - used by combo/forms at present.
8691 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8694 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8697 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8698 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8701 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8702 * on any HTTP request
8705 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8708 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8712 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8713 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8718 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8719 * loaded or when a record is removed. (defaults to false).
8721 pruneModifiedRecords : false,
8727 * Add Records to the Store and fires the add event.
8728 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8730 add : function(records){
8731 records = [].concat(records);
8732 for(var i = 0, len = records.length; i < len; i++){
8733 records[i].join(this);
8735 var index = this.data.length;
8736 this.data.addAll(records);
8737 this.fireEvent("add", this, records, index);
8741 * Remove a Record from the Store and fires the remove event.
8742 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8744 remove : function(record){
8745 var index = this.data.indexOf(record);
8746 this.data.removeAt(index);
8747 if(this.pruneModifiedRecords){
8748 this.modified.remove(record);
8750 this.fireEvent("remove", this, record, index);
8754 * Remove all Records from the Store and fires the clear event.
8756 removeAll : function(){
8758 if(this.pruneModifiedRecords){
8761 this.fireEvent("clear", this);
8765 * Inserts Records to the Store at the given index and fires the add event.
8766 * @param {Number} index The start index at which to insert the passed Records.
8767 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8769 insert : function(index, records){
8770 records = [].concat(records);
8771 for(var i = 0, len = records.length; i < len; i++){
8772 this.data.insert(index, records[i]);
8773 records[i].join(this);
8775 this.fireEvent("add", this, records, index);
8779 * Get the index within the cache of the passed Record.
8780 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8781 * @return {Number} The index of the passed Record. Returns -1 if not found.
8783 indexOf : function(record){
8784 return this.data.indexOf(record);
8788 * Get the index within the cache of the Record with the passed id.
8789 * @param {String} id The id of the Record to find.
8790 * @return {Number} The index of the Record. Returns -1 if not found.
8792 indexOfId : function(id){
8793 return this.data.indexOfKey(id);
8797 * Get the Record with the specified id.
8798 * @param {String} id The id of the Record to find.
8799 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8801 getById : function(id){
8802 return this.data.key(id);
8806 * Get the Record at the specified index.
8807 * @param {Number} index The index of the Record to find.
8808 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8810 getAt : function(index){
8811 return this.data.itemAt(index);
8815 * Returns a range of Records between specified indices.
8816 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8817 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8818 * @return {Roo.data.Record[]} An array of Records
8820 getRange : function(start, end){
8821 return this.data.getRange(start, end);
8825 storeOptions : function(o){
8826 o = Roo.apply({}, o);
8829 this.lastOptions = o;
8833 * Loads the Record cache from the configured Proxy using the configured Reader.
8835 * If using remote paging, then the first load call must specify the <em>start</em>
8836 * and <em>limit</em> properties in the options.params property to establish the initial
8837 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8839 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8840 * and this call will return before the new data has been loaded. Perform any post-processing
8841 * in a callback function, or in a "load" event handler.</strong>
8843 * @param {Object} options An object containing properties which control loading options:<ul>
8844 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8845 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8846 * passed the following arguments:<ul>
8847 * <li>r : Roo.data.Record[]</li>
8848 * <li>options: Options object from the load call</li>
8849 * <li>success: Boolean success indicator</li></ul></li>
8850 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8851 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8854 load : function(options){
8855 options = options || {};
8856 if(this.fireEvent("beforeload", this, options) !== false){
8857 this.storeOptions(options);
8858 var p = Roo.apply(options.params || {}, this.baseParams);
8859 // if meta was not loaded from remote source.. try requesting it.
8860 if (!this.reader.metaFromRemote) {
8863 if(this.sortInfo && this.remoteSort){
8864 var pn = this.paramNames;
8865 p[pn["sort"]] = this.sortInfo.field;
8866 p[pn["dir"]] = this.sortInfo.direction;
8868 if (this.multiSort) {
8869 var pn = this.paramNames;
8870 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8873 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8878 * Reloads the Record cache from the configured Proxy using the configured Reader and
8879 * the options from the last load operation performed.
8880 * @param {Object} options (optional) An object containing properties which may override the options
8881 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8882 * the most recently used options are reused).
8884 reload : function(options){
8885 this.load(Roo.applyIf(options||{}, this.lastOptions));
8889 // Called as a callback by the Reader during a load operation.
8890 loadRecords : function(o, options, success){
8891 if(!o || success === false){
8892 if(success !== false){
8893 this.fireEvent("load", this, [], options, o);
8895 if(options.callback){
8896 options.callback.call(options.scope || this, [], options, false);
8900 // if data returned failure - throw an exception.
8901 if (o.success === false) {
8902 // show a message if no listener is registered.
8903 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8904 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8906 // loadmask wil be hooked into this..
8907 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8910 var r = o.records, t = o.totalRecords || r.length;
8912 this.fireEvent("beforeloadadd", this, r, options, o);
8914 if(!options || options.add !== true){
8915 if(this.pruneModifiedRecords){
8918 for(var i = 0, len = r.length; i < len; i++){
8922 this.data = this.snapshot;
8923 delete this.snapshot;
8926 this.data.addAll(r);
8927 this.totalLength = t;
8929 this.fireEvent("datachanged", this);
8931 this.totalLength = Math.max(t, this.data.length+r.length);
8934 this.fireEvent("load", this, r, options, o);
8935 if(options.callback){
8936 options.callback.call(options.scope || this, r, options, true);
8942 * Loads data from a passed data block. A Reader which understands the format of the data
8943 * must have been configured in the constructor.
8944 * @param {Object} data The data block from which to read the Records. The format of the data expected
8945 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8946 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8948 loadData : function(o, append){
8949 var r = this.reader.readRecords(o);
8950 this.loadRecords(r, {add: append}, true);
8954 * Gets the number of cached records.
8956 * <em>If using paging, this may not be the total size of the dataset. If the data object
8957 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8958 * the data set size</em>
8960 getCount : function(){
8961 return this.data.length || 0;
8965 * Gets the total number of records in the dataset as returned by the server.
8967 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8968 * the dataset size</em>
8970 getTotalCount : function(){
8971 return this.totalLength || 0;
8975 * Returns the sort state of the Store as an object with two properties:
8977 field {String} The name of the field by which the Records are sorted
8978 direction {String} The sort order, "ASC" or "DESC"
8981 getSortState : function(){
8982 return this.sortInfo;
8986 applySort : function(){
8987 if(this.sortInfo && !this.remoteSort){
8988 var s = this.sortInfo, f = s.field;
8989 var st = this.fields.get(f).sortType;
8990 var fn = function(r1, r2){
8991 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8992 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8994 this.data.sort(s.direction, fn);
8995 if(this.snapshot && this.snapshot != this.data){
8996 this.snapshot.sort(s.direction, fn);
9002 * Sets the default sort column and order to be used by the next load operation.
9003 * @param {String} fieldName The name of the field to sort by.
9004 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9006 setDefaultSort : function(field, dir){
9007 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9012 * If remote sorting is used, the sort is performed on the server, and the cache is
9013 * reloaded. If local sorting is used, the cache is sorted internally.
9014 * @param {String} fieldName The name of the field to sort by.
9015 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9017 sort : function(fieldName, dir){
9018 var f = this.fields.get(fieldName);
9020 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9022 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9023 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9028 this.sortToggle[f.name] = dir;
9029 this.sortInfo = {field: f.name, direction: dir};
9030 if(!this.remoteSort){
9032 this.fireEvent("datachanged", this);
9034 this.load(this.lastOptions);
9039 * Calls the specified function for each of the Records in the cache.
9040 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9041 * Returning <em>false</em> aborts and exits the iteration.
9042 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9044 each : function(fn, scope){
9045 this.data.each(fn, scope);
9049 * Gets all records modified since the last commit. Modified records are persisted across load operations
9050 * (e.g., during paging).
9051 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9053 getModifiedRecords : function(){
9054 return this.modified;
9058 createFilterFn : function(property, value, anyMatch){
9059 if(!value.exec){ // not a regex
9060 value = String(value);
9061 if(value.length == 0){
9064 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9067 return value.test(r.data[property]);
9072 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9073 * @param {String} property A field on your records
9074 * @param {Number} start The record index to start at (defaults to 0)
9075 * @param {Number} end The last record index to include (defaults to length - 1)
9076 * @return {Number} The sum
9078 sum : function(property, start, end){
9079 var rs = this.data.items, v = 0;
9081 end = (end || end === 0) ? end : rs.length-1;
9083 for(var i = start; i <= end; i++){
9084 v += (rs[i].data[property] || 0);
9090 * Filter the records by a specified property.
9091 * @param {String} field A field on your records
9092 * @param {String/RegExp} value Either a string that the field
9093 * should start with or a RegExp to test against the field
9094 * @param {Boolean} anyMatch True to match any part not just the beginning
9096 filter : function(property, value, anyMatch){
9097 var fn = this.createFilterFn(property, value, anyMatch);
9098 return fn ? this.filterBy(fn) : this.clearFilter();
9102 * Filter by a function. The specified function will be called with each
9103 * record in this data source. If the function returns true the record is included,
9104 * otherwise it is filtered.
9105 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9106 * @param {Object} scope (optional) The scope of the function (defaults to this)
9108 filterBy : function(fn, scope){
9109 this.snapshot = this.snapshot || this.data;
9110 this.data = this.queryBy(fn, scope||this);
9111 this.fireEvent("datachanged", this);
9115 * Query the records by a specified property.
9116 * @param {String} field A field on your records
9117 * @param {String/RegExp} value Either a string that the field
9118 * should start with or a RegExp to test against the field
9119 * @param {Boolean} anyMatch True to match any part not just the beginning
9120 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9122 query : function(property, value, anyMatch){
9123 var fn = this.createFilterFn(property, value, anyMatch);
9124 return fn ? this.queryBy(fn) : this.data.clone();
9128 * Query by a function. The specified function will be called with each
9129 * record in this data source. If the function returns true the record is included
9131 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9132 * @param {Object} scope (optional) The scope of the function (defaults to this)
9133 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9135 queryBy : function(fn, scope){
9136 var data = this.snapshot || this.data;
9137 return data.filterBy(fn, scope||this);
9141 * Collects unique values for a particular dataIndex from this store.
9142 * @param {String} dataIndex The property to collect
9143 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9144 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9145 * @return {Array} An array of the unique values
9147 collect : function(dataIndex, allowNull, bypassFilter){
9148 var d = (bypassFilter === true && this.snapshot) ?
9149 this.snapshot.items : this.data.items;
9150 var v, sv, r = [], l = {};
9151 for(var i = 0, len = d.length; i < len; i++){
9152 v = d[i].data[dataIndex];
9154 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9163 * Revert to a view of the Record cache with no filtering applied.
9164 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9166 clearFilter : function(suppressEvent){
9167 if(this.snapshot && this.snapshot != this.data){
9168 this.data = this.snapshot;
9169 delete this.snapshot;
9170 if(suppressEvent !== true){
9171 this.fireEvent("datachanged", this);
9177 afterEdit : function(record){
9178 if(this.modified.indexOf(record) == -1){
9179 this.modified.push(record);
9181 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9185 afterReject : function(record){
9186 this.modified.remove(record);
9187 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9191 afterCommit : function(record){
9192 this.modified.remove(record);
9193 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9197 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9198 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9200 commitChanges : function(){
9201 var m = this.modified.slice(0);
9203 for(var i = 0, len = m.length; i < len; i++){
9209 * Cancel outstanding changes on all changed records.
9211 rejectChanges : function(){
9212 var m = this.modified.slice(0);
9214 for(var i = 0, len = m.length; i < len; i++){
9219 onMetaChange : function(meta, rtype, o){
9220 this.recordType = rtype;
9221 this.fields = rtype.prototype.fields;
9222 delete this.snapshot;
9223 this.sortInfo = meta.sortInfo || this.sortInfo;
9225 this.fireEvent('metachange', this, this.reader.meta);
9228 moveIndex : function(data, type)
9230 var index = this.indexOf(data);
9232 var newIndex = index + type;
9236 this.insert(newIndex, data);
9241 * Ext JS Library 1.1.1
9242 * Copyright(c) 2006-2007, Ext JS, LLC.
9244 * Originally Released Under LGPL - original licence link has changed is not relivant.
9247 * <script type="text/javascript">
9251 * @class Roo.data.SimpleStore
9252 * @extends Roo.data.Store
9253 * Small helper class to make creating Stores from Array data easier.
9254 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9255 * @cfg {Array} fields An array of field definition objects, or field name strings.
9256 * @cfg {Array} data The multi-dimensional array of data
9258 * @param {Object} config
9260 Roo.data.SimpleStore = function(config){
9261 Roo.data.SimpleStore.superclass.constructor.call(this, {
9263 reader: new Roo.data.ArrayReader({
9266 Roo.data.Record.create(config.fields)
9268 proxy : new Roo.data.MemoryProxy(config.data)
9272 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9274 * Ext JS Library 1.1.1
9275 * Copyright(c) 2006-2007, Ext JS, LLC.
9277 * Originally Released Under LGPL - original licence link has changed is not relivant.
9280 * <script type="text/javascript">
9285 * @extends Roo.data.Store
9286 * @class Roo.data.JsonStore
9287 * Small helper class to make creating Stores for JSON data easier. <br/>
9289 var store = new Roo.data.JsonStore({
9290 url: 'get-images.php',
9292 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9295 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9296 * JsonReader and HttpProxy (unless inline data is provided).</b>
9297 * @cfg {Array} fields An array of field definition objects, or field name strings.
9299 * @param {Object} config
9301 Roo.data.JsonStore = function(c){
9302 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9303 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9304 reader: new Roo.data.JsonReader(c, c.fields)
9307 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9309 * Ext JS Library 1.1.1
9310 * Copyright(c) 2006-2007, Ext JS, LLC.
9312 * Originally Released Under LGPL - original licence link has changed is not relivant.
9315 * <script type="text/javascript">
9319 Roo.data.Field = function(config){
9320 if(typeof config == "string"){
9321 config = {name: config};
9323 Roo.apply(this, config);
9329 var st = Roo.data.SortTypes;
9330 // named sortTypes are supported, here we look them up
9331 if(typeof this.sortType == "string"){
9332 this.sortType = st[this.sortType];
9335 // set default sortType for strings and dates
9339 this.sortType = st.asUCString;
9342 this.sortType = st.asDate;
9345 this.sortType = st.none;
9350 var stripRe = /[\$,%]/g;
9352 // prebuilt conversion function for this field, instead of
9353 // switching every time we're reading a value
9355 var cv, dateFormat = this.dateFormat;
9360 cv = function(v){ return v; };
9363 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9367 return v !== undefined && v !== null && v !== '' ?
9368 parseInt(String(v).replace(stripRe, ""), 10) : '';
9373 return v !== undefined && v !== null && v !== '' ?
9374 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9379 cv = function(v){ return v === true || v === "true" || v == 1; };
9386 if(v instanceof Date){
9390 if(dateFormat == "timestamp"){
9391 return new Date(v*1000);
9393 return Date.parseDate(v, dateFormat);
9395 var parsed = Date.parse(v);
9396 return parsed ? new Date(parsed) : null;
9405 Roo.data.Field.prototype = {
9413 * Ext JS Library 1.1.1
9414 * Copyright(c) 2006-2007, Ext JS, LLC.
9416 * Originally Released Under LGPL - original licence link has changed is not relivant.
9419 * <script type="text/javascript">
9422 // Base class for reading structured data from a data source. This class is intended to be
9423 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9426 * @class Roo.data.DataReader
9427 * Base class for reading structured data from a data source. This class is intended to be
9428 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9431 Roo.data.DataReader = function(meta, recordType){
9435 this.recordType = recordType instanceof Array ?
9436 Roo.data.Record.create(recordType) : recordType;
9439 Roo.data.DataReader.prototype = {
9441 * Create an empty record
9442 * @param {Object} data (optional) - overlay some values
9443 * @return {Roo.data.Record} record created.
9445 newRow : function(d) {
9447 this.recordType.prototype.fields.each(function(c) {
9449 case 'int' : da[c.name] = 0; break;
9450 case 'date' : da[c.name] = new Date(); break;
9451 case 'float' : da[c.name] = 0.0; break;
9452 case 'boolean' : da[c.name] = false; break;
9453 default : da[c.name] = ""; break;
9457 return new this.recordType(Roo.apply(da, d));
9462 * Ext JS Library 1.1.1
9463 * Copyright(c) 2006-2007, Ext JS, LLC.
9465 * Originally Released Under LGPL - original licence link has changed is not relivant.
9468 * <script type="text/javascript">
9472 * @class Roo.data.DataProxy
9473 * @extends Roo.data.Observable
9474 * This class is an abstract base class for implementations which provide retrieval of
9475 * unformatted data objects.<br>
9477 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9478 * (of the appropriate type which knows how to parse the data object) to provide a block of
9479 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9481 * Custom implementations must implement the load method as described in
9482 * {@link Roo.data.HttpProxy#load}.
9484 Roo.data.DataProxy = function(){
9488 * Fires before a network request is made to retrieve a data object.
9489 * @param {Object} This DataProxy object.
9490 * @param {Object} params The params parameter to the load function.
9495 * Fires before the load method's callback is called.
9496 * @param {Object} This DataProxy object.
9497 * @param {Object} o The data object.
9498 * @param {Object} arg The callback argument object passed to the load function.
9502 * @event loadexception
9503 * Fires if an Exception occurs during data retrieval.
9504 * @param {Object} This DataProxy object.
9505 * @param {Object} o The data object.
9506 * @param {Object} arg The callback argument object passed to the load function.
9507 * @param {Object} e The Exception.
9509 loadexception : true
9511 Roo.data.DataProxy.superclass.constructor.call(this);
9514 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9517 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9521 * Ext JS Library 1.1.1
9522 * Copyright(c) 2006-2007, Ext JS, LLC.
9524 * Originally Released Under LGPL - original licence link has changed is not relivant.
9527 * <script type="text/javascript">
9530 * @class Roo.data.MemoryProxy
9531 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9532 * to the Reader when its load method is called.
9534 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9536 Roo.data.MemoryProxy = function(data){
9540 Roo.data.MemoryProxy.superclass.constructor.call(this);
9544 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9546 * Load data from the requested source (in this case an in-memory
9547 * data object passed to the constructor), read the data object into
9548 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9549 * process that block using the passed callback.
9550 * @param {Object} params This parameter is not used by the MemoryProxy class.
9551 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9552 * object into a block of Roo.data.Records.
9553 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9554 * The function must be passed <ul>
9555 * <li>The Record block object</li>
9556 * <li>The "arg" argument from the load function</li>
9557 * <li>A boolean success indicator</li>
9559 * @param {Object} scope The scope in which to call the callback
9560 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9562 load : function(params, reader, callback, scope, arg){
9563 params = params || {};
9566 result = reader.readRecords(this.data);
9568 this.fireEvent("loadexception", this, arg, null, e);
9569 callback.call(scope, null, arg, false);
9572 callback.call(scope, result, arg, true);
9576 update : function(params, records){
9581 * Ext JS Library 1.1.1
9582 * Copyright(c) 2006-2007, Ext JS, LLC.
9584 * Originally Released Under LGPL - original licence link has changed is not relivant.
9587 * <script type="text/javascript">
9590 * @class Roo.data.HttpProxy
9591 * @extends Roo.data.DataProxy
9592 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9593 * configured to reference a certain URL.<br><br>
9595 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9596 * from which the running page was served.<br><br>
9598 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9600 * Be aware that to enable the browser to parse an XML document, the server must set
9601 * the Content-Type header in the HTTP response to "text/xml".
9603 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9604 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9605 * will be used to make the request.
9607 Roo.data.HttpProxy = function(conn){
9608 Roo.data.HttpProxy.superclass.constructor.call(this);
9609 // is conn a conn config or a real conn?
9611 this.useAjax = !conn || !conn.events;
9615 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9616 // thse are take from connection...
9619 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9622 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9623 * extra parameters to each request made by this object. (defaults to undefined)
9626 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9627 * to each request made by this object. (defaults to undefined)
9630 * @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)
9633 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9636 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9642 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9646 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9647 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9648 * a finer-grained basis than the DataProxy events.
9650 getConnection : function(){
9651 return this.useAjax ? Roo.Ajax : this.conn;
9655 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9656 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9657 * process that block using the passed callback.
9658 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9659 * for the request to the remote server.
9660 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9661 * object into a block of Roo.data.Records.
9662 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9663 * The function must be passed <ul>
9664 * <li>The Record block object</li>
9665 * <li>The "arg" argument from the load function</li>
9666 * <li>A boolean success indicator</li>
9668 * @param {Object} scope The scope in which to call the callback
9669 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9671 load : function(params, reader, callback, scope, arg){
9672 if(this.fireEvent("beforeload", this, params) !== false){
9674 params : params || {},
9676 callback : callback,
9681 callback : this.loadResponse,
9685 Roo.applyIf(o, this.conn);
9686 if(this.activeRequest){
9687 Roo.Ajax.abort(this.activeRequest);
9689 this.activeRequest = Roo.Ajax.request(o);
9691 this.conn.request(o);
9694 callback.call(scope||this, null, arg, false);
9699 loadResponse : function(o, success, response){
9700 delete this.activeRequest;
9702 this.fireEvent("loadexception", this, o, response);
9703 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9708 result = o.reader.read(response);
9710 this.fireEvent("loadexception", this, o, response, e);
9711 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9715 this.fireEvent("load", this, o, o.request.arg);
9716 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9720 update : function(dataSet){
9725 updateResponse : function(dataSet){
9730 * Ext JS Library 1.1.1
9731 * Copyright(c) 2006-2007, Ext JS, LLC.
9733 * Originally Released Under LGPL - original licence link has changed is not relivant.
9736 * <script type="text/javascript">
9740 * @class Roo.data.ScriptTagProxy
9741 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9742 * other than the originating domain of the running page.<br><br>
9744 * <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
9745 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9747 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9748 * source code that is used as the source inside a <script> tag.<br><br>
9750 * In order for the browser to process the returned data, the server must wrap the data object
9751 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9752 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9753 * depending on whether the callback name was passed:
9756 boolean scriptTag = false;
9757 String cb = request.getParameter("callback");
9760 response.setContentType("text/javascript");
9762 response.setContentType("application/x-json");
9764 Writer out = response.getWriter();
9766 out.write(cb + "(");
9768 out.print(dataBlock.toJsonString());
9775 * @param {Object} config A configuration object.
9777 Roo.data.ScriptTagProxy = function(config){
9778 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9779 Roo.apply(this, config);
9780 this.head = document.getElementsByTagName("head")[0];
9783 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9785 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9787 * @cfg {String} url The URL from which to request the data object.
9790 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9794 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9795 * the server the name of the callback function set up by the load call to process the returned data object.
9796 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9797 * javascript output which calls this named function passing the data object as its only parameter.
9799 callbackParam : "callback",
9801 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9802 * name to the request.
9807 * Load data from the configured URL, read the data object into
9808 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9809 * process that block using the passed callback.
9810 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9811 * for the request to the remote server.
9812 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9813 * object into a block of Roo.data.Records.
9814 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9815 * The function must be passed <ul>
9816 * <li>The Record block object</li>
9817 * <li>The "arg" argument from the load function</li>
9818 * <li>A boolean success indicator</li>
9820 * @param {Object} scope The scope in which to call the callback
9821 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9823 load : function(params, reader, callback, scope, arg){
9824 if(this.fireEvent("beforeload", this, params) !== false){
9826 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9829 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9831 url += "&_dc=" + (new Date().getTime());
9833 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9836 cb : "stcCallback"+transId,
9837 scriptId : "stcScript"+transId,
9841 callback : callback,
9847 window[trans.cb] = function(o){
9848 conn.handleResponse(o, trans);
9851 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9853 if(this.autoAbort !== false){
9857 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9859 var script = document.createElement("script");
9860 script.setAttribute("src", url);
9861 script.setAttribute("type", "text/javascript");
9862 script.setAttribute("id", trans.scriptId);
9863 this.head.appendChild(script);
9867 callback.call(scope||this, null, arg, false);
9872 isLoading : function(){
9873 return this.trans ? true : false;
9877 * Abort the current server request.
9880 if(this.isLoading()){
9881 this.destroyTrans(this.trans);
9886 destroyTrans : function(trans, isLoaded){
9887 this.head.removeChild(document.getElementById(trans.scriptId));
9888 clearTimeout(trans.timeoutId);
9890 window[trans.cb] = undefined;
9892 delete window[trans.cb];
9895 // if hasn't been loaded, wait for load to remove it to prevent script error
9896 window[trans.cb] = function(){
9897 window[trans.cb] = undefined;
9899 delete window[trans.cb];
9906 handleResponse : function(o, trans){
9908 this.destroyTrans(trans, true);
9911 result = trans.reader.readRecords(o);
9913 this.fireEvent("loadexception", this, o, trans.arg, e);
9914 trans.callback.call(trans.scope||window, null, trans.arg, false);
9917 this.fireEvent("load", this, o, trans.arg);
9918 trans.callback.call(trans.scope||window, result, trans.arg, true);
9922 handleFailure : function(trans){
9924 this.destroyTrans(trans, false);
9925 this.fireEvent("loadexception", this, null, trans.arg);
9926 trans.callback.call(trans.scope||window, null, trans.arg, false);
9930 * Ext JS Library 1.1.1
9931 * Copyright(c) 2006-2007, Ext JS, LLC.
9933 * Originally Released Under LGPL - original licence link has changed is not relivant.
9936 * <script type="text/javascript">
9940 * @class Roo.data.JsonReader
9941 * @extends Roo.data.DataReader
9942 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9943 * based on mappings in a provided Roo.data.Record constructor.
9945 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9946 * in the reply previously.
9951 var RecordDef = Roo.data.Record.create([
9952 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9953 {name: 'occupation'} // This field will use "occupation" as the mapping.
9955 var myReader = new Roo.data.JsonReader({
9956 totalProperty: "results", // The property which contains the total dataset size (optional)
9957 root: "rows", // The property which contains an Array of row objects
9958 id: "id" // The property within each row object that provides an ID for the record (optional)
9962 * This would consume a JSON file like this:
9964 { 'results': 2, 'rows': [
9965 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9966 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9969 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9970 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9971 * paged from the remote server.
9972 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9973 * @cfg {String} root name of the property which contains the Array of row objects.
9974 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9976 * Create a new JsonReader
9977 * @param {Object} meta Metadata configuration options
9978 * @param {Object} recordType Either an Array of field definition objects,
9979 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9981 Roo.data.JsonReader = function(meta, recordType){
9984 // set some defaults:
9986 totalProperty: 'total',
9987 successProperty : 'success',
9992 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9994 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9997 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9998 * Used by Store query builder to append _requestMeta to params.
10001 metaFromRemote : false,
10003 * This method is only used by a DataProxy which has retrieved data from a remote server.
10004 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10005 * @return {Object} data A data block which is used by an Roo.data.Store object as
10006 * a cache of Roo.data.Records.
10008 read : function(response){
10009 var json = response.responseText;
10011 var o = /* eval:var:o */ eval("("+json+")");
10013 throw {message: "JsonReader.read: Json object not found"};
10019 this.metaFromRemote = true;
10020 this.meta = o.metaData;
10021 this.recordType = Roo.data.Record.create(o.metaData.fields);
10022 this.onMetaChange(this.meta, this.recordType, o);
10024 return this.readRecords(o);
10027 // private function a store will implement
10028 onMetaChange : function(meta, recordType, o){
10035 simpleAccess: function(obj, subsc) {
10042 getJsonAccessor: function(){
10044 return function(expr) {
10046 return(re.test(expr))
10047 ? new Function("obj", "return obj." + expr)
10052 return Roo.emptyFn;
10057 * Create a data block containing Roo.data.Records from an XML document.
10058 * @param {Object} o An object which contains an Array of row objects in the property specified
10059 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10060 * which contains the total size of the dataset.
10061 * @return {Object} data A data block which is used by an Roo.data.Store object as
10062 * a cache of Roo.data.Records.
10064 readRecords : function(o){
10066 * After any data loads, the raw JSON data is available for further custom processing.
10070 var s = this.meta, Record = this.recordType,
10071 f = Record.prototype.fields, fi = f.items, fl = f.length;
10073 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10075 if(s.totalProperty) {
10076 this.getTotal = this.getJsonAccessor(s.totalProperty);
10078 if(s.successProperty) {
10079 this.getSuccess = this.getJsonAccessor(s.successProperty);
10081 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10083 var g = this.getJsonAccessor(s.id);
10084 this.getId = function(rec) {
10086 return (r === undefined || r === "") ? null : r;
10089 this.getId = function(){return null;};
10092 for(var jj = 0; jj < fl; jj++){
10094 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10095 this.ef[jj] = this.getJsonAccessor(map);
10099 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10100 if(s.totalProperty){
10101 var vt = parseInt(this.getTotal(o), 10);
10106 if(s.successProperty){
10107 var vs = this.getSuccess(o);
10108 if(vs === false || vs === 'false'){
10113 for(var i = 0; i < c; i++){
10116 var id = this.getId(n);
10117 for(var j = 0; j < fl; j++){
10119 var v = this.ef[j](n);
10121 Roo.log('missing convert for ' + f.name);
10125 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10127 var record = new Record(values, id);
10129 records[i] = record;
10135 totalRecords : totalRecords
10140 * Ext JS Library 1.1.1
10141 * Copyright(c) 2006-2007, Ext JS, LLC.
10143 * Originally Released Under LGPL - original licence link has changed is not relivant.
10146 * <script type="text/javascript">
10150 * @class Roo.data.ArrayReader
10151 * @extends Roo.data.DataReader
10152 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10153 * Each element of that Array represents a row of data fields. The
10154 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10155 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10159 var RecordDef = Roo.data.Record.create([
10160 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10161 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10163 var myReader = new Roo.data.ArrayReader({
10164 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10168 * This would consume an Array like this:
10170 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10172 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10174 * Create a new JsonReader
10175 * @param {Object} meta Metadata configuration options.
10176 * @param {Object} recordType Either an Array of field definition objects
10177 * as specified to {@link Roo.data.Record#create},
10178 * or an {@link Roo.data.Record} object
10179 * created using {@link Roo.data.Record#create}.
10181 Roo.data.ArrayReader = function(meta, recordType){
10182 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10185 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10187 * Create a data block containing Roo.data.Records from an XML document.
10188 * @param {Object} o An Array of row objects which represents the dataset.
10189 * @return {Object} data A data block which is used by an Roo.data.Store object as
10190 * a cache of Roo.data.Records.
10192 readRecords : function(o){
10193 var sid = this.meta ? this.meta.id : null;
10194 var recordType = this.recordType, fields = recordType.prototype.fields;
10197 for(var i = 0; i < root.length; i++){
10200 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10201 for(var j = 0, jlen = fields.length; j < jlen; j++){
10202 var f = fields.items[j];
10203 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10204 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10206 values[f.name] = v;
10208 var record = new recordType(values, id);
10210 records[records.length] = record;
10214 totalRecords : records.length
10223 * @class Roo.bootstrap.ComboBox
10224 * @extends Roo.bootstrap.TriggerField
10225 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10226 * @cfg {Boolean} append (true|false) default false
10227 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10228 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10229 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10230 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10231 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10233 * Create a new ComboBox.
10234 * @param {Object} config Configuration options
10236 Roo.bootstrap.ComboBox = function(config){
10237 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10241 * Fires when the dropdown list is expanded
10242 * @param {Roo.bootstrap.ComboBox} combo This combo box
10247 * Fires when the dropdown list is collapsed
10248 * @param {Roo.bootstrap.ComboBox} combo This combo box
10252 * @event beforeselect
10253 * Fires before a list item is selected. Return false to cancel the selection.
10254 * @param {Roo.bootstrap.ComboBox} combo This combo box
10255 * @param {Roo.data.Record} record The data record returned from the underlying store
10256 * @param {Number} index The index of the selected item in the dropdown list
10258 'beforeselect' : true,
10261 * Fires when a list item is selected
10262 * @param {Roo.bootstrap.ComboBox} combo This combo box
10263 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10264 * @param {Number} index The index of the selected item in the dropdown list
10268 * @event beforequery
10269 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10270 * The event object passed has these properties:
10271 * @param {Roo.bootstrap.ComboBox} combo This combo box
10272 * @param {String} query The query
10273 * @param {Boolean} forceAll true to force "all" query
10274 * @param {Boolean} cancel true to cancel the query
10275 * @param {Object} e The query event object
10277 'beforequery': true,
10280 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10281 * @param {Roo.bootstrap.ComboBox} combo This combo box
10286 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10287 * @param {Roo.bootstrap.ComboBox} combo This combo box
10288 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10293 * Fires when the remove value from the combobox array
10294 * @param {Roo.bootstrap.ComboBox} combo This combo box
10301 this.tickItems = [];
10303 this.selectedIndex = -1;
10304 if(this.mode == 'local'){
10305 if(config.queryDelay === undefined){
10306 this.queryDelay = 10;
10308 if(config.minChars === undefined){
10314 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10317 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10318 * rendering into an Roo.Editor, defaults to false)
10321 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10322 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10325 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10328 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10329 * the dropdown list (defaults to undefined, with no header element)
10333 * @cfg {String/Roo.Template} tpl The template to use to render the output
10337 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10339 listWidth: undefined,
10341 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10342 * mode = 'remote' or 'text' if mode = 'local')
10344 displayField: undefined,
10346 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10347 * mode = 'remote' or 'value' if mode = 'local').
10348 * Note: use of a valueField requires the user make a selection
10349 * in order for a value to be mapped.
10351 valueField: undefined,
10355 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10356 * field's data value (defaults to the underlying DOM element's name)
10358 hiddenName: undefined,
10360 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10364 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10366 selectedClass: 'active',
10369 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10373 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10374 * anchor positions (defaults to 'tl-bl')
10376 listAlign: 'tl-bl?',
10378 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10382 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10383 * query specified by the allQuery config option (defaults to 'query')
10385 triggerAction: 'query',
10387 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10388 * (defaults to 4, does not apply if editable = false)
10392 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10393 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10397 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10398 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10402 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10403 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10407 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10408 * when editable = true (defaults to false)
10410 selectOnFocus:false,
10412 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10414 queryParam: 'query',
10416 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10417 * when mode = 'remote' (defaults to 'Loading...')
10419 loadingText: 'Loading...',
10421 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10425 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10429 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10430 * traditional select (defaults to true)
10434 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10438 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10442 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10443 * listWidth has a higher value)
10447 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10448 * allow the user to set arbitrary text into the field (defaults to false)
10450 forceSelection:false,
10452 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10453 * if typeAhead = true (defaults to 250)
10455 typeAheadDelay : 250,
10457 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10458 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10460 valueNotFoundText : undefined,
10462 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10464 blockFocus : false,
10467 * @cfg {Boolean} disableClear Disable showing of clear button.
10469 disableClear : false,
10471 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10473 alwaysQuery : false,
10476 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10490 btnPosition : 'right',
10491 triggerList : true,
10492 showToggleBtn : true,
10493 // element that contains real text value.. (when hidden is used..)
10495 getAutoCreate : function()
10502 if(!this.tickable){
10503 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10508 * ComboBox with tickable selections
10511 var align = this.labelAlign || this.parentLabelAlign();
10514 cls : 'form-group roo-combobox-tickable' //input-group
10520 cls : 'tickable-buttons',
10525 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10532 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10539 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10546 Roo.each(buttons.cn, function(c){
10548 c.cls += ' btn-' + _this.size;
10551 if (_this.disabled) {
10562 cls: 'form-hidden-field'
10566 cls: 'select2-choices',
10570 cls: 'select2-search-field',
10582 cls: 'select2-container input-group select2-container-multi',
10587 // cls: 'typeahead typeahead-long dropdown-menu',
10588 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10593 if (align ==='left' && this.fieldLabel.length) {
10595 Roo.log("left and has label");
10601 cls : 'control-label col-sm-' + this.labelWidth,
10602 html : this.fieldLabel
10606 cls : "col-sm-" + (12 - this.labelWidth),
10613 } else if ( this.fieldLabel.length) {
10619 //cls : 'input-group-addon',
10620 html : this.fieldLabel
10630 Roo.log(" no label && no align");
10637 ['xs','sm','md','lg'].map(function(size){
10638 if (settings[size]) {
10639 cfg.cls += ' col-' + size + '-' + settings[size];
10648 initEvents: function()
10652 throw "can not find store for combo";
10654 this.store = Roo.factory(this.store, Roo.data);
10657 this.initTickableEvents();
10661 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10663 if(this.hiddenName){
10665 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10667 this.hiddenField.dom.value =
10668 this.hiddenValue !== undefined ? this.hiddenValue :
10669 this.value !== undefined ? this.value : '';
10671 // prevent input submission
10672 this.el.dom.removeAttribute('name');
10673 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10678 // this.el.dom.setAttribute('autocomplete', 'off');
10681 var cls = 'x-combo-list';
10683 //this.list = new Roo.Layer({
10684 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10690 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10691 _this.list.setWidth(lw);
10694 this.list.on('mouseover', this.onViewOver, this);
10695 this.list.on('mousemove', this.onViewMove, this);
10697 this.list.on('scroll', this.onViewScroll, this);
10700 this.list.swallowEvent('mousewheel');
10701 this.assetHeight = 0;
10704 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10705 this.assetHeight += this.header.getHeight();
10708 this.innerList = this.list.createChild({cls:cls+'-inner'});
10709 this.innerList.on('mouseover', this.onViewOver, this);
10710 this.innerList.on('mousemove', this.onViewMove, this);
10711 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10713 if(this.allowBlank && !this.pageSize && !this.disableClear){
10714 this.footer = this.list.createChild({cls:cls+'-ft'});
10715 this.pageTb = new Roo.Toolbar(this.footer);
10719 this.footer = this.list.createChild({cls:cls+'-ft'});
10720 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10721 {pageSize: this.pageSize});
10725 if (this.pageTb && this.allowBlank && !this.disableClear) {
10727 this.pageTb.add(new Roo.Toolbar.Fill(), {
10728 cls: 'x-btn-icon x-btn-clear',
10730 handler: function()
10733 _this.clearValue();
10734 _this.onSelect(false, -1);
10739 this.assetHeight += this.footer.getHeight();
10744 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10747 this.view = new Roo.View(this.list, this.tpl, {
10748 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10750 //this.view.wrapEl.setDisplayed(false);
10751 this.view.on('click', this.onViewClick, this);
10755 this.store.on('beforeload', this.onBeforeLoad, this);
10756 this.store.on('load', this.onLoad, this);
10757 this.store.on('loadexception', this.onLoadException, this);
10759 if(this.resizable){
10760 this.resizer = new Roo.Resizable(this.list, {
10761 pinned:true, handles:'se'
10763 this.resizer.on('resize', function(r, w, h){
10764 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10765 this.listWidth = w;
10766 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10767 this.restrictHeight();
10769 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10772 if(!this.editable){
10773 this.editable = true;
10774 this.setEditable(false);
10779 if (typeof(this.events.add.listeners) != 'undefined') {
10781 this.addicon = this.wrap.createChild(
10782 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10784 this.addicon.on('click', function(e) {
10785 this.fireEvent('add', this);
10788 if (typeof(this.events.edit.listeners) != 'undefined') {
10790 this.editicon = this.wrap.createChild(
10791 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10792 if (this.addicon) {
10793 this.editicon.setStyle('margin-left', '40px');
10795 this.editicon.on('click', function(e) {
10797 // we fire even if inothing is selected..
10798 this.fireEvent('edit', this, this.lastData );
10804 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10805 "up" : function(e){
10806 this.inKeyMode = true;
10810 "down" : function(e){
10811 if(!this.isExpanded()){
10812 this.onTriggerClick();
10814 this.inKeyMode = true;
10819 "enter" : function(e){
10820 // this.onViewClick();
10824 if(this.fireEvent("specialkey", this, e)){
10825 this.onViewClick(false);
10831 "esc" : function(e){
10835 "tab" : function(e){
10838 if(this.fireEvent("specialkey", this, e)){
10839 this.onViewClick(false);
10847 doRelay : function(foo, bar, hname){
10848 if(hname == 'down' || this.scope.isExpanded()){
10849 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10858 this.queryDelay = Math.max(this.queryDelay || 10,
10859 this.mode == 'local' ? 10 : 250);
10862 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10864 if(this.typeAhead){
10865 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10867 if(this.editable !== false){
10868 this.inputEl().on("keyup", this.onKeyUp, this);
10870 if(this.forceSelection){
10871 this.inputEl().on('blur', this.doForce, this);
10875 this.choices = this.el.select('ul.select2-choices', true).first();
10876 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10880 initTickableEvents: function()
10884 if(this.hiddenName){
10886 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10888 this.hiddenField.dom.value =
10889 this.hiddenValue !== undefined ? this.hiddenValue :
10890 this.value !== undefined ? this.value : '';
10892 // prevent input submission
10893 this.el.dom.removeAttribute('name');
10894 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10899 // this.list = this.el.select('ul.dropdown-menu',true).first();
10901 this.choices = this.el.select('ul.select2-choices', true).first();
10902 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10903 if(this.triggerList){
10904 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10907 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10908 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10910 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10911 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10913 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10914 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10916 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10917 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10918 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10921 this.cancelBtn.hide();
10926 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10927 _this.list.setWidth(lw);
10930 this.list.on('mouseover', this.onViewOver, this);
10931 this.list.on('mousemove', this.onViewMove, this);
10933 this.list.on('scroll', this.onViewScroll, this);
10936 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>';
10939 this.view = new Roo.View(this.list, this.tpl, {
10940 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10943 //this.view.wrapEl.setDisplayed(false);
10944 this.view.on('click', this.onViewClick, this);
10948 this.store.on('beforeload', this.onBeforeLoad, this);
10949 this.store.on('load', this.onLoad, this);
10950 this.store.on('loadexception', this.onLoadException, this);
10952 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10953 // "up" : function(e){
10954 // this.inKeyMode = true;
10955 // this.selectPrev();
10958 // "down" : function(e){
10959 // if(!this.isExpanded()){
10960 // this.onTriggerClick();
10962 // this.inKeyMode = true;
10963 // this.selectNext();
10967 // "enter" : function(e){
10968 //// this.onViewClick();
10970 // this.collapse();
10972 // if(this.fireEvent("specialkey", this, e)){
10973 // this.onViewClick(false);
10979 // "esc" : function(e){
10980 // this.collapse();
10983 // "tab" : function(e){
10984 // this.collapse();
10986 // if(this.fireEvent("specialkey", this, e)){
10987 // this.onViewClick(false);
10995 // doRelay : function(foo, bar, hname){
10996 // if(hname == 'down' || this.scope.isExpanded()){
10997 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11002 // forceKeyDown: true
11006 this.queryDelay = Math.max(this.queryDelay || 10,
11007 this.mode == 'local' ? 10 : 250);
11010 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11012 if(this.typeAhead){
11013 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11017 onDestroy : function(){
11019 this.view.setStore(null);
11020 this.view.el.removeAllListeners();
11021 this.view.el.remove();
11022 this.view.purgeListeners();
11025 this.list.dom.innerHTML = '';
11029 this.store.un('beforeload', this.onBeforeLoad, this);
11030 this.store.un('load', this.onLoad, this);
11031 this.store.un('loadexception', this.onLoadException, this);
11033 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11037 fireKey : function(e){
11038 if(e.isNavKeyPress() && !this.list.isVisible()){
11039 this.fireEvent("specialkey", this, e);
11044 onResize: function(w, h){
11045 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11047 // if(typeof w != 'number'){
11048 // // we do not handle it!?!?
11051 // var tw = this.trigger.getWidth();
11052 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11053 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11055 // this.inputEl().setWidth( this.adjustWidth('input', x));
11057 // //this.trigger.setStyle('left', x+'px');
11059 // if(this.list && this.listWidth === undefined){
11060 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11061 // this.list.setWidth(lw);
11062 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11070 * Allow or prevent the user from directly editing the field text. If false is passed,
11071 * the user will only be able to select from the items defined in the dropdown list. This method
11072 * is the runtime equivalent of setting the 'editable' config option at config time.
11073 * @param {Boolean} value True to allow the user to directly edit the field text
11075 setEditable : function(value){
11076 if(value == this.editable){
11079 this.editable = value;
11081 this.inputEl().dom.setAttribute('readOnly', true);
11082 this.inputEl().on('mousedown', this.onTriggerClick, this);
11083 this.inputEl().addClass('x-combo-noedit');
11085 this.inputEl().dom.setAttribute('readOnly', false);
11086 this.inputEl().un('mousedown', this.onTriggerClick, this);
11087 this.inputEl().removeClass('x-combo-noedit');
11093 onBeforeLoad : function(combo,opts){
11094 if(!this.hasFocus){
11098 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11100 // this.restrictHeight();
11101 this.selectedIndex = -1;
11105 onLoad : function(){
11107 this.hasQuery = false;
11109 if(!this.hasFocus){
11113 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11114 this.loading.hide();
11117 if(this.store.getCount() > 0){
11119 // this.restrictHeight();
11120 if(this.lastQuery == this.allQuery){
11121 if(this.editable && !this.tickable){
11122 this.inputEl().dom.select();
11126 !this.selectByValue(this.value, true) &&
11127 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11128 this.store.lastOptions.add != true)
11130 this.select(0, true);
11133 if(this.autoFocus){
11136 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11137 this.taTask.delay(this.typeAheadDelay);
11141 this.onEmptyResults();
11147 onLoadException : function()
11149 this.hasQuery = false;
11151 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11152 this.loading.hide();
11156 Roo.log(this.store.reader.jsonData);
11157 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11159 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11165 onTypeAhead : function(){
11166 if(this.store.getCount() > 0){
11167 var r = this.store.getAt(0);
11168 var newValue = r.data[this.displayField];
11169 var len = newValue.length;
11170 var selStart = this.getRawValue().length;
11172 if(selStart != len){
11173 this.setRawValue(newValue);
11174 this.selectText(selStart, newValue.length);
11180 onSelect : function(record, index){
11182 if(this.fireEvent('beforeselect', this, record, index) !== false){
11184 this.setFromData(index > -1 ? record.data : false);
11187 this.fireEvent('select', this, record, index);
11192 * Returns the currently selected field value or empty string if no value is set.
11193 * @return {String} value The selected value
11195 getValue : function(){
11198 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11201 if(this.valueField){
11202 return typeof this.value != 'undefined' ? this.value : '';
11204 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11209 * Clears any text/value currently set in the field
11211 clearValue : function(){
11212 if(this.hiddenField){
11213 this.hiddenField.dom.value = '';
11216 this.setRawValue('');
11217 this.lastSelectionText = '';
11222 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11223 * will be displayed in the field. If the value does not match the data value of an existing item,
11224 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11225 * Otherwise the field will be blank (although the value will still be set).
11226 * @param {String} value The value to match
11228 setValue : function(v){
11235 if(this.valueField){
11236 var r = this.findRecord(this.valueField, v);
11238 text = r.data[this.displayField];
11239 }else if(this.valueNotFoundText !== undefined){
11240 text = this.valueNotFoundText;
11243 this.lastSelectionText = text;
11244 if(this.hiddenField){
11245 this.hiddenField.dom.value = v;
11247 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11251 * @property {Object} the last set data for the element
11256 * Sets the value of the field based on a object which is related to the record format for the store.
11257 * @param {Object} value the value to set as. or false on reset?
11259 setFromData : function(o){
11262 if(typeof o.display_name !== 'string'){
11263 for(var i=0;i<o.display_name.length;i++){
11264 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11272 var dv = ''; // display value
11273 var vv = ''; // value value..
11275 if (this.displayField) {
11276 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11278 // this is an error condition!!!
11279 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11282 if(this.valueField){
11283 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11286 if(this.hiddenField){
11287 this.hiddenField.dom.value = vv;
11289 this.lastSelectionText = dv;
11290 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11294 // no hidden field.. - we store the value in 'value', but still display
11295 // display field!!!!
11296 this.lastSelectionText = dv;
11297 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11303 reset : function(){
11304 // overridden so that last data is reset..
11305 this.setValue(this.originalValue);
11306 this.clearInvalid();
11307 this.lastData = false;
11309 this.view.clearSelections();
11313 findRecord : function(prop, value){
11315 if(this.store.getCount() > 0){
11316 this.store.each(function(r){
11317 if(r.data[prop] == value){
11327 getName: function()
11329 // returns hidden if it's set..
11330 if (!this.rendered) {return ''};
11331 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11335 onViewMove : function(e, t){
11336 this.inKeyMode = false;
11340 onViewOver : function(e, t){
11341 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11344 var item = this.view.findItemFromChild(t);
11347 var index = this.view.indexOf(item);
11348 this.select(index, false);
11353 onViewClick : function(view, doFocus, el, e)
11355 var index = this.view.getSelectedIndexes()[0];
11357 var r = this.store.getAt(index);
11361 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11368 Roo.each(this.tickItems, function(v,k){
11370 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11371 _this.tickItems.splice(k, 1);
11381 this.tickItems.push(r.data);
11386 this.onSelect(r, index);
11388 if(doFocus !== false && !this.blockFocus){
11389 this.inputEl().focus();
11394 restrictHeight : function(){
11395 //this.innerList.dom.style.height = '';
11396 //var inner = this.innerList.dom;
11397 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11398 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11399 //this.list.beginUpdate();
11400 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11401 this.list.alignTo(this.inputEl(), this.listAlign);
11402 this.list.alignTo(this.inputEl(), this.listAlign);
11403 //this.list.endUpdate();
11407 onEmptyResults : function(){
11412 * Returns true if the dropdown list is expanded, else false.
11414 isExpanded : function(){
11415 return this.list.isVisible();
11419 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11420 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11421 * @param {String} value The data value of the item to select
11422 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11423 * selected item if it is not currently in view (defaults to true)
11424 * @return {Boolean} True if the value matched an item in the list, else false
11426 selectByValue : function(v, scrollIntoView){
11427 if(v !== undefined && v !== null){
11428 var r = this.findRecord(this.valueField || this.displayField, v);
11430 this.select(this.store.indexOf(r), scrollIntoView);
11438 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11439 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11440 * @param {Number} index The zero-based index of the list item to select
11441 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11442 * selected item if it is not currently in view (defaults to true)
11444 select : function(index, scrollIntoView){
11445 this.selectedIndex = index;
11446 this.view.select(index);
11447 if(scrollIntoView !== false){
11448 var el = this.view.getNode(index);
11449 if(el && !this.multiple && !this.tickable){
11450 this.list.scrollChildIntoView(el, false);
11456 selectNext : function(){
11457 var ct = this.store.getCount();
11459 if(this.selectedIndex == -1){
11461 }else if(this.selectedIndex < ct-1){
11462 this.select(this.selectedIndex+1);
11468 selectPrev : function(){
11469 var ct = this.store.getCount();
11471 if(this.selectedIndex == -1){
11473 }else if(this.selectedIndex != 0){
11474 this.select(this.selectedIndex-1);
11480 onKeyUp : function(e){
11481 if(this.editable !== false && !e.isSpecialKey()){
11482 this.lastKey = e.getKey();
11483 this.dqTask.delay(this.queryDelay);
11488 validateBlur : function(){
11489 return !this.list || !this.list.isVisible();
11493 initQuery : function(){
11494 this.doQuery(this.getRawValue());
11498 doForce : function(){
11499 if(this.inputEl().dom.value.length > 0){
11500 this.inputEl().dom.value =
11501 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11507 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11508 * query allowing the query action to be canceled if needed.
11509 * @param {String} query The SQL query to execute
11510 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11511 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11512 * saved in the current store (defaults to false)
11514 doQuery : function(q, forceAll){
11516 if(q === undefined || q === null){
11521 forceAll: forceAll,
11525 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11530 forceAll = qe.forceAll;
11531 if(forceAll === true || (q.length >= this.minChars)){
11533 this.hasQuery = true;
11535 if(this.lastQuery != q || this.alwaysQuery){
11536 this.lastQuery = q;
11537 if(this.mode == 'local'){
11538 this.selectedIndex = -1;
11540 this.store.clearFilter();
11542 this.store.filter(this.displayField, q);
11546 this.store.baseParams[this.queryParam] = q;
11548 var options = {params : this.getParams(q)};
11551 options.add = true;
11552 options.params.start = this.page * this.pageSize;
11555 this.store.load(options);
11557 * this code will make the page width larger, at the beginning, the list not align correctly,
11558 * we should expand the list on onLoad
11559 * so command out it
11564 this.selectedIndex = -1;
11569 this.loadNext = false;
11573 getParams : function(q){
11575 //p[this.queryParam] = q;
11579 p.limit = this.pageSize;
11585 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11587 collapse : function(){
11588 if(!this.isExpanded()){
11596 this.cancelBtn.hide();
11597 this.trigger.show();
11600 Roo.get(document).un('mousedown', this.collapseIf, this);
11601 Roo.get(document).un('mousewheel', this.collapseIf, this);
11602 if (!this.editable) {
11603 Roo.get(document).un('keydown', this.listKeyPress, this);
11605 this.fireEvent('collapse', this);
11609 collapseIf : function(e){
11610 var in_combo = e.within(this.el);
11611 var in_list = e.within(this.list);
11612 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11614 if (in_combo || in_list || is_list) {
11615 //e.stopPropagation();
11620 this.onTickableFooterButtonClick(e, false, false);
11628 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11630 expand : function(){
11632 if(this.isExpanded() || !this.hasFocus){
11636 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11637 this.list.setWidth(lw);
11642 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11643 this.list.setWidth(lw);
11647 this.restrictHeight();
11651 this.tickItems = Roo.apply([], this.item);
11654 this.cancelBtn.show();
11655 this.trigger.hide();
11659 Roo.get(document).on('mousedown', this.collapseIf, this);
11660 Roo.get(document).on('mousewheel', this.collapseIf, this);
11661 if (!this.editable) {
11662 Roo.get(document).on('keydown', this.listKeyPress, this);
11665 this.fireEvent('expand', this);
11669 // Implements the default empty TriggerField.onTriggerClick function
11670 onTriggerClick : function(e)
11672 Roo.log('trigger click');
11674 if(this.disabled || !this.triggerList){
11679 this.loadNext = false;
11681 if(this.isExpanded()){
11683 if (!this.blockFocus) {
11684 this.inputEl().focus();
11688 this.hasFocus = true;
11689 if(this.triggerAction == 'all') {
11690 this.doQuery(this.allQuery, true);
11692 this.doQuery(this.getRawValue());
11694 if (!this.blockFocus) {
11695 this.inputEl().focus();
11700 onTickableTriggerClick : function(e)
11707 this.loadNext = false;
11708 this.hasFocus = true;
11710 if(this.triggerAction == 'all') {
11711 this.doQuery(this.allQuery, true);
11713 this.doQuery(this.getRawValue());
11717 onSearchFieldClick : function(e)
11719 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11724 this.loadNext = false;
11725 this.hasFocus = true;
11727 if(this.triggerAction == 'all') {
11728 this.doQuery(this.allQuery, true);
11730 this.doQuery(this.getRawValue());
11734 listKeyPress : function(e)
11736 //Roo.log('listkeypress');
11737 // scroll to first matching element based on key pres..
11738 if (e.isSpecialKey()) {
11741 var k = String.fromCharCode(e.getKey()).toUpperCase();
11744 var csel = this.view.getSelectedNodes();
11745 var cselitem = false;
11747 var ix = this.view.indexOf(csel[0]);
11748 cselitem = this.store.getAt(ix);
11749 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11755 this.store.each(function(v) {
11757 // start at existing selection.
11758 if (cselitem.id == v.id) {
11764 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11765 match = this.store.indexOf(v);
11771 if (match === false) {
11772 return true; // no more action?
11775 this.view.select(match);
11776 var sn = Roo.get(this.view.getSelectedNodes()[0])
11777 //sn.scrollIntoView(sn.dom.parentNode, false);
11780 onViewScroll : function(e, t){
11782 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){
11786 this.hasQuery = true;
11788 this.loading = this.list.select('.loading', true).first();
11790 if(this.loading === null){
11791 this.list.createChild({
11793 cls: 'loading select2-more-results select2-active',
11794 html: 'Loading more results...'
11797 this.loading = this.list.select('.loading', true).first();
11799 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11801 this.loading.hide();
11804 this.loading.show();
11809 this.loadNext = true;
11811 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11816 addItem : function(o)
11818 var dv = ''; // display value
11820 if (this.displayField) {
11821 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11823 // this is an error condition!!!
11824 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11831 var choice = this.choices.createChild({
11833 cls: 'select2-search-choice',
11842 cls: 'select2-search-choice-close',
11847 }, this.searchField);
11849 var close = choice.select('a.select2-search-choice-close', true).first()
11851 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11859 this.inputEl().dom.value = '';
11863 onRemoveItem : function(e, _self, o)
11865 e.preventDefault();
11866 var index = this.item.indexOf(o.data) * 1;
11869 Roo.log('not this item?!');
11873 this.item.splice(index, 1);
11878 this.fireEvent('remove', this, e);
11882 syncValue : function()
11884 if(!this.item.length){
11891 Roo.each(this.item, function(i){
11892 if(_this.valueField){
11893 value.push(i[_this.valueField]);
11900 this.value = value.join(',');
11902 if(this.hiddenField){
11903 this.hiddenField.dom.value = this.value;
11907 clearItem : function()
11909 if(!this.multiple){
11915 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11922 inputEl: function ()
11925 return this.searchField;
11927 return this.el.select('input.form-control',true).first();
11931 onTickableFooterButtonClick : function(e, btn, el)
11933 e.preventDefault();
11935 if(btn && btn.name == 'cancel'){
11936 this.tickItems = Roo.apply([], this.item);
11945 Roo.each(this.tickItems, function(o){
11956 * @cfg {Boolean} grow
11960 * @cfg {Number} growMin
11964 * @cfg {Number} growMax
11974 * Ext JS Library 1.1.1
11975 * Copyright(c) 2006-2007, Ext JS, LLC.
11977 * Originally Released Under LGPL - original licence link has changed is not relivant.
11980 * <script type="text/javascript">
11985 * @extends Roo.util.Observable
11986 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11987 * This class also supports single and multi selection modes. <br>
11988 * Create a data model bound view:
11990 var store = new Roo.data.Store(...);
11992 var view = new Roo.View({
11994 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11996 singleSelect: true,
11997 selectedClass: "ydataview-selected",
12001 // listen for node click?
12002 view.on("click", function(vw, index, node, e){
12003 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12007 dataModel.load("foobar.xml");
12009 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12011 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12012 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12014 * Note: old style constructor is still suported (container, template, config)
12017 * Create a new View
12018 * @param {Object} config The config object
12021 Roo.View = function(config, depreciated_tpl, depreciated_config){
12023 this.parent = false;
12025 if (typeof(depreciated_tpl) == 'undefined') {
12026 // new way.. - universal constructor.
12027 Roo.apply(this, config);
12028 this.el = Roo.get(this.el);
12031 this.el = Roo.get(config);
12032 this.tpl = depreciated_tpl;
12033 Roo.apply(this, depreciated_config);
12035 this.wrapEl = this.el.wrap().wrap();
12036 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12039 if(typeof(this.tpl) == "string"){
12040 this.tpl = new Roo.Template(this.tpl);
12042 // support xtype ctors..
12043 this.tpl = new Roo.factory(this.tpl, Roo);
12047 this.tpl.compile();
12052 * @event beforeclick
12053 * Fires before a click is processed. Returns false to cancel the default action.
12054 * @param {Roo.View} this
12055 * @param {Number} index The index of the target node
12056 * @param {HTMLElement} node The target node
12057 * @param {Roo.EventObject} e The raw event object
12059 "beforeclick" : true,
12062 * Fires when a template node is clicked.
12063 * @param {Roo.View} this
12064 * @param {Number} index The index of the target node
12065 * @param {HTMLElement} node The target node
12066 * @param {Roo.EventObject} e The raw event object
12071 * Fires when a template node is double clicked.
12072 * @param {Roo.View} this
12073 * @param {Number} index The index of the target node
12074 * @param {HTMLElement} node The target node
12075 * @param {Roo.EventObject} e The raw event object
12079 * @event contextmenu
12080 * Fires when a template node is right clicked.
12081 * @param {Roo.View} this
12082 * @param {Number} index The index of the target node
12083 * @param {HTMLElement} node The target node
12084 * @param {Roo.EventObject} e The raw event object
12086 "contextmenu" : true,
12088 * @event selectionchange
12089 * Fires when the selected nodes change.
12090 * @param {Roo.View} this
12091 * @param {Array} selections Array of the selected nodes
12093 "selectionchange" : true,
12096 * @event beforeselect
12097 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12098 * @param {Roo.View} this
12099 * @param {HTMLElement} node The node to be selected
12100 * @param {Array} selections Array of currently selected nodes
12102 "beforeselect" : true,
12104 * @event preparedata
12105 * Fires on every row to render, to allow you to change the data.
12106 * @param {Roo.View} this
12107 * @param {Object} data to be rendered (change this)
12109 "preparedata" : true
12117 "click": this.onClick,
12118 "dblclick": this.onDblClick,
12119 "contextmenu": this.onContextMenu,
12123 this.selections = [];
12125 this.cmp = new Roo.CompositeElementLite([]);
12127 this.store = Roo.factory(this.store, Roo.data);
12128 this.setStore(this.store, true);
12131 if ( this.footer && this.footer.xtype) {
12133 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12135 this.footer.dataSource = this.store
12136 this.footer.container = fctr;
12137 this.footer = Roo.factory(this.footer, Roo);
12138 fctr.insertFirst(this.el);
12140 // this is a bit insane - as the paging toolbar seems to detach the el..
12141 // dom.parentNode.parentNode.parentNode
12142 // they get detached?
12146 Roo.View.superclass.constructor.call(this);
12151 Roo.extend(Roo.View, Roo.util.Observable, {
12154 * @cfg {Roo.data.Store} store Data store to load data from.
12159 * @cfg {String|Roo.Element} el The container element.
12164 * @cfg {String|Roo.Template} tpl The template used by this View
12168 * @cfg {String} dataName the named area of the template to use as the data area
12169 * Works with domtemplates roo-name="name"
12173 * @cfg {String} selectedClass The css class to add to selected nodes
12175 selectedClass : "x-view-selected",
12177 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12182 * @cfg {String} text to display on mask (default Loading)
12186 * @cfg {Boolean} multiSelect Allow multiple selection
12188 multiSelect : false,
12190 * @cfg {Boolean} singleSelect Allow single selection
12192 singleSelect: false,
12195 * @cfg {Boolean} toggleSelect - selecting
12197 toggleSelect : false,
12200 * @cfg {Boolean} tickable - selecting
12205 * Returns the element this view is bound to.
12206 * @return {Roo.Element}
12208 getEl : function(){
12209 return this.wrapEl;
12215 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12217 refresh : function(){
12218 Roo.log('refresh');
12221 // if we are using something like 'domtemplate', then
12222 // the what gets used is:
12223 // t.applySubtemplate(NAME, data, wrapping data..)
12224 // the outer template then get' applied with
12225 // the store 'extra data'
12226 // and the body get's added to the
12227 // roo-name="data" node?
12228 // <span class='roo-tpl-{name}'></span> ?????
12232 this.clearSelections();
12233 this.el.update("");
12235 var records = this.store.getRange();
12236 if(records.length < 1) {
12238 // is this valid?? = should it render a template??
12240 this.el.update(this.emptyText);
12244 if (this.dataName) {
12245 this.el.update(t.apply(this.store.meta)); //????
12246 el = this.el.child('.roo-tpl-' + this.dataName);
12249 for(var i = 0, len = records.length; i < len; i++){
12250 var data = this.prepareData(records[i].data, i, records[i]);
12251 this.fireEvent("preparedata", this, data, i, records[i]);
12253 var d = Roo.apply({}, data);
12256 Roo.apply(d, {'roo-id' : Roo.id()});
12260 Roo.each(this.parent.item, function(item){
12261 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12264 Roo.apply(d, {'roo-data-checked' : 'checked'});
12268 html[html.length] = Roo.util.Format.trim(
12270 t.applySubtemplate(this.dataName, d, this.store.meta) :
12277 el.update(html.join(""));
12278 this.nodes = el.dom.childNodes;
12279 this.updateIndexes(0);
12284 * Function to override to reformat the data that is sent to
12285 * the template for each node.
12286 * DEPRICATED - use the preparedata event handler.
12287 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12288 * a JSON object for an UpdateManager bound view).
12290 prepareData : function(data, index, record)
12292 this.fireEvent("preparedata", this, data, index, record);
12296 onUpdate : function(ds, record){
12297 Roo.log('on update');
12298 this.clearSelections();
12299 var index = this.store.indexOf(record);
12300 var n = this.nodes[index];
12301 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12302 n.parentNode.removeChild(n);
12303 this.updateIndexes(index, index);
12309 onAdd : function(ds, records, index)
12311 Roo.log(['on Add', ds, records, index] );
12312 this.clearSelections();
12313 if(this.nodes.length == 0){
12317 var n = this.nodes[index];
12318 for(var i = 0, len = records.length; i < len; i++){
12319 var d = this.prepareData(records[i].data, i, records[i]);
12321 this.tpl.insertBefore(n, d);
12324 this.tpl.append(this.el, d);
12327 this.updateIndexes(index);
12330 onRemove : function(ds, record, index){
12331 Roo.log('onRemove');
12332 this.clearSelections();
12333 var el = this.dataName ?
12334 this.el.child('.roo-tpl-' + this.dataName) :
12337 el.dom.removeChild(this.nodes[index]);
12338 this.updateIndexes(index);
12342 * Refresh an individual node.
12343 * @param {Number} index
12345 refreshNode : function(index){
12346 this.onUpdate(this.store, this.store.getAt(index));
12349 updateIndexes : function(startIndex, endIndex){
12350 var ns = this.nodes;
12351 startIndex = startIndex || 0;
12352 endIndex = endIndex || ns.length - 1;
12353 for(var i = startIndex; i <= endIndex; i++){
12354 ns[i].nodeIndex = i;
12359 * Changes the data store this view uses and refresh the view.
12360 * @param {Store} store
12362 setStore : function(store, initial){
12363 if(!initial && this.store){
12364 this.store.un("datachanged", this.refresh);
12365 this.store.un("add", this.onAdd);
12366 this.store.un("remove", this.onRemove);
12367 this.store.un("update", this.onUpdate);
12368 this.store.un("clear", this.refresh);
12369 this.store.un("beforeload", this.onBeforeLoad);
12370 this.store.un("load", this.onLoad);
12371 this.store.un("loadexception", this.onLoad);
12375 store.on("datachanged", this.refresh, this);
12376 store.on("add", this.onAdd, this);
12377 store.on("remove", this.onRemove, this);
12378 store.on("update", this.onUpdate, this);
12379 store.on("clear", this.refresh, this);
12380 store.on("beforeload", this.onBeforeLoad, this);
12381 store.on("load", this.onLoad, this);
12382 store.on("loadexception", this.onLoad, this);
12390 * onbeforeLoad - masks the loading area.
12393 onBeforeLoad : function(store,opts)
12395 Roo.log('onBeforeLoad');
12397 this.el.update("");
12399 this.el.mask(this.mask ? this.mask : "Loading" );
12401 onLoad : function ()
12408 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12409 * @param {HTMLElement} node
12410 * @return {HTMLElement} The template node
12412 findItemFromChild : function(node){
12413 var el = this.dataName ?
12414 this.el.child('.roo-tpl-' + this.dataName,true) :
12417 if(!node || node.parentNode == el){
12420 var p = node.parentNode;
12421 while(p && p != el){
12422 if(p.parentNode == el){
12431 onClick : function(e){
12432 var item = this.findItemFromChild(e.getTarget());
12434 var index = this.indexOf(item);
12435 if(this.onItemClick(item, index, e) !== false){
12436 this.fireEvent("click", this, index, item, e);
12439 this.clearSelections();
12444 onContextMenu : function(e){
12445 var item = this.findItemFromChild(e.getTarget());
12447 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12452 onDblClick : function(e){
12453 var item = this.findItemFromChild(e.getTarget());
12455 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12459 onItemClick : function(item, index, e)
12461 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12464 if (this.toggleSelect) {
12465 var m = this.isSelected(item) ? 'unselect' : 'select';
12468 _t[m](item, true, false);
12471 if(this.multiSelect || this.singleSelect){
12472 if(this.multiSelect && e.shiftKey && this.lastSelection){
12473 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12475 this.select(item, this.multiSelect && e.ctrlKey);
12476 this.lastSelection = item;
12479 if(!this.tickable){
12480 e.preventDefault();
12488 * Get the number of selected nodes.
12491 getSelectionCount : function(){
12492 return this.selections.length;
12496 * Get the currently selected nodes.
12497 * @return {Array} An array of HTMLElements
12499 getSelectedNodes : function(){
12500 return this.selections;
12504 * Get the indexes of the selected nodes.
12507 getSelectedIndexes : function(){
12508 var indexes = [], s = this.selections;
12509 for(var i = 0, len = s.length; i < len; i++){
12510 indexes.push(s[i].nodeIndex);
12516 * Clear all selections
12517 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12519 clearSelections : function(suppressEvent){
12520 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12521 this.cmp.elements = this.selections;
12522 this.cmp.removeClass(this.selectedClass);
12523 this.selections = [];
12524 if(!suppressEvent){
12525 this.fireEvent("selectionchange", this, this.selections);
12531 * Returns true if the passed node is selected
12532 * @param {HTMLElement/Number} node The node or node index
12533 * @return {Boolean}
12535 isSelected : function(node){
12536 var s = this.selections;
12540 node = this.getNode(node);
12541 return s.indexOf(node) !== -1;
12546 * @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
12547 * @param {Boolean} keepExisting (optional) true to keep existing selections
12548 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12550 select : function(nodeInfo, keepExisting, suppressEvent){
12551 if(nodeInfo instanceof Array){
12553 this.clearSelections(true);
12555 for(var i = 0, len = nodeInfo.length; i < len; i++){
12556 this.select(nodeInfo[i], true, true);
12560 var node = this.getNode(nodeInfo);
12561 if(!node || this.isSelected(node)){
12562 return; // already selected.
12565 this.clearSelections(true);
12567 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12568 Roo.fly(node).addClass(this.selectedClass);
12569 this.selections.push(node);
12570 if(!suppressEvent){
12571 this.fireEvent("selectionchange", this, this.selections);
12579 * @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
12580 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12581 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12583 unselect : function(nodeInfo, keepExisting, suppressEvent)
12585 if(nodeInfo instanceof Array){
12586 Roo.each(this.selections, function(s) {
12587 this.unselect(s, nodeInfo);
12591 var node = this.getNode(nodeInfo);
12592 if(!node || !this.isSelected(node)){
12593 Roo.log("not selected");
12594 return; // not selected.
12598 Roo.each(this.selections, function(s) {
12600 Roo.fly(node).removeClass(this.selectedClass);
12607 this.selections= ns;
12608 this.fireEvent("selectionchange", this, this.selections);
12612 * Gets a template node.
12613 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12614 * @return {HTMLElement} The node or null if it wasn't found
12616 getNode : function(nodeInfo){
12617 if(typeof nodeInfo == "string"){
12618 return document.getElementById(nodeInfo);
12619 }else if(typeof nodeInfo == "number"){
12620 return this.nodes[nodeInfo];
12626 * Gets a range template nodes.
12627 * @param {Number} startIndex
12628 * @param {Number} endIndex
12629 * @return {Array} An array of nodes
12631 getNodes : function(start, end){
12632 var ns = this.nodes;
12633 start = start || 0;
12634 end = typeof end == "undefined" ? ns.length - 1 : end;
12637 for(var i = start; i <= end; i++){
12641 for(var i = start; i >= end; i--){
12649 * Finds the index of the passed node
12650 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12651 * @return {Number} The index of the node or -1
12653 indexOf : function(node){
12654 node = this.getNode(node);
12655 if(typeof node.nodeIndex == "number"){
12656 return node.nodeIndex;
12658 var ns = this.nodes;
12659 for(var i = 0, len = ns.length; i < len; i++){
12670 * based on jquery fullcalendar
12674 Roo.bootstrap = Roo.bootstrap || {};
12676 * @class Roo.bootstrap.Calendar
12677 * @extends Roo.bootstrap.Component
12678 * Bootstrap Calendar class
12679 * @cfg {Boolean} loadMask (true|false) default false
12680 * @cfg {Object} header generate the user specific header of the calendar, default false
12683 * Create a new Container
12684 * @param {Object} config The config object
12689 Roo.bootstrap.Calendar = function(config){
12690 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12694 * Fires when a date is selected
12695 * @param {DatePicker} this
12696 * @param {Date} date The selected date
12700 * @event monthchange
12701 * Fires when the displayed month changes
12702 * @param {DatePicker} this
12703 * @param {Date} date The selected month
12705 'monthchange': true,
12707 * @event evententer
12708 * Fires when mouse over an event
12709 * @param {Calendar} this
12710 * @param {event} Event
12712 'evententer': true,
12714 * @event eventleave
12715 * Fires when the mouse leaves an
12716 * @param {Calendar} this
12719 'eventleave': true,
12721 * @event eventclick
12722 * Fires when the mouse click an
12723 * @param {Calendar} this
12732 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12735 * @cfg {Number} startDay
12736 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12744 getAutoCreate : function(){
12747 var fc_button = function(name, corner, style, content ) {
12748 return Roo.apply({},{
12750 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12752 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12755 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12766 style : 'width:100%',
12773 cls : 'fc-header-left',
12775 fc_button('prev', 'left', 'arrow', '‹' ),
12776 fc_button('next', 'right', 'arrow', '›' ),
12777 { tag: 'span', cls: 'fc-header-space' },
12778 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12786 cls : 'fc-header-center',
12790 cls: 'fc-header-title',
12793 html : 'month / year'
12801 cls : 'fc-header-right',
12803 /* fc_button('month', 'left', '', 'month' ),
12804 fc_button('week', '', '', 'week' ),
12805 fc_button('day', 'right', '', 'day' )
12817 header = this.header;
12820 var cal_heads = function() {
12822 // fixme - handle this.
12824 for (var i =0; i < Date.dayNames.length; i++) {
12825 var d = Date.dayNames[i];
12828 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12829 html : d.substring(0,3)
12833 ret[0].cls += ' fc-first';
12834 ret[6].cls += ' fc-last';
12837 var cal_cell = function(n) {
12840 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12845 cls: 'fc-day-number',
12849 cls: 'fc-day-content',
12853 style: 'position: relative;' // height: 17px;
12865 var cal_rows = function() {
12868 for (var r = 0; r < 6; r++) {
12875 for (var i =0; i < Date.dayNames.length; i++) {
12876 var d = Date.dayNames[i];
12877 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12880 row.cn[0].cls+=' fc-first';
12881 row.cn[0].cn[0].style = 'min-height:90px';
12882 row.cn[6].cls+=' fc-last';
12886 ret[0].cls += ' fc-first';
12887 ret[4].cls += ' fc-prev-last';
12888 ret[5].cls += ' fc-last';
12895 cls: 'fc-border-separate',
12896 style : 'width:100%',
12904 cls : 'fc-first fc-last',
12922 cls : 'fc-content',
12923 style : "position: relative;",
12926 cls : 'fc-view fc-view-month fc-grid',
12927 style : 'position: relative',
12928 unselectable : 'on',
12931 cls : 'fc-event-container',
12932 style : 'position:absolute;z-index:8;top:0;left:0;'
12950 initEvents : function()
12953 throw "can not find store for calendar";
12959 style: "text-align:center",
12963 style: "background-color:white;width:50%;margin:250 auto",
12967 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12978 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12980 var size = this.el.select('.fc-content', true).first().getSize();
12981 this.maskEl.setSize(size.width, size.height);
12982 this.maskEl.enableDisplayMode("block");
12983 if(!this.loadMask){
12984 this.maskEl.hide();
12987 this.store = Roo.factory(this.store, Roo.data);
12988 this.store.on('load', this.onLoad, this);
12989 this.store.on('beforeload', this.onBeforeLoad, this);
12993 this.cells = this.el.select('.fc-day',true);
12994 //Roo.log(this.cells);
12995 this.textNodes = this.el.query('.fc-day-number');
12996 this.cells.addClassOnOver('fc-state-hover');
12998 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12999 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13000 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13001 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13003 this.on('monthchange', this.onMonthChange, this);
13005 this.update(new Date().clearTime());
13008 resize : function() {
13009 var sz = this.el.getSize();
13011 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13012 this.el.select('.fc-day-content div',true).setHeight(34);
13017 showPrevMonth : function(e){
13018 this.update(this.activeDate.add("mo", -1));
13020 showToday : function(e){
13021 this.update(new Date().clearTime());
13024 showNextMonth : function(e){
13025 this.update(this.activeDate.add("mo", 1));
13029 showPrevYear : function(){
13030 this.update(this.activeDate.add("y", -1));
13034 showNextYear : function(){
13035 this.update(this.activeDate.add("y", 1));
13040 update : function(date)
13042 var vd = this.activeDate;
13043 this.activeDate = date;
13044 // if(vd && this.el){
13045 // var t = date.getTime();
13046 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13047 // Roo.log('using add remove');
13049 // this.fireEvent('monthchange', this, date);
13051 // this.cells.removeClass("fc-state-highlight");
13052 // this.cells.each(function(c){
13053 // if(c.dateValue == t){
13054 // c.addClass("fc-state-highlight");
13055 // setTimeout(function(){
13056 // try{c.dom.firstChild.focus();}catch(e){}
13066 var days = date.getDaysInMonth();
13068 var firstOfMonth = date.getFirstDateOfMonth();
13069 var startingPos = firstOfMonth.getDay()-this.startDay;
13071 if(startingPos < this.startDay){
13075 var pm = date.add(Date.MONTH, -1);
13076 var prevStart = pm.getDaysInMonth()-startingPos;
13078 this.cells = this.el.select('.fc-day',true);
13079 this.textNodes = this.el.query('.fc-day-number');
13080 this.cells.addClassOnOver('fc-state-hover');
13082 var cells = this.cells.elements;
13083 var textEls = this.textNodes;
13085 Roo.each(cells, function(cell){
13086 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13089 days += startingPos;
13091 // convert everything to numbers so it's fast
13092 var day = 86400000;
13093 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13096 //Roo.log(prevStart);
13098 var today = new Date().clearTime().getTime();
13099 var sel = date.clearTime().getTime();
13100 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13101 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13102 var ddMatch = this.disabledDatesRE;
13103 var ddText = this.disabledDatesText;
13104 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13105 var ddaysText = this.disabledDaysText;
13106 var format = this.format;
13108 var setCellClass = function(cal, cell){
13112 //Roo.log('set Cell Class');
13114 var t = d.getTime();
13118 cell.dateValue = t;
13120 cell.className += " fc-today";
13121 cell.className += " fc-state-highlight";
13122 cell.title = cal.todayText;
13125 // disable highlight in other month..
13126 //cell.className += " fc-state-highlight";
13131 cell.className = " fc-state-disabled";
13132 cell.title = cal.minText;
13136 cell.className = " fc-state-disabled";
13137 cell.title = cal.maxText;
13141 if(ddays.indexOf(d.getDay()) != -1){
13142 cell.title = ddaysText;
13143 cell.className = " fc-state-disabled";
13146 if(ddMatch && format){
13147 var fvalue = d.dateFormat(format);
13148 if(ddMatch.test(fvalue)){
13149 cell.title = ddText.replace("%0", fvalue);
13150 cell.className = " fc-state-disabled";
13154 if (!cell.initialClassName) {
13155 cell.initialClassName = cell.dom.className;
13158 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13163 for(; i < startingPos; i++) {
13164 textEls[i].innerHTML = (++prevStart);
13165 d.setDate(d.getDate()+1);
13167 cells[i].className = "fc-past fc-other-month";
13168 setCellClass(this, cells[i]);
13173 for(; i < days; i++){
13174 intDay = i - startingPos + 1;
13175 textEls[i].innerHTML = (intDay);
13176 d.setDate(d.getDate()+1);
13178 cells[i].className = ''; // "x-date-active";
13179 setCellClass(this, cells[i]);
13183 for(; i < 42; i++) {
13184 textEls[i].innerHTML = (++extraDays);
13185 d.setDate(d.getDate()+1);
13187 cells[i].className = "fc-future fc-other-month";
13188 setCellClass(this, cells[i]);
13191 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13193 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13195 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13196 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13198 if(totalRows != 6){
13199 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13200 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13203 this.fireEvent('monthchange', this, date);
13207 if(!this.internalRender){
13208 var main = this.el.dom.firstChild;
13209 var w = main.offsetWidth;
13210 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13211 Roo.fly(main).setWidth(w);
13212 this.internalRender = true;
13213 // opera does not respect the auto grow header center column
13214 // then, after it gets a width opera refuses to recalculate
13215 // without a second pass
13216 if(Roo.isOpera && !this.secondPass){
13217 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13218 this.secondPass = true;
13219 this.update.defer(10, this, [date]);
13226 findCell : function(dt) {
13227 dt = dt.clearTime().getTime();
13229 this.cells.each(function(c){
13230 //Roo.log("check " +c.dateValue + '?=' + dt);
13231 if(c.dateValue == dt){
13241 findCells : function(ev) {
13242 var s = ev.start.clone().clearTime().getTime();
13244 var e= ev.end.clone().clearTime().getTime();
13247 this.cells.each(function(c){
13248 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13250 if(c.dateValue > e){
13253 if(c.dateValue < s){
13262 // findBestRow: function(cells)
13266 // for (var i =0 ; i < cells.length;i++) {
13267 // ret = Math.max(cells[i].rows || 0,ret);
13274 addItem : function(ev)
13276 // look for vertical location slot in
13277 var cells = this.findCells(ev);
13279 // ev.row = this.findBestRow(cells);
13281 // work out the location.
13285 for(var i =0; i < cells.length; i++) {
13287 cells[i].row = cells[0].row;
13290 cells[i].row = cells[i].row + 1;
13300 if (crow.start.getY() == cells[i].getY()) {
13302 crow.end = cells[i];
13319 cells[0].events.push(ev);
13321 this.calevents.push(ev);
13324 clearEvents: function() {
13326 if(!this.calevents){
13330 Roo.each(this.cells.elements, function(c){
13336 Roo.each(this.calevents, function(e) {
13337 Roo.each(e.els, function(el) {
13338 el.un('mouseenter' ,this.onEventEnter, this);
13339 el.un('mouseleave' ,this.onEventLeave, this);
13344 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13350 renderEvents: function()
13354 this.cells.each(function(c) {
13363 if(c.row != c.events.length){
13364 r = 4 - (4 - (c.row - c.events.length));
13367 c.events = ev.slice(0, r);
13368 c.more = ev.slice(r);
13370 if(c.more.length && c.more.length == 1){
13371 c.events.push(c.more.pop());
13374 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13378 this.cells.each(function(c) {
13380 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13383 for (var e = 0; e < c.events.length; e++){
13384 var ev = c.events[e];
13385 var rows = ev.rows;
13387 for(var i = 0; i < rows.length; i++) {
13389 // how many rows should it span..
13392 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13393 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13395 unselectable : "on",
13398 cls: 'fc-event-inner',
13402 // cls: 'fc-event-time',
13403 // html : cells.length > 1 ? '' : ev.time
13407 cls: 'fc-event-title',
13408 html : String.format('{0}', ev.title)
13415 cls: 'ui-resizable-handle ui-resizable-e',
13416 html : '  '
13423 cfg.cls += ' fc-event-start';
13425 if ((i+1) == rows.length) {
13426 cfg.cls += ' fc-event-end';
13429 var ctr = _this.el.select('.fc-event-container',true).first();
13430 var cg = ctr.createChild(cfg);
13432 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13433 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13435 var r = (c.more.length) ? 1 : 0;
13436 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13437 cg.setWidth(ebox.right - sbox.x -2);
13439 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13440 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13441 cg.on('click', _this.onEventClick, _this, ev);
13452 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13453 style : 'position: absolute',
13454 unselectable : "on",
13457 cls: 'fc-event-inner',
13461 cls: 'fc-event-title',
13469 cls: 'ui-resizable-handle ui-resizable-e',
13470 html : '  '
13476 var ctr = _this.el.select('.fc-event-container',true).first();
13477 var cg = ctr.createChild(cfg);
13479 var sbox = c.select('.fc-day-content',true).first().getBox();
13480 var ebox = c.select('.fc-day-content',true).first().getBox();
13482 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13483 cg.setWidth(ebox.right - sbox.x -2);
13485 cg.on('click', _this.onMoreEventClick, _this, c.more);
13495 onEventEnter: function (e, el,event,d) {
13496 this.fireEvent('evententer', this, el, event);
13499 onEventLeave: function (e, el,event,d) {
13500 this.fireEvent('eventleave', this, el, event);
13503 onEventClick: function (e, el,event,d) {
13504 this.fireEvent('eventclick', this, el, event);
13507 onMonthChange: function () {
13511 onMoreEventClick: function(e, el, more)
13515 this.calpopover.placement = 'right';
13516 this.calpopover.setTitle('More');
13518 this.calpopover.setContent('');
13520 var ctr = this.calpopover.el.select('.popover-content', true).first();
13522 Roo.each(more, function(m){
13524 cls : 'fc-event-hori fc-event-draggable',
13527 var cg = ctr.createChild(cfg);
13529 cg.on('click', _this.onEventClick, _this, m);
13532 this.calpopover.show(el);
13537 onLoad: function ()
13539 this.calevents = [];
13542 if(this.store.getCount() > 0){
13543 this.store.data.each(function(d){
13546 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13547 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13548 time : d.data.start_time,
13549 title : d.data.title,
13550 description : d.data.description,
13551 venue : d.data.venue
13556 this.renderEvents();
13558 if(this.calevents.length && this.loadMask){
13559 this.maskEl.hide();
13563 onBeforeLoad: function()
13565 this.clearEvents();
13567 this.maskEl.show();
13581 * @class Roo.bootstrap.Popover
13582 * @extends Roo.bootstrap.Component
13583 * Bootstrap Popover class
13584 * @cfg {String} html contents of the popover (or false to use children..)
13585 * @cfg {String} title of popover (or false to hide)
13586 * @cfg {String} placement how it is placed
13587 * @cfg {String} trigger click || hover (or false to trigger manually)
13588 * @cfg {String} over what (parent or false to trigger manually.)
13591 * Create a new Popover
13592 * @param {Object} config The config object
13595 Roo.bootstrap.Popover = function(config){
13596 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13599 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13601 title: 'Fill in a title',
13604 placement : 'right',
13605 trigger : 'hover', // hover
13609 can_build_overlaid : false,
13611 getChildContainer : function()
13613 return this.el.select('.popover-content',true).first();
13616 getAutoCreate : function(){
13617 Roo.log('make popover?');
13619 cls : 'popover roo-dynamic',
13620 style: 'display:block',
13626 cls : 'popover-inner',
13630 cls: 'popover-title',
13634 cls : 'popover-content',
13645 setTitle: function(str)
13647 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13649 setContent: function(str)
13651 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13653 // as it get's added to the bottom of the page.
13654 onRender : function(ct, position)
13656 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13658 var cfg = Roo.apply({}, this.getAutoCreate());
13662 cfg.cls += ' ' + this.cls;
13665 cfg.style = this.style;
13667 Roo.log("adding to ")
13668 this.el = Roo.get(document.body).createChild(cfg, position);
13674 initEvents : function()
13676 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13677 this.el.enableDisplayMode('block');
13679 if (this.over === false) {
13682 if (this.triggers === false) {
13685 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13686 var triggers = this.trigger ? this.trigger.split(' ') : [];
13687 Roo.each(triggers, function(trigger) {
13689 if (trigger == 'click') {
13690 on_el.on('click', this.toggle, this);
13691 } else if (trigger != 'manual') {
13692 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13693 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13695 on_el.on(eventIn ,this.enter, this);
13696 on_el.on(eventOut, this.leave, this);
13707 toggle : function () {
13708 this.hoverState == 'in' ? this.leave() : this.enter();
13711 enter : function () {
13714 clearTimeout(this.timeout);
13716 this.hoverState = 'in'
13718 if (!this.delay || !this.delay.show) {
13723 this.timeout = setTimeout(function () {
13724 if (_t.hoverState == 'in') {
13727 }, this.delay.show)
13729 leave : function() {
13730 clearTimeout(this.timeout);
13732 this.hoverState = 'out'
13734 if (!this.delay || !this.delay.hide) {
13739 this.timeout = setTimeout(function () {
13740 if (_t.hoverState == 'out') {
13743 }, this.delay.hide)
13746 show : function (on_el)
13749 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13752 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13753 if (this.html !== false) {
13754 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13756 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13757 if (!this.title.length) {
13758 this.el.select('.popover-title',true).hide();
13761 var placement = typeof this.placement == 'function' ?
13762 this.placement.call(this, this.el, on_el) :
13765 var autoToken = /\s?auto?\s?/i;
13766 var autoPlace = autoToken.test(placement);
13768 placement = placement.replace(autoToken, '') || 'top';
13772 //this.el.setXY([0,0]);
13774 this.el.dom.style.display='block';
13775 this.el.addClass(placement);
13777 //this.el.appendTo(on_el);
13779 var p = this.getPosition();
13780 var box = this.el.getBox();
13785 var align = Roo.bootstrap.Popover.alignment[placement]
13786 this.el.alignTo(on_el, align[0],align[1]);
13787 //var arrow = this.el.select('.arrow',true).first();
13788 //arrow.set(align[2],
13790 this.el.addClass('in');
13791 this.hoverState = null;
13793 if (this.el.hasClass('fade')) {
13800 this.el.setXY([0,0]);
13801 this.el.removeClass('in');
13808 Roo.bootstrap.Popover.alignment = {
13809 'left' : ['r-l', [-10,0], 'right'],
13810 'right' : ['l-r', [10,0], 'left'],
13811 'bottom' : ['t-b', [0,10], 'top'],
13812 'top' : [ 'b-t', [0,-10], 'bottom']
13823 * @class Roo.bootstrap.Progress
13824 * @extends Roo.bootstrap.Component
13825 * Bootstrap Progress class
13826 * @cfg {Boolean} striped striped of the progress bar
13827 * @cfg {Boolean} active animated of the progress bar
13831 * Create a new Progress
13832 * @param {Object} config The config object
13835 Roo.bootstrap.Progress = function(config){
13836 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13839 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13844 getAutoCreate : function(){
13852 cfg.cls += ' progress-striped';
13856 cfg.cls += ' active';
13875 * @class Roo.bootstrap.ProgressBar
13876 * @extends Roo.bootstrap.Component
13877 * Bootstrap ProgressBar class
13878 * @cfg {Number} aria_valuenow aria-value now
13879 * @cfg {Number} aria_valuemin aria-value min
13880 * @cfg {Number} aria_valuemax aria-value max
13881 * @cfg {String} label label for the progress bar
13882 * @cfg {String} panel (success | info | warning | danger )
13883 * @cfg {String} role role of the progress bar
13884 * @cfg {String} sr_only text
13888 * Create a new ProgressBar
13889 * @param {Object} config The config object
13892 Roo.bootstrap.ProgressBar = function(config){
13893 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13896 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13900 aria_valuemax : 100,
13906 getAutoCreate : function()
13911 cls: 'progress-bar',
13912 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13924 cfg.role = this.role;
13927 if(this.aria_valuenow){
13928 cfg['aria-valuenow'] = this.aria_valuenow;
13931 if(this.aria_valuemin){
13932 cfg['aria-valuemin'] = this.aria_valuemin;
13935 if(this.aria_valuemax){
13936 cfg['aria-valuemax'] = this.aria_valuemax;
13939 if(this.label && !this.sr_only){
13940 cfg.html = this.label;
13944 cfg.cls += ' progress-bar-' + this.panel;
13950 update : function(aria_valuenow)
13952 this.aria_valuenow = aria_valuenow;
13954 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13969 * @class Roo.bootstrap.TabGroup
13970 * @extends Roo.bootstrap.Column
13971 * Bootstrap Column class
13972 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13973 * @cfg {Boolean} carousel true to make the group behave like a carousel
13976 * Create a new TabGroup
13977 * @param {Object} config The config object
13980 Roo.bootstrap.TabGroup = function(config){
13981 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13983 this.navId = Roo.id();
13986 Roo.bootstrap.TabGroup.register(this);
13990 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13993 transition : false,
13995 getAutoCreate : function()
13997 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13999 cfg.cls += ' tab-content';
14001 if (this.carousel) {
14002 cfg.cls += ' carousel slide';
14004 cls : 'carousel-inner'
14011 getChildContainer : function()
14013 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14017 * register a Navigation item
14018 * @param {Roo.bootstrap.NavItem} the navitem to add
14020 register : function(item)
14022 this.tabs.push( item);
14023 item.navId = this.navId; // not really needed..
14027 getActivePanel : function()
14030 Roo.each(this.tabs, function(t) {
14040 getPanelByName : function(n)
14043 Roo.each(this.tabs, function(t) {
14044 if (t.tabId == n) {
14052 indexOfPanel : function(p)
14055 Roo.each(this.tabs, function(t,i) {
14056 if (t.tabId == p.tabId) {
14065 * show a specific panel
14066 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14067 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14069 showPanel : function (pan)
14072 if (typeof(pan) == 'number') {
14073 pan = this.tabs[pan];
14075 if (typeof(pan) == 'string') {
14076 pan = this.getPanelByName(pan);
14078 if (pan.tabId == this.getActivePanel().tabId) {
14081 var cur = this.getActivePanel();
14083 if (false === cur.fireEvent('beforedeactivate')) {
14087 if (this.carousel) {
14088 this.transition = true;
14089 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14090 var lr = dir == 'next' ? 'left' : 'right';
14091 pan.el.addClass(dir); // or prev
14092 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14093 cur.el.addClass(lr); // or right
14094 pan.el.addClass(lr);
14097 cur.el.on('transitionend', function() {
14098 Roo.log("trans end?");
14100 pan.el.removeClass([lr,dir]);
14101 pan.setActive(true);
14103 cur.el.removeClass([lr]);
14104 cur.setActive(false);
14106 _this.transition = false;
14108 }, this, { single: true } );
14112 cur.setActive(false);
14113 pan.setActive(true);
14117 showPanelNext : function()
14119 var i = this.indexOfPanel(this.getActivePanel());
14120 if (i > this.tabs.length) {
14123 this.showPanel(this.tabs[i+1]);
14125 showPanelPrev : function()
14127 var i = this.indexOfPanel(this.getActivePanel());
14131 this.showPanel(this.tabs[i-1]);
14142 Roo.apply(Roo.bootstrap.TabGroup, {
14146 * register a Navigation Group
14147 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14149 register : function(navgrp)
14151 this.groups[navgrp.navId] = navgrp;
14155 * fetch a Navigation Group based on the navigation ID
14156 * if one does not exist , it will get created.
14157 * @param {string} the navgroup to add
14158 * @returns {Roo.bootstrap.NavGroup} the navgroup
14160 get: function(navId) {
14161 if (typeof(this.groups[navId]) == 'undefined') {
14162 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14164 return this.groups[navId] ;
14179 * @class Roo.bootstrap.TabPanel
14180 * @extends Roo.bootstrap.Component
14181 * Bootstrap TabPanel class
14182 * @cfg {Boolean} active panel active
14183 * @cfg {String} html panel content
14184 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14185 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14189 * Create a new TabPanel
14190 * @param {Object} config The config object
14193 Roo.bootstrap.TabPanel = function(config){
14194 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14198 * Fires when the active status changes
14199 * @param {Roo.bootstrap.TabPanel} this
14200 * @param {Boolean} state the new state
14205 * @event beforedeactivate
14206 * Fires before a tab is de-activated - can be used to do validation on a form.
14207 * @param {Roo.bootstrap.TabPanel} this
14208 * @return {Boolean} false if there is an error
14211 'beforedeactivate': true
14214 this.tabId = this.tabId || Roo.id();
14218 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14225 getAutoCreate : function(){
14228 // item is needed for carousel - not sure if it has any effect otherwise
14229 cls: 'tab-pane item',
14230 html: this.html || ''
14234 cfg.cls += ' active';
14238 cfg.tabId = this.tabId;
14245 initEvents: function()
14247 Roo.log('-------- init events on tab panel ---------');
14249 var p = this.parent();
14250 this.navId = this.navId || p.navId;
14252 if (typeof(this.navId) != 'undefined') {
14253 // not really needed.. but just in case.. parent should be a NavGroup.
14254 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14255 Roo.log(['register', tg, this]);
14261 onRender : function(ct, position)
14263 // Roo.log("Call onRender: " + this.xtype);
14265 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14273 setActive: function(state)
14275 Roo.log("panel - set active " + this.tabId + "=" + state);
14277 this.active = state;
14279 this.el.removeClass('active');
14281 } else if (!this.el.hasClass('active')) {
14282 this.el.addClass('active');
14284 this.fireEvent('changed', this, state);
14301 * @class Roo.bootstrap.DateField
14302 * @extends Roo.bootstrap.Input
14303 * Bootstrap DateField class
14304 * @cfg {Number} weekStart default 0
14305 * @cfg {Number} weekStart default 0
14306 * @cfg {Number} viewMode default empty, (months|years)
14307 * @cfg {Number} minViewMode default empty, (months|years)
14308 * @cfg {Number} startDate default -Infinity
14309 * @cfg {Number} endDate default Infinity
14310 * @cfg {Boolean} todayHighlight default false
14311 * @cfg {Boolean} todayBtn default false
14312 * @cfg {Boolean} calendarWeeks default false
14313 * @cfg {Object} daysOfWeekDisabled default empty
14315 * @cfg {Boolean} keyboardNavigation default true
14316 * @cfg {String} language default en
14319 * Create a new DateField
14320 * @param {Object} config The config object
14323 Roo.bootstrap.DateField = function(config){
14324 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14328 * Fires when this field show.
14329 * @param {Roo.bootstrap.DateField} this
14330 * @param {Mixed} date The date value
14335 * Fires when this field hide.
14336 * @param {Roo.bootstrap.DateField} this
14337 * @param {Mixed} date The date value
14342 * Fires when select a date.
14343 * @param {Roo.bootstrap.DateField} this
14344 * @param {Mixed} date The date value
14350 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14353 * @cfg {String} format
14354 * The default date format string which can be overriden for localization support. The format must be
14355 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14359 * @cfg {String} altFormats
14360 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14361 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14363 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14371 todayHighlight : false,
14377 keyboardNavigation: true,
14379 calendarWeeks: false,
14381 startDate: -Infinity,
14385 daysOfWeekDisabled: [],
14389 UTCDate: function()
14391 return new Date(Date.UTC.apply(Date, arguments));
14394 UTCToday: function()
14396 var today = new Date();
14397 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14400 getDate: function() {
14401 var d = this.getUTCDate();
14402 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14405 getUTCDate: function() {
14409 setDate: function(d) {
14410 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14413 setUTCDate: function(d) {
14415 this.setValue(this.formatDate(this.date));
14418 onRender: function(ct, position)
14421 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14423 this.language = this.language || 'en';
14424 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14425 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14427 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14428 this.format = this.format || 'm/d/y';
14429 this.isInline = false;
14430 this.isInput = true;
14431 this.component = this.el.select('.add-on', true).first() || false;
14432 this.component = (this.component && this.component.length === 0) ? false : this.component;
14433 this.hasInput = this.component && this.inputEL().length;
14435 if (typeof(this.minViewMode === 'string')) {
14436 switch (this.minViewMode) {
14438 this.minViewMode = 1;
14441 this.minViewMode = 2;
14444 this.minViewMode = 0;
14449 if (typeof(this.viewMode === 'string')) {
14450 switch (this.viewMode) {
14463 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14465 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14467 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14469 this.picker().on('mousedown', this.onMousedown, this);
14470 this.picker().on('click', this.onClick, this);
14472 this.picker().addClass('datepicker-dropdown');
14474 this.startViewMode = this.viewMode;
14477 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14478 if(!this.calendarWeeks){
14483 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14484 v.attr('colspan', function(i, val){
14485 return parseInt(val) + 1;
14490 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14492 this.setStartDate(this.startDate);
14493 this.setEndDate(this.endDate);
14495 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14502 if(this.isInline) {
14507 picker : function()
14509 return this.pickerEl;
14510 // return this.el.select('.datepicker', true).first();
14513 fillDow: function()
14515 var dowCnt = this.weekStart;
14524 if(this.calendarWeeks){
14532 while (dowCnt < this.weekStart + 7) {
14536 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14540 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14543 fillMonths: function()
14546 var months = this.picker().select('>.datepicker-months td', true).first();
14548 months.dom.innerHTML = '';
14554 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14557 months.createChild(month);
14564 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;
14566 if (this.date < this.startDate) {
14567 this.viewDate = new Date(this.startDate);
14568 } else if (this.date > this.endDate) {
14569 this.viewDate = new Date(this.endDate);
14571 this.viewDate = new Date(this.date);
14579 var d = new Date(this.viewDate),
14580 year = d.getUTCFullYear(),
14581 month = d.getUTCMonth(),
14582 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14583 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14584 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14585 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14586 currentDate = this.date && this.date.valueOf(),
14587 today = this.UTCToday();
14589 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14591 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14593 // this.picker.select('>tfoot th.today').
14594 // .text(dates[this.language].today)
14595 // .toggle(this.todayBtn !== false);
14597 this.updateNavArrows();
14600 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14602 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14604 prevMonth.setUTCDate(day);
14606 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14608 var nextMonth = new Date(prevMonth);
14610 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14612 nextMonth = nextMonth.valueOf();
14614 var fillMonths = false;
14616 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14618 while(prevMonth.valueOf() < nextMonth) {
14621 if (prevMonth.getUTCDay() === this.weekStart) {
14623 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14631 if(this.calendarWeeks){
14632 // ISO 8601: First week contains first thursday.
14633 // ISO also states week starts on Monday, but we can be more abstract here.
14635 // Start of current week: based on weekstart/current date
14636 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14637 // Thursday of this week
14638 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14639 // First Thursday of year, year from thursday
14640 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14641 // Calendar week: ms between thursdays, div ms per day, div 7 days
14642 calWeek = (th - yth) / 864e5 / 7 + 1;
14644 fillMonths.cn.push({
14652 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14654 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14657 if (this.todayHighlight &&
14658 prevMonth.getUTCFullYear() == today.getFullYear() &&
14659 prevMonth.getUTCMonth() == today.getMonth() &&
14660 prevMonth.getUTCDate() == today.getDate()) {
14661 clsName += ' today';
14664 if (currentDate && prevMonth.valueOf() === currentDate) {
14665 clsName += ' active';
14668 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14669 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14670 clsName += ' disabled';
14673 fillMonths.cn.push({
14675 cls: 'day ' + clsName,
14676 html: prevMonth.getDate()
14679 prevMonth.setDate(prevMonth.getDate()+1);
14682 var currentYear = this.date && this.date.getUTCFullYear();
14683 var currentMonth = this.date && this.date.getUTCMonth();
14685 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14687 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14688 v.removeClass('active');
14690 if(currentYear === year && k === currentMonth){
14691 v.addClass('active');
14694 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14695 v.addClass('disabled');
14701 year = parseInt(year/10, 10) * 10;
14703 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14705 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14708 for (var i = -1; i < 11; i++) {
14709 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14711 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14719 showMode: function(dir)
14722 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14724 Roo.each(this.picker().select('>div',true).elements, function(v){
14725 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14728 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14733 if(this.isInline) return;
14735 this.picker().removeClass(['bottom', 'top']);
14737 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14739 * place to the top of element!
14743 this.picker().addClass('top');
14744 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14749 this.picker().addClass('bottom');
14751 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14754 parseDate : function(value)
14756 if(!value || value instanceof Date){
14759 var v = Date.parseDate(value, this.format);
14760 if (!v && this.useIso) {
14761 v = Date.parseDate(value, 'Y-m-d');
14763 if(!v && this.altFormats){
14764 if(!this.altFormatsArray){
14765 this.altFormatsArray = this.altFormats.split("|");
14767 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14768 v = Date.parseDate(value, this.altFormatsArray[i]);
14774 formatDate : function(date, fmt)
14776 return (!date || !(date instanceof Date)) ?
14777 date : date.dateFormat(fmt || this.format);
14780 onFocus : function()
14782 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14786 onBlur : function()
14788 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14790 var d = this.inputEl().getValue();
14799 this.picker().show();
14803 this.fireEvent('show', this, this.date);
14808 if(this.isInline) return;
14809 this.picker().hide();
14810 this.viewMode = this.startViewMode;
14813 this.fireEvent('hide', this, this.date);
14817 onMousedown: function(e)
14819 e.stopPropagation();
14820 e.preventDefault();
14825 Roo.bootstrap.DateField.superclass.keyup.call(this);
14829 setValue: function(v)
14831 var d = new Date(v).clearTime();
14833 if(isNaN(d.getTime())){
14834 this.date = this.viewDate = '';
14835 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14839 v = this.formatDate(d);
14841 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14843 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14847 this.fireEvent('select', this, this.date);
14851 getValue: function()
14853 return this.formatDate(this.date);
14856 fireKey: function(e)
14858 if (!this.picker().isVisible()){
14859 if (e.keyCode == 27) // allow escape to hide and re-show picker
14864 var dateChanged = false,
14866 newDate, newViewDate;
14871 e.preventDefault();
14875 if (!this.keyboardNavigation) break;
14876 dir = e.keyCode == 37 ? -1 : 1;
14879 newDate = this.moveYear(this.date, dir);
14880 newViewDate = this.moveYear(this.viewDate, dir);
14881 } else if (e.shiftKey){
14882 newDate = this.moveMonth(this.date, dir);
14883 newViewDate = this.moveMonth(this.viewDate, dir);
14885 newDate = new Date(this.date);
14886 newDate.setUTCDate(this.date.getUTCDate() + dir);
14887 newViewDate = new Date(this.viewDate);
14888 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14890 if (this.dateWithinRange(newDate)){
14891 this.date = newDate;
14892 this.viewDate = newViewDate;
14893 this.setValue(this.formatDate(this.date));
14895 e.preventDefault();
14896 dateChanged = true;
14901 if (!this.keyboardNavigation) break;
14902 dir = e.keyCode == 38 ? -1 : 1;
14904 newDate = this.moveYear(this.date, dir);
14905 newViewDate = this.moveYear(this.viewDate, dir);
14906 } else if (e.shiftKey){
14907 newDate = this.moveMonth(this.date, dir);
14908 newViewDate = this.moveMonth(this.viewDate, dir);
14910 newDate = new Date(this.date);
14911 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14912 newViewDate = new Date(this.viewDate);
14913 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14915 if (this.dateWithinRange(newDate)){
14916 this.date = newDate;
14917 this.viewDate = newViewDate;
14918 this.setValue(this.formatDate(this.date));
14920 e.preventDefault();
14921 dateChanged = true;
14925 this.setValue(this.formatDate(this.date));
14927 e.preventDefault();
14930 this.setValue(this.formatDate(this.date));
14944 onClick: function(e)
14946 e.stopPropagation();
14947 e.preventDefault();
14949 var target = e.getTarget();
14951 if(target.nodeName.toLowerCase() === 'i'){
14952 target = Roo.get(target).dom.parentNode;
14955 var nodeName = target.nodeName;
14956 var className = target.className;
14957 var html = target.innerHTML;
14959 switch(nodeName.toLowerCase()) {
14961 switch(className) {
14967 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14968 switch(this.viewMode){
14970 this.viewDate = this.moveMonth(this.viewDate, dir);
14974 this.viewDate = this.moveYear(this.viewDate, dir);
14980 var date = new Date();
14981 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14983 this.setValue(this.formatDate(this.date));
14990 if (className.indexOf('disabled') === -1) {
14991 this.viewDate.setUTCDate(1);
14992 if (className.indexOf('month') !== -1) {
14993 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14995 var year = parseInt(html, 10) || 0;
14996 this.viewDate.setUTCFullYear(year);
15005 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
15006 var day = parseInt(html, 10) || 1;
15007 var year = this.viewDate.getUTCFullYear(),
15008 month = this.viewDate.getUTCMonth();
15010 if (className.indexOf('old') !== -1) {
15017 } else if (className.indexOf('new') !== -1) {
15025 this.date = this.UTCDate(year, month, day,0,0,0,0);
15026 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15028 this.setValue(this.formatDate(this.date));
15035 setStartDate: function(startDate)
15037 this.startDate = startDate || -Infinity;
15038 if (this.startDate !== -Infinity) {
15039 this.startDate = this.parseDate(this.startDate);
15042 this.updateNavArrows();
15045 setEndDate: function(endDate)
15047 this.endDate = endDate || Infinity;
15048 if (this.endDate !== Infinity) {
15049 this.endDate = this.parseDate(this.endDate);
15052 this.updateNavArrows();
15055 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15057 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15058 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15059 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15061 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15062 return parseInt(d, 10);
15065 this.updateNavArrows();
15068 updateNavArrows: function()
15070 var d = new Date(this.viewDate),
15071 year = d.getUTCFullYear(),
15072 month = d.getUTCMonth();
15074 Roo.each(this.picker().select('.prev', true).elements, function(v){
15076 switch (this.viewMode) {
15079 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15085 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15092 Roo.each(this.picker().select('.next', true).elements, function(v){
15094 switch (this.viewMode) {
15097 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15103 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15111 moveMonth: function(date, dir)
15113 if (!dir) return date;
15114 var new_date = new Date(date.valueOf()),
15115 day = new_date.getUTCDate(),
15116 month = new_date.getUTCMonth(),
15117 mag = Math.abs(dir),
15119 dir = dir > 0 ? 1 : -1;
15122 // If going back one month, make sure month is not current month
15123 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15125 return new_date.getUTCMonth() == month;
15127 // If going forward one month, make sure month is as expected
15128 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15130 return new_date.getUTCMonth() != new_month;
15132 new_month = month + dir;
15133 new_date.setUTCMonth(new_month);
15134 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15135 if (new_month < 0 || new_month > 11)
15136 new_month = (new_month + 12) % 12;
15138 // For magnitudes >1, move one month at a time...
15139 for (var i=0; i<mag; i++)
15140 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15141 new_date = this.moveMonth(new_date, dir);
15142 // ...then reset the day, keeping it in the new month
15143 new_month = new_date.getUTCMonth();
15144 new_date.setUTCDate(day);
15146 return new_month != new_date.getUTCMonth();
15149 // Common date-resetting loop -- if date is beyond end of month, make it
15152 new_date.setUTCDate(--day);
15153 new_date.setUTCMonth(new_month);
15158 moveYear: function(date, dir)
15160 return this.moveMonth(date, dir*12);
15163 dateWithinRange: function(date)
15165 return date >= this.startDate && date <= this.endDate;
15171 this.picker().remove();
15176 Roo.apply(Roo.bootstrap.DateField, {
15187 html: '<i class="fa fa-arrow-left"/>'
15197 html: '<i class="fa fa-arrow-right"/>'
15239 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15240 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15241 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15242 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15243 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15256 navFnc: 'FullYear',
15261 navFnc: 'FullYear',
15266 Roo.apply(Roo.bootstrap.DateField, {
15270 cls: 'datepicker dropdown-menu',
15274 cls: 'datepicker-days',
15278 cls: 'table-condensed',
15280 Roo.bootstrap.DateField.head,
15284 Roo.bootstrap.DateField.footer
15291 cls: 'datepicker-months',
15295 cls: 'table-condensed',
15297 Roo.bootstrap.DateField.head,
15298 Roo.bootstrap.DateField.content,
15299 Roo.bootstrap.DateField.footer
15306 cls: 'datepicker-years',
15310 cls: 'table-condensed',
15312 Roo.bootstrap.DateField.head,
15313 Roo.bootstrap.DateField.content,
15314 Roo.bootstrap.DateField.footer
15333 * @class Roo.bootstrap.TimeField
15334 * @extends Roo.bootstrap.Input
15335 * Bootstrap DateField class
15339 * Create a new TimeField
15340 * @param {Object} config The config object
15343 Roo.bootstrap.TimeField = function(config){
15344 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15348 * Fires when this field show.
15349 * @param {Roo.bootstrap.DateField} this
15350 * @param {Mixed} date The date value
15355 * Fires when this field hide.
15356 * @param {Roo.bootstrap.DateField} this
15357 * @param {Mixed} date The date value
15362 * Fires when select a date.
15363 * @param {Roo.bootstrap.DateField} this
15364 * @param {Mixed} date The date value
15370 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15373 * @cfg {String} format
15374 * The default time format string which can be overriden for localization support. The format must be
15375 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15379 onRender: function(ct, position)
15382 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15384 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15386 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15388 this.pop = this.picker().select('>.datepicker-time',true).first();
15389 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15391 this.picker().on('mousedown', this.onMousedown, this);
15392 this.picker().on('click', this.onClick, this);
15394 this.picker().addClass('datepicker-dropdown');
15399 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15400 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15401 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15402 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15403 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15404 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15408 fireKey: function(e){
15409 if (!this.picker().isVisible()){
15410 if (e.keyCode == 27) // allow escape to hide and re-show picker
15415 e.preventDefault();
15423 this.onTogglePeriod();
15426 this.onIncrementMinutes();
15429 this.onDecrementMinutes();
15438 onClick: function(e) {
15439 e.stopPropagation();
15440 e.preventDefault();
15443 picker : function()
15445 return this.el.select('.datepicker', true).first();
15448 fillTime: function()
15450 var time = this.pop.select('tbody', true).first();
15452 time.dom.innerHTML = '';
15467 cls: 'hours-up glyphicon glyphicon-chevron-up'
15487 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15508 cls: 'timepicker-hour',
15523 cls: 'timepicker-minute',
15538 cls: 'btn btn-primary period',
15560 cls: 'hours-down glyphicon glyphicon-chevron-down'
15580 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15598 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15605 var hours = this.time.getHours();
15606 var minutes = this.time.getMinutes();
15619 hours = hours - 12;
15623 hours = '0' + hours;
15627 minutes = '0' + minutes;
15630 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15631 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15632 this.pop.select('button', true).first().dom.innerHTML = period;
15638 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15640 var cls = ['bottom'];
15642 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15649 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15654 this.picker().addClass(cls.join('-'));
15658 Roo.each(cls, function(c){
15660 _this.picker().setTop(_this.inputEl().getHeight());
15664 _this.picker().setTop(0 - _this.picker().getHeight());
15669 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15673 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15680 onFocus : function()
15682 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15686 onBlur : function()
15688 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15694 this.picker().show();
15699 this.fireEvent('show', this, this.date);
15704 this.picker().hide();
15707 this.fireEvent('hide', this, this.date);
15710 setTime : function()
15713 this.setValue(this.time.format(this.format));
15715 this.fireEvent('select', this, this.date);
15720 onMousedown: function(e){
15721 e.stopPropagation();
15722 e.preventDefault();
15725 onIncrementHours: function()
15727 Roo.log('onIncrementHours');
15728 this.time = this.time.add(Date.HOUR, 1);
15733 onDecrementHours: function()
15735 Roo.log('onDecrementHours');
15736 this.time = this.time.add(Date.HOUR, -1);
15740 onIncrementMinutes: function()
15742 Roo.log('onIncrementMinutes');
15743 this.time = this.time.add(Date.MINUTE, 1);
15747 onDecrementMinutes: function()
15749 Roo.log('onDecrementMinutes');
15750 this.time = this.time.add(Date.MINUTE, -1);
15754 onTogglePeriod: function()
15756 Roo.log('onTogglePeriod');
15757 this.time = this.time.add(Date.HOUR, 12);
15764 Roo.apply(Roo.bootstrap.TimeField, {
15794 cls: 'btn btn-info ok',
15806 Roo.apply(Roo.bootstrap.TimeField, {
15810 cls: 'datepicker dropdown-menu',
15814 cls: 'datepicker-time',
15818 cls: 'table-condensed',
15820 Roo.bootstrap.TimeField.content,
15821 Roo.bootstrap.TimeField.footer
15840 * @class Roo.bootstrap.CheckBox
15841 * @extends Roo.bootstrap.Input
15842 * Bootstrap CheckBox class
15844 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15845 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15846 * @cfg {String} boxLabel The text that appears beside the checkbox
15847 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15848 * @cfg {Boolean} checked initnal the element
15852 * Create a new CheckBox
15853 * @param {Object} config The config object
15856 Roo.bootstrap.CheckBox = function(config){
15857 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15862 * Fires when the element is checked or unchecked.
15863 * @param {Roo.bootstrap.CheckBox} this This input
15864 * @param {Boolean} checked The new checked value
15870 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15872 inputType: 'checkbox',
15879 getAutoCreate : function()
15881 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15887 cfg.cls = 'form-group checkbox' //input-group
15895 type : this.inputType,
15896 value : (!this.checked) ? this.valueOff : this.inputValue,
15897 cls : 'roo-checkbox', //'form-box',
15898 placeholder : this.placeholder || ''
15902 if (this.weight) { // Validity check?
15903 cfg.cls += " checkbox-" + this.weight;
15906 if (this.disabled) {
15907 input.disabled=true;
15911 input.checked = this.checked;
15915 input.name = this.name;
15919 input.cls += ' input-' + this.size;
15923 ['xs','sm','md','lg'].map(function(size){
15924 if (settings[size]) {
15925 cfg.cls += ' col-' + size + '-' + settings[size];
15931 var inputblock = input;
15936 if (this.before || this.after) {
15939 cls : 'input-group',
15943 inputblock.cn.push({
15945 cls : 'input-group-addon',
15949 inputblock.cn.push(input);
15951 inputblock.cn.push({
15953 cls : 'input-group-addon',
15960 if (align ==='left' && this.fieldLabel.length) {
15961 Roo.log("left and has label");
15967 cls : 'control-label col-md-' + this.labelWidth,
15968 html : this.fieldLabel
15972 cls : "col-md-" + (12 - this.labelWidth),
15979 } else if ( this.fieldLabel.length) {
15984 tag: this.boxLabel ? 'span' : 'label',
15986 cls: 'control-label box-input-label',
15987 //cls : 'input-group-addon',
15988 html : this.fieldLabel
15998 Roo.log(" no label && no align");
15999 cfg.cn = [ inputblock ] ;
16008 html: this.boxLabel
16020 * return the real input element.
16022 inputEl: function ()
16024 return this.el.select('input.roo-checkbox',true).first();
16029 return this.el.select('label.control-label',true).first();
16032 initEvents : function()
16034 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16036 this.inputEl().on('click', this.onClick, this);
16040 onClick : function()
16042 this.setChecked(!this.checked);
16045 setChecked : function(state,suppressEvent)
16047 this.checked = state;
16049 this.inputEl().dom.checked = state;
16051 if(suppressEvent !== true){
16052 this.fireEvent('check', this, state);
16055 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16059 setValue : function(v,suppressEvent)
16061 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16075 * @class Roo.bootstrap.Radio
16076 * @extends Roo.bootstrap.CheckBox
16077 * Bootstrap Radio class
16080 * Create a new Radio
16081 * @param {Object} config The config object
16084 Roo.bootstrap.Radio = function(config){
16085 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16089 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16091 inputType: 'radio',
16095 getAutoCreate : function()
16097 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16103 cfg.cls = 'form-group radio' //input-group
16108 type : this.inputType,
16109 value : (!this.checked) ? this.valueOff : this.inputValue,
16111 placeholder : this.placeholder || ''
16114 if (this.weight) { // Validity check?
16115 cfg.cls += " radio-" + this.weight;
16117 if (this.disabled) {
16118 input.disabled=true;
16122 input.checked = this.checked;
16126 input.name = this.name;
16130 input.cls += ' input-' + this.size;
16134 ['xs','sm','md','lg'].map(function(size){
16135 if (settings[size]) {
16136 cfg.cls += ' col-' + size + '-' + settings[size];
16140 var inputblock = input;
16142 if (this.before || this.after) {
16145 cls : 'input-group',
16149 inputblock.cn.push({
16151 cls : 'input-group-addon',
16155 inputblock.cn.push(input);
16157 inputblock.cn.push({
16159 cls : 'input-group-addon',
16166 if (align ==='left' && this.fieldLabel.length) {
16167 Roo.log("left and has label");
16173 cls : 'control-label col-md-' + this.labelWidth,
16174 html : this.fieldLabel
16178 cls : "col-md-" + (12 - this.labelWidth),
16185 } else if ( this.fieldLabel.length) {
16192 cls: 'control-label box-input-label',
16193 //cls : 'input-group-addon',
16194 html : this.fieldLabel
16204 Roo.log(" no label && no align");
16219 html: this.boxLabel
16226 inputEl: function ()
16228 return this.el.select('input.roo-radio',true).first();
16230 onClick : function()
16232 this.setChecked(true);
16235 setChecked : function(state,suppressEvent)
16238 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16239 v.dom.checked = false;
16243 this.checked = state;
16244 this.inputEl().dom.checked = state;
16246 if(suppressEvent !== true){
16247 this.fireEvent('check', this, state);
16250 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16254 getGroupValue : function()
16257 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16258 if(v.dom.checked == true){
16259 value = v.dom.value;
16267 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16268 * @return {Mixed} value The field value
16270 getValue : function(){
16271 return this.getGroupValue();
16277 //<script type="text/javascript">
16280 * Based Ext JS Library 1.1.1
16281 * Copyright(c) 2006-2007, Ext JS, LLC.
16287 * @class Roo.HtmlEditorCore
16288 * @extends Roo.Component
16289 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16291 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16294 Roo.HtmlEditorCore = function(config){
16297 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16300 * @event initialize
16301 * Fires when the editor is fully initialized (including the iframe)
16302 * @param {Roo.HtmlEditorCore} this
16307 * Fires when the editor is first receives the focus. Any insertion must wait
16308 * until after this event.
16309 * @param {Roo.HtmlEditorCore} this
16313 * @event beforesync
16314 * Fires before the textarea is updated with content from the editor iframe. Return false
16315 * to cancel the sync.
16316 * @param {Roo.HtmlEditorCore} this
16317 * @param {String} html
16321 * @event beforepush
16322 * Fires before the iframe editor is updated with content from the textarea. Return false
16323 * to cancel the push.
16324 * @param {Roo.HtmlEditorCore} this
16325 * @param {String} html
16330 * Fires when the textarea is updated with content from the editor iframe.
16331 * @param {Roo.HtmlEditorCore} this
16332 * @param {String} html
16337 * Fires when the iframe editor is updated with content from the textarea.
16338 * @param {Roo.HtmlEditorCore} this
16339 * @param {String} html
16344 * @event editorevent
16345 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16346 * @param {Roo.HtmlEditorCore} this
16354 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16358 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16364 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16369 * @cfg {Number} height (in pixels)
16373 * @cfg {Number} width (in pixels)
16378 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16381 stylesheets: false,
16386 // private properties
16387 validationEvent : false,
16389 initialized : false,
16391 sourceEditMode : false,
16392 onFocus : Roo.emptyFn,
16394 hideMode:'offsets',
16402 * Protected method that will not generally be called directly. It
16403 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16404 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16406 getDocMarkup : function(){
16409 Roo.log(this.stylesheets);
16411 // inherit styels from page...??
16412 if (this.stylesheets === false) {
16414 Roo.get(document.head).select('style').each(function(node) {
16415 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16418 Roo.get(document.head).select('link').each(function(node) {
16419 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16422 } else if (!this.stylesheets.length) {
16424 st = '<style type="text/css">' +
16425 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16428 Roo.each(this.stylesheets, function(s) {
16429 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16434 st += '<style type="text/css">' +
16435 'IMG { cursor: pointer } ' +
16439 return '<html><head>' + st +
16440 //<style type="text/css">' +
16441 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16443 ' </head><body class="roo-htmleditor-body"></body></html>';
16447 onRender : function(ct, position)
16450 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16451 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16454 this.el.dom.style.border = '0 none';
16455 this.el.dom.setAttribute('tabIndex', -1);
16456 this.el.addClass('x-hidden hide');
16460 if(Roo.isIE){ // fix IE 1px bogus margin
16461 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16465 this.frameId = Roo.id();
16469 var iframe = this.owner.wrap.createChild({
16471 cls: 'form-control', // bootstrap..
16473 name: this.frameId,
16474 frameBorder : 'no',
16475 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16480 this.iframe = iframe.dom;
16482 this.assignDocWin();
16484 this.doc.designMode = 'on';
16487 this.doc.write(this.getDocMarkup());
16491 var task = { // must defer to wait for browser to be ready
16493 //console.log("run task?" + this.doc.readyState);
16494 this.assignDocWin();
16495 if(this.doc.body || this.doc.readyState == 'complete'){
16497 this.doc.designMode="on";
16501 Roo.TaskMgr.stop(task);
16502 this.initEditor.defer(10, this);
16509 Roo.TaskMgr.start(task);
16516 onResize : function(w, h)
16518 Roo.log('resize: ' +w + ',' + h );
16519 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16523 if(typeof w == 'number'){
16525 this.iframe.style.width = w + 'px';
16527 if(typeof h == 'number'){
16529 this.iframe.style.height = h + 'px';
16531 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16538 * Toggles the editor between standard and source edit mode.
16539 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16541 toggleSourceEdit : function(sourceEditMode){
16543 this.sourceEditMode = sourceEditMode === true;
16545 if(this.sourceEditMode){
16547 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16550 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16551 //this.iframe.className = '';
16554 //this.setSize(this.owner.wrap.getSize());
16555 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16562 * Protected method that will not generally be called directly. If you need/want
16563 * custom HTML cleanup, this is the method you should override.
16564 * @param {String} html The HTML to be cleaned
16565 * return {String} The cleaned HTML
16567 cleanHtml : function(html){
16568 html = String(html);
16569 if(html.length > 5){
16570 if(Roo.isSafari){ // strip safari nonsense
16571 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16574 if(html == ' '){
16581 * HTML Editor -> Textarea
16582 * Protected method that will not generally be called directly. Syncs the contents
16583 * of the editor iframe with the textarea.
16585 syncValue : function(){
16586 if(this.initialized){
16587 var bd = (this.doc.body || this.doc.documentElement);
16588 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16589 var html = bd.innerHTML;
16591 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16592 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16594 html = '<div style="'+m[0]+'">' + html + '</div>';
16597 html = this.cleanHtml(html);
16598 // fix up the special chars.. normaly like back quotes in word...
16599 // however we do not want to do this with chinese..
16600 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16601 var cc = b.charCodeAt();
16603 (cc >= 0x4E00 && cc < 0xA000 ) ||
16604 (cc >= 0x3400 && cc < 0x4E00 ) ||
16605 (cc >= 0xf900 && cc < 0xfb00 )
16611 if(this.owner.fireEvent('beforesync', this, html) !== false){
16612 this.el.dom.value = html;
16613 this.owner.fireEvent('sync', this, html);
16619 * Protected method that will not generally be called directly. Pushes the value of the textarea
16620 * into the iframe editor.
16622 pushValue : function(){
16623 if(this.initialized){
16624 var v = this.el.dom.value.trim();
16626 // if(v.length < 1){
16630 if(this.owner.fireEvent('beforepush', this, v) !== false){
16631 var d = (this.doc.body || this.doc.documentElement);
16633 this.cleanUpPaste();
16634 this.el.dom.value = d.innerHTML;
16635 this.owner.fireEvent('push', this, v);
16641 deferFocus : function(){
16642 this.focus.defer(10, this);
16646 focus : function(){
16647 if(this.win && !this.sourceEditMode){
16654 assignDocWin: function()
16656 var iframe = this.iframe;
16659 this.doc = iframe.contentWindow.document;
16660 this.win = iframe.contentWindow;
16662 // if (!Roo.get(this.frameId)) {
16665 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16666 // this.win = Roo.get(this.frameId).dom.contentWindow;
16668 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16672 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16673 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16678 initEditor : function(){
16679 //console.log("INIT EDITOR");
16680 this.assignDocWin();
16684 this.doc.designMode="on";
16686 this.doc.write(this.getDocMarkup());
16689 var dbody = (this.doc.body || this.doc.documentElement);
16690 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16691 // this copies styles from the containing element into thsi one..
16692 // not sure why we need all of this..
16693 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16695 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16696 //ss['background-attachment'] = 'fixed'; // w3c
16697 dbody.bgProperties = 'fixed'; // ie
16698 //Roo.DomHelper.applyStyles(dbody, ss);
16699 Roo.EventManager.on(this.doc, {
16700 //'mousedown': this.onEditorEvent,
16701 'mouseup': this.onEditorEvent,
16702 'dblclick': this.onEditorEvent,
16703 'click': this.onEditorEvent,
16704 'keyup': this.onEditorEvent,
16709 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16711 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16712 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16714 this.initialized = true;
16716 this.owner.fireEvent('initialize', this);
16721 onDestroy : function(){
16727 //for (var i =0; i < this.toolbars.length;i++) {
16728 // // fixme - ask toolbars for heights?
16729 // this.toolbars[i].onDestroy();
16732 //this.wrap.dom.innerHTML = '';
16733 //this.wrap.remove();
16738 onFirstFocus : function(){
16740 this.assignDocWin();
16743 this.activated = true;
16746 if(Roo.isGecko){ // prevent silly gecko errors
16748 var s = this.win.getSelection();
16749 if(!s.focusNode || s.focusNode.nodeType != 3){
16750 var r = s.getRangeAt(0);
16751 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16756 this.execCmd('useCSS', true);
16757 this.execCmd('styleWithCSS', false);
16760 this.owner.fireEvent('activate', this);
16764 adjustFont: function(btn){
16765 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16766 //if(Roo.isSafari){ // safari
16769 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16770 if(Roo.isSafari){ // safari
16771 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16772 v = (v < 10) ? 10 : v;
16773 v = (v > 48) ? 48 : v;
16774 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16779 v = Math.max(1, v+adjust);
16781 this.execCmd('FontSize', v );
16784 onEditorEvent : function(e){
16785 this.owner.fireEvent('editorevent', this, e);
16786 // this.updateToolbar();
16787 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16790 insertTag : function(tg)
16792 // could be a bit smarter... -> wrap the current selected tRoo..
16793 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16795 range = this.createRange(this.getSelection());
16796 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16797 wrappingNode.appendChild(range.extractContents());
16798 range.insertNode(wrappingNode);
16805 this.execCmd("formatblock", tg);
16809 insertText : function(txt)
16813 var range = this.createRange();
16814 range.deleteContents();
16815 //alert(Sender.getAttribute('label'));
16817 range.insertNode(this.doc.createTextNode(txt));
16823 * Executes a Midas editor command on the editor document and performs necessary focus and
16824 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16825 * @param {String} cmd The Midas command
16826 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16828 relayCmd : function(cmd, value){
16830 this.execCmd(cmd, value);
16831 this.owner.fireEvent('editorevent', this);
16832 //this.updateToolbar();
16833 this.owner.deferFocus();
16837 * Executes a Midas editor command directly on the editor document.
16838 * For visual commands, you should use {@link #relayCmd} instead.
16839 * <b>This should only be called after the editor is initialized.</b>
16840 * @param {String} cmd The Midas command
16841 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16843 execCmd : function(cmd, value){
16844 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16851 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16853 * @param {String} text | dom node..
16855 insertAtCursor : function(text)
16860 if(!this.activated){
16866 var r = this.doc.selection.createRange();
16877 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16881 // from jquery ui (MIT licenced)
16883 var win = this.win;
16885 if (win.getSelection && win.getSelection().getRangeAt) {
16886 range = win.getSelection().getRangeAt(0);
16887 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16888 range.insertNode(node);
16889 } else if (win.document.selection && win.document.selection.createRange) {
16890 // no firefox support
16891 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16892 win.document.selection.createRange().pasteHTML(txt);
16894 // no firefox support
16895 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16896 this.execCmd('InsertHTML', txt);
16905 mozKeyPress : function(e){
16907 var c = e.getCharCode(), cmd;
16910 c = String.fromCharCode(c).toLowerCase();
16924 this.cleanUpPaste.defer(100, this);
16932 e.preventDefault();
16940 fixKeys : function(){ // load time branching for fastest keydown performance
16942 return function(e){
16943 var k = e.getKey(), r;
16946 r = this.doc.selection.createRange();
16949 r.pasteHTML('    ');
16956 r = this.doc.selection.createRange();
16958 var target = r.parentElement();
16959 if(!target || target.tagName.toLowerCase() != 'li'){
16961 r.pasteHTML('<br />');
16967 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16968 this.cleanUpPaste.defer(100, this);
16974 }else if(Roo.isOpera){
16975 return function(e){
16976 var k = e.getKey();
16980 this.execCmd('InsertHTML','    ');
16983 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16984 this.cleanUpPaste.defer(100, this);
16989 }else if(Roo.isSafari){
16990 return function(e){
16991 var k = e.getKey();
16995 this.execCmd('InsertText','\t');
16999 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17000 this.cleanUpPaste.defer(100, this);
17008 getAllAncestors: function()
17010 var p = this.getSelectedNode();
17013 a.push(p); // push blank onto stack..
17014 p = this.getParentElement();
17018 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17022 a.push(this.doc.body);
17026 lastSelNode : false,
17029 getSelection : function()
17031 this.assignDocWin();
17032 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17035 getSelectedNode: function()
17037 // this may only work on Gecko!!!
17039 // should we cache this!!!!
17044 var range = this.createRange(this.getSelection()).cloneRange();
17047 var parent = range.parentElement();
17049 var testRange = range.duplicate();
17050 testRange.moveToElementText(parent);
17051 if (testRange.inRange(range)) {
17054 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17057 parent = parent.parentElement;
17062 // is ancestor a text element.
17063 var ac = range.commonAncestorContainer;
17064 if (ac.nodeType == 3) {
17065 ac = ac.parentNode;
17068 var ar = ac.childNodes;
17071 var other_nodes = [];
17072 var has_other_nodes = false;
17073 for (var i=0;i<ar.length;i++) {
17074 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17077 // fullly contained node.
17079 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17084 // probably selected..
17085 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17086 other_nodes.push(ar[i]);
17090 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17095 has_other_nodes = true;
17097 if (!nodes.length && other_nodes.length) {
17098 nodes= other_nodes;
17100 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17106 createRange: function(sel)
17108 // this has strange effects when using with
17109 // top toolbar - not sure if it's a great idea.
17110 //this.editor.contentWindow.focus();
17111 if (typeof sel != "undefined") {
17113 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17115 return this.doc.createRange();
17118 return this.doc.createRange();
17121 getParentElement: function()
17124 this.assignDocWin();
17125 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17127 var range = this.createRange(sel);
17130 var p = range.commonAncestorContainer;
17131 while (p.nodeType == 3) { // text node
17142 * Range intersection.. the hard stuff...
17146 * [ -- selected range --- ]
17150 * if end is before start or hits it. fail.
17151 * if start is after end or hits it fail.
17153 * if either hits (but other is outside. - then it's not
17159 // @see http://www.thismuchiknow.co.uk/?p=64.
17160 rangeIntersectsNode : function(range, node)
17162 var nodeRange = node.ownerDocument.createRange();
17164 nodeRange.selectNode(node);
17166 nodeRange.selectNodeContents(node);
17169 var rangeStartRange = range.cloneRange();
17170 rangeStartRange.collapse(true);
17172 var rangeEndRange = range.cloneRange();
17173 rangeEndRange.collapse(false);
17175 var nodeStartRange = nodeRange.cloneRange();
17176 nodeStartRange.collapse(true);
17178 var nodeEndRange = nodeRange.cloneRange();
17179 nodeEndRange.collapse(false);
17181 return rangeStartRange.compareBoundaryPoints(
17182 Range.START_TO_START, nodeEndRange) == -1 &&
17183 rangeEndRange.compareBoundaryPoints(
17184 Range.START_TO_START, nodeStartRange) == 1;
17188 rangeCompareNode : function(range, node)
17190 var nodeRange = node.ownerDocument.createRange();
17192 nodeRange.selectNode(node);
17194 nodeRange.selectNodeContents(node);
17198 range.collapse(true);
17200 nodeRange.collapse(true);
17202 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17203 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17205 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17207 var nodeIsBefore = ss == 1;
17208 var nodeIsAfter = ee == -1;
17210 if (nodeIsBefore && nodeIsAfter)
17212 if (!nodeIsBefore && nodeIsAfter)
17213 return 1; //right trailed.
17215 if (nodeIsBefore && !nodeIsAfter)
17216 return 2; // left trailed.
17221 // private? - in a new class?
17222 cleanUpPaste : function()
17224 // cleans up the whole document..
17225 Roo.log('cleanuppaste');
17227 this.cleanUpChildren(this.doc.body);
17228 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17229 if (clean != this.doc.body.innerHTML) {
17230 this.doc.body.innerHTML = clean;
17235 cleanWordChars : function(input) {// change the chars to hex code
17236 var he = Roo.HtmlEditorCore;
17238 var output = input;
17239 Roo.each(he.swapCodes, function(sw) {
17240 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17242 output = output.replace(swapper, sw[1]);
17249 cleanUpChildren : function (n)
17251 if (!n.childNodes.length) {
17254 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17255 this.cleanUpChild(n.childNodes[i]);
17262 cleanUpChild : function (node)
17265 //console.log(node);
17266 if (node.nodeName == "#text") {
17267 // clean up silly Windows -- stuff?
17270 if (node.nodeName == "#comment") {
17271 node.parentNode.removeChild(node);
17272 // clean up silly Windows -- stuff?
17276 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17278 node.parentNode.removeChild(node);
17283 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17285 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17286 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17288 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17289 // remove_keep_children = true;
17292 if (remove_keep_children) {
17293 this.cleanUpChildren(node);
17294 // inserts everything just before this node...
17295 while (node.childNodes.length) {
17296 var cn = node.childNodes[0];
17297 node.removeChild(cn);
17298 node.parentNode.insertBefore(cn, node);
17300 node.parentNode.removeChild(node);
17304 if (!node.attributes || !node.attributes.length) {
17305 this.cleanUpChildren(node);
17309 function cleanAttr(n,v)
17312 if (v.match(/^\./) || v.match(/^\//)) {
17315 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17318 if (v.match(/^#/)) {
17321 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17322 node.removeAttribute(n);
17326 function cleanStyle(n,v)
17328 if (v.match(/expression/)) { //XSS?? should we even bother..
17329 node.removeAttribute(n);
17332 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17333 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17336 var parts = v.split(/;/);
17339 Roo.each(parts, function(p) {
17340 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17344 var l = p.split(':').shift().replace(/\s+/g,'');
17345 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17347 if ( cblack.indexOf(l) > -1) {
17348 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17349 //node.removeAttribute(n);
17353 // only allow 'c whitelisted system attributes'
17354 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17355 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17356 //node.removeAttribute(n);
17366 if (clean.length) {
17367 node.setAttribute(n, clean.join(';'));
17369 node.removeAttribute(n);
17375 for (var i = node.attributes.length-1; i > -1 ; i--) {
17376 var a = node.attributes[i];
17379 if (a.name.toLowerCase().substr(0,2)=='on') {
17380 node.removeAttribute(a.name);
17383 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17384 node.removeAttribute(a.name);
17387 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17388 cleanAttr(a.name,a.value); // fixme..
17391 if (a.name == 'style') {
17392 cleanStyle(a.name,a.value);
17395 /// clean up MS crap..
17396 // tecnically this should be a list of valid class'es..
17399 if (a.name == 'class') {
17400 if (a.value.match(/^Mso/)) {
17401 node.className = '';
17404 if (a.value.match(/body/)) {
17405 node.className = '';
17416 this.cleanUpChildren(node);
17421 * Clean up MS wordisms...
17423 cleanWord : function(node)
17426 var cleanWordChildren = function()
17428 if (!node.childNodes.length) {
17431 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17432 _t.cleanWord(node.childNodes[i]);
17438 this.cleanWord(this.doc.body);
17441 if (node.nodeName == "#text") {
17442 // clean up silly Windows -- stuff?
17445 if (node.nodeName == "#comment") {
17446 node.parentNode.removeChild(node);
17447 // clean up silly Windows -- stuff?
17451 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17452 node.parentNode.removeChild(node);
17456 // remove - but keep children..
17457 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17458 while (node.childNodes.length) {
17459 var cn = node.childNodes[0];
17460 node.removeChild(cn);
17461 node.parentNode.insertBefore(cn, node);
17463 node.parentNode.removeChild(node);
17464 cleanWordChildren();
17468 if (node.className.length) {
17470 var cn = node.className.split(/\W+/);
17472 Roo.each(cn, function(cls) {
17473 if (cls.match(/Mso[a-zA-Z]+/)) {
17478 node.className = cna.length ? cna.join(' ') : '';
17480 node.removeAttribute("class");
17484 if (node.hasAttribute("lang")) {
17485 node.removeAttribute("lang");
17488 if (node.hasAttribute("style")) {
17490 var styles = node.getAttribute("style").split(";");
17492 Roo.each(styles, function(s) {
17493 if (!s.match(/:/)) {
17496 var kv = s.split(":");
17497 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17500 // what ever is left... we allow.
17503 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17504 if (!nstyle.length) {
17505 node.removeAttribute('style');
17509 cleanWordChildren();
17513 domToHTML : function(currentElement, depth, nopadtext) {
17515 depth = depth || 0;
17516 nopadtext = nopadtext || false;
17518 if (!currentElement) {
17519 return this.domToHTML(this.doc.body);
17522 //Roo.log(currentElement);
17524 var allText = false;
17525 var nodeName = currentElement.nodeName;
17526 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17528 if (nodeName == '#text') {
17529 return currentElement.nodeValue;
17534 if (nodeName != 'BODY') {
17537 // Prints the node tagName, such as <A>, <IMG>, etc
17540 for(i = 0; i < currentElement.attributes.length;i++) {
17542 var aname = currentElement.attributes.item(i).name;
17543 if (!currentElement.attributes.item(i).value.length) {
17546 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17549 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17558 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17561 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17566 // Traverse the tree
17568 var currentElementChild = currentElement.childNodes.item(i);
17569 var allText = true;
17570 var innerHTML = '';
17572 while (currentElementChild) {
17573 // Formatting code (indent the tree so it looks nice on the screen)
17574 var nopad = nopadtext;
17575 if (lastnode == 'SPAN') {
17579 if (currentElementChild.nodeName == '#text') {
17580 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17581 if (!nopad && toadd.length > 80) {
17582 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17584 innerHTML += toadd;
17587 currentElementChild = currentElement.childNodes.item(i);
17593 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17595 // Recursively traverse the tree structure of the child node
17596 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17597 lastnode = currentElementChild.nodeName;
17599 currentElementChild=currentElement.childNodes.item(i);
17605 // The remaining code is mostly for formatting the tree
17606 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17611 ret+= "</"+tagName+">";
17617 // hide stuff that is not compatible
17631 * @event specialkey
17635 * @cfg {String} fieldClass @hide
17638 * @cfg {String} focusClass @hide
17641 * @cfg {String} autoCreate @hide
17644 * @cfg {String} inputType @hide
17647 * @cfg {String} invalidClass @hide
17650 * @cfg {String} invalidText @hide
17653 * @cfg {String} msgFx @hide
17656 * @cfg {String} validateOnBlur @hide
17660 Roo.HtmlEditorCore.white = [
17661 'area', 'br', 'img', 'input', 'hr', 'wbr',
17663 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17664 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17665 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17666 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17667 'table', 'ul', 'xmp',
17669 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17672 'dir', 'menu', 'ol', 'ul', 'dl',
17678 Roo.HtmlEditorCore.black = [
17679 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17681 'base', 'basefont', 'bgsound', 'blink', 'body',
17682 'frame', 'frameset', 'head', 'html', 'ilayer',
17683 'iframe', 'layer', 'link', 'meta', 'object',
17684 'script', 'style' ,'title', 'xml' // clean later..
17686 Roo.HtmlEditorCore.clean = [
17687 'script', 'style', 'title', 'xml'
17689 Roo.HtmlEditorCore.remove = [
17694 Roo.HtmlEditorCore.ablack = [
17698 Roo.HtmlEditorCore.aclean = [
17699 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17703 Roo.HtmlEditorCore.pwhite= [
17704 'http', 'https', 'mailto'
17707 // white listed style attributes.
17708 Roo.HtmlEditorCore.cwhite= [
17709 // 'text-align', /// default is to allow most things..
17715 // black listed style attributes.
17716 Roo.HtmlEditorCore.cblack= [
17717 // 'font-size' -- this can be set by the project
17721 Roo.HtmlEditorCore.swapCodes =[
17740 * @class Roo.bootstrap.HtmlEditor
17741 * @extends Roo.bootstrap.TextArea
17742 * Bootstrap HtmlEditor class
17745 * Create a new HtmlEditor
17746 * @param {Object} config The config object
17749 Roo.bootstrap.HtmlEditor = function(config){
17750 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17751 if (!this.toolbars) {
17752 this.toolbars = [];
17754 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17757 * @event initialize
17758 * Fires when the editor is fully initialized (including the iframe)
17759 * @param {HtmlEditor} this
17764 * Fires when the editor is first receives the focus. Any insertion must wait
17765 * until after this event.
17766 * @param {HtmlEditor} this
17770 * @event beforesync
17771 * Fires before the textarea is updated with content from the editor iframe. Return false
17772 * to cancel the sync.
17773 * @param {HtmlEditor} this
17774 * @param {String} html
17778 * @event beforepush
17779 * Fires before the iframe editor is updated with content from the textarea. Return false
17780 * to cancel the push.
17781 * @param {HtmlEditor} this
17782 * @param {String} html
17787 * Fires when the textarea is updated with content from the editor iframe.
17788 * @param {HtmlEditor} this
17789 * @param {String} html
17794 * Fires when the iframe editor is updated with content from the textarea.
17795 * @param {HtmlEditor} this
17796 * @param {String} html
17800 * @event editmodechange
17801 * Fires when the editor switches edit modes
17802 * @param {HtmlEditor} this
17803 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17805 editmodechange: true,
17807 * @event editorevent
17808 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17809 * @param {HtmlEditor} this
17813 * @event firstfocus
17814 * Fires when on first focus - needed by toolbars..
17815 * @param {HtmlEditor} this
17820 * Auto save the htmlEditor value as a file into Events
17821 * @param {HtmlEditor} this
17825 * @event savedpreview
17826 * preview the saved version of htmlEditor
17827 * @param {HtmlEditor} this
17834 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17838 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17843 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17848 * @cfg {Number} height (in pixels)
17852 * @cfg {Number} width (in pixels)
17857 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17860 stylesheets: false,
17865 // private properties
17866 validationEvent : false,
17868 initialized : false,
17871 onFocus : Roo.emptyFn,
17873 hideMode:'offsets',
17876 tbContainer : false,
17878 toolbarContainer :function() {
17879 return this.wrap.select('.x-html-editor-tb',true).first();
17883 * Protected method that will not generally be called directly. It
17884 * is called when the editor creates its toolbar. Override this method if you need to
17885 * add custom toolbar buttons.
17886 * @param {HtmlEditor} editor
17888 createToolbar : function(){
17890 Roo.log("create toolbars");
17892 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17893 this.toolbars[0].render(this.toolbarContainer());
17897 // if (!editor.toolbars || !editor.toolbars.length) {
17898 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17901 // for (var i =0 ; i < editor.toolbars.length;i++) {
17902 // editor.toolbars[i] = Roo.factory(
17903 // typeof(editor.toolbars[i]) == 'string' ?
17904 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17905 // Roo.bootstrap.HtmlEditor);
17906 // editor.toolbars[i].init(editor);
17912 onRender : function(ct, position)
17914 // Roo.log("Call onRender: " + this.xtype);
17916 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17918 this.wrap = this.inputEl().wrap({
17919 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17922 this.editorcore.onRender(ct, position);
17924 if (this.resizable) {
17925 this.resizeEl = new Roo.Resizable(this.wrap, {
17929 minHeight : this.height,
17930 height: this.height,
17931 handles : this.resizable,
17934 resize : function(r, w, h) {
17935 _t.onResize(w,h); // -something
17941 this.createToolbar(this);
17944 if(!this.width && this.resizable){
17945 this.setSize(this.wrap.getSize());
17947 if (this.resizeEl) {
17948 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17949 // should trigger onReize..
17955 onResize : function(w, h)
17957 Roo.log('resize: ' +w + ',' + h );
17958 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17962 if(this.inputEl() ){
17963 if(typeof w == 'number'){
17964 var aw = w - this.wrap.getFrameWidth('lr');
17965 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17968 if(typeof h == 'number'){
17969 var tbh = -11; // fixme it needs to tool bar size!
17970 for (var i =0; i < this.toolbars.length;i++) {
17971 // fixme - ask toolbars for heights?
17972 tbh += this.toolbars[i].el.getHeight();
17973 //if (this.toolbars[i].footer) {
17974 // tbh += this.toolbars[i].footer.el.getHeight();
17982 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17983 ah -= 5; // knock a few pixes off for look..
17984 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17988 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17989 this.editorcore.onResize(ew,eh);
17994 * Toggles the editor between standard and source edit mode.
17995 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17997 toggleSourceEdit : function(sourceEditMode)
17999 this.editorcore.toggleSourceEdit(sourceEditMode);
18001 if(this.editorcore.sourceEditMode){
18002 Roo.log('editor - showing textarea');
18005 // Roo.log(this.syncValue());
18007 this.inputEl().removeClass(['hide', 'x-hidden']);
18008 this.inputEl().dom.removeAttribute('tabIndex');
18009 this.inputEl().focus();
18011 Roo.log('editor - hiding textarea');
18013 // Roo.log(this.pushValue());
18016 this.inputEl().addClass(['hide', 'x-hidden']);
18017 this.inputEl().dom.setAttribute('tabIndex', -1);
18018 //this.deferFocus();
18021 if(this.resizable){
18022 this.setSize(this.wrap.getSize());
18025 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18028 // private (for BoxComponent)
18029 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18031 // private (for BoxComponent)
18032 getResizeEl : function(){
18036 // private (for BoxComponent)
18037 getPositionEl : function(){
18042 initEvents : function(){
18043 this.originalValue = this.getValue();
18047 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18050 // markInvalid : Roo.emptyFn,
18052 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18055 // clearInvalid : Roo.emptyFn,
18057 setValue : function(v){
18058 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18059 this.editorcore.pushValue();
18064 deferFocus : function(){
18065 this.focus.defer(10, this);
18069 focus : function(){
18070 this.editorcore.focus();
18076 onDestroy : function(){
18082 for (var i =0; i < this.toolbars.length;i++) {
18083 // fixme - ask toolbars for heights?
18084 this.toolbars[i].onDestroy();
18087 this.wrap.dom.innerHTML = '';
18088 this.wrap.remove();
18093 onFirstFocus : function(){
18094 //Roo.log("onFirstFocus");
18095 this.editorcore.onFirstFocus();
18096 for (var i =0; i < this.toolbars.length;i++) {
18097 this.toolbars[i].onFirstFocus();
18103 syncValue : function()
18105 this.editorcore.syncValue();
18108 pushValue : function()
18110 this.editorcore.pushValue();
18114 // hide stuff that is not compatible
18128 * @event specialkey
18132 * @cfg {String} fieldClass @hide
18135 * @cfg {String} focusClass @hide
18138 * @cfg {String} autoCreate @hide
18141 * @cfg {String} inputType @hide
18144 * @cfg {String} invalidClass @hide
18147 * @cfg {String} invalidText @hide
18150 * @cfg {String} msgFx @hide
18153 * @cfg {String} validateOnBlur @hide
18162 Roo.namespace('Roo.bootstrap.htmleditor');
18164 * @class Roo.bootstrap.HtmlEditorToolbar1
18169 new Roo.bootstrap.HtmlEditor({
18172 new Roo.bootstrap.HtmlEditorToolbar1({
18173 disable : { fonts: 1 , format: 1, ..., ... , ...],
18179 * @cfg {Object} disable List of elements to disable..
18180 * @cfg {Array} btns List of additional buttons.
18184 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18187 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18190 Roo.apply(this, config);
18192 // default disabled, based on 'good practice'..
18193 this.disable = this.disable || {};
18194 Roo.applyIf(this.disable, {
18197 specialElements : true
18199 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18201 this.editor = config.editor;
18202 this.editorcore = config.editor.editorcore;
18204 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18206 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18207 // dont call parent... till later.
18209 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18214 editorcore : false,
18219 "h1","h2","h3","h4","h5","h6",
18221 "abbr", "acronym", "address", "cite", "samp", "var",
18225 onRender : function(ct, position)
18227 // Roo.log("Call onRender: " + this.xtype);
18229 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18231 this.el.dom.style.marginBottom = '0';
18233 var editorcore = this.editorcore;
18234 var editor= this.editor;
18237 var btn = function(id,cmd , toggle, handler){
18239 var event = toggle ? 'toggle' : 'click';
18244 xns: Roo.bootstrap,
18247 enableToggle:toggle !== false,
18249 pressed : toggle ? false : null,
18252 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18253 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18262 xns: Roo.bootstrap,
18263 glyphicon : 'font',
18267 xns: Roo.bootstrap,
18271 Roo.each(this.formats, function(f) {
18272 style.menu.items.push({
18274 xns: Roo.bootstrap,
18275 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18280 editorcore.insertTag(this.tagname);
18287 children.push(style);
18290 btn('bold',false,true);
18291 btn('italic',false,true);
18292 btn('align-left', 'justifyleft',true);
18293 btn('align-center', 'justifycenter',true);
18294 btn('align-right' , 'justifyright',true);
18295 btn('link', false, false, function(btn) {
18296 //Roo.log("create link?");
18297 var url = prompt(this.createLinkText, this.defaultLinkValue);
18298 if(url && url != 'http:/'+'/'){
18299 this.editorcore.relayCmd('createlink', url);
18302 btn('list','insertunorderedlist',true);
18303 btn('pencil', false,true, function(btn){
18306 this.toggleSourceEdit(btn.pressed);
18312 xns: Roo.bootstrap,
18317 xns: Roo.bootstrap,
18322 cog.menu.items.push({
18324 xns: Roo.bootstrap,
18325 html : Clean styles,
18330 editorcore.insertTag(this.tagname);
18339 this.xtype = 'NavSimplebar';
18341 for(var i=0;i< children.length;i++) {
18343 this.buttons.add(this.addxtypeChild(children[i]));
18347 editor.on('editorevent', this.updateToolbar, this);
18349 onBtnClick : function(id)
18351 this.editorcore.relayCmd(id);
18352 this.editorcore.focus();
18356 * Protected method that will not generally be called directly. It triggers
18357 * a toolbar update by reading the markup state of the current selection in the editor.
18359 updateToolbar: function(){
18361 if(!this.editorcore.activated){
18362 this.editor.onFirstFocus(); // is this neeed?
18366 var btns = this.buttons;
18367 var doc = this.editorcore.doc;
18368 btns.get('bold').setActive(doc.queryCommandState('bold'));
18369 btns.get('italic').setActive(doc.queryCommandState('italic'));
18370 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18372 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18373 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18374 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18376 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18377 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18380 var ans = this.editorcore.getAllAncestors();
18381 if (this.formatCombo) {
18384 var store = this.formatCombo.store;
18385 this.formatCombo.setValue("");
18386 for (var i =0; i < ans.length;i++) {
18387 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18389 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18397 // hides menus... - so this cant be on a menu...
18398 Roo.bootstrap.MenuMgr.hideAll();
18400 Roo.bootstrap.MenuMgr.hideAll();
18401 //this.editorsyncValue();
18403 onFirstFocus: function() {
18404 this.buttons.each(function(item){
18408 toggleSourceEdit : function(sourceEditMode){
18411 if(sourceEditMode){
18412 Roo.log("disabling buttons");
18413 this.buttons.each( function(item){
18414 if(item.cmd != 'pencil'){
18420 Roo.log("enabling buttons");
18421 if(this.editorcore.initialized){
18422 this.buttons.each( function(item){
18428 Roo.log("calling toggole on editor");
18429 // tell the editor that it's been pressed..
18430 this.editor.toggleSourceEdit(sourceEditMode);
18440 * @class Roo.bootstrap.Table.AbstractSelectionModel
18441 * @extends Roo.util.Observable
18442 * Abstract base class for grid SelectionModels. It provides the interface that should be
18443 * implemented by descendant classes. This class should not be directly instantiated.
18446 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18447 this.locked = false;
18448 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18452 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18453 /** @ignore Called by the grid automatically. Do not call directly. */
18454 init : function(grid){
18460 * Locks the selections.
18463 this.locked = true;
18467 * Unlocks the selections.
18469 unlock : function(){
18470 this.locked = false;
18474 * Returns true if the selections are locked.
18475 * @return {Boolean}
18477 isLocked : function(){
18478 return this.locked;
18482 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18483 * @class Roo.bootstrap.Table.RowSelectionModel
18484 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18485 * It supports multiple selections and keyboard selection/navigation.
18487 * @param {Object} config
18490 Roo.bootstrap.Table.RowSelectionModel = function(config){
18491 Roo.apply(this, config);
18492 this.selections = new Roo.util.MixedCollection(false, function(o){
18497 this.lastActive = false;
18501 * @event selectionchange
18502 * Fires when the selection changes
18503 * @param {SelectionModel} this
18505 "selectionchange" : true,
18507 * @event afterselectionchange
18508 * Fires after the selection changes (eg. by key press or clicking)
18509 * @param {SelectionModel} this
18511 "afterselectionchange" : true,
18513 * @event beforerowselect
18514 * Fires when a row is selected being selected, return false to cancel.
18515 * @param {SelectionModel} this
18516 * @param {Number} rowIndex The selected index
18517 * @param {Boolean} keepExisting False if other selections will be cleared
18519 "beforerowselect" : true,
18522 * Fires when a row is selected.
18523 * @param {SelectionModel} this
18524 * @param {Number} rowIndex The selected index
18525 * @param {Roo.data.Record} r The record
18527 "rowselect" : true,
18529 * @event rowdeselect
18530 * Fires when a row is deselected.
18531 * @param {SelectionModel} this
18532 * @param {Number} rowIndex The selected index
18534 "rowdeselect" : true
18536 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18537 this.locked = false;
18540 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18542 * @cfg {Boolean} singleSelect
18543 * True to allow selection of only one row at a time (defaults to false)
18545 singleSelect : false,
18548 initEvents : function(){
18550 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18551 this.grid.on("mousedown", this.handleMouseDown, this);
18552 }else{ // allow click to work like normal
18553 this.grid.on("rowclick", this.handleDragableRowClick, this);
18556 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18557 "up" : function(e){
18559 this.selectPrevious(e.shiftKey);
18560 }else if(this.last !== false && this.lastActive !== false){
18561 var last = this.last;
18562 this.selectRange(this.last, this.lastActive-1);
18563 this.grid.getView().focusRow(this.lastActive);
18564 if(last !== false){
18568 this.selectFirstRow();
18570 this.fireEvent("afterselectionchange", this);
18572 "down" : function(e){
18574 this.selectNext(e.shiftKey);
18575 }else if(this.last !== false && this.lastActive !== false){
18576 var last = this.last;
18577 this.selectRange(this.last, this.lastActive+1);
18578 this.grid.getView().focusRow(this.lastActive);
18579 if(last !== false){
18583 this.selectFirstRow();
18585 this.fireEvent("afterselectionchange", this);
18590 var view = this.grid.view;
18591 view.on("refresh", this.onRefresh, this);
18592 view.on("rowupdated", this.onRowUpdated, this);
18593 view.on("rowremoved", this.onRemove, this);
18597 onRefresh : function(){
18598 var ds = this.grid.dataSource, i, v = this.grid.view;
18599 var s = this.selections;
18600 s.each(function(r){
18601 if((i = ds.indexOfId(r.id)) != -1){
18610 onRemove : function(v, index, r){
18611 this.selections.remove(r);
18615 onRowUpdated : function(v, index, r){
18616 if(this.isSelected(r)){
18617 v.onRowSelect(index);
18623 * @param {Array} records The records to select
18624 * @param {Boolean} keepExisting (optional) True to keep existing selections
18626 selectRecords : function(records, keepExisting){
18628 this.clearSelections();
18630 var ds = this.grid.dataSource;
18631 for(var i = 0, len = records.length; i < len; i++){
18632 this.selectRow(ds.indexOf(records[i]), true);
18637 * Gets the number of selected rows.
18640 getCount : function(){
18641 return this.selections.length;
18645 * Selects the first row in the grid.
18647 selectFirstRow : function(){
18652 * Select the last row.
18653 * @param {Boolean} keepExisting (optional) True to keep existing selections
18655 selectLastRow : function(keepExisting){
18656 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18660 * Selects the row immediately following the last selected row.
18661 * @param {Boolean} keepExisting (optional) True to keep existing selections
18663 selectNext : function(keepExisting){
18664 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18665 this.selectRow(this.last+1, keepExisting);
18666 this.grid.getView().focusRow(this.last);
18671 * Selects the row that precedes the last selected row.
18672 * @param {Boolean} keepExisting (optional) True to keep existing selections
18674 selectPrevious : function(keepExisting){
18676 this.selectRow(this.last-1, keepExisting);
18677 this.grid.getView().focusRow(this.last);
18682 * Returns the selected records
18683 * @return {Array} Array of selected records
18685 getSelections : function(){
18686 return [].concat(this.selections.items);
18690 * Returns the first selected record.
18693 getSelected : function(){
18694 return this.selections.itemAt(0);
18699 * Clears all selections.
18701 clearSelections : function(fast){
18702 if(this.locked) return;
18704 var ds = this.grid.dataSource;
18705 var s = this.selections;
18706 s.each(function(r){
18707 this.deselectRow(ds.indexOfId(r.id));
18711 this.selections.clear();
18718 * Selects all rows.
18720 selectAll : function(){
18721 if(this.locked) return;
18722 this.selections.clear();
18723 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18724 this.selectRow(i, true);
18729 * Returns True if there is a selection.
18730 * @return {Boolean}
18732 hasSelection : function(){
18733 return this.selections.length > 0;
18737 * Returns True if the specified row is selected.
18738 * @param {Number/Record} record The record or index of the record to check
18739 * @return {Boolean}
18741 isSelected : function(index){
18742 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18743 return (r && this.selections.key(r.id) ? true : false);
18747 * Returns True if the specified record id is selected.
18748 * @param {String} id The id of record to check
18749 * @return {Boolean}
18751 isIdSelected : function(id){
18752 return (this.selections.key(id) ? true : false);
18756 handleMouseDown : function(e, t){
18757 var view = this.grid.getView(), rowIndex;
18758 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18761 if(e.shiftKey && this.last !== false){
18762 var last = this.last;
18763 this.selectRange(last, rowIndex, e.ctrlKey);
18764 this.last = last; // reset the last
18765 view.focusRow(rowIndex);
18767 var isSelected = this.isSelected(rowIndex);
18768 if(e.button !== 0 && isSelected){
18769 view.focusRow(rowIndex);
18770 }else if(e.ctrlKey && isSelected){
18771 this.deselectRow(rowIndex);
18772 }else if(!isSelected){
18773 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18774 view.focusRow(rowIndex);
18777 this.fireEvent("afterselectionchange", this);
18780 handleDragableRowClick : function(grid, rowIndex, e)
18782 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18783 this.selectRow(rowIndex, false);
18784 grid.view.focusRow(rowIndex);
18785 this.fireEvent("afterselectionchange", this);
18790 * Selects multiple rows.
18791 * @param {Array} rows Array of the indexes of the row to select
18792 * @param {Boolean} keepExisting (optional) True to keep existing selections
18794 selectRows : function(rows, keepExisting){
18796 this.clearSelections();
18798 for(var i = 0, len = rows.length; i < len; i++){
18799 this.selectRow(rows[i], true);
18804 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18805 * @param {Number} startRow The index of the first row in the range
18806 * @param {Number} endRow The index of the last row in the range
18807 * @param {Boolean} keepExisting (optional) True to retain existing selections
18809 selectRange : function(startRow, endRow, keepExisting){
18810 if(this.locked) return;
18812 this.clearSelections();
18814 if(startRow <= endRow){
18815 for(var i = startRow; i <= endRow; i++){
18816 this.selectRow(i, true);
18819 for(var i = startRow; i >= endRow; i--){
18820 this.selectRow(i, true);
18826 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18827 * @param {Number} startRow The index of the first row in the range
18828 * @param {Number} endRow The index of the last row in the range
18830 deselectRange : function(startRow, endRow, preventViewNotify){
18831 if(this.locked) return;
18832 for(var i = startRow; i <= endRow; i++){
18833 this.deselectRow(i, preventViewNotify);
18839 * @param {Number} row The index of the row to select
18840 * @param {Boolean} keepExisting (optional) True to keep existing selections
18842 selectRow : function(index, keepExisting, preventViewNotify){
18843 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18844 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18845 if(!keepExisting || this.singleSelect){
18846 this.clearSelections();
18848 var r = this.grid.dataSource.getAt(index);
18849 this.selections.add(r);
18850 this.last = this.lastActive = index;
18851 if(!preventViewNotify){
18852 this.grid.getView().onRowSelect(index);
18854 this.fireEvent("rowselect", this, index, r);
18855 this.fireEvent("selectionchange", this);
18861 * @param {Number} row The index of the row to deselect
18863 deselectRow : function(index, preventViewNotify){
18864 if(this.locked) return;
18865 if(this.last == index){
18868 if(this.lastActive == index){
18869 this.lastActive = false;
18871 var r = this.grid.dataSource.getAt(index);
18872 this.selections.remove(r);
18873 if(!preventViewNotify){
18874 this.grid.getView().onRowDeselect(index);
18876 this.fireEvent("rowdeselect", this, index);
18877 this.fireEvent("selectionchange", this);
18881 restoreLast : function(){
18883 this.last = this._last;
18888 acceptsNav : function(row, col, cm){
18889 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18893 onEditorKey : function(field, e){
18894 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18899 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18901 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18903 }else if(k == e.ENTER && !e.ctrlKey){
18907 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18909 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18911 }else if(k == e.ESC){
18915 g.startEditing(newCell[0], newCell[1]);
18920 * Ext JS Library 1.1.1
18921 * Copyright(c) 2006-2007, Ext JS, LLC.
18923 * Originally Released Under LGPL - original licence link has changed is not relivant.
18926 * <script type="text/javascript">
18930 * @class Roo.bootstrap.PagingToolbar
18932 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18934 * Create a new PagingToolbar
18935 * @param {Object} config The config object
18937 Roo.bootstrap.PagingToolbar = function(config)
18939 // old args format still supported... - xtype is prefered..
18940 // created from xtype...
18941 var ds = config.dataSource;
18942 this.toolbarItems = [];
18943 if (config.items) {
18944 this.toolbarItems = config.items;
18945 // config.items = [];
18948 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18955 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18959 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18961 * @cfg {Roo.data.Store} dataSource
18962 * The underlying data store providing the paged data
18965 * @cfg {String/HTMLElement/Element} container
18966 * container The id or element that will contain the toolbar
18969 * @cfg {Boolean} displayInfo
18970 * True to display the displayMsg (defaults to false)
18973 * @cfg {Number} pageSize
18974 * The number of records to display per page (defaults to 20)
18978 * @cfg {String} displayMsg
18979 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18981 displayMsg : 'Displaying {0} - {1} of {2}',
18983 * @cfg {String} emptyMsg
18984 * The message to display when no records are found (defaults to "No data to display")
18986 emptyMsg : 'No data to display',
18988 * Customizable piece of the default paging text (defaults to "Page")
18991 beforePageText : "Page",
18993 * Customizable piece of the default paging text (defaults to "of %0")
18996 afterPageText : "of {0}",
18998 * Customizable piece of the default paging text (defaults to "First Page")
19001 firstText : "First Page",
19003 * Customizable piece of the default paging text (defaults to "Previous Page")
19006 prevText : "Previous Page",
19008 * Customizable piece of the default paging text (defaults to "Next Page")
19011 nextText : "Next Page",
19013 * Customizable piece of the default paging text (defaults to "Last Page")
19016 lastText : "Last Page",
19018 * Customizable piece of the default paging text (defaults to "Refresh")
19021 refreshText : "Refresh",
19025 onRender : function(ct, position)
19027 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19028 this.navgroup.parentId = this.id;
19029 this.navgroup.onRender(this.el, null);
19030 // add the buttons to the navgroup
19032 if(this.displayInfo){
19033 Roo.log(this.el.select('ul.navbar-nav',true).first());
19034 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19035 this.displayEl = this.el.select('.x-paging-info', true).first();
19036 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19037 // this.displayEl = navel.el.select('span',true).first();
19043 Roo.each(_this.buttons, function(e){
19044 Roo.factory(e).onRender(_this.el, null);
19048 Roo.each(_this.toolbarItems, function(e) {
19049 _this.navgroup.addItem(e);
19052 this.first = this.navgroup.addItem({
19053 tooltip: this.firstText,
19055 icon : 'fa fa-backward',
19057 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19060 this.prev = this.navgroup.addItem({
19061 tooltip: this.prevText,
19063 icon : 'fa fa-step-backward',
19065 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19067 //this.addSeparator();
19070 var field = this.navgroup.addItem( {
19072 cls : 'x-paging-position',
19074 html : this.beforePageText +
19075 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19076 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19079 this.field = field.el.select('input', true).first();
19080 this.field.on("keydown", this.onPagingKeydown, this);
19081 this.field.on("focus", function(){this.dom.select();});
19084 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19085 //this.field.setHeight(18);
19086 //this.addSeparator();
19087 this.next = this.navgroup.addItem({
19088 tooltip: this.nextText,
19090 html : ' <i class="fa fa-step-forward">',
19092 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19094 this.last = this.navgroup.addItem({
19095 tooltip: this.lastText,
19096 icon : 'fa fa-forward',
19099 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19101 //this.addSeparator();
19102 this.loading = this.navgroup.addItem({
19103 tooltip: this.refreshText,
19104 icon: 'fa fa-refresh',
19106 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19112 updateInfo : function(){
19113 if(this.displayEl){
19114 var count = this.ds.getCount();
19115 var msg = count == 0 ?
19119 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19121 this.displayEl.update(msg);
19126 onLoad : function(ds, r, o){
19127 this.cursor = o.params ? o.params.start : 0;
19128 var d = this.getPageData(),
19132 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19133 this.field.dom.value = ap;
19134 this.first.setDisabled(ap == 1);
19135 this.prev.setDisabled(ap == 1);
19136 this.next.setDisabled(ap == ps);
19137 this.last.setDisabled(ap == ps);
19138 this.loading.enable();
19143 getPageData : function(){
19144 var total = this.ds.getTotalCount();
19147 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19148 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19153 onLoadError : function(){
19154 this.loading.enable();
19158 onPagingKeydown : function(e){
19159 var k = e.getKey();
19160 var d = this.getPageData();
19162 var v = this.field.dom.value, pageNum;
19163 if(!v || isNaN(pageNum = parseInt(v, 10))){
19164 this.field.dom.value = d.activePage;
19167 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19168 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19171 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))
19173 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19174 this.field.dom.value = pageNum;
19175 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19178 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19180 var v = this.field.dom.value, pageNum;
19181 var increment = (e.shiftKey) ? 10 : 1;
19182 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19184 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19185 this.field.dom.value = d.activePage;
19188 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19190 this.field.dom.value = parseInt(v, 10) + increment;
19191 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19192 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19199 beforeLoad : function(){
19201 this.loading.disable();
19206 onClick : function(which){
19213 ds.load({params:{start: 0, limit: this.pageSize}});
19216 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19219 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19222 var total = ds.getTotalCount();
19223 var extra = total % this.pageSize;
19224 var lastStart = extra ? (total - extra) : total-this.pageSize;
19225 ds.load({params:{start: lastStart, limit: this.pageSize}});
19228 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19234 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19235 * @param {Roo.data.Store} store The data store to unbind
19237 unbind : function(ds){
19238 ds.un("beforeload", this.beforeLoad, this);
19239 ds.un("load", this.onLoad, this);
19240 ds.un("loadexception", this.onLoadError, this);
19241 ds.un("remove", this.updateInfo, this);
19242 ds.un("add", this.updateInfo, this);
19243 this.ds = undefined;
19247 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19248 * @param {Roo.data.Store} store The data store to bind
19250 bind : function(ds){
19251 ds.on("beforeload", this.beforeLoad, this);
19252 ds.on("load", this.onLoad, this);
19253 ds.on("loadexception", this.onLoadError, this);
19254 ds.on("remove", this.updateInfo, this);
19255 ds.on("add", this.updateInfo, this);
19266 * @class Roo.bootstrap.MessageBar
19267 * @extends Roo.bootstrap.Component
19268 * Bootstrap MessageBar class
19269 * @cfg {String} html contents of the MessageBar
19270 * @cfg {String} weight (info | success | warning | danger) default info
19271 * @cfg {String} beforeClass insert the bar before the given class
19272 * @cfg {Boolean} closable (true | false) default false
19273 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19276 * Create a new Element
19277 * @param {Object} config The config object
19280 Roo.bootstrap.MessageBar = function(config){
19281 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19284 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19290 beforeClass: 'bootstrap-sticky-wrap',
19292 getAutoCreate : function(){
19296 cls: 'alert alert-dismissable alert-' + this.weight,
19301 html: this.html || ''
19307 cfg.cls += ' alert-messages-fixed';
19321 onRender : function(ct, position)
19323 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19326 var cfg = Roo.apply({}, this.getAutoCreate());
19330 cfg.cls += ' ' + this.cls;
19333 cfg.style = this.style;
19335 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19337 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19340 this.el.select('>button.close').on('click', this.hide, this);
19346 if (!this.rendered) {
19352 this.fireEvent('show', this);
19358 if (!this.rendered) {
19364 this.fireEvent('hide', this);
19367 update : function()
19369 // var e = this.el.dom.firstChild;
19371 // if(this.closable){
19372 // e = e.nextSibling;
19375 // e.data = this.html || '';
19377 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19393 * @class Roo.bootstrap.Graph
19394 * @extends Roo.bootstrap.Component
19395 * Bootstrap Graph class
19399 @cfg {String} graphtype bar | vbar | pie
19400 @cfg {number} g_x coodinator | centre x (pie)
19401 @cfg {number} g_y coodinator | centre y (pie)
19402 @cfg {number} g_r radius (pie)
19403 @cfg {number} g_height height of the chart (respected by all elements in the set)
19404 @cfg {number} g_width width of the chart (respected by all elements in the set)
19405 @cfg {Object} title The title of the chart
19408 -opts (object) options for the chart
19410 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19411 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19413 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.
19414 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19416 o stretch (boolean)
19418 -opts (object) options for the pie
19421 o startAngle (number)
19422 o endAngle (number)
19426 * Create a new Input
19427 * @param {Object} config The config object
19430 Roo.bootstrap.Graph = function(config){
19431 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19437 * The img click event for the img.
19438 * @param {Roo.EventObject} e
19444 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19455 //g_colors: this.colors,
19462 getAutoCreate : function(){
19473 onRender : function(ct,position){
19474 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19475 this.raphael = Raphael(this.el.dom);
19477 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19478 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19479 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19480 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19482 r.text(160, 10, "Single Series Chart").attr(txtattr);
19483 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19484 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19485 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19487 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19488 r.barchart(330, 10, 300, 220, data1);
19489 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19490 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19493 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19494 // r.barchart(30, 30, 560, 250, xdata, {
19495 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19496 // axis : "0 0 1 1",
19497 // axisxlabels : xdata
19498 // //yvalues : cols,
19501 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19503 // this.load(null,xdata,{
19504 // axis : "0 0 1 1",
19505 // axisxlabels : xdata
19510 load : function(graphtype,xdata,opts){
19511 this.raphael.clear();
19513 graphtype = this.graphtype;
19518 var r = this.raphael,
19519 fin = function () {
19520 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19522 fout = function () {
19523 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19525 pfin = function() {
19526 this.sector.stop();
19527 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19530 this.label[0].stop();
19531 this.label[0].attr({ r: 7.5 });
19532 this.label[1].attr({ "font-weight": 800 });
19535 pfout = function() {
19536 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19539 this.label[0].animate({ r: 5 }, 500, "bounce");
19540 this.label[1].attr({ "font-weight": 400 });
19546 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19549 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19552 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19553 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19555 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19562 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19567 setTitle: function(o)
19572 initEvents: function() {
19575 this.el.on('click', this.onClick, this);
19579 onClick : function(e)
19581 Roo.log('img onclick');
19582 this.fireEvent('click', this, e);
19594 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19597 * @class Roo.bootstrap.dash.NumberBox
19598 * @extends Roo.bootstrap.Component
19599 * Bootstrap NumberBox class
19600 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19601 * @cfg {String} headline Box headline
19602 * @cfg {String} content Box content
19603 * @cfg {String} icon Box icon
19604 * @cfg {String} footer Footer text
19605 * @cfg {String} fhref Footer href
19608 * Create a new NumberBox
19609 * @param {Object} config The config object
19613 Roo.bootstrap.dash.NumberBox = function(config){
19614 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19618 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19628 getAutoCreate : function(){
19632 cls : 'small-box bg-' + this.bgcolor,
19640 cls : 'roo-headline',
19641 html : this.headline
19645 cls : 'roo-content',
19646 html : this.content
19660 cls : 'ion ' + this.icon
19669 cls : 'small-box-footer',
19670 href : this.fhref || '#',
19674 cfg.cn.push(footer);
19681 onRender : function(ct,position){
19682 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19689 setHeadline: function (value)
19691 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19694 setFooter: function (value, href)
19696 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19699 this.el.select('a.small-box-footer',true).first().attr('href', href);
19704 setContent: function (value)
19706 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19709 initEvents: function()
19723 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19726 * @class Roo.bootstrap.dash.TabBox
19727 * @extends Roo.bootstrap.Component
19728 * Bootstrap TabBox class
19729 * @cfg {String} title Title of the TabBox
19730 * @cfg {String} icon Icon of the TabBox
19731 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19734 * Create a new TabBox
19735 * @param {Object} config The config object
19739 Roo.bootstrap.dash.TabBox = function(config){
19740 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19745 * When a pane is added
19746 * @param {Roo.bootstrap.dash.TabPane} pane
19753 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19759 getChildContainer : function()
19761 return this.el.select('.tab-content', true).first();
19764 getAutoCreate : function(){
19768 cls: 'pull-left header',
19776 cls: 'fa ' + this.icon
19783 cls: 'nav-tabs-custom',
19787 cls: 'nav nav-tabs pull-right',
19794 cls: 'tab-content no-padding',
19802 initEvents : function()
19804 //Roo.log('add add pane handler');
19805 this.on('addpane', this.onAddPane, this);
19808 * Updates the box title
19809 * @param {String} html to set the title to.
19811 setTitle : function(value)
19813 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19815 onAddPane : function(pane)
19817 //Roo.log('addpane');
19819 // tabs are rendere left to right..
19820 if(!this.showtabs){
19824 var ctr = this.el.select('.nav-tabs', true).first();
19827 var existing = ctr.select('.nav-tab',true);
19828 var qty = existing.getCount();;
19831 var tab = ctr.createChild({
19833 cls : 'nav-tab' + (qty ? '' : ' active'),
19841 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19844 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19846 pane.el.addClass('active');
19851 onTabClick : function(ev,un,ob,pane)
19853 //Roo.log('tab - prev default');
19854 ev.preventDefault();
19857 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19858 pane.tab.addClass('active');
19859 //Roo.log(pane.title);
19860 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19861 // technically we should have a deactivate event.. but maybe add later.
19862 // and it should not de-activate the selected tab...
19864 pane.el.addClass('active');
19865 pane.fireEvent('activate');
19880 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19882 * @class Roo.bootstrap.TabPane
19883 * @extends Roo.bootstrap.Component
19884 * Bootstrap TabPane class
19885 * @cfg {Boolean} active (false | true) Default false
19886 * @cfg {String} title title of panel
19890 * Create a new TabPane
19891 * @param {Object} config The config object
19894 Roo.bootstrap.dash.TabPane = function(config){
19895 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19901 * When a pane is activated
19902 * @param {Roo.bootstrap.dash.TabPane} pane
19909 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19914 // the tabBox that this is attached to.
19917 getAutoCreate : function()
19925 cfg.cls += ' active';
19930 initEvents : function()
19932 //Roo.log('trigger add pane handler');
19933 this.parent().fireEvent('addpane', this)
19937 * Updates the tab title
19938 * @param {String} html to set the title to.
19940 setTitle: function(str)
19946 this.tab.select('a', true).first().dom.innerHTML = str;
19963 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19966 * @class Roo.bootstrap.menu.Menu
19967 * @extends Roo.bootstrap.Component
19968 * Bootstrap Menu class - container for Menu
19969 * @cfg {String} html Text of the menu
19970 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19971 * @cfg {String} icon Font awesome icon
19972 * @cfg {String} pos Menu align to (top | bottom) default bottom
19976 * Create a new Menu
19977 * @param {Object} config The config object
19981 Roo.bootstrap.menu.Menu = function(config){
19982 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19986 * @event beforeshow
19987 * Fires before this menu is displayed
19988 * @param {Roo.bootstrap.menu.Menu} this
19992 * @event beforehide
19993 * Fires before this menu is hidden
19994 * @param {Roo.bootstrap.menu.Menu} this
19999 * Fires after this menu is displayed
20000 * @param {Roo.bootstrap.menu.Menu} this
20005 * Fires after this menu is hidden
20006 * @param {Roo.bootstrap.menu.Menu} this
20011 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20012 * @param {Roo.bootstrap.menu.Menu} this
20013 * @param {Roo.EventObject} e
20020 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20024 weight : 'default',
20029 getChildContainer : function() {
20030 if(this.isSubMenu){
20034 return this.el.select('ul.dropdown-menu', true).first();
20037 getAutoCreate : function()
20042 cls : 'roo-menu-text',
20050 cls : 'fa ' + this.icon
20061 cls : 'dropdown-button btn btn-' + this.weight,
20066 cls : 'dropdown-toggle btn btn-' + this.weight,
20076 cls : 'dropdown-menu'
20082 if(this.pos == 'top'){
20083 cfg.cls += ' dropup';
20086 if(this.isSubMenu){
20089 cls : 'dropdown-menu'
20096 onRender : function(ct, position)
20098 this.isSubMenu = ct.hasClass('dropdown-submenu');
20100 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20103 initEvents : function()
20105 if(this.isSubMenu){
20109 this.hidden = true;
20111 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20112 this.triggerEl.on('click', this.onTriggerPress, this);
20114 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20115 this.buttonEl.on('click', this.onClick, this);
20121 if(this.isSubMenu){
20125 return this.el.select('ul.dropdown-menu', true).first();
20128 onClick : function(e)
20130 this.fireEvent("click", this, e);
20133 onTriggerPress : function(e)
20135 if (this.isVisible()) {
20142 isVisible : function(){
20143 return !this.hidden;
20148 this.fireEvent("beforeshow", this);
20150 this.hidden = false;
20151 this.el.addClass('open');
20153 Roo.get(document).on("mouseup", this.onMouseUp, this);
20155 this.fireEvent("show", this);
20162 this.fireEvent("beforehide", this);
20164 this.hidden = true;
20165 this.el.removeClass('open');
20167 Roo.get(document).un("mouseup", this.onMouseUp);
20169 this.fireEvent("hide", this);
20172 onMouseUp : function()
20186 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20189 * @class Roo.bootstrap.menu.Item
20190 * @extends Roo.bootstrap.Component
20191 * Bootstrap MenuItem class
20192 * @cfg {Boolean} submenu (true | false) default false
20193 * @cfg {String} html text of the item
20194 * @cfg {String} href the link
20195 * @cfg {Boolean} disable (true | false) default false
20196 * @cfg {Boolean} preventDefault (true | false) default true
20197 * @cfg {String} icon Font awesome icon
20198 * @cfg {String} pos Submenu align to (left | right) default right
20202 * Create a new Item
20203 * @param {Object} config The config object
20207 Roo.bootstrap.menu.Item = function(config){
20208 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20212 * Fires when the mouse is hovering over this menu
20213 * @param {Roo.bootstrap.menu.Item} this
20214 * @param {Roo.EventObject} e
20219 * Fires when the mouse exits this menu
20220 * @param {Roo.bootstrap.menu.Item} this
20221 * @param {Roo.EventObject} e
20227 * The raw click event for the entire grid.
20228 * @param {Roo.EventObject} e
20234 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20239 preventDefault: true,
20244 getAutoCreate : function()
20249 cls : 'roo-menu-item-text',
20257 cls : 'fa ' + this.icon
20266 href : this.href || '#',
20273 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20277 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20279 if(this.pos == 'left'){
20280 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20287 initEvents : function()
20289 this.el.on('mouseover', this.onMouseOver, this);
20290 this.el.on('mouseout', this.onMouseOut, this);
20292 this.el.select('a', true).first().on('click', this.onClick, this);
20296 onClick : function(e)
20298 if(this.preventDefault){
20299 e.preventDefault();
20302 this.fireEvent("click", this, e);
20305 onMouseOver : function(e)
20307 if(this.submenu && this.pos == 'left'){
20308 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20311 this.fireEvent("mouseover", this, e);
20314 onMouseOut : function(e)
20316 this.fireEvent("mouseout", this, e);
20328 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20331 * @class Roo.bootstrap.menu.Separator
20332 * @extends Roo.bootstrap.Component
20333 * Bootstrap Separator class
20336 * Create a new Separator
20337 * @param {Object} config The config object
20341 Roo.bootstrap.menu.Separator = function(config){
20342 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20345 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20347 getAutoCreate : function(){