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');
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'));
228 skip_children = false;
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
234 skip_children = true;
239 // actually if flexy:foreach is found, we really want to create
240 // multiple copies here...
242 //Roo.log(this[cntr]());
243 cn.render(this[cntr](true));
245 // then add the element..
253 if (typeof (tree.menu) != 'undefined') {
254 tree.menu.parentType = cn.xtype;
255 tree.menu.triggerEl = cn.el;
256 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
260 if (!tree.items || !tree.items.length) {
264 var items = tree.items;
267 //Roo.log(items.length);
269 if (!skip_children) {
270 for(var i =0;i < items.length;i++) {
271 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
293 * @class Roo.bootstrap.Body
294 * @extends Roo.bootstrap.Component
295 * Bootstrap Body class
299 * @param {Object} config The config object
302 Roo.bootstrap.Body = function(config){
303 Roo.bootstrap.Body.superclass.constructor.call(this, config);
304 this.el = Roo.get(document.body);
305 if (this.cls && this.cls.length) {
306 Roo.get(document.body).addClass(this.cls);
310 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
315 onRender : function(ct, position)
317 /* Roo.log("Roo.bootstrap.Body - onRender");
318 if (this.cls && this.cls.length) {
319 Roo.get(document.body).addClass(this.cls);
339 * @class Roo.bootstrap.ButtonGroup
340 * @extends Roo.bootstrap.Component
341 * Bootstrap ButtonGroup class
342 * @cfg {String} size lg | sm | xs (default empty normal)
343 * @cfg {String} align vertical | justified (default none)
344 * @cfg {String} direction up | down (default down)
345 * @cfg {Boolean} toolbar false | true
346 * @cfg {Boolean} btn true | false
351 * @param {Object} config The config object
354 Roo.bootstrap.ButtonGroup = function(config){
355 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
358 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
366 getAutoCreate : function(){
372 cfg.html = this.html || cfg.html;
383 if (['vertical','justified'].indexOf(this.align)!==-1) {
384 cfg.cls = 'btn-group-' + this.align;
386 if (this.align == 'justified') {
387 console.log(this.items);
391 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
392 cfg.cls += ' btn-group-' + this.size;
395 if (this.direction == 'up') {
396 cfg.cls += ' dropup' ;
412 * @class Roo.bootstrap.Button
413 * @extends Roo.bootstrap.Component
414 * Bootstrap Button class
415 * @cfg {String} html The button content
416 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
417 * @cfg {String} size empty | lg | sm | xs
418 * @cfg {String} tag empty | a | input | submit
419 * @cfg {String} href empty or href
420 * @cfg {Boolean} disabled false | true
421 * @cfg {Boolean} isClose false | true
422 * @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
423 * @cfg {String} badge text for badge
424 * @cfg {String} theme default (or empty) | glow
425 * @cfg {Boolean} inverse false | true
426 * @cfg {Boolean} toggle false | true
427 * @cfg {String} ontext text for on toggle state
428 * @cfg {String} offtext text for off toggle state
429 * @cfg {Boolean} defaulton true | false
430 * @cfg {Boolean} preventDefault (true | false) default true
431 * @cfg {Boolean} removeClass true | false remove the standard class..
432 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
435 * Create a new button
436 * @param {Object} config The config object
440 Roo.bootstrap.Button = function(config){
441 Roo.bootstrap.Button.superclass.constructor.call(this, config);
446 * When a butotn is pressed
447 * @param {Roo.EventObject} e
452 * After the button has been toggles
453 * @param {Roo.EventObject} e
454 * @param {boolean} pressed (also available as button.pressed)
460 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
478 preventDefault: true,
487 getAutoCreate : function(){
495 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
496 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
501 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
503 if (this.toggle == true) {
506 cls: 'slider-frame roo-button',
511 'data-off-text':'OFF',
512 cls: 'slider-button',
518 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
519 cfg.cls += ' '+this.weight;
528 cfg["aria-hidden"] = true;
530 cfg.html = "×";
536 if (this.theme==='default') {
537 cfg.cls = 'btn roo-button';
539 //if (this.parentType != 'Navbar') {
540 this.weight = this.weight.length ? this.weight : 'default';
542 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
544 cfg.cls += ' btn-' + this.weight;
546 } else if (this.theme==='glow') {
549 cfg.cls = 'btn-glow roo-button';
551 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
553 cfg.cls += ' ' + this.weight;
559 this.cls += ' inverse';
564 cfg.cls += ' active';
568 cfg.disabled = 'disabled';
572 Roo.log('changing to ul' );
574 this.glyphicon = 'caret';
577 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
579 //gsRoo.log(this.parentType);
580 if (this.parentType === 'Navbar' && !this.parent().bar) {
581 Roo.log('changing to li?');
590 href : this.href || '#'
593 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
594 cfg.cls += ' dropdown';
601 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
603 if (this.glyphicon) {
604 cfg.html = ' ' + cfg.html;
609 cls: 'glyphicon glyphicon-' + this.glyphicon
619 // cfg.cls='btn roo-button';
623 var value = cfg.html;
628 cls: 'glyphicon glyphicon-' + this.glyphicon,
647 cfg.cls += ' dropdown';
648 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
651 if (cfg.tag !== 'a' && this.href !== '') {
652 throw "Tag must be a to set href.";
653 } else if (this.href.length > 0) {
654 cfg.href = this.href;
657 if(this.removeClass){
662 cfg.target = this.target;
667 initEvents: function() {
668 // Roo.log('init events?');
669 // Roo.log(this.el.dom);
672 if (typeof (this.menu) != 'undefined') {
673 this.menu.parentType = this.xtype;
674 this.menu.triggerEl = this.el;
675 this.addxtype(Roo.apply({}, this.menu));
679 if (this.el.hasClass('roo-button')) {
680 this.el.on('click', this.onClick, this);
682 this.el.select('.roo-button').on('click', this.onClick, this);
685 if(this.removeClass){
686 this.el.on('click', this.onClick, this);
689 this.el.enableDisplayMode();
692 onClick : function(e)
698 Roo.log('button on click ');
699 if(this.preventDefault){
702 if (this.pressed === true || this.pressed === false) {
703 this.pressed = !this.pressed;
704 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
705 this.fireEvent('toggle', this, e, this.pressed);
709 this.fireEvent('click', this, e);
713 * Enables this button
717 this.disabled = false;
718 this.el.removeClass('disabled');
722 * Disable this button
726 this.disabled = true;
727 this.el.addClass('disabled');
730 * sets the active state on/off,
731 * @param {Boolean} state (optional) Force a particular state
733 setActive : function(v) {
735 this.el[v ? 'addClass' : 'removeClass']('active');
738 * toggles the current active state
740 toggleActive : function()
742 var active = this.el.hasClass('active');
743 this.setActive(!active);
747 setText : function(str)
749 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
753 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
776 * @class Roo.bootstrap.Column
777 * @extends Roo.bootstrap.Component
778 * Bootstrap Column class
779 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
780 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
781 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
782 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
783 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
784 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
785 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
786 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
789 * @cfg {Boolean} hidden (true|false) hide the element
790 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
791 * @cfg {String} fa (ban|check|...) font awesome icon
792 * @cfg {Number} fasize (1|2|....) font awsome size
794 * @cfg {String} icon (info-sign|check|...) glyphicon name
796 * @cfg {String} html content of column.
799 * Create a new Column
800 * @param {Object} config The config object
803 Roo.bootstrap.Column = function(config){
804 Roo.bootstrap.Column.superclass.constructor.call(this, config);
807 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
825 getAutoCreate : function(){
826 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
834 ['xs','sm','md','lg'].map(function(size){
835 //Roo.log( size + ':' + settings[size]);
837 if (settings[size+'off'] !== false) {
838 cfg.cls += ' col-' + settings[size+'off'] + '-offset';
841 if (settings[size] === false) {
844 Roo.log(settings[size]);
845 if (!settings[size]) { // 0 = hidden
846 cfg.cls += ' hidden-' + size;
849 cfg.cls += ' col-' + size + '-' + settings[size];
854 cfg.cls += ' hidden';
857 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
858 cfg.cls +=' alert alert-' + this.alert;
862 if (this.html.length) {
863 cfg.html = this.html;
867 if (this.fasize > 1) {
868 fasize = ' fa-' + this.fasize + 'x';
870 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
875 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
894 * @class Roo.bootstrap.Container
895 * @extends Roo.bootstrap.Component
896 * Bootstrap Container class
897 * @cfg {Boolean} jumbotron is it a jumbotron element
898 * @cfg {String} html content of element
899 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
900 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
901 * @cfg {String} header content of header (for panel)
902 * @cfg {String} footer content of footer (for panel)
903 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
904 * @cfg {String} tag (header|aside|section) type of HTML tag.
905 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
906 * @cfg {String} fa (ban|check|...) font awesome icon
907 * @cfg {String} icon (info-sign|check|...) glyphicon name
908 * @cfg {Boolean} hidden (true|false) hide the element
912 * Create a new Container
913 * @param {Object} config The config object
916 Roo.bootstrap.Container = function(config){
917 Roo.bootstrap.Container.superclass.constructor.call(this, config);
920 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
934 getChildContainer : function() {
940 if (this.panel.length) {
941 return this.el.select('.panel-body',true).first();
948 getAutoCreate : function(){
951 tag : this.tag || 'div',
955 if (this.jumbotron) {
956 cfg.cls = 'jumbotron';
961 // - this is applied by the parent..
963 // cfg.cls = this.cls + '';
966 if (this.sticky.length) {
968 var bd = Roo.get(document.body);
969 if (!bd.hasClass('bootstrap-sticky')) {
970 bd.addClass('bootstrap-sticky');
971 Roo.select('html',true).setStyle('height', '100%');
974 cfg.cls += 'bootstrap-sticky-' + this.sticky;
978 if (this.well.length) {
982 cfg.cls +=' well well-' +this.well;
991 cfg.cls += ' hidden';
995 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
996 cfg.cls +=' alert alert-' + this.alert;
1001 if (this.panel.length) {
1002 cfg.cls += ' panel panel-' + this.panel;
1004 if (this.header.length) {
1007 cls : 'panel-heading',
1010 cls : 'panel-title',
1023 if (this.footer.length) {
1025 cls : 'panel-footer',
1034 body.html = this.html || cfg.html;
1035 // prefix with the icons..
1037 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1040 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1045 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1046 cfg.cls = 'container';
1052 titleEl : function()
1054 if(!this.el || !this.panel.length || !this.header.length){
1058 return this.el.select('.panel-title',true).first();
1061 setTitle : function(v)
1063 var titleEl = this.titleEl();
1069 titleEl.dom.innerHTML = v;
1072 getTitle : function()
1075 var titleEl = this.titleEl();
1081 return titleEl.dom.innerHTML;
1095 * @class Roo.bootstrap.Img
1096 * @extends Roo.bootstrap.Component
1097 * Bootstrap Img class
1098 * @cfg {Boolean} imgResponsive false | true
1099 * @cfg {String} border rounded | circle | thumbnail
1100 * @cfg {String} src image source
1101 * @cfg {String} alt image alternative text
1102 * @cfg {String} href a tag href
1103 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1106 * Create a new Input
1107 * @param {Object} config The config object
1110 Roo.bootstrap.Img = function(config){
1111 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1117 * The img click event for the img.
1118 * @param {Roo.EventObject} e
1124 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1126 imgResponsive: true,
1132 getAutoCreate : function(){
1136 cls: (this.imgResponsive) ? 'img-responsive' : '',
1140 cfg.html = this.html || cfg.html;
1142 cfg.src = this.src || cfg.src;
1144 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1145 cfg.cls += ' img-' + this.border;
1162 a.target = this.target;
1168 return (this.href) ? a : cfg;
1171 initEvents: function() {
1174 this.el.on('click', this.onClick, this);
1178 onClick : function(e)
1180 Roo.log('img onclick');
1181 this.fireEvent('click', this, e);
1195 * @class Roo.bootstrap.Link
1196 * @extends Roo.bootstrap.Component
1197 * Bootstrap Link Class
1198 * @cfg {String} alt image alternative text
1199 * @cfg {String} href a tag href
1200 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1201 * @cfg {String} html the content of the link.
1202 * @cfg {String} anchor name for the anchor link
1204 * @cfg {Boolean} preventDefault (true | false) default false
1208 * Create a new Input
1209 * @param {Object} config The config object
1212 Roo.bootstrap.Link = function(config){
1213 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1219 * The img click event for the img.
1220 * @param {Roo.EventObject} e
1226 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1230 preventDefault: false,
1234 getAutoCreate : function()
1240 // anchor's do not require html/href...
1241 if (this.anchor === false) {
1242 cfg.html = this.html || 'html-missing';
1243 cfg.href = this.href || '#';
1245 cfg.name = this.anchor;
1246 if (this.html !== false) {
1247 cfg.html = this.html;
1249 if (this.href !== false) {
1250 cfg.href = this.href;
1254 if(this.alt !== false){
1259 if(this.target !== false) {
1260 cfg.target = this.target;
1266 initEvents: function() {
1268 if(!this.href || this.preventDefault){
1269 this.el.on('click', this.onClick, this);
1273 onClick : function(e)
1275 if(this.preventDefault){
1278 //Roo.log('img onclick');
1279 this.fireEvent('click', this, e);
1292 * @class Roo.bootstrap.Header
1293 * @extends Roo.bootstrap.Component
1294 * Bootstrap Header class
1295 * @cfg {String} html content of header
1296 * @cfg {Number} level (1|2|3|4|5|6) default 1
1299 * Create a new Header
1300 * @param {Object} config The config object
1304 Roo.bootstrap.Header = function(config){
1305 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1308 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1316 getAutoCreate : function(){
1319 tag: 'h' + (1 *this.level),
1320 html: this.html || 'fill in html'
1332 * Ext JS Library 1.1.1
1333 * Copyright(c) 2006-2007, Ext JS, LLC.
1335 * Originally Released Under LGPL - original licence link has changed is not relivant.
1338 * <script type="text/javascript">
1342 * @class Roo.bootstrap.MenuMgr
1343 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1346 Roo.bootstrap.MenuMgr = function(){
1347 var menus, active, groups = {}, attached = false, lastShow = new Date();
1349 // private - called when first menu is created
1352 active = new Roo.util.MixedCollection();
1353 Roo.get(document).addKeyListener(27, function(){
1354 if(active.length > 0){
1362 if(active && active.length > 0){
1363 var c = active.clone();
1373 if(active.length < 1){
1374 Roo.get(document).un("mouseup", onMouseDown);
1382 var last = active.last();
1383 lastShow = new Date();
1386 Roo.get(document).on("mouseup", onMouseDown);
1391 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1392 m.parentMenu.activeChild = m;
1393 }else if(last && last.isVisible()){
1394 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1399 function onBeforeHide(m){
1401 m.activeChild.hide();
1403 if(m.autoHideTimer){
1404 clearTimeout(m.autoHideTimer);
1405 delete m.autoHideTimer;
1410 function onBeforeShow(m){
1411 var pm = m.parentMenu;
1412 if(!pm && !m.allowOtherMenus){
1414 }else if(pm && pm.activeChild && active != m){
1415 pm.activeChild.hide();
1420 function onMouseDown(e){
1421 Roo.log("on MouseDown");
1422 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1430 function onBeforeCheck(mi, state){
1432 var g = groups[mi.group];
1433 for(var i = 0, l = g.length; i < l; i++){
1435 g[i].setChecked(false);
1444 * Hides all menus that are currently visible
1446 hideAll : function(){
1451 register : function(menu){
1455 menus[menu.id] = menu;
1456 menu.on("beforehide", onBeforeHide);
1457 menu.on("hide", onHide);
1458 menu.on("beforeshow", onBeforeShow);
1459 menu.on("show", onShow);
1461 if(g && menu.events["checkchange"]){
1465 groups[g].push(menu);
1466 menu.on("checkchange", onCheck);
1471 * Returns a {@link Roo.menu.Menu} object
1472 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1473 * be used to generate and return a new Menu instance.
1475 get : function(menu){
1476 if(typeof menu == "string"){ // menu id
1478 }else if(menu.events){ // menu instance
1481 /*else if(typeof menu.length == 'number'){ // array of menu items?
1482 return new Roo.bootstrap.Menu({items:menu});
1483 }else{ // otherwise, must be a config
1484 return new Roo.bootstrap.Menu(menu);
1491 unregister : function(menu){
1492 delete menus[menu.id];
1493 menu.un("beforehide", onBeforeHide);
1494 menu.un("hide", onHide);
1495 menu.un("beforeshow", onBeforeShow);
1496 menu.un("show", onShow);
1498 if(g && menu.events["checkchange"]){
1499 groups[g].remove(menu);
1500 menu.un("checkchange", onCheck);
1505 registerCheckable : function(menuItem){
1506 var g = menuItem.group;
1511 groups[g].push(menuItem);
1512 menuItem.on("beforecheckchange", onBeforeCheck);
1517 unregisterCheckable : function(menuItem){
1518 var g = menuItem.group;
1520 groups[g].remove(menuItem);
1521 menuItem.un("beforecheckchange", onBeforeCheck);
1533 * @class Roo.bootstrap.Menu
1534 * @extends Roo.bootstrap.Component
1535 * Bootstrap Menu class - container for MenuItems
1536 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1540 * @param {Object} config The config object
1544 Roo.bootstrap.Menu = function(config){
1545 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1546 if (this.registerMenu) {
1547 Roo.bootstrap.MenuMgr.register(this);
1552 * Fires before this menu is displayed
1553 * @param {Roo.menu.Menu} this
1558 * Fires before this menu is hidden
1559 * @param {Roo.menu.Menu} this
1564 * Fires after this menu is displayed
1565 * @param {Roo.menu.Menu} this
1570 * Fires after this menu is hidden
1571 * @param {Roo.menu.Menu} this
1576 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1577 * @param {Roo.menu.Menu} this
1578 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1579 * @param {Roo.EventObject} e
1584 * Fires when the mouse is hovering over this menu
1585 * @param {Roo.menu.Menu} this
1586 * @param {Roo.EventObject} e
1587 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1592 * Fires when the mouse exits this menu
1593 * @param {Roo.menu.Menu} this
1594 * @param {Roo.EventObject} e
1595 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1600 * Fires when a menu item contained in this menu is clicked
1601 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1602 * @param {Roo.EventObject} e
1606 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1609 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1613 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1616 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1618 registerMenu : true,
1620 menuItems :false, // stores the menu items..
1626 getChildContainer : function() {
1630 getAutoCreate : function(){
1632 //if (['right'].indexOf(this.align)!==-1) {
1633 // cfg.cn[1].cls += ' pull-right'
1639 cls : 'dropdown-menu' ,
1640 style : 'z-index:1000'
1644 if (this.type === 'submenu') {
1645 cfg.cls = 'submenu active';
1647 if (this.type === 'treeview') {
1648 cfg.cls = 'treeview-menu';
1653 initEvents : function() {
1655 // Roo.log("ADD event");
1656 // Roo.log(this.triggerEl.dom);
1657 this.triggerEl.on('click', this.onTriggerPress, this);
1658 this.triggerEl.addClass('dropdown-toggle');
1659 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1661 this.el.on("mouseover", this.onMouseOver, this);
1662 this.el.on("mouseout", this.onMouseOut, this);
1666 findTargetItem : function(e){
1667 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1671 //Roo.log(t); Roo.log(t.id);
1673 //Roo.log(this.menuitems);
1674 return this.menuitems.get(t.id);
1676 //return this.items.get(t.menuItemId);
1681 onClick : function(e){
1682 Roo.log("menu.onClick");
1683 var t = this.findTargetItem(e);
1689 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1690 if(t == this.activeItem && t.shouldDeactivate(e)){
1691 this.activeItem.deactivate();
1692 delete this.activeItem;
1696 this.setActiveItem(t, true);
1703 Roo.log('pass click event');
1707 this.fireEvent("click", this, t, e);
1711 onMouseOver : function(e){
1712 var t = this.findTargetItem(e);
1715 // if(t.canActivate && !t.disabled){
1716 // this.setActiveItem(t, true);
1720 this.fireEvent("mouseover", this, e, t);
1722 isVisible : function(){
1723 return !this.hidden;
1725 onMouseOut : function(e){
1726 var t = this.findTargetItem(e);
1729 // if(t == this.activeItem && t.shouldDeactivate(e)){
1730 // this.activeItem.deactivate();
1731 // delete this.activeItem;
1734 this.fireEvent("mouseout", this, e, t);
1739 * Displays this menu relative to another element
1740 * @param {String/HTMLElement/Roo.Element} element The element to align to
1741 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1742 * the element (defaults to this.defaultAlign)
1743 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1745 show : function(el, pos, parentMenu){
1746 this.parentMenu = parentMenu;
1750 this.fireEvent("beforeshow", this);
1751 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1754 * Displays this menu at a specific xy position
1755 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1756 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1758 showAt : function(xy, parentMenu, /* private: */_e){
1759 this.parentMenu = parentMenu;
1764 this.fireEvent("beforeshow", this);
1766 //xy = this.el.adjustForConstraints(xy);
1768 //this.el.setXY(xy);
1770 this.hideMenuItems();
1771 this.hidden = false;
1772 this.triggerEl.addClass('open');
1774 this.fireEvent("show", this);
1780 this.doFocus.defer(50, this);
1784 doFocus : function(){
1786 this.focusEl.focus();
1791 * Hides this menu and optionally all parent menus
1792 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1794 hide : function(deep){
1796 this.hideMenuItems();
1797 if(this.el && this.isVisible()){
1798 this.fireEvent("beforehide", this);
1799 if(this.activeItem){
1800 this.activeItem.deactivate();
1801 this.activeItem = null;
1803 this.triggerEl.removeClass('open');;
1805 this.fireEvent("hide", this);
1807 if(deep === true && this.parentMenu){
1808 this.parentMenu.hide(true);
1812 onTriggerPress : function(e)
1815 Roo.log('trigger press');
1816 //Roo.log(e.getTarget());
1817 // Roo.log(this.triggerEl.dom);
1818 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1821 if (this.isVisible()) {
1825 this.show(this.triggerEl, false, false);
1834 hideMenuItems : function()
1836 //$(backdrop).remove()
1837 Roo.select('.open',true).each(function(aa) {
1839 aa.removeClass('open');
1840 //var parent = getParent($(this))
1841 //var relatedTarget = { relatedTarget: this }
1843 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1844 //if (e.isDefaultPrevented()) return
1845 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1848 addxtypeChild : function (tree, cntr) {
1849 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1851 this.menuitems.add(comp);
1872 * @class Roo.bootstrap.MenuItem
1873 * @extends Roo.bootstrap.Component
1874 * Bootstrap MenuItem class
1875 * @cfg {String} html the menu label
1876 * @cfg {String} href the link
1877 * @cfg {Boolean} preventDefault (true | false) default true
1881 * Create a new MenuItem
1882 * @param {Object} config The config object
1886 Roo.bootstrap.MenuItem = function(config){
1887 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1892 * The raw click event for the entire grid.
1893 * @param {Roo.EventObject} e
1899 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1903 preventDefault: true,
1905 getAutoCreate : function(){
1908 cls: 'dropdown-menu-item',
1917 if (this.parent().type == 'treeview') {
1918 cfg.cls = 'treeview-menu';
1921 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1922 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1926 initEvents: function() {
1928 //this.el.select('a').on('click', this.onClick, this);
1931 onClick : function(e)
1933 Roo.log('item on click ');
1934 //if(this.preventDefault){
1935 // e.preventDefault();
1937 //this.parent().hideMenuItems();
1939 this.fireEvent('click', this, e);
1958 * @class Roo.bootstrap.MenuSeparator
1959 * @extends Roo.bootstrap.Component
1960 * Bootstrap MenuSeparator class
1963 * Create a new MenuItem
1964 * @param {Object} config The config object
1968 Roo.bootstrap.MenuSeparator = function(config){
1969 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1972 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1974 getAutoCreate : function(){
1989 <div class="modal fade">
1990 <div class="modal-dialog">
1991 <div class="modal-content">
1992 <div class="modal-header">
1993 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1994 <h4 class="modal-title">Modal title</h4>
1996 <div class="modal-body">
1997 <p>One fine body…</p>
1999 <div class="modal-footer">
2000 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2001 <button type="button" class="btn btn-primary">Save changes</button>
2003 </div><!-- /.modal-content -->
2004 </div><!-- /.modal-dialog -->
2005 </div><!-- /.modal -->
2015 * @class Roo.bootstrap.Modal
2016 * @extends Roo.bootstrap.Component
2017 * Bootstrap Modal class
2018 * @cfg {String} title Title of dialog
2019 * @cfg {Boolean} specificTitle (true|false) default false
2020 * @cfg {Array} buttons Array of buttons or standard button set..
2021 * @cfg {String} buttonPosition (left|right|center) default right
2024 * Create a new Modal Dialog
2025 * @param {Object} config The config object
2028 Roo.bootstrap.Modal = function(config){
2029 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2034 * The raw btnclick event for the button
2035 * @param {Roo.EventObject} e
2039 this.buttons = this.buttons || [];
2042 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2044 title : 'test dialog',
2051 specificTitle: false,
2053 buttonPosition: 'right',
2055 onRender : function(ct, position)
2057 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2060 var cfg = Roo.apply({}, this.getAutoCreate());
2063 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2065 //if (!cfg.name.length) {
2069 cfg.cls += ' ' + this.cls;
2072 cfg.style = this.style;
2074 this.el = Roo.get(document.body).createChild(cfg, position);
2076 //var type = this.el.dom.type;
2078 if(this.tabIndex !== undefined){
2079 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2084 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2085 this.maskEl.enableDisplayMode("block");
2087 //this.el.addClass("x-dlg-modal");
2089 if (this.buttons.length) {
2090 Roo.each(this.buttons, function(bb) {
2091 b = Roo.apply({}, bb);
2092 b.xns = b.xns || Roo.bootstrap;
2093 b.xtype = b.xtype || 'Button';
2094 if (typeof(b.listeners) == 'undefined') {
2095 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2098 var btn = Roo.factory(b);
2100 btn.onRender(this.el.select('.modal-footer div').first());
2104 // render the children.
2107 if(typeof(this.items) != 'undefined'){
2108 var items = this.items;
2111 for(var i =0;i < items.length;i++) {
2112 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2116 this.items = nitems;
2118 this.body = this.el.select('.modal-body',true).first();
2119 this.close = this.el.select('.modal-header .close', true).first();
2120 this.footer = this.el.select('.modal-footer',true).first();
2122 //this.el.addClass([this.fieldClass, this.cls]);
2125 getAutoCreate : function(){
2130 html : this.html || ''
2135 cls : 'modal-title',
2139 if(this.specificTitle){
2145 style : 'display: none',
2148 cls: "modal-dialog",
2151 cls : "modal-content",
2154 cls : 'modal-header',
2166 cls : 'modal-footer',
2170 cls: 'btn-' + this.buttonPosition
2189 getChildContainer : function() {
2191 return this.el.select('.modal-body',true).first();
2194 getButtonContainer : function() {
2195 return this.el.select('.modal-footer div',true).first();
2198 initEvents : function()
2200 this.el.select('.modal-header .close').on('click', this.hide, this);
2202 // this.addxtype(this);
2206 if (!this.rendered) {
2210 this.el.addClass('on');
2211 this.el.removeClass('fade');
2212 this.el.setStyle('display', 'block');
2213 Roo.get(document.body).addClass("x-body-masked");
2214 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2216 this.el.setStyle('zIndex', '10001');
2217 this.fireEvent('show', this);
2223 Roo.log('Modal hide?!');
2225 Roo.get(document.body).removeClass("x-body-masked");
2226 this.el.removeClass('on');
2227 this.el.addClass('fade');
2228 this.el.setStyle('display', 'none');
2229 this.fireEvent('hide', this);
2232 addButton : function(str, cb)
2236 var b = Roo.apply({}, { html : str } );
2237 b.xns = b.xns || Roo.bootstrap;
2238 b.xtype = b.xtype || 'Button';
2239 if (typeof(b.listeners) == 'undefined') {
2240 b.listeners = { click : cb.createDelegate(this) };
2243 var btn = Roo.factory(b);
2245 btn.onRender(this.el.select('.modal-footer div').first());
2251 setDefaultButton : function(btn)
2253 //this.el.select('.modal-footer').()
2255 resizeTo: function(w,h)
2259 setContentSize : function(w, h)
2263 onButtonClick: function(btn,e)
2266 this.fireEvent('btnclick', btn.name, e);
2268 setTitle: function(str) {
2269 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2275 Roo.apply(Roo.bootstrap.Modal, {
2277 * Button config that displays a single OK button
2286 * Button config that displays Yes and No buttons
2302 * Button config that displays OK and Cancel buttons
2317 * Button config that displays Yes, No and Cancel buttons
2339 * messagebox - can be used as a replace
2343 * @class Roo.MessageBox
2344 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2348 Roo.Msg.alert('Status', 'Changes saved successfully.');
2350 // Prompt for user data:
2351 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2353 // process text value...
2357 // Show a dialog using config options:
2359 title:'Save Changes?',
2360 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2361 buttons: Roo.Msg.YESNOCANCEL,
2368 Roo.bootstrap.MessageBox = function(){
2369 var dlg, opt, mask, waitTimer;
2370 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2371 var buttons, activeTextEl, bwidth;
2375 var handleButton = function(button){
2377 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2381 var handleHide = function(){
2383 dlg.el.removeClass(opt.cls);
2386 // Roo.TaskMgr.stop(waitTimer);
2387 // waitTimer = null;
2392 var updateButtons = function(b){
2395 buttons["ok"].hide();
2396 buttons["cancel"].hide();
2397 buttons["yes"].hide();
2398 buttons["no"].hide();
2399 //dlg.footer.dom.style.display = 'none';
2402 dlg.footer.dom.style.display = '';
2403 for(var k in buttons){
2404 if(typeof buttons[k] != "function"){
2407 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2408 width += buttons[k].el.getWidth()+15;
2418 var handleEsc = function(d, k, e){
2419 if(opt && opt.closable !== false){
2429 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2430 * @return {Roo.BasicDialog} The BasicDialog element
2432 getDialog : function(){
2434 dlg = new Roo.bootstrap.Modal( {
2437 //constraintoviewport:false,
2439 //collapsible : false,
2444 //buttonAlign:"center",
2445 closeClick : function(){
2446 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2449 handleButton("cancel");
2454 dlg.on("hide", handleHide);
2456 //dlg.addKeyListener(27, handleEsc);
2458 this.buttons = buttons;
2459 var bt = this.buttonText;
2460 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2461 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2462 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2463 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2465 bodyEl = dlg.body.createChild({
2467 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2468 '<textarea class="roo-mb-textarea"></textarea>' +
2469 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2471 msgEl = bodyEl.dom.firstChild;
2472 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2473 textboxEl.enableDisplayMode();
2474 textboxEl.addKeyListener([10,13], function(){
2475 if(dlg.isVisible() && opt && opt.buttons){
2478 }else if(opt.buttons.yes){
2479 handleButton("yes");
2483 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2484 textareaEl.enableDisplayMode();
2485 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2486 progressEl.enableDisplayMode();
2487 var pf = progressEl.dom.firstChild;
2489 pp = Roo.get(pf.firstChild);
2490 pp.setHeight(pf.offsetHeight);
2498 * Updates the message box body text
2499 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2500 * the XHTML-compliant non-breaking space character '&#160;')
2501 * @return {Roo.MessageBox} This message box
2503 updateText : function(text){
2504 if(!dlg.isVisible() && !opt.width){
2505 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2507 msgEl.innerHTML = text || ' ';
2509 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2510 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2512 Math.min(opt.width || cw , this.maxWidth),
2513 Math.max(opt.minWidth || this.minWidth, bwidth)
2516 activeTextEl.setWidth(w);
2518 if(dlg.isVisible()){
2519 dlg.fixedcenter = false;
2521 // to big, make it scroll. = But as usual stupid IE does not support
2524 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2525 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2526 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2528 bodyEl.dom.style.height = '';
2529 bodyEl.dom.style.overflowY = '';
2532 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2534 bodyEl.dom.style.overflowX = '';
2537 dlg.setContentSize(w, bodyEl.getHeight());
2538 if(dlg.isVisible()){
2539 dlg.fixedcenter = true;
2545 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2546 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2547 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2548 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2549 * @return {Roo.MessageBox} This message box
2551 updateProgress : function(value, text){
2553 this.updateText(text);
2555 if (pp) { // weird bug on my firefox - for some reason this is not defined
2556 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2562 * Returns true if the message box is currently displayed
2563 * @return {Boolean} True if the message box is visible, else false
2565 isVisible : function(){
2566 return dlg && dlg.isVisible();
2570 * Hides the message box if it is displayed
2573 if(this.isVisible()){
2579 * Displays a new message box, or reinitializes an existing message box, based on the config options
2580 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2581 * The following config object properties are supported:
2583 Property Type Description
2584 ---------- --------------- ------------------------------------------------------------------------------------
2585 animEl String/Element An id or Element from which the message box should animate as it opens and
2586 closes (defaults to undefined)
2587 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2588 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2589 closable Boolean False to hide the top-right close button (defaults to true). Note that
2590 progress and wait dialogs will ignore this property and always hide the
2591 close button as they can only be closed programmatically.
2592 cls String A custom CSS class to apply to the message box element
2593 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2594 displayed (defaults to 75)
2595 fn Function A callback function to execute after closing the dialog. The arguments to the
2596 function will be btn (the name of the button that was clicked, if applicable,
2597 e.g. "ok"), and text (the value of the active text field, if applicable).
2598 Progress and wait dialogs will ignore this option since they do not respond to
2599 user actions and can only be closed programmatically, so any required function
2600 should be called by the same code after it closes the dialog.
2601 icon String A CSS class that provides a background image to be used as an icon for
2602 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2603 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2604 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2605 modal Boolean False to allow user interaction with the page while the message box is
2606 displayed (defaults to true)
2607 msg String A string that will replace the existing message box body text (defaults
2608 to the XHTML-compliant non-breaking space character ' ')
2609 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2610 progress Boolean True to display a progress bar (defaults to false)
2611 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2612 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2613 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2614 title String The title text
2615 value String The string value to set into the active textbox element if displayed
2616 wait Boolean True to display a progress bar (defaults to false)
2617 width Number The width of the dialog in pixels
2624 msg: 'Please enter your address:',
2626 buttons: Roo.MessageBox.OKCANCEL,
2629 animEl: 'addAddressBtn'
2632 * @param {Object} config Configuration options
2633 * @return {Roo.MessageBox} This message box
2635 show : function(options)
2638 // this causes nightmares if you show one dialog after another
2639 // especially on callbacks..
2641 if(this.isVisible()){
2644 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2645 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2646 Roo.log("New Dialog Message:" + options.msg )
2647 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2648 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2651 var d = this.getDialog();
2653 d.setTitle(opt.title || " ");
2654 d.close.setDisplayed(opt.closable !== false);
2655 activeTextEl = textboxEl;
2656 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2661 textareaEl.setHeight(typeof opt.multiline == "number" ?
2662 opt.multiline : this.defaultTextHeight);
2663 activeTextEl = textareaEl;
2672 progressEl.setDisplayed(opt.progress === true);
2673 this.updateProgress(0);
2674 activeTextEl.dom.value = opt.value || "";
2676 dlg.setDefaultButton(activeTextEl);
2678 var bs = opt.buttons;
2682 }else if(bs && bs.yes){
2683 db = buttons["yes"];
2685 dlg.setDefaultButton(db);
2687 bwidth = updateButtons(opt.buttons);
2688 this.updateText(opt.msg);
2690 d.el.addClass(opt.cls);
2692 d.proxyDrag = opt.proxyDrag === true;
2693 d.modal = opt.modal !== false;
2694 d.mask = opt.modal !== false ? mask : false;
2696 // force it to the end of the z-index stack so it gets a cursor in FF
2697 document.body.appendChild(dlg.el.dom);
2698 d.animateTarget = null;
2699 d.show(options.animEl);
2705 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2706 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2707 * and closing the message box when the process is complete.
2708 * @param {String} title The title bar text
2709 * @param {String} msg The message box body text
2710 * @return {Roo.MessageBox} This message box
2712 progress : function(title, msg){
2719 minWidth: this.minProgressWidth,
2726 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2727 * If a callback function is passed it will be called after the user clicks the button, and the
2728 * id of the button that was clicked will be passed as the only parameter to the callback
2729 * (could also be the top-right close button).
2730 * @param {String} title The title bar text
2731 * @param {String} msg The message box body text
2732 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2733 * @param {Object} scope (optional) The scope of the callback function
2734 * @return {Roo.MessageBox} This message box
2736 alert : function(title, msg, fn, scope){
2749 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2750 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2751 * You are responsible for closing the message box when the process is complete.
2752 * @param {String} msg The message box body text
2753 * @param {String} title (optional) The title bar text
2754 * @return {Roo.MessageBox} This message box
2756 wait : function(msg, title){
2767 waitTimer = Roo.TaskMgr.start({
2769 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2777 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2778 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2779 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2780 * @param {String} title The title bar text
2781 * @param {String} msg The message box body text
2782 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2783 * @param {Object} scope (optional) The scope of the callback function
2784 * @return {Roo.MessageBox} This message box
2786 confirm : function(title, msg, fn, scope){
2790 buttons: this.YESNO,
2799 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2800 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2801 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2802 * (could also be the top-right close button) and the text that was entered will be passed as the two
2803 * parameters to the callback.
2804 * @param {String} title The title bar text
2805 * @param {String} msg The message box body text
2806 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2807 * @param {Object} scope (optional) The scope of the callback function
2808 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2809 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2810 * @return {Roo.MessageBox} This message box
2812 prompt : function(title, msg, fn, scope, multiline){
2816 buttons: this.OKCANCEL,
2821 multiline: multiline,
2828 * Button config that displays a single OK button
2833 * Button config that displays Yes and No buttons
2836 YESNO : {yes:true, no:true},
2838 * Button config that displays OK and Cancel buttons
2841 OKCANCEL : {ok:true, cancel:true},
2843 * Button config that displays Yes, No and Cancel buttons
2846 YESNOCANCEL : {yes:true, no:true, cancel:true},
2849 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2852 defaultTextHeight : 75,
2854 * The maximum width in pixels of the message box (defaults to 600)
2859 * The minimum width in pixels of the message box (defaults to 100)
2864 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2865 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2868 minProgressWidth : 250,
2870 * An object containing the default button text strings that can be overriden for localized language support.
2871 * Supported properties are: ok, cancel, yes and no.
2872 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2885 * Shorthand for {@link Roo.MessageBox}
2887 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2888 Roo.Msg = Roo.Msg || Roo.MessageBox;
2897 * @class Roo.bootstrap.Navbar
2898 * @extends Roo.bootstrap.Component
2899 * Bootstrap Navbar class
2902 * Create a new Navbar
2903 * @param {Object} config The config object
2907 Roo.bootstrap.Navbar = function(config){
2908 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2912 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2921 getAutoCreate : function(){
2924 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2928 initEvents :function ()
2930 //Roo.log(this.el.select('.navbar-toggle',true));
2931 this.el.select('.navbar-toggle',true).on('click', function() {
2932 // Roo.log('click');
2933 this.el.select('.navbar-collapse',true).toggleClass('in');
2941 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2943 var size = this.el.getSize();
2944 this.maskEl.setSize(size.width, size.height);
2945 this.maskEl.enableDisplayMode("block");
2954 getChildContainer : function()
2956 if (this.el.select('.collapse').getCount()) {
2957 return this.el.select('.collapse',true).first();
2990 * @class Roo.bootstrap.NavSimplebar
2991 * @extends Roo.bootstrap.Navbar
2992 * Bootstrap Sidebar class
2994 * @cfg {Boolean} inverse is inverted color
2996 * @cfg {String} type (nav | pills | tabs)
2997 * @cfg {Boolean} arrangement stacked | justified
2998 * @cfg {String} align (left | right) alignment
3000 * @cfg {Boolean} main (true|false) main nav bar? default false
3001 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3003 * @cfg {String} tag (header|footer|nav|div) default is nav
3009 * Create a new Sidebar
3010 * @param {Object} config The config object
3014 Roo.bootstrap.NavSimplebar = function(config){
3015 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3018 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3034 getAutoCreate : function(){
3038 tag : this.tag || 'div',
3051 this.type = this.type || 'nav';
3052 if (['tabs','pills'].indexOf(this.type)!==-1) {
3053 cfg.cn[0].cls += ' nav-' + this.type
3057 if (this.type!=='nav') {
3058 Roo.log('nav type must be nav/tabs/pills')
3060 cfg.cn[0].cls += ' navbar-nav'
3066 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3067 cfg.cn[0].cls += ' nav-' + this.arrangement;
3071 if (this.align === 'right') {
3072 cfg.cn[0].cls += ' navbar-right';
3076 cfg.cls += ' navbar-inverse';
3103 * @class Roo.bootstrap.NavHeaderbar
3104 * @extends Roo.bootstrap.NavSimplebar
3105 * Bootstrap Sidebar class
3107 * @cfg {String} brand what is brand
3108 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3109 * @cfg {String} brand_href href of the brand
3110 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3111 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3114 * Create a new Sidebar
3115 * @param {Object} config The config object
3119 Roo.bootstrap.NavHeaderbar = function(config){
3120 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3123 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3131 getAutoCreate : function(){
3134 tag: this.nav || 'nav',
3143 cls: 'navbar-header',
3148 cls: 'navbar-toggle',
3149 'data-toggle': 'collapse',
3154 html: 'Toggle navigation'
3176 cls: 'collapse navbar-collapse',
3180 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3182 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3183 cfg.cls += ' navbar-' + this.position;
3185 // tag can override this..
3187 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3190 if (this.brand !== '') {
3193 href: this.brand_href ? this.brand_href : '#',
3194 cls: 'navbar-brand',
3202 cfg.cls += ' main-nav';
3210 initEvents : function()
3212 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3214 if (this.autohide) {
3219 Roo.get(document).on('scroll',function(e) {
3220 var ns = Roo.get(document).getScroll().top;
3221 var os = prevScroll;
3225 ft.removeClass('slideDown');
3226 ft.addClass('slideUp');
3229 ft.removeClass('slideUp');
3230 ft.addClass('slideDown');
3254 * @class Roo.bootstrap.NavSidebar
3255 * @extends Roo.bootstrap.Navbar
3256 * Bootstrap Sidebar class
3259 * Create a new Sidebar
3260 * @param {Object} config The config object
3264 Roo.bootstrap.NavSidebar = function(config){
3265 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3268 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3270 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3272 getAutoCreate : function(){
3277 cls: 'sidebar sidebar-nav'
3299 * @class Roo.bootstrap.NavGroup
3300 * @extends Roo.bootstrap.Component
3301 * Bootstrap NavGroup class
3302 * @cfg {String} align left | right
3303 * @cfg {Boolean} inverse false | true
3304 * @cfg {String} type (nav|pills|tab) default nav
3305 * @cfg {String} navId - reference Id for navbar.
3309 * Create a new nav group
3310 * @param {Object} config The config object
3313 Roo.bootstrap.NavGroup = function(config){
3314 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3317 Roo.bootstrap.NavGroup.register(this);
3321 * Fires when the active item changes
3322 * @param {Roo.bootstrap.NavGroup} this
3323 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3324 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3331 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3342 getAutoCreate : function()
3344 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3351 if (['tabs','pills'].indexOf(this.type)!==-1) {
3352 cfg.cls += ' nav-' + this.type
3354 if (this.type!=='nav') {
3355 Roo.log('nav type must be nav/tabs/pills')
3357 cfg.cls += ' navbar-nav'
3360 if (this.parent().sidebar) {
3363 cls: 'dashboard-menu sidebar-menu'
3369 if (this.form === true) {
3375 if (this.align === 'right') {
3376 cfg.cls += ' navbar-right';
3378 cfg.cls += ' navbar-left';
3382 if (this.align === 'right') {
3383 cfg.cls += ' navbar-right';
3387 cfg.cls += ' navbar-inverse';
3395 * sets the active Navigation item
3396 * @param {Roo.bootstrap.NavItem} the new current navitem
3398 setActiveItem : function(item)
3401 Roo.each(this.navItems, function(v){
3406 v.setActive(false, true);
3413 item.setActive(true, true);
3414 this.fireEvent('changed', this, item, prev);
3419 * gets the active Navigation item
3420 * @return {Roo.bootstrap.NavItem} the current navitem
3422 getActive : function()
3426 Roo.each(this.navItems, function(v){
3437 indexOfNav : function()
3441 Roo.each(this.navItems, function(v,i){
3452 * adds a Navigation item
3453 * @param {Roo.bootstrap.NavItem} the navitem to add
3455 addItem : function(cfg)
3457 var cn = new Roo.bootstrap.NavItem(cfg);
3459 cn.parentId = this.id;
3460 cn.onRender(this.el, null);
3464 * register a Navigation item
3465 * @param {Roo.bootstrap.NavItem} the navitem to add
3467 register : function(item)
3469 this.navItems.push( item);
3470 item.navId = this.navId;
3475 getNavItem: function(tabId)
3478 Roo.each(this.navItems, function(e) {
3479 if (e.tabId == tabId) {
3489 setActiveNext : function()
3491 var i = this.indexOfNav(this.getActive());
3492 if (i > this.navItems.length) {
3495 this.setActiveItem(this.navItems[i+1]);
3497 setActivePrev : function()
3499 var i = this.indexOfNav(this.getActive());
3503 this.setActiveItem(this.navItems[i-1]);
3505 clearWasActive : function(except) {
3506 Roo.each(this.navItems, function(e) {
3507 if (e.tabId != except.tabId && e.was_active) {
3508 e.was_active = false;
3515 getWasActive : function ()
3518 Roo.each(this.navItems, function(e) {
3533 Roo.apply(Roo.bootstrap.NavGroup, {
3537 * register a Navigation Group
3538 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3540 register : function(navgrp)
3542 this.groups[navgrp.navId] = navgrp;
3546 * fetch a Navigation Group based on the navigation ID
3547 * @param {string} the navgroup to add
3548 * @returns {Roo.bootstrap.NavGroup} the navgroup
3550 get: function(navId) {
3551 if (typeof(this.groups[navId]) == 'undefined') {
3553 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3555 return this.groups[navId] ;
3570 * @class Roo.bootstrap.NavItem
3571 * @extends Roo.bootstrap.Component
3572 * Bootstrap Navbar.NavItem class
3573 * @cfg {String} href link to
3574 * @cfg {String} html content of button
3575 * @cfg {String} badge text inside badge
3576 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3577 * @cfg {String} glyphicon name of glyphicon
3578 * @cfg {String} icon name of font awesome icon
3579 * @cfg {Boolean} active Is item active
3580 * @cfg {Boolean} disabled Is item disabled
3582 * @cfg {Boolean} preventDefault (true | false) default false
3583 * @cfg {String} tabId the tab that this item activates.
3584 * @cfg {String} tagtype (a|span) render as a href or span?
3587 * Create a new Navbar Item
3588 * @param {Object} config The config object
3590 Roo.bootstrap.NavItem = function(config){
3591 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3596 * The raw click event for the entire grid.
3597 * @param {Roo.EventObject} e
3602 * Fires when the active item active state changes
3603 * @param {Roo.bootstrap.NavItem} this
3604 * @param {boolean} state the new state
3612 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3620 preventDefault : false,
3627 getAutoCreate : function(){
3635 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3637 if (this.disabled) {
3638 cfg.cls += ' disabled';
3641 if (this.href || this.html || this.glyphicon || this.icon) {
3645 href : this.href || "#",
3646 html: this.html || ''
3651 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3654 if(this.glyphicon) {
3655 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3660 cfg.cn[0].html += " <span class='caret'></span>";
3664 if (this.badge !== '') {
3666 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3674 initEvents: function() {
3675 // Roo.log('init events?');
3676 // Roo.log(this.el.dom);
3677 if (typeof (this.menu) != 'undefined') {
3678 this.menu.parentType = this.xtype;
3679 this.menu.triggerEl = this.el;
3680 this.addxtype(Roo.apply({}, this.menu));
3684 this.el.select('a',true).on('click', this.onClick, this);
3685 // at this point parent should be available..
3686 this.parent().register(this);
3689 onClick : function(e)
3692 if(this.preventDefault){
3695 if (this.disabled) {
3699 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3700 if (tg && tg.transition) {
3701 Roo.log("waiting for the transitionend");
3705 Roo.log("fire event clicked");
3706 if(this.fireEvent('click', this, e) === false){
3709 var p = this.parent();
3710 if (['tabs','pills'].indexOf(p.type)!==-1) {
3711 if (typeof(p.setActiveItem) !== 'undefined') {
3712 p.setActiveItem(this);
3715 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3716 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3717 // remove the collapsed menu expand...
3718 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3723 isActive: function () {
3726 setActive : function(state, fire, is_was_active)
3728 if (this.active && !state & this.navId) {
3729 this.was_active = true;
3730 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3732 nv.clearWasActive(this);
3736 this.active = state;
3739 this.el.removeClass('active');
3740 } else if (!this.el.hasClass('active')) {
3741 this.el.addClass('active');
3744 this.fireEvent('changed', this, state);
3747 // show a panel if it's registered and related..
3749 if (!this.navId || !this.tabId || !state || is_was_active) {
3753 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3757 var pan = tg.getPanelByName(this.tabId);
3761 // if we can not flip to new panel - go back to old nav highlight..
3762 if (false == tg.showPanel(pan)) {
3763 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3765 var onav = nv.getWasActive();
3767 onav.setActive(true, false, true);
3776 // this should not be here...
3777 setDisabled : function(state)
3779 this.disabled = state;
3781 this.el.removeClass('disabled');
3782 } else if (!this.el.hasClass('disabled')) {
3783 this.el.addClass('disabled');
3796 * <span> icon </span>
3797 * <span> text </span>
3798 * <span>badge </span>
3802 * @class Roo.bootstrap.NavSidebarItem
3803 * @extends Roo.bootstrap.NavItem
3804 * Bootstrap Navbar.NavSidebarItem class
3806 * Create a new Navbar Button
3807 * @param {Object} config The config object
3809 Roo.bootstrap.NavSidebarItem = function(config){
3810 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3815 * The raw click event for the entire grid.
3816 * @param {Roo.EventObject} e
3821 * Fires when the active item active state changes
3822 * @param {Roo.bootstrap.NavSidebarItem} this
3823 * @param {boolean} state the new state
3831 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3834 getAutoCreate : function(){
3839 href : this.href || '#',
3851 html : this.html || ''
3856 cfg.cls += ' active';
3860 if (this.glyphicon || this.icon) {
3861 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3862 a.cn.push({ tag : 'i', cls : c }) ;
3867 if (this.badge !== '') {
3868 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3872 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3873 a.cls += 'dropdown-toggle treeview' ;
3897 * @class Roo.bootstrap.Row
3898 * @extends Roo.bootstrap.Component
3899 * Bootstrap Row class (contains columns...)
3903 * @param {Object} config The config object
3906 Roo.bootstrap.Row = function(config){
3907 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3910 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3912 getAutoCreate : function(){
3931 * @class Roo.bootstrap.Element
3932 * @extends Roo.bootstrap.Component
3933 * Bootstrap Element class
3934 * @cfg {String} html contents of the element
3935 * @cfg {String} tag tag of the element
3936 * @cfg {String} cls class of the element
3939 * Create a new Element
3940 * @param {Object} config The config object
3943 Roo.bootstrap.Element = function(config){
3944 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3947 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3954 getAutoCreate : function(){
3979 * @class Roo.bootstrap.Pagination
3980 * @extends Roo.bootstrap.Component
3981 * Bootstrap Pagination class
3982 * @cfg {String} size xs | sm | md | lg
3983 * @cfg {Boolean} inverse false | true
3986 * Create a new Pagination
3987 * @param {Object} config The config object
3990 Roo.bootstrap.Pagination = function(config){
3991 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3994 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4000 getAutoCreate : function(){
4006 cfg.cls += ' inverse';
4012 cfg.cls += " " + this.cls;
4030 * @class Roo.bootstrap.PaginationItem
4031 * @extends Roo.bootstrap.Component
4032 * Bootstrap PaginationItem class
4033 * @cfg {String} html text
4034 * @cfg {String} href the link
4035 * @cfg {Boolean} preventDefault (true | false) default true
4036 * @cfg {Boolean} active (true | false) default false
4040 * Create a new PaginationItem
4041 * @param {Object} config The config object
4045 Roo.bootstrap.PaginationItem = function(config){
4046 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4051 * The raw click event for the entire grid.
4052 * @param {Roo.EventObject} e
4058 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4062 preventDefault: true,
4066 getAutoCreate : function(){
4072 href : this.href ? this.href : '#',
4073 html : this.html ? this.html : ''
4083 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4089 initEvents: function() {
4091 this.el.on('click', this.onClick, this);
4094 onClick : function(e)
4096 Roo.log('PaginationItem on click ');
4097 if(this.preventDefault){
4101 this.fireEvent('click', this, e);
4117 * @class Roo.bootstrap.Slider
4118 * @extends Roo.bootstrap.Component
4119 * Bootstrap Slider class
4122 * Create a new Slider
4123 * @param {Object} config The config object
4126 Roo.bootstrap.Slider = function(config){
4127 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4130 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4132 getAutoCreate : function(){
4136 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4140 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4152 * Ext JS Library 1.1.1
4153 * Copyright(c) 2006-2007, Ext JS, LLC.
4155 * Originally Released Under LGPL - original licence link has changed is not relivant.
4158 * <script type="text/javascript">
4163 * @class Roo.grid.ColumnModel
4164 * @extends Roo.util.Observable
4165 * This is the default implementation of a ColumnModel used by the Grid. It defines
4166 * the columns in the grid.
4169 var colModel = new Roo.grid.ColumnModel([
4170 {header: "Ticker", width: 60, sortable: true, locked: true},
4171 {header: "Company Name", width: 150, sortable: true},
4172 {header: "Market Cap.", width: 100, sortable: true},
4173 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4174 {header: "Employees", width: 100, sortable: true, resizable: false}
4179 * The config options listed for this class are options which may appear in each
4180 * individual column definition.
4181 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4183 * @param {Object} config An Array of column config objects. See this class's
4184 * config objects for details.
4186 Roo.grid.ColumnModel = function(config){
4188 * The config passed into the constructor
4190 this.config = config;
4193 // if no id, create one
4194 // if the column does not have a dataIndex mapping,
4195 // map it to the order it is in the config
4196 for(var i = 0, len = config.length; i < len; i++){
4198 if(typeof c.dataIndex == "undefined"){
4201 if(typeof c.renderer == "string"){
4202 c.renderer = Roo.util.Format[c.renderer];
4204 if(typeof c.id == "undefined"){
4207 if(c.editor && c.editor.xtype){
4208 c.editor = Roo.factory(c.editor, Roo.grid);
4210 if(c.editor && c.editor.isFormField){
4211 c.editor = new Roo.grid.GridEditor(c.editor);
4213 this.lookup[c.id] = c;
4217 * The width of columns which have no width specified (defaults to 100)
4220 this.defaultWidth = 100;
4223 * Default sortable of columns which have no sortable specified (defaults to false)
4226 this.defaultSortable = false;
4230 * @event widthchange
4231 * Fires when the width of a column changes.
4232 * @param {ColumnModel} this
4233 * @param {Number} columnIndex The column index
4234 * @param {Number} newWidth The new width
4236 "widthchange": true,
4238 * @event headerchange
4239 * Fires when the text of a header changes.
4240 * @param {ColumnModel} this
4241 * @param {Number} columnIndex The column index
4242 * @param {Number} newText The new header text
4244 "headerchange": true,
4246 * @event hiddenchange
4247 * Fires when a column is hidden or "unhidden".
4248 * @param {ColumnModel} this
4249 * @param {Number} columnIndex The column index
4250 * @param {Boolean} hidden true if hidden, false otherwise
4252 "hiddenchange": true,
4254 * @event columnmoved
4255 * Fires when a column is moved.
4256 * @param {ColumnModel} this
4257 * @param {Number} oldIndex
4258 * @param {Number} newIndex
4260 "columnmoved" : true,
4262 * @event columlockchange
4263 * Fires when a column's locked state is changed
4264 * @param {ColumnModel} this
4265 * @param {Number} colIndex
4266 * @param {Boolean} locked true if locked
4268 "columnlockchange" : true
4270 Roo.grid.ColumnModel.superclass.constructor.call(this);
4272 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4274 * @cfg {String} header The header text to display in the Grid view.
4277 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4278 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4279 * specified, the column's index is used as an index into the Record's data Array.
4282 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4283 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4286 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4287 * Defaults to the value of the {@link #defaultSortable} property.
4288 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4291 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4294 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4297 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4300 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4303 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4304 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4305 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4306 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4309 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4312 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4316 * Returns the id of the column at the specified index.
4317 * @param {Number} index The column index
4318 * @return {String} the id
4320 getColumnId : function(index){
4321 return this.config[index].id;
4325 * Returns the column for a specified id.
4326 * @param {String} id The column id
4327 * @return {Object} the column
4329 getColumnById : function(id){
4330 return this.lookup[id];
4335 * Returns the column for a specified dataIndex.
4336 * @param {String} dataIndex The column dataIndex
4337 * @return {Object|Boolean} the column or false if not found
4339 getColumnByDataIndex: function(dataIndex){
4340 var index = this.findColumnIndex(dataIndex);
4341 return index > -1 ? this.config[index] : false;
4345 * Returns the index for a specified column id.
4346 * @param {String} id The column id
4347 * @return {Number} the index, or -1 if not found
4349 getIndexById : function(id){
4350 for(var i = 0, len = this.config.length; i < len; i++){
4351 if(this.config[i].id == id){
4359 * Returns the index for a specified column dataIndex.
4360 * @param {String} dataIndex The column dataIndex
4361 * @return {Number} the index, or -1 if not found
4364 findColumnIndex : function(dataIndex){
4365 for(var i = 0, len = this.config.length; i < len; i++){
4366 if(this.config[i].dataIndex == dataIndex){
4374 moveColumn : function(oldIndex, newIndex){
4375 var c = this.config[oldIndex];
4376 this.config.splice(oldIndex, 1);
4377 this.config.splice(newIndex, 0, c);
4378 this.dataMap = null;
4379 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4382 isLocked : function(colIndex){
4383 return this.config[colIndex].locked === true;
4386 setLocked : function(colIndex, value, suppressEvent){
4387 if(this.isLocked(colIndex) == value){
4390 this.config[colIndex].locked = value;
4392 this.fireEvent("columnlockchange", this, colIndex, value);
4396 getTotalLockedWidth : function(){
4398 for(var i = 0; i < this.config.length; i++){
4399 if(this.isLocked(i) && !this.isHidden(i)){
4400 this.totalWidth += this.getColumnWidth(i);
4406 getLockedCount : function(){
4407 for(var i = 0, len = this.config.length; i < len; i++){
4408 if(!this.isLocked(i)){
4415 * Returns the number of columns.
4418 getColumnCount : function(visibleOnly){
4419 if(visibleOnly === true){
4421 for(var i = 0, len = this.config.length; i < len; i++){
4422 if(!this.isHidden(i)){
4428 return this.config.length;
4432 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4433 * @param {Function} fn
4434 * @param {Object} scope (optional)
4435 * @return {Array} result
4437 getColumnsBy : function(fn, scope){
4439 for(var i = 0, len = this.config.length; i < len; i++){
4440 var c = this.config[i];
4441 if(fn.call(scope||this, c, i) === true){
4449 * Returns true if the specified column is sortable.
4450 * @param {Number} col The column index
4453 isSortable : function(col){
4454 if(typeof this.config[col].sortable == "undefined"){
4455 return this.defaultSortable;
4457 return this.config[col].sortable;
4461 * Returns the rendering (formatting) function defined for the column.
4462 * @param {Number} col The column index.
4463 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4465 getRenderer : function(col){
4466 if(!this.config[col].renderer){
4467 return Roo.grid.ColumnModel.defaultRenderer;
4469 return this.config[col].renderer;
4473 * Sets the rendering (formatting) function for a column.
4474 * @param {Number} col The column index
4475 * @param {Function} fn The function to use to process the cell's raw data
4476 * to return HTML markup for the grid view. The render function is called with
4477 * the following parameters:<ul>
4478 * <li>Data value.</li>
4479 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4480 * <li>css A CSS style string to apply to the table cell.</li>
4481 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4482 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4483 * <li>Row index</li>
4484 * <li>Column index</li>
4485 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4487 setRenderer : function(col, fn){
4488 this.config[col].renderer = fn;
4492 * Returns the width for the specified column.
4493 * @param {Number} col The column index
4496 getColumnWidth : function(col){
4497 return this.config[col].width * 1 || this.defaultWidth;
4501 * Sets the width for a column.
4502 * @param {Number} col The column index
4503 * @param {Number} width The new width
4505 setColumnWidth : function(col, width, suppressEvent){
4506 this.config[col].width = width;
4507 this.totalWidth = null;
4509 this.fireEvent("widthchange", this, col, width);
4514 * Returns the total width of all columns.
4515 * @param {Boolean} includeHidden True to include hidden column widths
4518 getTotalWidth : function(includeHidden){
4519 if(!this.totalWidth){
4520 this.totalWidth = 0;
4521 for(var i = 0, len = this.config.length; i < len; i++){
4522 if(includeHidden || !this.isHidden(i)){
4523 this.totalWidth += this.getColumnWidth(i);
4527 return this.totalWidth;
4531 * Returns the header for the specified column.
4532 * @param {Number} col The column index
4535 getColumnHeader : function(col){
4536 return this.config[col].header;
4540 * Sets the header for a column.
4541 * @param {Number} col The column index
4542 * @param {String} header The new header
4544 setColumnHeader : function(col, header){
4545 this.config[col].header = header;
4546 this.fireEvent("headerchange", this, col, header);
4550 * Returns the tooltip for the specified column.
4551 * @param {Number} col The column index
4554 getColumnTooltip : function(col){
4555 return this.config[col].tooltip;
4558 * Sets the tooltip for a column.
4559 * @param {Number} col The column index
4560 * @param {String} tooltip The new tooltip
4562 setColumnTooltip : function(col, tooltip){
4563 this.config[col].tooltip = tooltip;
4567 * Returns the dataIndex for the specified column.
4568 * @param {Number} col The column index
4571 getDataIndex : function(col){
4572 return this.config[col].dataIndex;
4576 * Sets the dataIndex for a column.
4577 * @param {Number} col The column index
4578 * @param {Number} dataIndex The new dataIndex
4580 setDataIndex : function(col, dataIndex){
4581 this.config[col].dataIndex = dataIndex;
4587 * Returns true if the cell is editable.
4588 * @param {Number} colIndex The column index
4589 * @param {Number} rowIndex The row index
4592 isCellEditable : function(colIndex, rowIndex){
4593 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4597 * Returns the editor defined for the cell/column.
4598 * return false or null to disable editing.
4599 * @param {Number} colIndex The column index
4600 * @param {Number} rowIndex The row index
4603 getCellEditor : function(colIndex, rowIndex){
4604 return this.config[colIndex].editor;
4608 * Sets if a column is editable.
4609 * @param {Number} col The column index
4610 * @param {Boolean} editable True if the column is editable
4612 setEditable : function(col, editable){
4613 this.config[col].editable = editable;
4618 * Returns true if the column is hidden.
4619 * @param {Number} colIndex The column index
4622 isHidden : function(colIndex){
4623 return this.config[colIndex].hidden;
4628 * Returns true if the column width cannot be changed
4630 isFixed : function(colIndex){
4631 return this.config[colIndex].fixed;
4635 * Returns true if the column can be resized
4638 isResizable : function(colIndex){
4639 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4642 * Sets if a column is hidden.
4643 * @param {Number} colIndex The column index
4644 * @param {Boolean} hidden True if the column is hidden
4646 setHidden : function(colIndex, hidden){
4647 this.config[colIndex].hidden = hidden;
4648 this.totalWidth = null;
4649 this.fireEvent("hiddenchange", this, colIndex, hidden);
4653 * Sets the editor for a column.
4654 * @param {Number} col The column index
4655 * @param {Object} editor The editor object
4657 setEditor : function(col, editor){
4658 this.config[col].editor = editor;
4662 Roo.grid.ColumnModel.defaultRenderer = function(value){
4663 if(typeof value == "string" && value.length < 1){
4669 // Alias for backwards compatibility
4670 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4673 * Ext JS Library 1.1.1
4674 * Copyright(c) 2006-2007, Ext JS, LLC.
4676 * Originally Released Under LGPL - original licence link has changed is not relivant.
4679 * <script type="text/javascript">
4683 * @class Roo.LoadMask
4684 * A simple utility class for generically masking elements while loading data. If the element being masked has
4685 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4686 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4687 * element's UpdateManager load indicator and will be destroyed after the initial load.
4689 * Create a new LoadMask
4690 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4691 * @param {Object} config The config object
4693 Roo.LoadMask = function(el, config){
4694 this.el = Roo.get(el);
4695 Roo.apply(this, config);
4697 this.store.on('beforeload', this.onBeforeLoad, this);
4698 this.store.on('load', this.onLoad, this);
4699 this.store.on('loadexception', this.onLoadException, this);
4700 this.removeMask = false;
4702 var um = this.el.getUpdateManager();
4703 um.showLoadIndicator = false; // disable the default indicator
4704 um.on('beforeupdate', this.onBeforeLoad, this);
4705 um.on('update', this.onLoad, this);
4706 um.on('failure', this.onLoad, this);
4707 this.removeMask = true;
4711 Roo.LoadMask.prototype = {
4713 * @cfg {Boolean} removeMask
4714 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4715 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4719 * The text to display in a centered loading message box (defaults to 'Loading...')
4723 * @cfg {String} msgCls
4724 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4726 msgCls : 'x-mask-loading',
4729 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4735 * Disables the mask to prevent it from being displayed
4737 disable : function(){
4738 this.disabled = true;
4742 * Enables the mask so that it can be displayed
4744 enable : function(){
4745 this.disabled = false;
4748 onLoadException : function()
4752 if (typeof(arguments[3]) != 'undefined') {
4753 Roo.MessageBox.alert("Error loading",arguments[3]);
4757 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4758 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4767 this.el.unmask(this.removeMask);
4772 this.el.unmask(this.removeMask);
4776 onBeforeLoad : function(){
4778 this.el.mask(this.msg, this.msgCls);
4783 destroy : function(){
4785 this.store.un('beforeload', this.onBeforeLoad, this);
4786 this.store.un('load', this.onLoad, this);
4787 this.store.un('loadexception', this.onLoadException, this);
4789 var um = this.el.getUpdateManager();
4790 um.un('beforeupdate', this.onBeforeLoad, this);
4791 um.un('update', this.onLoad, this);
4792 um.un('failure', this.onLoad, this);
4803 * @class Roo.bootstrap.Table
4804 * @extends Roo.bootstrap.Component
4805 * Bootstrap Table class
4806 * @cfg {String} cls table class
4807 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4808 * @cfg {String} bgcolor Specifies the background color for a table
4809 * @cfg {Number} border Specifies whether the table cells should have borders or not
4810 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4811 * @cfg {Number} cellspacing Specifies the space between cells
4812 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4813 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4814 * @cfg {String} sortable Specifies that the table should be sortable
4815 * @cfg {String} summary Specifies a summary of the content of a table
4816 * @cfg {Number} width Specifies the width of a table
4817 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4819 * @cfg {boolean} striped Should the rows be alternative striped
4820 * @cfg {boolean} bordered Add borders to the table
4821 * @cfg {boolean} hover Add hover highlighting
4822 * @cfg {boolean} condensed Format condensed
4823 * @cfg {boolean} responsive Format condensed
4824 * @cfg {Boolean} loadMask (true|false) default false
4825 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4826 * @cfg {Boolean} thead (true|false) generate thead, default true
4827 * @cfg {Boolean} RowSelection (true|false) default false
4828 * @cfg {Boolean} CellSelection (true|false) default false
4830 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4834 * Create a new Table
4835 * @param {Object} config The config object
4838 Roo.bootstrap.Table = function(config){
4839 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4842 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4843 this.sm = this.selModel;
4844 this.sm.xmodule = this.xmodule || false;
4846 if (this.cm && typeof(this.cm.config) == 'undefined') {
4847 this.colModel = new Roo.grid.ColumnModel(this.cm);
4848 this.cm = this.colModel;
4849 this.cm.xmodule = this.xmodule || false;
4852 this.store= Roo.factory(this.store, Roo.data);
4853 this.ds = this.store;
4854 this.ds.xmodule = this.xmodule || false;
4857 if (this.footer && this.store) {
4858 this.footer.dataSource = this.ds;
4859 this.footer = Roo.factory(this.footer);
4866 * Fires when a cell is clicked
4867 * @param {Roo.bootstrap.Table} this
4868 * @param {Roo.Element} el
4869 * @param {Number} rowIndex
4870 * @param {Number} columnIndex
4871 * @param {Roo.EventObject} e
4875 * @event celldblclick
4876 * Fires when a cell is double clicked
4877 * @param {Roo.bootstrap.Table} this
4878 * @param {Roo.Element} el
4879 * @param {Number} rowIndex
4880 * @param {Number} columnIndex
4881 * @param {Roo.EventObject} e
4883 "celldblclick" : true,
4886 * Fires when a row is clicked
4887 * @param {Roo.bootstrap.Table} this
4888 * @param {Roo.Element} el
4889 * @param {Number} rowIndex
4890 * @param {Roo.EventObject} e
4894 * @event rowdblclick
4895 * Fires when a row is double clicked
4896 * @param {Roo.bootstrap.Table} this
4897 * @param {Roo.Element} el
4898 * @param {Number} rowIndex
4899 * @param {Roo.EventObject} e
4901 "rowdblclick" : true,
4904 * Fires when a mouseover occur
4905 * @param {Roo.bootstrap.Table} this
4906 * @param {Roo.Element} el
4907 * @param {Number} rowIndex
4908 * @param {Number} columnIndex
4909 * @param {Roo.EventObject} e
4914 * Fires when a mouseout occur
4915 * @param {Roo.bootstrap.Table} this
4916 * @param {Roo.Element} el
4917 * @param {Number} rowIndex
4918 * @param {Number} columnIndex
4919 * @param {Roo.EventObject} e
4924 * Fires when a row is rendered, so you can change add a style to it.
4925 * @param {Roo.bootstrap.Table} this
4926 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4933 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4957 RowSelection : false,
4958 CellSelection : false,
4961 // Roo.Element - the tbody
4964 getAutoCreate : function(){
4965 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4974 cfg.cls += ' table-striped';
4978 cfg.cls += ' table-hover';
4980 if (this.bordered) {
4981 cfg.cls += ' table-bordered';
4983 if (this.condensed) {
4984 cfg.cls += ' table-condensed';
4986 if (this.responsive) {
4987 cfg.cls += ' table-responsive';
4991 cfg.cls+= ' ' +this.cls;
4994 // this lot should be simplifed...
4997 cfg.align=this.align;
5000 cfg.bgcolor=this.bgcolor;
5003 cfg.border=this.border;
5005 if (this.cellpadding) {
5006 cfg.cellpadding=this.cellpadding;
5008 if (this.cellspacing) {
5009 cfg.cellspacing=this.cellspacing;
5012 cfg.frame=this.frame;
5015 cfg.rules=this.rules;
5017 if (this.sortable) {
5018 cfg.sortable=this.sortable;
5021 cfg.summary=this.summary;
5024 cfg.width=this.width;
5027 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5030 if(this.store || this.cm){
5032 cfg.cn.push(this.renderHeader());
5035 cfg.cn.push(this.renderBody());
5038 cfg.cn.push(this.renderFooter());
5041 cfg.cls+= ' TableGrid';
5044 return { cn : [ cfg ] };
5047 initEvents : function()
5049 if(!this.store || !this.cm){
5053 //Roo.log('initEvents with ds!!!!');
5055 this.mainBody = this.el.select('tbody', true).first();
5060 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5061 e.on('click', _this.sort, _this);
5064 this.el.on("click", this.onClick, this);
5065 this.el.on("dblclick", this.onDblClick, this);
5067 this.parent().el.setStyle('position', 'relative');
5069 this.footer.parentId = this.id;
5070 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5073 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5075 this.store.on('load', this.onLoad, this);
5076 this.store.on('beforeload', this.onBeforeLoad, this);
5077 this.store.on('update', this.onUpdate, this);
5081 onMouseover : function(e, el)
5083 var cell = Roo.get(el);
5089 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5090 cell = cell.findParent('td', false, true);
5093 var row = cell.findParent('tr', false, true);
5094 var cellIndex = cell.dom.cellIndex;
5095 var rowIndex = row.dom.rowIndex - 1; // start from 0
5097 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5101 onMouseout : function(e, el)
5103 var cell = Roo.get(el);
5109 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5110 cell = cell.findParent('td', false, true);
5113 var row = cell.findParent('tr', false, true);
5114 var cellIndex = cell.dom.cellIndex;
5115 var rowIndex = row.dom.rowIndex - 1; // start from 0
5117 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5121 onClick : function(e, el)
5123 var cell = Roo.get(el);
5125 if(!cell || (!this.CellSelection && !this.RowSelection)){
5130 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5131 cell = cell.findParent('td', false, true);
5134 var row = cell.findParent('tr', false, true);
5135 var cellIndex = cell.dom.cellIndex;
5136 var rowIndex = row.dom.rowIndex - 1;
5138 if(this.CellSelection){
5139 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5142 if(this.RowSelection){
5143 this.fireEvent('rowclick', this, row, rowIndex, e);
5149 onDblClick : function(e,el)
5151 var cell = Roo.get(el);
5153 if(!cell || (!this.CellSelection && !this.RowSelection)){
5157 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5158 cell = cell.findParent('td', false, true);
5161 var row = cell.findParent('tr', false, true);
5162 var cellIndex = cell.dom.cellIndex;
5163 var rowIndex = row.dom.rowIndex - 1;
5165 if(this.CellSelection){
5166 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5169 if(this.RowSelection){
5170 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5174 sort : function(e,el)
5176 var col = Roo.get(el)
5178 if(!col.hasClass('sortable')){
5182 var sort = col.attr('sort');
5185 if(col.hasClass('glyphicon-arrow-up')){
5189 this.store.sortInfo = {field : sort, direction : dir};
5192 Roo.log("calling footer first");
5193 this.footer.onClick('first');
5196 this.store.load({ params : { start : 0 } });
5200 renderHeader : function()
5209 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5211 var config = cm.config[i];
5216 html: cm.getColumnHeader(i)
5219 if(typeof(config.hidden) != 'undefined' && config.hidden){
5220 c.style += ' display:none;';
5223 if(typeof(config.dataIndex) != 'undefined'){
5224 c.sort = config.dataIndex;
5227 if(typeof(config.sortable) != 'undefined' && config.sortable){
5231 if(typeof(config.align) != 'undefined' && config.align.length){
5232 c.style += ' text-align:' + config.align + ';';
5235 if(typeof(config.width) != 'undefined'){
5236 c.style += ' width:' + config.width + 'px;';
5245 renderBody : function()
5255 colspan : this.cm.getColumnCount()
5265 renderFooter : function()
5275 colspan : this.cm.getColumnCount()
5289 Roo.log('ds onload');
5294 var ds = this.store;
5296 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5297 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5299 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5300 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5303 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5304 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5308 var tbody = this.mainBody;
5310 if(ds.getCount() > 0){
5311 ds.data.each(function(d,rowIndex){
5312 var row = this.renderRow(cm, ds, rowIndex);
5314 tbody.createChild(row);
5318 if(row.cellObjects.length){
5319 Roo.each(row.cellObjects, function(r){
5320 _this.renderCellObject(r);
5327 Roo.each(this.el.select('tbody td', true).elements, function(e){
5328 e.on('mouseover', _this.onMouseover, _this);
5331 Roo.each(this.el.select('tbody td', true).elements, function(e){
5332 e.on('mouseout', _this.onMouseout, _this);
5335 //if(this.loadMask){
5336 // this.maskEl.hide();
5341 onUpdate : function(ds,record)
5343 this.refreshRow(record);
5345 onRemove : function(ds, record, index, isUpdate){
5346 if(isUpdate !== true){
5347 this.fireEvent("beforerowremoved", this, index, record);
5349 var bt = this.mainBody.dom;
5351 bt.removeChild(bt.rows[index]);
5354 if(isUpdate !== true){
5355 //this.stripeRows(index);
5356 //this.syncRowHeights(index, index);
5358 this.fireEvent("rowremoved", this, index, record);
5363 refreshRow : function(record){
5364 var ds = this.store, index;
5365 if(typeof record == 'number'){
5367 record = ds.getAt(index);
5369 index = ds.indexOf(record);
5371 this.insertRow(ds, index, true);
5372 this.onRemove(ds, record, index+1, true);
5373 //this.syncRowHeights(index, index);
5375 this.fireEvent("rowupdated", this, index, record);
5378 insertRow : function(dm, rowIndex, isUpdate){
5381 this.fireEvent("beforerowsinserted", this, rowIndex);
5383 //var s = this.getScrollState();
5384 var row = this.renderRow(this.cm, this.store, rowIndex);
5385 // insert before rowIndex..
5386 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5390 if(row.cellObjects.length){
5391 Roo.each(row.cellObjects, function(r){
5392 _this.renderCellObject(r);
5397 this.fireEvent("rowsinserted", this, rowIndex);
5398 //this.syncRowHeights(firstRow, lastRow);
5399 //this.stripeRows(firstRow);
5406 getRowDom : function(rowIndex)
5408 // not sure if I need to check this.. but let's do it anyway..
5409 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5410 this.mainBody.dom.rows[rowIndex] : false
5412 // returns the object tree for a tr..
5415 renderRow : function(cm, ds, rowIndex) {
5417 var d = ds.getAt(rowIndex);
5424 var cellObjects = [];
5426 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5427 var config = cm.config[i];
5429 var renderer = cm.getRenderer(i);
5433 if(typeof(renderer) !== 'undefined'){
5434 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5436 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5437 // and are rendered into the cells after the row is rendered - using the id for the element.
5439 if(typeof(value) === 'object'){
5449 rowIndex : rowIndex,
5454 this.fireEvent('rowclass', this, rowcfg);
5458 cls : rowcfg.rowClass,
5460 html: (typeof(value) === 'object') ? '' : value
5467 if(typeof(config.hidden) != 'undefined' && config.hidden){
5468 td.style += ' display:none;';
5471 if(typeof(config.align) != 'undefined' && config.align.length){
5472 td.style += ' text-align:' + config.align + ';';
5475 if(typeof(config.width) != 'undefined'){
5476 td.style += ' width:' + config.width + 'px;';
5483 row.cellObjects = cellObjects;
5491 onBeforeLoad : function()
5493 //Roo.log('ds onBeforeLoad');
5497 //if(this.loadMask){
5498 // this.maskEl.show();
5504 this.el.select('tbody', true).first().dom.innerHTML = '';
5507 getSelectionModel : function(){
5509 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5511 return this.selModel;
5514 * Render the Roo.bootstrap object from renderder
5516 renderCellObject : function(r)
5520 var t = r.cfg.render(r.container);
5523 Roo.each(r.cfg.cn, function(c){
5525 container: t.getChildContainer(),
5528 _this.renderCellObject(child);
5545 * @class Roo.bootstrap.TableCell
5546 * @extends Roo.bootstrap.Component
5547 * Bootstrap TableCell class
5548 * @cfg {String} html cell contain text
5549 * @cfg {String} cls cell class
5550 * @cfg {String} tag cell tag (td|th) default td
5551 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5552 * @cfg {String} align Aligns the content in a cell
5553 * @cfg {String} axis Categorizes cells
5554 * @cfg {String} bgcolor Specifies the background color of a cell
5555 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5556 * @cfg {Number} colspan Specifies the number of columns a cell should span
5557 * @cfg {String} headers Specifies one or more header cells a cell is related to
5558 * @cfg {Number} height Sets the height of a cell
5559 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5560 * @cfg {Number} rowspan Sets the number of rows a cell should span
5561 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5562 * @cfg {String} valign Vertical aligns the content in a cell
5563 * @cfg {Number} width Specifies the width of a cell
5566 * Create a new TableCell
5567 * @param {Object} config The config object
5570 Roo.bootstrap.TableCell = function(config){
5571 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5574 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5594 getAutoCreate : function(){
5595 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5615 cfg.align=this.align
5621 cfg.bgcolor=this.bgcolor
5624 cfg.charoff=this.charoff
5627 cfg.colspan=this.colspan
5630 cfg.headers=this.headers
5633 cfg.height=this.height
5636 cfg.nowrap=this.nowrap
5639 cfg.rowspan=this.rowspan
5642 cfg.scope=this.scope
5645 cfg.valign=this.valign
5648 cfg.width=this.width
5667 * @class Roo.bootstrap.TableRow
5668 * @extends Roo.bootstrap.Component
5669 * Bootstrap TableRow class
5670 * @cfg {String} cls row class
5671 * @cfg {String} align Aligns the content in a table row
5672 * @cfg {String} bgcolor Specifies a background color for a table row
5673 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5674 * @cfg {String} valign Vertical aligns the content in a table row
5677 * Create a new TableRow
5678 * @param {Object} config The config object
5681 Roo.bootstrap.TableRow = function(config){
5682 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5685 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5693 getAutoCreate : function(){
5694 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5704 cfg.align = this.align;
5707 cfg.bgcolor = this.bgcolor;
5710 cfg.charoff = this.charoff;
5713 cfg.valign = this.valign;
5731 * @class Roo.bootstrap.TableBody
5732 * @extends Roo.bootstrap.Component
5733 * Bootstrap TableBody class
5734 * @cfg {String} cls element class
5735 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5736 * @cfg {String} align Aligns the content inside the element
5737 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5738 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5741 * Create a new TableBody
5742 * @param {Object} config The config object
5745 Roo.bootstrap.TableBody = function(config){
5746 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5749 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5757 getAutoCreate : function(){
5758 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5772 cfg.align = this.align;
5775 cfg.charoff = this.charoff;
5778 cfg.valign = this.valign;
5785 // initEvents : function()
5792 // this.store = Roo.factory(this.store, Roo.data);
5793 // this.store.on('load', this.onLoad, this);
5795 // this.store.load();
5799 // onLoad: function ()
5801 // this.fireEvent('load', this);
5811 * Ext JS Library 1.1.1
5812 * Copyright(c) 2006-2007, Ext JS, LLC.
5814 * Originally Released Under LGPL - original licence link has changed is not relivant.
5817 * <script type="text/javascript">
5820 // as we use this in bootstrap.
5821 Roo.namespace('Roo.form');
5823 * @class Roo.form.Action
5824 * Internal Class used to handle form actions
5826 * @param {Roo.form.BasicForm} el The form element or its id
5827 * @param {Object} config Configuration options
5832 // define the action interface
5833 Roo.form.Action = function(form, options){
5835 this.options = options || {};
5838 * Client Validation Failed
5841 Roo.form.Action.CLIENT_INVALID = 'client';
5843 * Server Validation Failed
5846 Roo.form.Action.SERVER_INVALID = 'server';
5848 * Connect to Server Failed
5851 Roo.form.Action.CONNECT_FAILURE = 'connect';
5853 * Reading Data from Server Failed
5856 Roo.form.Action.LOAD_FAILURE = 'load';
5858 Roo.form.Action.prototype = {
5860 failureType : undefined,
5861 response : undefined,
5865 run : function(options){
5870 success : function(response){
5875 handleResponse : function(response){
5879 // default connection failure
5880 failure : function(response){
5882 this.response = response;
5883 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5884 this.form.afterAction(this, false);
5887 processResponse : function(response){
5888 this.response = response;
5889 if(!response.responseText){
5892 this.result = this.handleResponse(response);
5896 // utility functions used internally
5897 getUrl : function(appendParams){
5898 var url = this.options.url || this.form.url || this.form.el.dom.action;
5900 var p = this.getParams();
5902 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5908 getMethod : function(){
5909 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5912 getParams : function(){
5913 var bp = this.form.baseParams;
5914 var p = this.options.params;
5916 if(typeof p == "object"){
5917 p = Roo.urlEncode(Roo.applyIf(p, bp));
5918 }else if(typeof p == 'string' && bp){
5919 p += '&' + Roo.urlEncode(bp);
5922 p = Roo.urlEncode(bp);
5927 createCallback : function(){
5929 success: this.success,
5930 failure: this.failure,
5932 timeout: (this.form.timeout*1000),
5933 upload: this.form.fileUpload ? this.success : undefined
5938 Roo.form.Action.Submit = function(form, options){
5939 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5942 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5945 haveProgress : false,
5946 uploadComplete : false,
5948 // uploadProgress indicator.
5949 uploadProgress : function()
5951 if (!this.form.progressUrl) {
5955 if (!this.haveProgress) {
5956 Roo.MessageBox.progress("Uploading", "Uploading");
5958 if (this.uploadComplete) {
5959 Roo.MessageBox.hide();
5963 this.haveProgress = true;
5965 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5967 var c = new Roo.data.Connection();
5969 url : this.form.progressUrl,
5974 success : function(req){
5975 //console.log(data);
5979 rdata = Roo.decode(req.responseText)
5981 Roo.log("Invalid data from server..");
5985 if (!rdata || !rdata.success) {
5987 Roo.MessageBox.alert(Roo.encode(rdata));
5990 var data = rdata.data;
5992 if (this.uploadComplete) {
5993 Roo.MessageBox.hide();
5998 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5999 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6002 this.uploadProgress.defer(2000,this);
6005 failure: function(data) {
6006 Roo.log('progress url failed ');
6017 // run get Values on the form, so it syncs any secondary forms.
6018 this.form.getValues();
6020 var o = this.options;
6021 var method = this.getMethod();
6022 var isPost = method == 'POST';
6023 if(o.clientValidation === false || this.form.isValid()){
6025 if (this.form.progressUrl) {
6026 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6027 (new Date() * 1) + '' + Math.random());
6032 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6033 form:this.form.el.dom,
6034 url:this.getUrl(!isPost),
6036 params:isPost ? this.getParams() : null,
6037 isUpload: this.form.fileUpload
6040 this.uploadProgress();
6042 }else if (o.clientValidation !== false){ // client validation failed
6043 this.failureType = Roo.form.Action.CLIENT_INVALID;
6044 this.form.afterAction(this, false);
6048 success : function(response)
6050 this.uploadComplete= true;
6051 if (this.haveProgress) {
6052 Roo.MessageBox.hide();
6056 var result = this.processResponse(response);
6057 if(result === true || result.success){
6058 this.form.afterAction(this, true);
6062 this.form.markInvalid(result.errors);
6063 this.failureType = Roo.form.Action.SERVER_INVALID;
6065 this.form.afterAction(this, false);
6067 failure : function(response)
6069 this.uploadComplete= true;
6070 if (this.haveProgress) {
6071 Roo.MessageBox.hide();
6074 this.response = response;
6075 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6076 this.form.afterAction(this, false);
6079 handleResponse : function(response){
6080 if(this.form.errorReader){
6081 var rs = this.form.errorReader.read(response);
6084 for(var i = 0, len = rs.records.length; i < len; i++) {
6085 var r = rs.records[i];
6089 if(errors.length < 1){
6093 success : rs.success,
6099 ret = Roo.decode(response.responseText);
6103 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6113 Roo.form.Action.Load = function(form, options){
6114 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6115 this.reader = this.form.reader;
6118 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6123 Roo.Ajax.request(Roo.apply(
6124 this.createCallback(), {
6125 method:this.getMethod(),
6126 url:this.getUrl(false),
6127 params:this.getParams()
6131 success : function(response){
6133 var result = this.processResponse(response);
6134 if(result === true || !result.success || !result.data){
6135 this.failureType = Roo.form.Action.LOAD_FAILURE;
6136 this.form.afterAction(this, false);
6139 this.form.clearInvalid();
6140 this.form.setValues(result.data);
6141 this.form.afterAction(this, true);
6144 handleResponse : function(response){
6145 if(this.form.reader){
6146 var rs = this.form.reader.read(response);
6147 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6149 success : rs.success,
6153 return Roo.decode(response.responseText);
6157 Roo.form.Action.ACTION_TYPES = {
6158 'load' : Roo.form.Action.Load,
6159 'submit' : Roo.form.Action.Submit
6168 * @class Roo.bootstrap.Form
6169 * @extends Roo.bootstrap.Component
6170 * Bootstrap Form class
6171 * @cfg {String} method GET | POST (default POST)
6172 * @cfg {String} labelAlign top | left (default top)
6173 * @cfg {String} align left | right - for navbars
6174 * @cfg {Boolean} loadMask load mask when submit (default true)
6179 * @param {Object} config The config object
6183 Roo.bootstrap.Form = function(config){
6184 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6187 * @event clientvalidation
6188 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6189 * @param {Form} this
6190 * @param {Boolean} valid true if the form has passed client-side validation
6192 clientvalidation: true,
6194 * @event beforeaction
6195 * Fires before any action is performed. Return false to cancel the action.
6196 * @param {Form} this
6197 * @param {Action} action The action to be performed
6201 * @event actionfailed
6202 * Fires when an action fails.
6203 * @param {Form} this
6204 * @param {Action} action The action that failed
6206 actionfailed : true,
6208 * @event actioncomplete
6209 * Fires when an action is completed.
6210 * @param {Form} this
6211 * @param {Action} action The action that completed
6213 actioncomplete : true
6218 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6221 * @cfg {String} method
6222 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6227 * The URL to use for form actions if one isn't supplied in the action options.
6230 * @cfg {Boolean} fileUpload
6231 * Set to true if this form is a file upload.
6235 * @cfg {Object} baseParams
6236 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6240 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6244 * @cfg {Sting} align (left|right) for navbar forms
6249 activeAction : null,
6252 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6253 * element by passing it or its id or mask the form itself by passing in true.
6256 waitMsgTarget : false,
6260 getAutoCreate : function(){
6264 method : this.method || 'POST',
6265 id : this.id || Roo.id(),
6268 if (this.parent().xtype.match(/^Nav/)) {
6269 cfg.cls = 'navbar-form navbar-' + this.align;
6273 if (this.labelAlign == 'left' ) {
6274 cfg.cls += ' form-horizontal';
6280 initEvents : function()
6282 this.el.on('submit', this.onSubmit, this);
6283 // this was added as random key presses on the form where triggering form submit.
6284 this.el.on('keypress', function(e) {
6285 if (e.getCharCode() != 13) {
6288 // we might need to allow it for textareas.. and some other items.
6289 // check e.getTarget().
6291 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6295 Roo.log("keypress blocked");
6303 onSubmit : function(e){
6308 * Returns true if client-side validation on the form is successful.
6311 isValid : function(){
6312 var items = this.getItems();
6314 items.each(function(f){
6323 * Returns true if any fields in this form have changed since their original load.
6326 isDirty : function(){
6328 var items = this.getItems();
6329 items.each(function(f){
6339 * Performs a predefined action (submit or load) or custom actions you define on this form.
6340 * @param {String} actionName The name of the action type
6341 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6342 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6343 * accept other config options):
6345 Property Type Description
6346 ---------------- --------------- ----------------------------------------------------------------------------------
6347 url String The url for the action (defaults to the form's url)
6348 method String The form method to use (defaults to the form's method, or POST if not defined)
6349 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6350 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6351 validate the form on the client (defaults to false)
6353 * @return {BasicForm} this
6355 doAction : function(action, options){
6356 if(typeof action == 'string'){
6357 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6359 if(this.fireEvent('beforeaction', this, action) !== false){
6360 this.beforeAction(action);
6361 action.run.defer(100, action);
6367 beforeAction : function(action){
6368 var o = action.options;
6371 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6373 // not really supported yet.. ??
6375 //if(this.waitMsgTarget === true){
6376 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6377 //}else if(this.waitMsgTarget){
6378 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6379 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6381 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6387 afterAction : function(action, success){
6388 this.activeAction = null;
6389 var o = action.options;
6391 //if(this.waitMsgTarget === true){
6393 //}else if(this.waitMsgTarget){
6394 // this.waitMsgTarget.unmask();
6396 // Roo.MessageBox.updateProgress(1);
6397 // Roo.MessageBox.hide();
6404 Roo.callback(o.success, o.scope, [this, action]);
6405 this.fireEvent('actioncomplete', this, action);
6409 // failure condition..
6410 // we have a scenario where updates need confirming.
6411 // eg. if a locking scenario exists..
6412 // we look for { errors : { needs_confirm : true }} in the response.
6414 (typeof(action.result) != 'undefined') &&
6415 (typeof(action.result.errors) != 'undefined') &&
6416 (typeof(action.result.errors.needs_confirm) != 'undefined')
6419 Roo.log("not supported yet");
6422 Roo.MessageBox.confirm(
6423 "Change requires confirmation",
6424 action.result.errorMsg,
6429 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6439 Roo.callback(o.failure, o.scope, [this, action]);
6440 // show an error message if no failed handler is set..
6441 if (!this.hasListener('actionfailed')) {
6442 Roo.log("need to add dialog support");
6444 Roo.MessageBox.alert("Error",
6445 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6446 action.result.errorMsg :
6447 "Saving Failed, please check your entries or try again"
6452 this.fireEvent('actionfailed', this, action);
6457 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6458 * @param {String} id The value to search for
6461 findField : function(id){
6462 var items = this.getItems();
6463 var field = items.get(id);
6465 items.each(function(f){
6466 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6473 return field || null;
6476 * Mark fields in this form invalid in bulk.
6477 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6478 * @return {BasicForm} this
6480 markInvalid : function(errors){
6481 if(errors instanceof Array){
6482 for(var i = 0, len = errors.length; i < len; i++){
6483 var fieldError = errors[i];
6484 var f = this.findField(fieldError.id);
6486 f.markInvalid(fieldError.msg);
6492 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6493 field.markInvalid(errors[id]);
6497 //Roo.each(this.childForms || [], function (f) {
6498 // f.markInvalid(errors);
6505 * Set values for fields in this form in bulk.
6506 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6507 * @return {BasicForm} this
6509 setValues : function(values){
6510 if(values instanceof Array){ // array of objects
6511 for(var i = 0, len = values.length; i < len; i++){
6513 var f = this.findField(v.id);
6515 f.setValue(v.value);
6516 if(this.trackResetOnLoad){
6517 f.originalValue = f.getValue();
6521 }else{ // object hash
6524 if(typeof values[id] != 'function' && (field = this.findField(id))){
6526 if (field.setFromData &&
6528 field.displayField &&
6529 // combos' with local stores can
6530 // be queried via setValue()
6531 // to set their value..
6532 (field.store && !field.store.isLocal)
6536 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6537 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6538 field.setFromData(sd);
6541 field.setValue(values[id]);
6545 if(this.trackResetOnLoad){
6546 field.originalValue = field.getValue();
6552 //Roo.each(this.childForms || [], function (f) {
6553 // f.setValues(values);
6560 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6561 * they are returned as an array.
6562 * @param {Boolean} asString
6565 getValues : function(asString){
6566 //if (this.childForms) {
6567 // copy values from the child forms
6568 // Roo.each(this.childForms, function (f) {
6569 // this.setValues(f.getValues());
6575 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6576 if(asString === true){
6579 return Roo.urlDecode(fs);
6583 * Returns the fields in this form as an object with key/value pairs.
6584 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6587 getFieldValues : function(with_hidden)
6589 var items = this.getItems();
6591 items.each(function(f){
6595 var v = f.getValue();
6596 if (f.inputType =='radio') {
6597 if (typeof(ret[f.getName()]) == 'undefined') {
6598 ret[f.getName()] = ''; // empty..
6601 if (!f.el.dom.checked) {
6609 // not sure if this supported any more..
6610 if ((typeof(v) == 'object') && f.getRawValue) {
6611 v = f.getRawValue() ; // dates..
6613 // combo boxes where name != hiddenName...
6614 if (f.name != f.getName()) {
6615 ret[f.name] = f.getRawValue();
6617 ret[f.getName()] = v;
6624 * Clears all invalid messages in this form.
6625 * @return {BasicForm} this
6627 clearInvalid : function(){
6628 var items = this.getItems();
6630 items.each(function(f){
6641 * @return {BasicForm} this
6644 var items = this.getItems();
6645 items.each(function(f){
6649 Roo.each(this.childForms || [], function (f) {
6656 getItems : function()
6658 var r=new Roo.util.MixedCollection(false, function(o){
6659 return o.id || (o.id = Roo.id());
6661 var iter = function(el) {
6668 Roo.each(el.items,function(e) {
6687 * Ext JS Library 1.1.1
6688 * Copyright(c) 2006-2007, Ext JS, LLC.
6690 * Originally Released Under LGPL - original licence link has changed is not relivant.
6693 * <script type="text/javascript">
6696 * @class Roo.form.VTypes
6697 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6700 Roo.form.VTypes = function(){
6701 // closure these in so they are only created once.
6702 var alpha = /^[a-zA-Z_]+$/;
6703 var alphanum = /^[a-zA-Z0-9_]+$/;
6704 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6705 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6707 // All these messages and functions are configurable
6710 * The function used to validate email addresses
6711 * @param {String} value The email address
6713 'email' : function(v){
6714 return email.test(v);
6717 * The error text to display when the email validation function returns false
6720 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6722 * The keystroke filter mask to be applied on email input
6725 'emailMask' : /[a-z0-9_\.\-@]/i,
6728 * The function used to validate URLs
6729 * @param {String} value The URL
6731 'url' : function(v){
6735 * The error text to display when the url validation function returns false
6738 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6741 * The function used to validate alpha values
6742 * @param {String} value The value
6744 'alpha' : function(v){
6745 return alpha.test(v);
6748 * The error text to display when the alpha validation function returns false
6751 'alphaText' : 'This field should only contain letters and _',
6753 * The keystroke filter mask to be applied on alpha input
6756 'alphaMask' : /[a-z_]/i,
6759 * The function used to validate alphanumeric values
6760 * @param {String} value The value
6762 'alphanum' : function(v){
6763 return alphanum.test(v);
6766 * The error text to display when the alphanumeric validation function returns false
6769 'alphanumText' : 'This field should only contain letters, numbers and _',
6771 * The keystroke filter mask to be applied on alphanumeric input
6774 'alphanumMask' : /[a-z0-9_]/i
6784 * @class Roo.bootstrap.Input
6785 * @extends Roo.bootstrap.Component
6786 * Bootstrap Input class
6787 * @cfg {Boolean} disabled is it disabled
6788 * @cfg {String} fieldLabel - the label associated
6789 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6790 * @cfg {String} name name of the input
6791 * @cfg {string} fieldLabel - the label associated
6792 * @cfg {string} inputType - input / file submit ...
6793 * @cfg {string} placeholder - placeholder to put in text.
6794 * @cfg {string} before - input group add on before
6795 * @cfg {string} after - input group add on after
6796 * @cfg {string} size - (lg|sm) or leave empty..
6797 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6798 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6799 * @cfg {Number} md colspan out of 12 for computer-sized screens
6800 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6801 * @cfg {string} value default value of the input
6802 * @cfg {Number} labelWidth set the width of label (0-12)
6803 * @cfg {String} labelAlign (top|left)
6804 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6805 * @cfg {String} align (left|center|right) Default left
6809 * Create a new Input
6810 * @param {Object} config The config object
6813 Roo.bootstrap.Input = function(config){
6814 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6819 * Fires when this field receives input focus.
6820 * @param {Roo.form.Field} this
6825 * Fires when this field loses input focus.
6826 * @param {Roo.form.Field} this
6831 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6832 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6833 * @param {Roo.form.Field} this
6834 * @param {Roo.EventObject} e The event object
6839 * Fires just before the field blurs if the field value has changed.
6840 * @param {Roo.form.Field} this
6841 * @param {Mixed} newValue The new value
6842 * @param {Mixed} oldValue The original value
6847 * Fires after the field has been marked as invalid.
6848 * @param {Roo.form.Field} this
6849 * @param {String} msg The validation message
6854 * Fires after the field has been validated with no errors.
6855 * @param {Roo.form.Field} this
6860 * Fires after the key up
6861 * @param {Roo.form.Field} this
6862 * @param {Roo.EventObject} e The event Object
6868 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6870 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6871 automatic validation (defaults to "keyup").
6873 validationEvent : "keyup",
6875 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6877 validateOnBlur : true,
6879 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6881 validationDelay : 250,
6883 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6885 focusClass : "x-form-focus", // not needed???
6889 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6891 invalidClass : "has-error",
6894 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6896 selectOnFocus : false,
6899 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6903 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6908 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6910 disableKeyFilter : false,
6913 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6917 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6921 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6923 blankText : "This field is required",
6926 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6930 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6932 maxLength : Number.MAX_VALUE,
6934 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6936 minLengthText : "The minimum length for this field is {0}",
6938 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6940 maxLengthText : "The maximum length for this field is {0}",
6944 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6945 * If available, this function will be called only after the basic validators all return true, and will be passed the
6946 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6950 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6951 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6952 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6956 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6979 formatedValue : false,
6981 parentLabelAlign : function()
6984 while (parent.parent()) {
6985 parent = parent.parent();
6986 if (typeof(parent.labelAlign) !='undefined') {
6987 return parent.labelAlign;
6994 getAutoCreate : function(){
6996 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7002 if(this.inputType != 'hidden'){
7003 cfg.cls = 'form-group' //input-group
7009 type : this.inputType,
7011 cls : 'form-control',
7012 placeholder : this.placeholder || ''
7017 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7020 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7021 input.maxLength = this.maxLength;
7024 if (this.disabled) {
7025 input.disabled=true;
7028 if (this.readOnly) {
7029 input.readonly=true;
7033 input.name = this.name;
7036 input.cls += ' input-' + this.size;
7039 ['xs','sm','md','lg'].map(function(size){
7040 if (settings[size]) {
7041 cfg.cls += ' col-' + size + '-' + settings[size];
7045 var inputblock = input;
7047 if (this.before || this.after) {
7050 cls : 'input-group',
7053 if (this.before && typeof(this.before) == 'string') {
7055 inputblock.cn.push({
7057 cls : 'roo-input-before input-group-addon',
7061 if (this.before && typeof(this.before) == 'object') {
7062 this.before = Roo.factory(this.before);
7063 Roo.log(this.before);
7064 inputblock.cn.push({
7066 cls : 'roo-input-before input-group-' +
7067 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7071 inputblock.cn.push(input);
7073 if (this.after && typeof(this.after) == 'string') {
7074 inputblock.cn.push({
7076 cls : 'roo-input-after input-group-addon',
7080 if (this.after && typeof(this.after) == 'object') {
7081 this.after = Roo.factory(this.after);
7082 Roo.log(this.after);
7083 inputblock.cn.push({
7085 cls : 'roo-input-after input-group-' +
7086 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7091 if (align ==='left' && this.fieldLabel.length) {
7092 Roo.log("left and has label");
7098 cls : 'control-label col-sm-' + this.labelWidth,
7099 html : this.fieldLabel
7103 cls : "col-sm-" + (12 - this.labelWidth),
7110 } else if ( this.fieldLabel.length) {
7116 //cls : 'input-group-addon',
7117 html : this.fieldLabel
7127 Roo.log(" no label && no align");
7136 Roo.log('input-parentType: ' + this.parentType);
7138 if (this.parentType === 'Navbar' && this.parent().bar) {
7139 cfg.cls += ' navbar-form';
7147 * return the real input element.
7149 inputEl: function ()
7151 return this.el.select('input.form-control',true).first();
7153 setDisabled : function(v)
7155 var i = this.inputEl().dom;
7157 i.removeAttribute('disabled');
7161 i.setAttribute('disabled','true');
7163 initEvents : function()
7166 this.inputEl().on("keydown" , this.fireKey, this);
7167 this.inputEl().on("focus", this.onFocus, this);
7168 this.inputEl().on("blur", this.onBlur, this);
7170 this.inputEl().relayEvent('keyup', this);
7172 // reference to original value for reset
7173 this.originalValue = this.getValue();
7174 //Roo.form.TextField.superclass.initEvents.call(this);
7175 if(this.validationEvent == 'keyup'){
7176 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7177 this.inputEl().on('keyup', this.filterValidation, this);
7179 else if(this.validationEvent !== false){
7180 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7183 if(this.selectOnFocus){
7184 this.on("focus", this.preFocus, this);
7187 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7188 this.inputEl().on("keypress", this.filterKeys, this);
7191 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7192 this.el.on("click", this.autoSize, this);
7195 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7196 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7199 if (typeof(this.before) == 'object') {
7200 this.before.render(this.el.select('.roo-input-before',true).first());
7202 if (typeof(this.after) == 'object') {
7203 this.after.render(this.el.select('.roo-input-after',true).first());
7208 filterValidation : function(e){
7209 if(!e.isNavKeyPress()){
7210 this.validationTask.delay(this.validationDelay);
7214 * Validates the field value
7215 * @return {Boolean} True if the value is valid, else false
7217 validate : function(){
7218 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7219 if(this.disabled || this.validateValue(this.getRawValue())){
7220 this.clearInvalid();
7228 * Validates a value according to the field's validation rules and marks the field as invalid
7229 * if the validation fails
7230 * @param {Mixed} value The value to validate
7231 * @return {Boolean} True if the value is valid, else false
7233 validateValue : function(value){
7234 if(value.length < 1) { // if it's blank
7235 if(this.allowBlank){
7236 this.clearInvalid();
7239 this.markInvalid(this.blankText);
7243 if(value.length < this.minLength){
7244 this.markInvalid(String.format(this.minLengthText, this.minLength));
7247 if(value.length > this.maxLength){
7248 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7252 var vt = Roo.form.VTypes;
7253 if(!vt[this.vtype](value, this)){
7254 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7258 if(typeof this.validator == "function"){
7259 var msg = this.validator(value);
7261 this.markInvalid(msg);
7265 if(this.regex && !this.regex.test(value)){
7266 this.markInvalid(this.regexText);
7275 fireKey : function(e){
7276 //Roo.log('field ' + e.getKey());
7277 if(e.isNavKeyPress()){
7278 this.fireEvent("specialkey", this, e);
7281 focus : function (selectText){
7283 this.inputEl().focus();
7284 if(selectText === true){
7285 this.inputEl().dom.select();
7291 onFocus : function(){
7292 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7293 // this.el.addClass(this.focusClass);
7296 this.hasFocus = true;
7297 this.startValue = this.getValue();
7298 this.fireEvent("focus", this);
7302 beforeBlur : Roo.emptyFn,
7306 onBlur : function(){
7308 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7309 //this.el.removeClass(this.focusClass);
7311 this.hasFocus = false;
7312 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7315 var v = this.getValue();
7316 if(String(v) !== String(this.startValue)){
7317 this.fireEvent('change', this, v, this.startValue);
7319 this.fireEvent("blur", this);
7323 * Resets the current field value to the originally loaded value and clears any validation messages
7326 this.setValue(this.originalValue);
7327 this.clearInvalid();
7330 * Returns the name of the field
7331 * @return {Mixed} name The name field
7333 getName: function(){
7337 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7338 * @return {Mixed} value The field value
7340 getValue : function(){
7342 var v = this.inputEl().getValue();
7347 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7348 * @return {Mixed} value The field value
7350 getRawValue : function(){
7351 var v = this.inputEl().getValue();
7357 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7358 * @param {Mixed} value The value to set
7360 setRawValue : function(v){
7361 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7364 selectText : function(start, end){
7365 var v = this.getRawValue();
7367 start = start === undefined ? 0 : start;
7368 end = end === undefined ? v.length : end;
7369 var d = this.inputEl().dom;
7370 if(d.setSelectionRange){
7371 d.setSelectionRange(start, end);
7372 }else if(d.createTextRange){
7373 var range = d.createTextRange();
7374 range.moveStart("character", start);
7375 range.moveEnd("character", v.length-end);
7382 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7383 * @param {Mixed} value The value to set
7385 setValue : function(v){
7388 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7394 processValue : function(value){
7395 if(this.stripCharsRe){
7396 var newValue = value.replace(this.stripCharsRe, '');
7397 if(newValue !== value){
7398 this.setRawValue(newValue);
7405 preFocus : function(){
7407 if(this.selectOnFocus){
7408 this.inputEl().dom.select();
7411 filterKeys : function(e){
7413 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7416 var c = e.getCharCode(), cc = String.fromCharCode(c);
7417 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7420 if(!this.maskRe.test(cc)){
7425 * Clear any invalid styles/messages for this field
7427 clearInvalid : function(){
7429 if(!this.el || this.preventMark){ // not rendered
7432 this.el.removeClass(this.invalidClass);
7434 switch(this.msgTarget){
7436 this.el.dom.qtip = '';
7439 this.el.dom.title = '';
7443 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7448 this.errorIcon.dom.qtip = '';
7449 this.errorIcon.hide();
7450 this.un('resize', this.alignErrorIcon, this);
7454 var t = Roo.getDom(this.msgTarget);
7456 t.style.display = 'none';
7460 this.fireEvent('valid', this);
7463 * Mark this field as invalid
7464 * @param {String} msg The validation message
7466 markInvalid : function(msg){
7467 if(!this.el || this.preventMark){ // not rendered
7470 this.el.addClass(this.invalidClass);
7472 msg = msg || this.invalidText;
7473 switch(this.msgTarget){
7475 this.el.dom.qtip = msg;
7476 this.el.dom.qclass = 'x-form-invalid-tip';
7477 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7478 Roo.QuickTips.enable();
7482 this.el.dom.title = msg;
7486 var elp = this.el.findParent('.x-form-element', 5, true);
7487 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7488 this.errorEl.setWidth(elp.getWidth(true)-20);
7490 this.errorEl.update(msg);
7491 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7494 if(!this.errorIcon){
7495 var elp = this.el.findParent('.x-form-element', 5, true);
7496 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7498 this.alignErrorIcon();
7499 this.errorIcon.dom.qtip = msg;
7500 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7501 this.errorIcon.show();
7502 this.on('resize', this.alignErrorIcon, this);
7505 var t = Roo.getDom(this.msgTarget);
7507 t.style.display = this.msgDisplay;
7511 this.fireEvent('invalid', this, msg);
7514 SafariOnKeyDown : function(event)
7516 // this is a workaround for a password hang bug on chrome/ webkit.
7518 var isSelectAll = false;
7520 if(this.inputEl().dom.selectionEnd > 0){
7521 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7523 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7524 event.preventDefault();
7529 if(isSelectAll){ // backspace and delete key
7531 event.preventDefault();
7532 // this is very hacky as keydown always get's upper case.
7534 var cc = String.fromCharCode(event.getCharCode());
7535 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7539 adjustWidth : function(tag, w){
7540 tag = tag.toLowerCase();
7541 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7542 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7546 if(tag == 'textarea'){
7549 }else if(Roo.isOpera){
7553 if(tag == 'textarea'){
7572 * @class Roo.bootstrap.TextArea
7573 * @extends Roo.bootstrap.Input
7574 * Bootstrap TextArea class
7575 * @cfg {Number} cols Specifies the visible width of a text area
7576 * @cfg {Number} rows Specifies the visible number of lines in a text area
7577 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7578 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7579 * @cfg {string} html text
7582 * Create a new TextArea
7583 * @param {Object} config The config object
7586 Roo.bootstrap.TextArea = function(config){
7587 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7591 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7601 getAutoCreate : function(){
7603 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7614 value : this.value || '',
7615 html: this.html || '',
7616 cls : 'form-control',
7617 placeholder : this.placeholder || ''
7621 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7622 input.maxLength = this.maxLength;
7626 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7630 input.cols = this.cols;
7633 if (this.readOnly) {
7634 input.readonly = true;
7638 input.name = this.name;
7642 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7646 ['xs','sm','md','lg'].map(function(size){
7647 if (settings[size]) {
7648 cfg.cls += ' col-' + size + '-' + settings[size];
7652 var inputblock = input;
7654 if (this.before || this.after) {
7657 cls : 'input-group',
7661 inputblock.cn.push({
7663 cls : 'input-group-addon',
7667 inputblock.cn.push(input);
7669 inputblock.cn.push({
7671 cls : 'input-group-addon',
7678 if (align ==='left' && this.fieldLabel.length) {
7679 Roo.log("left and has label");
7685 cls : 'control-label col-sm-' + this.labelWidth,
7686 html : this.fieldLabel
7690 cls : "col-sm-" + (12 - this.labelWidth),
7697 } else if ( this.fieldLabel.length) {
7703 //cls : 'input-group-addon',
7704 html : this.fieldLabel
7714 Roo.log(" no label && no align");
7724 if (this.disabled) {
7725 input.disabled=true;
7732 * return the real textarea element.
7734 inputEl: function ()
7736 return this.el.select('textarea.form-control',true).first();
7744 * trigger field - base class for combo..
7749 * @class Roo.bootstrap.TriggerField
7750 * @extends Roo.bootstrap.Input
7751 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7752 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7753 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7754 * for which you can provide a custom implementation. For example:
7756 var trigger = new Roo.bootstrap.TriggerField();
7757 trigger.onTriggerClick = myTriggerFn;
7758 trigger.applyTo('my-field');
7761 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7762 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7763 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7764 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7766 * Create a new TriggerField.
7767 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7768 * to the base TextField)
7770 Roo.bootstrap.TriggerField = function(config){
7771 this.mimicing = false;
7772 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7775 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7777 * @cfg {String} triggerClass A CSS class to apply to the trigger
7780 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7784 /** @cfg {Boolean} grow @hide */
7785 /** @cfg {Number} growMin @hide */
7786 /** @cfg {Number} growMax @hide */
7792 autoSize: Roo.emptyFn,
7799 actionMode : 'wrap',
7803 getAutoCreate : function(){
7805 var align = this.labelAlign || this.parentLabelAlign();
7810 cls: 'form-group' //input-group
7817 type : this.inputType,
7818 cls : 'form-control',
7819 autocomplete: 'off',
7820 placeholder : this.placeholder || ''
7824 input.name = this.name;
7827 input.cls += ' input-' + this.size;
7830 if (this.disabled) {
7831 input.disabled=true;
7834 var inputblock = input;
7836 if (this.before || this.after) {
7839 cls : 'input-group',
7843 inputblock.cn.push({
7845 cls : 'input-group-addon',
7849 inputblock.cn.push(input);
7851 inputblock.cn.push({
7853 cls : 'input-group-addon',
7866 cls: 'form-hidden-field'
7874 Roo.log('multiple');
7882 cls: 'form-hidden-field'
7886 cls: 'select2-choices',
7890 cls: 'select2-search-field',
7903 cls: 'select2-container input-group',
7908 // cls: 'typeahead typeahead-long dropdown-menu',
7909 // style: 'display:none'
7914 if(!this.multiple && this.showToggleBtn){
7917 cls : 'input-group-addon btn dropdown-toggle',
7925 cls: 'combobox-clear',
7939 combobox.cls += ' select2-container-multi';
7942 if (align ==='left' && this.fieldLabel.length) {
7944 Roo.log("left and has label");
7950 cls : 'control-label col-sm-' + this.labelWidth,
7951 html : this.fieldLabel
7955 cls : "col-sm-" + (12 - this.labelWidth),
7962 } else if ( this.fieldLabel.length) {
7968 //cls : 'input-group-addon',
7969 html : this.fieldLabel
7979 Roo.log(" no label && no align");
7986 ['xs','sm','md','lg'].map(function(size){
7987 if (settings[size]) {
7988 cfg.cls += ' col-' + size + '-' + settings[size];
7999 onResize : function(w, h){
8000 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8001 // if(typeof w == 'number'){
8002 // var x = w - this.trigger.getWidth();
8003 // this.inputEl().setWidth(this.adjustWidth('input', x));
8004 // this.trigger.setStyle('left', x+'px');
8009 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8012 getResizeEl : function(){
8013 return this.inputEl();
8017 getPositionEl : function(){
8018 return this.inputEl();
8022 alignErrorIcon : function(){
8023 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8027 initEvents : function(){
8031 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8032 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8033 if(!this.multiple && this.showToggleBtn){
8034 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8035 if(this.hideTrigger){
8036 this.trigger.setDisplayed(false);
8038 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8042 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8045 //this.trigger.addClassOnOver('x-form-trigger-over');
8046 //this.trigger.addClassOnClick('x-form-trigger-click');
8049 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8053 createList : function()
8055 this.list = Roo.get(document.body).createChild({
8057 cls: 'typeahead typeahead-long dropdown-menu',
8058 style: 'display:none'
8061 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8066 initTrigger : function(){
8071 onDestroy : function(){
8073 this.trigger.removeAllListeners();
8074 // this.trigger.remove();
8077 // this.wrap.remove();
8079 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8083 onFocus : function(){
8084 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8087 this.wrap.addClass('x-trigger-wrap-focus');
8088 this.mimicing = true;
8089 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8090 if(this.monitorTab){
8091 this.el.on("keydown", this.checkTab, this);
8098 checkTab : function(e){
8099 if(e.getKey() == e.TAB){
8105 onBlur : function(){
8110 mimicBlur : function(e, t){
8112 if(!this.wrap.contains(t) && this.validateBlur()){
8119 triggerBlur : function(){
8120 this.mimicing = false;
8121 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8122 if(this.monitorTab){
8123 this.el.un("keydown", this.checkTab, this);
8125 //this.wrap.removeClass('x-trigger-wrap-focus');
8126 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8130 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8131 validateBlur : function(e, t){
8136 onDisable : function(){
8137 this.inputEl().dom.disabled = true;
8138 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8140 // this.wrap.addClass('x-item-disabled');
8145 onEnable : function(){
8146 this.inputEl().dom.disabled = false;
8147 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8149 // this.el.removeClass('x-item-disabled');
8154 onShow : function(){
8155 var ae = this.getActionEl();
8158 ae.dom.style.display = '';
8159 ae.dom.style.visibility = 'visible';
8165 onHide : function(){
8166 var ae = this.getActionEl();
8167 ae.dom.style.display = 'none';
8171 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8172 * by an implementing function.
8174 * @param {EventObject} e
8176 onTriggerClick : Roo.emptyFn
8180 * Ext JS Library 1.1.1
8181 * Copyright(c) 2006-2007, Ext JS, LLC.
8183 * Originally Released Under LGPL - original licence link has changed is not relivant.
8186 * <script type="text/javascript">
8191 * @class Roo.data.SortTypes
8193 * Defines the default sorting (casting?) comparison functions used when sorting data.
8195 Roo.data.SortTypes = {
8197 * Default sort that does nothing
8198 * @param {Mixed} s The value being converted
8199 * @return {Mixed} The comparison value
8206 * The regular expression used to strip tags
8210 stripTagsRE : /<\/?[^>]+>/gi,
8213 * Strips all HTML tags to sort on text only
8214 * @param {Mixed} s The value being converted
8215 * @return {String} The comparison value
8217 asText : function(s){
8218 return String(s).replace(this.stripTagsRE, "");
8222 * Strips all HTML tags to sort on text only - Case insensitive
8223 * @param {Mixed} s The value being converted
8224 * @return {String} The comparison value
8226 asUCText : function(s){
8227 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8231 * Case insensitive string
8232 * @param {Mixed} s The value being converted
8233 * @return {String} The comparison value
8235 asUCString : function(s) {
8236 return String(s).toUpperCase();
8241 * @param {Mixed} s The value being converted
8242 * @return {Number} The comparison value
8244 asDate : function(s) {
8248 if(s instanceof Date){
8251 return Date.parse(String(s));
8256 * @param {Mixed} s The value being converted
8257 * @return {Float} The comparison value
8259 asFloat : function(s) {
8260 var val = parseFloat(String(s).replace(/,/g, ""));
8261 if(isNaN(val)) val = 0;
8267 * @param {Mixed} s The value being converted
8268 * @return {Number} The comparison value
8270 asInt : function(s) {
8271 var val = parseInt(String(s).replace(/,/g, ""));
8272 if(isNaN(val)) val = 0;
8277 * Ext JS Library 1.1.1
8278 * Copyright(c) 2006-2007, Ext JS, LLC.
8280 * Originally Released Under LGPL - original licence link has changed is not relivant.
8283 * <script type="text/javascript">
8287 * @class Roo.data.Record
8288 * Instances of this class encapsulate both record <em>definition</em> information, and record
8289 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8290 * to access Records cached in an {@link Roo.data.Store} object.<br>
8292 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8293 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8296 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8298 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8299 * {@link #create}. The parameters are the same.
8300 * @param {Array} data An associative Array of data values keyed by the field name.
8301 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8302 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8303 * not specified an integer id is generated.
8305 Roo.data.Record = function(data, id){
8306 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8311 * Generate a constructor for a specific record layout.
8312 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8313 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8314 * Each field definition object may contain the following properties: <ul>
8315 * <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,
8316 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8317 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8318 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8319 * is being used, then this is a string containing the javascript expression to reference the data relative to
8320 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8321 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8322 * this may be omitted.</p></li>
8323 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8324 * <ul><li>auto (Default, implies no conversion)</li>
8329 * <li>date</li></ul></p></li>
8330 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8331 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8332 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8333 * by the Reader into an object that will be stored in the Record. It is passed the
8334 * following parameters:<ul>
8335 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8337 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8339 * <br>usage:<br><pre><code>
8340 var TopicRecord = Roo.data.Record.create(
8341 {name: 'title', mapping: 'topic_title'},
8342 {name: 'author', mapping: 'username'},
8343 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8344 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8345 {name: 'lastPoster', mapping: 'user2'},
8346 {name: 'excerpt', mapping: 'post_text'}
8349 var myNewRecord = new TopicRecord({
8350 title: 'Do my job please',
8353 lastPost: new Date(),
8354 lastPoster: 'Animal',
8355 excerpt: 'No way dude!'
8357 myStore.add(myNewRecord);
8362 Roo.data.Record.create = function(o){
8364 f.superclass.constructor.apply(this, arguments);
8366 Roo.extend(f, Roo.data.Record);
8367 var p = f.prototype;
8368 p.fields = new Roo.util.MixedCollection(false, function(field){
8371 for(var i = 0, len = o.length; i < len; i++){
8372 p.fields.add(new Roo.data.Field(o[i]));
8374 f.getField = function(name){
8375 return p.fields.get(name);
8380 Roo.data.Record.AUTO_ID = 1000;
8381 Roo.data.Record.EDIT = 'edit';
8382 Roo.data.Record.REJECT = 'reject';
8383 Roo.data.Record.COMMIT = 'commit';
8385 Roo.data.Record.prototype = {
8387 * Readonly flag - true if this record has been modified.
8396 join : function(store){
8401 * Set the named field to the specified value.
8402 * @param {String} name The name of the field to set.
8403 * @param {Object} value The value to set the field to.
8405 set : function(name, value){
8406 if(this.data[name] == value){
8413 if(typeof this.modified[name] == 'undefined'){
8414 this.modified[name] = this.data[name];
8416 this.data[name] = value;
8417 if(!this.editing && this.store){
8418 this.store.afterEdit(this);
8423 * Get the value of the named field.
8424 * @param {String} name The name of the field to get the value of.
8425 * @return {Object} The value of the field.
8427 get : function(name){
8428 return this.data[name];
8432 beginEdit : function(){
8433 this.editing = true;
8438 cancelEdit : function(){
8439 this.editing = false;
8440 delete this.modified;
8444 endEdit : function(){
8445 this.editing = false;
8446 if(this.dirty && this.store){
8447 this.store.afterEdit(this);
8452 * Usually called by the {@link Roo.data.Store} which owns the Record.
8453 * Rejects all changes made to the Record since either creation, or the last commit operation.
8454 * Modified fields are reverted to their original values.
8456 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8457 * of reject operations.
8459 reject : function(){
8460 var m = this.modified;
8462 if(typeof m[n] != "function"){
8463 this.data[n] = m[n];
8467 delete this.modified;
8468 this.editing = false;
8470 this.store.afterReject(this);
8475 * Usually called by the {@link Roo.data.Store} which owns the Record.
8476 * Commits all changes made to the Record since either creation, or the last commit operation.
8478 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8479 * of commit operations.
8481 commit : function(){
8483 delete this.modified;
8484 this.editing = false;
8486 this.store.afterCommit(this);
8491 hasError : function(){
8492 return this.error != null;
8496 clearError : function(){
8501 * Creates a copy of this record.
8502 * @param {String} id (optional) A new record id if you don't want to use this record's id
8505 copy : function(newId) {
8506 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8510 * Ext JS Library 1.1.1
8511 * Copyright(c) 2006-2007, Ext JS, LLC.
8513 * Originally Released Under LGPL - original licence link has changed is not relivant.
8516 * <script type="text/javascript">
8522 * @class Roo.data.Store
8523 * @extends Roo.util.Observable
8524 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8525 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8527 * 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
8528 * has no knowledge of the format of the data returned by the Proxy.<br>
8530 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8531 * instances from the data object. These records are cached and made available through accessor functions.
8533 * Creates a new Store.
8534 * @param {Object} config A config object containing the objects needed for the Store to access data,
8535 * and read the data into Records.
8537 Roo.data.Store = function(config){
8538 this.data = new Roo.util.MixedCollection(false);
8539 this.data.getKey = function(o){
8542 this.baseParams = {};
8549 "multisort" : "_multisort"
8552 if(config && config.data){
8553 this.inlineData = config.data;
8557 Roo.apply(this, config);
8559 if(this.reader){ // reader passed
8560 this.reader = Roo.factory(this.reader, Roo.data);
8561 this.reader.xmodule = this.xmodule || false;
8562 if(!this.recordType){
8563 this.recordType = this.reader.recordType;
8565 if(this.reader.onMetaChange){
8566 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8570 if(this.recordType){
8571 this.fields = this.recordType.prototype.fields;
8577 * @event datachanged
8578 * Fires when the data cache has changed, and a widget which is using this Store
8579 * as a Record cache should refresh its view.
8580 * @param {Store} this
8585 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8586 * @param {Store} this
8587 * @param {Object} meta The JSON metadata
8592 * Fires when Records have been added to the Store
8593 * @param {Store} this
8594 * @param {Roo.data.Record[]} records The array of Records added
8595 * @param {Number} index The index at which the record(s) were added
8600 * Fires when a Record has been removed from the Store
8601 * @param {Store} this
8602 * @param {Roo.data.Record} record The Record that was removed
8603 * @param {Number} index The index at which the record was removed
8608 * Fires when a Record has been updated
8609 * @param {Store} this
8610 * @param {Roo.data.Record} record The Record that was updated
8611 * @param {String} operation The update operation being performed. Value may be one of:
8613 Roo.data.Record.EDIT
8614 Roo.data.Record.REJECT
8615 Roo.data.Record.COMMIT
8621 * Fires when the data cache has been cleared.
8622 * @param {Store} this
8627 * Fires before a request is made for a new data object. If the beforeload handler returns false
8628 * the load action will be canceled.
8629 * @param {Store} this
8630 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8634 * @event beforeloadadd
8635 * Fires after a new set of Records has been loaded.
8636 * @param {Store} this
8637 * @param {Roo.data.Record[]} records The Records that were loaded
8638 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8640 beforeloadadd : true,
8643 * Fires after a new set of Records has been loaded, before they are added to the store.
8644 * @param {Store} this
8645 * @param {Roo.data.Record[]} records The Records that were loaded
8646 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8647 * @params {Object} return from reader
8651 * @event loadexception
8652 * Fires if an exception occurs in the Proxy during loading.
8653 * Called with the signature of the Proxy's "loadexception" event.
8654 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8657 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8658 * @param {Object} load options
8659 * @param {Object} jsonData from your request (normally this contains the Exception)
8661 loadexception : true
8665 this.proxy = Roo.factory(this.proxy, Roo.data);
8666 this.proxy.xmodule = this.xmodule || false;
8667 this.relayEvents(this.proxy, ["loadexception"]);
8669 this.sortToggle = {};
8670 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8672 Roo.data.Store.superclass.constructor.call(this);
8674 if(this.inlineData){
8675 this.loadData(this.inlineData);
8676 delete this.inlineData;
8680 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8682 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8683 * without a remote query - used by combo/forms at present.
8687 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8690 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8693 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8694 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8697 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8698 * on any HTTP request
8701 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8704 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8708 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8709 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8714 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8715 * loaded or when a record is removed. (defaults to false).
8717 pruneModifiedRecords : false,
8723 * Add Records to the Store and fires the add event.
8724 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8726 add : function(records){
8727 records = [].concat(records);
8728 for(var i = 0, len = records.length; i < len; i++){
8729 records[i].join(this);
8731 var index = this.data.length;
8732 this.data.addAll(records);
8733 this.fireEvent("add", this, records, index);
8737 * Remove a Record from the Store and fires the remove event.
8738 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8740 remove : function(record){
8741 var index = this.data.indexOf(record);
8742 this.data.removeAt(index);
8743 if(this.pruneModifiedRecords){
8744 this.modified.remove(record);
8746 this.fireEvent("remove", this, record, index);
8750 * Remove all Records from the Store and fires the clear event.
8752 removeAll : function(){
8754 if(this.pruneModifiedRecords){
8757 this.fireEvent("clear", this);
8761 * Inserts Records to the Store at the given index and fires the add event.
8762 * @param {Number} index The start index at which to insert the passed Records.
8763 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8765 insert : function(index, records){
8766 records = [].concat(records);
8767 for(var i = 0, len = records.length; i < len; i++){
8768 this.data.insert(index, records[i]);
8769 records[i].join(this);
8771 this.fireEvent("add", this, records, index);
8775 * Get the index within the cache of the passed Record.
8776 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8777 * @return {Number} The index of the passed Record. Returns -1 if not found.
8779 indexOf : function(record){
8780 return this.data.indexOf(record);
8784 * Get the index within the cache of the Record with the passed id.
8785 * @param {String} id The id of the Record to find.
8786 * @return {Number} The index of the Record. Returns -1 if not found.
8788 indexOfId : function(id){
8789 return this.data.indexOfKey(id);
8793 * Get the Record with the specified id.
8794 * @param {String} id The id of the Record to find.
8795 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8797 getById : function(id){
8798 return this.data.key(id);
8802 * Get the Record at the specified index.
8803 * @param {Number} index The index of the Record to find.
8804 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8806 getAt : function(index){
8807 return this.data.itemAt(index);
8811 * Returns a range of Records between specified indices.
8812 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8813 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8814 * @return {Roo.data.Record[]} An array of Records
8816 getRange : function(start, end){
8817 return this.data.getRange(start, end);
8821 storeOptions : function(o){
8822 o = Roo.apply({}, o);
8825 this.lastOptions = o;
8829 * Loads the Record cache from the configured Proxy using the configured Reader.
8831 * If using remote paging, then the first load call must specify the <em>start</em>
8832 * and <em>limit</em> properties in the options.params property to establish the initial
8833 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8835 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8836 * and this call will return before the new data has been loaded. Perform any post-processing
8837 * in a callback function, or in a "load" event handler.</strong>
8839 * @param {Object} options An object containing properties which control loading options:<ul>
8840 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8841 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8842 * passed the following arguments:<ul>
8843 * <li>r : Roo.data.Record[]</li>
8844 * <li>options: Options object from the load call</li>
8845 * <li>success: Boolean success indicator</li></ul></li>
8846 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8847 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8850 load : function(options){
8851 options = options || {};
8852 if(this.fireEvent("beforeload", this, options) !== false){
8853 this.storeOptions(options);
8854 var p = Roo.apply(options.params || {}, this.baseParams);
8855 // if meta was not loaded from remote source.. try requesting it.
8856 if (!this.reader.metaFromRemote) {
8859 if(this.sortInfo && this.remoteSort){
8860 var pn = this.paramNames;
8861 p[pn["sort"]] = this.sortInfo.field;
8862 p[pn["dir"]] = this.sortInfo.direction;
8864 if (this.multiSort) {
8865 var pn = this.paramNames;
8866 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8869 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8874 * Reloads the Record cache from the configured Proxy using the configured Reader and
8875 * the options from the last load operation performed.
8876 * @param {Object} options (optional) An object containing properties which may override the options
8877 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8878 * the most recently used options are reused).
8880 reload : function(options){
8881 this.load(Roo.applyIf(options||{}, this.lastOptions));
8885 // Called as a callback by the Reader during a load operation.
8886 loadRecords : function(o, options, success){
8887 if(!o || success === false){
8888 if(success !== false){
8889 this.fireEvent("load", this, [], options, o);
8891 if(options.callback){
8892 options.callback.call(options.scope || this, [], options, false);
8896 // if data returned failure - throw an exception.
8897 if (o.success === false) {
8898 // show a message if no listener is registered.
8899 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8900 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8902 // loadmask wil be hooked into this..
8903 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8906 var r = o.records, t = o.totalRecords || r.length;
8908 this.fireEvent("beforeloadadd", this, r, options, o);
8910 if(!options || options.add !== true){
8911 if(this.pruneModifiedRecords){
8914 for(var i = 0, len = r.length; i < len; i++){
8918 this.data = this.snapshot;
8919 delete this.snapshot;
8922 this.data.addAll(r);
8923 this.totalLength = t;
8925 this.fireEvent("datachanged", this);
8927 this.totalLength = Math.max(t, this.data.length+r.length);
8930 this.fireEvent("load", this, r, options, o);
8931 if(options.callback){
8932 options.callback.call(options.scope || this, r, options, true);
8938 * Loads data from a passed data block. A Reader which understands the format of the data
8939 * must have been configured in the constructor.
8940 * @param {Object} data The data block from which to read the Records. The format of the data expected
8941 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8942 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8944 loadData : function(o, append){
8945 var r = this.reader.readRecords(o);
8946 this.loadRecords(r, {add: append}, true);
8950 * Gets the number of cached records.
8952 * <em>If using paging, this may not be the total size of the dataset. If the data object
8953 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8954 * the data set size</em>
8956 getCount : function(){
8957 return this.data.length || 0;
8961 * Gets the total number of records in the dataset as returned by the server.
8963 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8964 * the dataset size</em>
8966 getTotalCount : function(){
8967 return this.totalLength || 0;
8971 * Returns the sort state of the Store as an object with two properties:
8973 field {String} The name of the field by which the Records are sorted
8974 direction {String} The sort order, "ASC" or "DESC"
8977 getSortState : function(){
8978 return this.sortInfo;
8982 applySort : function(){
8983 if(this.sortInfo && !this.remoteSort){
8984 var s = this.sortInfo, f = s.field;
8985 var st = this.fields.get(f).sortType;
8986 var fn = function(r1, r2){
8987 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8988 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8990 this.data.sort(s.direction, fn);
8991 if(this.snapshot && this.snapshot != this.data){
8992 this.snapshot.sort(s.direction, fn);
8998 * Sets the default sort column and order to be used by the next load operation.
8999 * @param {String} fieldName The name of the field to sort by.
9000 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9002 setDefaultSort : function(field, dir){
9003 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9008 * If remote sorting is used, the sort is performed on the server, and the cache is
9009 * reloaded. If local sorting is used, the cache is sorted internally.
9010 * @param {String} fieldName The name of the field to sort by.
9011 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9013 sort : function(fieldName, dir){
9014 var f = this.fields.get(fieldName);
9016 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9018 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9019 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9024 this.sortToggle[f.name] = dir;
9025 this.sortInfo = {field: f.name, direction: dir};
9026 if(!this.remoteSort){
9028 this.fireEvent("datachanged", this);
9030 this.load(this.lastOptions);
9035 * Calls the specified function for each of the Records in the cache.
9036 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9037 * Returning <em>false</em> aborts and exits the iteration.
9038 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9040 each : function(fn, scope){
9041 this.data.each(fn, scope);
9045 * Gets all records modified since the last commit. Modified records are persisted across load operations
9046 * (e.g., during paging).
9047 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9049 getModifiedRecords : function(){
9050 return this.modified;
9054 createFilterFn : function(property, value, anyMatch){
9055 if(!value.exec){ // not a regex
9056 value = String(value);
9057 if(value.length == 0){
9060 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9063 return value.test(r.data[property]);
9068 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9069 * @param {String} property A field on your records
9070 * @param {Number} start The record index to start at (defaults to 0)
9071 * @param {Number} end The last record index to include (defaults to length - 1)
9072 * @return {Number} The sum
9074 sum : function(property, start, end){
9075 var rs = this.data.items, v = 0;
9077 end = (end || end === 0) ? end : rs.length-1;
9079 for(var i = start; i <= end; i++){
9080 v += (rs[i].data[property] || 0);
9086 * Filter the records by a specified property.
9087 * @param {String} field A field on your records
9088 * @param {String/RegExp} value Either a string that the field
9089 * should start with or a RegExp to test against the field
9090 * @param {Boolean} anyMatch True to match any part not just the beginning
9092 filter : function(property, value, anyMatch){
9093 var fn = this.createFilterFn(property, value, anyMatch);
9094 return fn ? this.filterBy(fn) : this.clearFilter();
9098 * Filter by a function. The specified function will be called with each
9099 * record in this data source. If the function returns true the record is included,
9100 * otherwise it is filtered.
9101 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9102 * @param {Object} scope (optional) The scope of the function (defaults to this)
9104 filterBy : function(fn, scope){
9105 this.snapshot = this.snapshot || this.data;
9106 this.data = this.queryBy(fn, scope||this);
9107 this.fireEvent("datachanged", this);
9111 * Query the records by a specified property.
9112 * @param {String} field A field on your records
9113 * @param {String/RegExp} value Either a string that the field
9114 * should start with or a RegExp to test against the field
9115 * @param {Boolean} anyMatch True to match any part not just the beginning
9116 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9118 query : function(property, value, anyMatch){
9119 var fn = this.createFilterFn(property, value, anyMatch);
9120 return fn ? this.queryBy(fn) : this.data.clone();
9124 * Query by a function. The specified function will be called with each
9125 * record in this data source. If the function returns true the record is included
9127 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9128 * @param {Object} scope (optional) The scope of the function (defaults to this)
9129 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9131 queryBy : function(fn, scope){
9132 var data = this.snapshot || this.data;
9133 return data.filterBy(fn, scope||this);
9137 * Collects unique values for a particular dataIndex from this store.
9138 * @param {String} dataIndex The property to collect
9139 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9140 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9141 * @return {Array} An array of the unique values
9143 collect : function(dataIndex, allowNull, bypassFilter){
9144 var d = (bypassFilter === true && this.snapshot) ?
9145 this.snapshot.items : this.data.items;
9146 var v, sv, r = [], l = {};
9147 for(var i = 0, len = d.length; i < len; i++){
9148 v = d[i].data[dataIndex];
9150 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9159 * Revert to a view of the Record cache with no filtering applied.
9160 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9162 clearFilter : function(suppressEvent){
9163 if(this.snapshot && this.snapshot != this.data){
9164 this.data = this.snapshot;
9165 delete this.snapshot;
9166 if(suppressEvent !== true){
9167 this.fireEvent("datachanged", this);
9173 afterEdit : function(record){
9174 if(this.modified.indexOf(record) == -1){
9175 this.modified.push(record);
9177 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9181 afterReject : function(record){
9182 this.modified.remove(record);
9183 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9187 afterCommit : function(record){
9188 this.modified.remove(record);
9189 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9193 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9194 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9196 commitChanges : function(){
9197 var m = this.modified.slice(0);
9199 for(var i = 0, len = m.length; i < len; i++){
9205 * Cancel outstanding changes on all changed records.
9207 rejectChanges : function(){
9208 var m = this.modified.slice(0);
9210 for(var i = 0, len = m.length; i < len; i++){
9215 onMetaChange : function(meta, rtype, o){
9216 this.recordType = rtype;
9217 this.fields = rtype.prototype.fields;
9218 delete this.snapshot;
9219 this.sortInfo = meta.sortInfo || this.sortInfo;
9221 this.fireEvent('metachange', this, this.reader.meta);
9224 moveIndex : function(data, type)
9226 var index = this.indexOf(data);
9228 var newIndex = index + type;
9232 this.insert(newIndex, data);
9237 * Ext JS Library 1.1.1
9238 * Copyright(c) 2006-2007, Ext JS, LLC.
9240 * Originally Released Under LGPL - original licence link has changed is not relivant.
9243 * <script type="text/javascript">
9247 * @class Roo.data.SimpleStore
9248 * @extends Roo.data.Store
9249 * Small helper class to make creating Stores from Array data easier.
9250 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9251 * @cfg {Array} fields An array of field definition objects, or field name strings.
9252 * @cfg {Array} data The multi-dimensional array of data
9254 * @param {Object} config
9256 Roo.data.SimpleStore = function(config){
9257 Roo.data.SimpleStore.superclass.constructor.call(this, {
9259 reader: new Roo.data.ArrayReader({
9262 Roo.data.Record.create(config.fields)
9264 proxy : new Roo.data.MemoryProxy(config.data)
9268 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9270 * Ext JS Library 1.1.1
9271 * Copyright(c) 2006-2007, Ext JS, LLC.
9273 * Originally Released Under LGPL - original licence link has changed is not relivant.
9276 * <script type="text/javascript">
9281 * @extends Roo.data.Store
9282 * @class Roo.data.JsonStore
9283 * Small helper class to make creating Stores for JSON data easier. <br/>
9285 var store = new Roo.data.JsonStore({
9286 url: 'get-images.php',
9288 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9291 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9292 * JsonReader and HttpProxy (unless inline data is provided).</b>
9293 * @cfg {Array} fields An array of field definition objects, or field name strings.
9295 * @param {Object} config
9297 Roo.data.JsonStore = function(c){
9298 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9299 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9300 reader: new Roo.data.JsonReader(c, c.fields)
9303 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9305 * Ext JS Library 1.1.1
9306 * Copyright(c) 2006-2007, Ext JS, LLC.
9308 * Originally Released Under LGPL - original licence link has changed is not relivant.
9311 * <script type="text/javascript">
9315 Roo.data.Field = function(config){
9316 if(typeof config == "string"){
9317 config = {name: config};
9319 Roo.apply(this, config);
9325 var st = Roo.data.SortTypes;
9326 // named sortTypes are supported, here we look them up
9327 if(typeof this.sortType == "string"){
9328 this.sortType = st[this.sortType];
9331 // set default sortType for strings and dates
9335 this.sortType = st.asUCString;
9338 this.sortType = st.asDate;
9341 this.sortType = st.none;
9346 var stripRe = /[\$,%]/g;
9348 // prebuilt conversion function for this field, instead of
9349 // switching every time we're reading a value
9351 var cv, dateFormat = this.dateFormat;
9356 cv = function(v){ return v; };
9359 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9363 return v !== undefined && v !== null && v !== '' ?
9364 parseInt(String(v).replace(stripRe, ""), 10) : '';
9369 return v !== undefined && v !== null && v !== '' ?
9370 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9375 cv = function(v){ return v === true || v === "true" || v == 1; };
9382 if(v instanceof Date){
9386 if(dateFormat == "timestamp"){
9387 return new Date(v*1000);
9389 return Date.parseDate(v, dateFormat);
9391 var parsed = Date.parse(v);
9392 return parsed ? new Date(parsed) : null;
9401 Roo.data.Field.prototype = {
9409 * Ext JS Library 1.1.1
9410 * Copyright(c) 2006-2007, Ext JS, LLC.
9412 * Originally Released Under LGPL - original licence link has changed is not relivant.
9415 * <script type="text/javascript">
9418 // Base class for reading structured data from a data source. This class is intended to be
9419 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9422 * @class Roo.data.DataReader
9423 * Base class for reading structured data from a data source. This class is intended to be
9424 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9427 Roo.data.DataReader = function(meta, recordType){
9431 this.recordType = recordType instanceof Array ?
9432 Roo.data.Record.create(recordType) : recordType;
9435 Roo.data.DataReader.prototype = {
9437 * Create an empty record
9438 * @param {Object} data (optional) - overlay some values
9439 * @return {Roo.data.Record} record created.
9441 newRow : function(d) {
9443 this.recordType.prototype.fields.each(function(c) {
9445 case 'int' : da[c.name] = 0; break;
9446 case 'date' : da[c.name] = new Date(); break;
9447 case 'float' : da[c.name] = 0.0; break;
9448 case 'boolean' : da[c.name] = false; break;
9449 default : da[c.name] = ""; break;
9453 return new this.recordType(Roo.apply(da, d));
9458 * Ext JS Library 1.1.1
9459 * Copyright(c) 2006-2007, Ext JS, LLC.
9461 * Originally Released Under LGPL - original licence link has changed is not relivant.
9464 * <script type="text/javascript">
9468 * @class Roo.data.DataProxy
9469 * @extends Roo.data.Observable
9470 * This class is an abstract base class for implementations which provide retrieval of
9471 * unformatted data objects.<br>
9473 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9474 * (of the appropriate type which knows how to parse the data object) to provide a block of
9475 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9477 * Custom implementations must implement the load method as described in
9478 * {@link Roo.data.HttpProxy#load}.
9480 Roo.data.DataProxy = function(){
9484 * Fires before a network request is made to retrieve a data object.
9485 * @param {Object} This DataProxy object.
9486 * @param {Object} params The params parameter to the load function.
9491 * Fires before the load method's callback is called.
9492 * @param {Object} This DataProxy object.
9493 * @param {Object} o The data object.
9494 * @param {Object} arg The callback argument object passed to the load function.
9498 * @event loadexception
9499 * Fires if an Exception occurs during data retrieval.
9500 * @param {Object} This DataProxy object.
9501 * @param {Object} o The data object.
9502 * @param {Object} arg The callback argument object passed to the load function.
9503 * @param {Object} e The Exception.
9505 loadexception : true
9507 Roo.data.DataProxy.superclass.constructor.call(this);
9510 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9513 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9517 * Ext JS Library 1.1.1
9518 * Copyright(c) 2006-2007, Ext JS, LLC.
9520 * Originally Released Under LGPL - original licence link has changed is not relivant.
9523 * <script type="text/javascript">
9526 * @class Roo.data.MemoryProxy
9527 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9528 * to the Reader when its load method is called.
9530 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9532 Roo.data.MemoryProxy = function(data){
9536 Roo.data.MemoryProxy.superclass.constructor.call(this);
9540 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9542 * Load data from the requested source (in this case an in-memory
9543 * data object passed to the constructor), read the data object into
9544 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9545 * process that block using the passed callback.
9546 * @param {Object} params This parameter is not used by the MemoryProxy class.
9547 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9548 * object into a block of Roo.data.Records.
9549 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9550 * The function must be passed <ul>
9551 * <li>The Record block object</li>
9552 * <li>The "arg" argument from the load function</li>
9553 * <li>A boolean success indicator</li>
9555 * @param {Object} scope The scope in which to call the callback
9556 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9558 load : function(params, reader, callback, scope, arg){
9559 params = params || {};
9562 result = reader.readRecords(this.data);
9564 this.fireEvent("loadexception", this, arg, null, e);
9565 callback.call(scope, null, arg, false);
9568 callback.call(scope, result, arg, true);
9572 update : function(params, records){
9577 * Ext JS Library 1.1.1
9578 * Copyright(c) 2006-2007, Ext JS, LLC.
9580 * Originally Released Under LGPL - original licence link has changed is not relivant.
9583 * <script type="text/javascript">
9586 * @class Roo.data.HttpProxy
9587 * @extends Roo.data.DataProxy
9588 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9589 * configured to reference a certain URL.<br><br>
9591 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9592 * from which the running page was served.<br><br>
9594 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9596 * Be aware that to enable the browser to parse an XML document, the server must set
9597 * the Content-Type header in the HTTP response to "text/xml".
9599 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9600 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9601 * will be used to make the request.
9603 Roo.data.HttpProxy = function(conn){
9604 Roo.data.HttpProxy.superclass.constructor.call(this);
9605 // is conn a conn config or a real conn?
9607 this.useAjax = !conn || !conn.events;
9611 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9612 // thse are take from connection...
9615 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9618 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9619 * extra parameters to each request made by this object. (defaults to undefined)
9622 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9623 * to each request made by this object. (defaults to undefined)
9626 * @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)
9629 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9632 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9638 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9642 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9643 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9644 * a finer-grained basis than the DataProxy events.
9646 getConnection : function(){
9647 return this.useAjax ? Roo.Ajax : this.conn;
9651 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9652 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9653 * process that block using the passed callback.
9654 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9655 * for the request to the remote server.
9656 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9657 * object into a block of Roo.data.Records.
9658 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9659 * The function must be passed <ul>
9660 * <li>The Record block object</li>
9661 * <li>The "arg" argument from the load function</li>
9662 * <li>A boolean success indicator</li>
9664 * @param {Object} scope The scope in which to call the callback
9665 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9667 load : function(params, reader, callback, scope, arg){
9668 if(this.fireEvent("beforeload", this, params) !== false){
9670 params : params || {},
9672 callback : callback,
9677 callback : this.loadResponse,
9681 Roo.applyIf(o, this.conn);
9682 if(this.activeRequest){
9683 Roo.Ajax.abort(this.activeRequest);
9685 this.activeRequest = Roo.Ajax.request(o);
9687 this.conn.request(o);
9690 callback.call(scope||this, null, arg, false);
9695 loadResponse : function(o, success, response){
9696 delete this.activeRequest;
9698 this.fireEvent("loadexception", this, o, response);
9699 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9704 result = o.reader.read(response);
9706 this.fireEvent("loadexception", this, o, response, e);
9707 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9711 this.fireEvent("load", this, o, o.request.arg);
9712 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9716 update : function(dataSet){
9721 updateResponse : function(dataSet){
9726 * Ext JS Library 1.1.1
9727 * Copyright(c) 2006-2007, Ext JS, LLC.
9729 * Originally Released Under LGPL - original licence link has changed is not relivant.
9732 * <script type="text/javascript">
9736 * @class Roo.data.ScriptTagProxy
9737 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9738 * other than the originating domain of the running page.<br><br>
9740 * <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
9741 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9743 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9744 * source code that is used as the source inside a <script> tag.<br><br>
9746 * In order for the browser to process the returned data, the server must wrap the data object
9747 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9748 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9749 * depending on whether the callback name was passed:
9752 boolean scriptTag = false;
9753 String cb = request.getParameter("callback");
9756 response.setContentType("text/javascript");
9758 response.setContentType("application/x-json");
9760 Writer out = response.getWriter();
9762 out.write(cb + "(");
9764 out.print(dataBlock.toJsonString());
9771 * @param {Object} config A configuration object.
9773 Roo.data.ScriptTagProxy = function(config){
9774 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9775 Roo.apply(this, config);
9776 this.head = document.getElementsByTagName("head")[0];
9779 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9781 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9783 * @cfg {String} url The URL from which to request the data object.
9786 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9790 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9791 * the server the name of the callback function set up by the load call to process the returned data object.
9792 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9793 * javascript output which calls this named function passing the data object as its only parameter.
9795 callbackParam : "callback",
9797 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9798 * name to the request.
9803 * Load data from the configured URL, read the data object into
9804 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9805 * process that block using the passed callback.
9806 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9807 * for the request to the remote server.
9808 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9809 * object into a block of Roo.data.Records.
9810 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9811 * The function must be passed <ul>
9812 * <li>The Record block object</li>
9813 * <li>The "arg" argument from the load function</li>
9814 * <li>A boolean success indicator</li>
9816 * @param {Object} scope The scope in which to call the callback
9817 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9819 load : function(params, reader, callback, scope, arg){
9820 if(this.fireEvent("beforeload", this, params) !== false){
9822 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9825 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9827 url += "&_dc=" + (new Date().getTime());
9829 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9832 cb : "stcCallback"+transId,
9833 scriptId : "stcScript"+transId,
9837 callback : callback,
9843 window[trans.cb] = function(o){
9844 conn.handleResponse(o, trans);
9847 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9849 if(this.autoAbort !== false){
9853 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9855 var script = document.createElement("script");
9856 script.setAttribute("src", url);
9857 script.setAttribute("type", "text/javascript");
9858 script.setAttribute("id", trans.scriptId);
9859 this.head.appendChild(script);
9863 callback.call(scope||this, null, arg, false);
9868 isLoading : function(){
9869 return this.trans ? true : false;
9873 * Abort the current server request.
9876 if(this.isLoading()){
9877 this.destroyTrans(this.trans);
9882 destroyTrans : function(trans, isLoaded){
9883 this.head.removeChild(document.getElementById(trans.scriptId));
9884 clearTimeout(trans.timeoutId);
9886 window[trans.cb] = undefined;
9888 delete window[trans.cb];
9891 // if hasn't been loaded, wait for load to remove it to prevent script error
9892 window[trans.cb] = function(){
9893 window[trans.cb] = undefined;
9895 delete window[trans.cb];
9902 handleResponse : function(o, trans){
9904 this.destroyTrans(trans, true);
9907 result = trans.reader.readRecords(o);
9909 this.fireEvent("loadexception", this, o, trans.arg, e);
9910 trans.callback.call(trans.scope||window, null, trans.arg, false);
9913 this.fireEvent("load", this, o, trans.arg);
9914 trans.callback.call(trans.scope||window, result, trans.arg, true);
9918 handleFailure : function(trans){
9920 this.destroyTrans(trans, false);
9921 this.fireEvent("loadexception", this, null, trans.arg);
9922 trans.callback.call(trans.scope||window, null, trans.arg, false);
9926 * Ext JS Library 1.1.1
9927 * Copyright(c) 2006-2007, Ext JS, LLC.
9929 * Originally Released Under LGPL - original licence link has changed is not relivant.
9932 * <script type="text/javascript">
9936 * @class Roo.data.JsonReader
9937 * @extends Roo.data.DataReader
9938 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9939 * based on mappings in a provided Roo.data.Record constructor.
9941 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9942 * in the reply previously.
9947 var RecordDef = Roo.data.Record.create([
9948 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9949 {name: 'occupation'} // This field will use "occupation" as the mapping.
9951 var myReader = new Roo.data.JsonReader({
9952 totalProperty: "results", // The property which contains the total dataset size (optional)
9953 root: "rows", // The property which contains an Array of row objects
9954 id: "id" // The property within each row object that provides an ID for the record (optional)
9958 * This would consume a JSON file like this:
9960 { 'results': 2, 'rows': [
9961 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9962 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9965 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9966 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9967 * paged from the remote server.
9968 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9969 * @cfg {String} root name of the property which contains the Array of row objects.
9970 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9972 * Create a new JsonReader
9973 * @param {Object} meta Metadata configuration options
9974 * @param {Object} recordType Either an Array of field definition objects,
9975 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9977 Roo.data.JsonReader = function(meta, recordType){
9980 // set some defaults:
9982 totalProperty: 'total',
9983 successProperty : 'success',
9988 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9990 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9993 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9994 * Used by Store query builder to append _requestMeta to params.
9997 metaFromRemote : false,
9999 * This method is only used by a DataProxy which has retrieved data from a remote server.
10000 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10001 * @return {Object} data A data block which is used by an Roo.data.Store object as
10002 * a cache of Roo.data.Records.
10004 read : function(response){
10005 var json = response.responseText;
10007 var o = /* eval:var:o */ eval("("+json+")");
10009 throw {message: "JsonReader.read: Json object not found"};
10015 this.metaFromRemote = true;
10016 this.meta = o.metaData;
10017 this.recordType = Roo.data.Record.create(o.metaData.fields);
10018 this.onMetaChange(this.meta, this.recordType, o);
10020 return this.readRecords(o);
10023 // private function a store will implement
10024 onMetaChange : function(meta, recordType, o){
10031 simpleAccess: function(obj, subsc) {
10038 getJsonAccessor: function(){
10040 return function(expr) {
10042 return(re.test(expr))
10043 ? new Function("obj", "return obj." + expr)
10048 return Roo.emptyFn;
10053 * Create a data block containing Roo.data.Records from an XML document.
10054 * @param {Object} o An object which contains an Array of row objects in the property specified
10055 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10056 * which contains the total size of the dataset.
10057 * @return {Object} data A data block which is used by an Roo.data.Store object as
10058 * a cache of Roo.data.Records.
10060 readRecords : function(o){
10062 * After any data loads, the raw JSON data is available for further custom processing.
10066 var s = this.meta, Record = this.recordType,
10067 f = Record.prototype.fields, fi = f.items, fl = f.length;
10069 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10071 if(s.totalProperty) {
10072 this.getTotal = this.getJsonAccessor(s.totalProperty);
10074 if(s.successProperty) {
10075 this.getSuccess = this.getJsonAccessor(s.successProperty);
10077 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10079 var g = this.getJsonAccessor(s.id);
10080 this.getId = function(rec) {
10082 return (r === undefined || r === "") ? null : r;
10085 this.getId = function(){return null;};
10088 for(var jj = 0; jj < fl; jj++){
10090 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10091 this.ef[jj] = this.getJsonAccessor(map);
10095 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10096 if(s.totalProperty){
10097 var vt = parseInt(this.getTotal(o), 10);
10102 if(s.successProperty){
10103 var vs = this.getSuccess(o);
10104 if(vs === false || vs === 'false'){
10109 for(var i = 0; i < c; i++){
10112 var id = this.getId(n);
10113 for(var j = 0; j < fl; j++){
10115 var v = this.ef[j](n);
10117 Roo.log('missing convert for ' + f.name);
10121 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10123 var record = new Record(values, id);
10125 records[i] = record;
10131 totalRecords : totalRecords
10136 * Ext JS Library 1.1.1
10137 * Copyright(c) 2006-2007, Ext JS, LLC.
10139 * Originally Released Under LGPL - original licence link has changed is not relivant.
10142 * <script type="text/javascript">
10146 * @class Roo.data.ArrayReader
10147 * @extends Roo.data.DataReader
10148 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10149 * Each element of that Array represents a row of data fields. The
10150 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10151 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10155 var RecordDef = Roo.data.Record.create([
10156 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10157 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10159 var myReader = new Roo.data.ArrayReader({
10160 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10164 * This would consume an Array like this:
10166 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10168 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10170 * Create a new JsonReader
10171 * @param {Object} meta Metadata configuration options.
10172 * @param {Object} recordType Either an Array of field definition objects
10173 * as specified to {@link Roo.data.Record#create},
10174 * or an {@link Roo.data.Record} object
10175 * created using {@link Roo.data.Record#create}.
10177 Roo.data.ArrayReader = function(meta, recordType){
10178 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10181 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10183 * Create a data block containing Roo.data.Records from an XML document.
10184 * @param {Object} o An Array of row objects which represents the dataset.
10185 * @return {Object} data A data block which is used by an Roo.data.Store object as
10186 * a cache of Roo.data.Records.
10188 readRecords : function(o){
10189 var sid = this.meta ? this.meta.id : null;
10190 var recordType = this.recordType, fields = recordType.prototype.fields;
10193 for(var i = 0; i < root.length; i++){
10196 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10197 for(var j = 0, jlen = fields.length; j < jlen; j++){
10198 var f = fields.items[j];
10199 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10200 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10202 values[f.name] = v;
10204 var record = new recordType(values, id);
10206 records[records.length] = record;
10210 totalRecords : records.length
10219 * @class Roo.bootstrap.ComboBox
10220 * @extends Roo.bootstrap.TriggerField
10221 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10222 * @cfg {Boolean} append (true|false) default false
10223 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10224 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10225 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10226 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10227 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10229 * Create a new ComboBox.
10230 * @param {Object} config Configuration options
10232 Roo.bootstrap.ComboBox = function(config){
10233 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10237 * Fires when the dropdown list is expanded
10238 * @param {Roo.bootstrap.ComboBox} combo This combo box
10243 * Fires when the dropdown list is collapsed
10244 * @param {Roo.bootstrap.ComboBox} combo This combo box
10248 * @event beforeselect
10249 * Fires before a list item is selected. Return false to cancel the selection.
10250 * @param {Roo.bootstrap.ComboBox} combo This combo box
10251 * @param {Roo.data.Record} record The data record returned from the underlying store
10252 * @param {Number} index The index of the selected item in the dropdown list
10254 'beforeselect' : true,
10257 * Fires when a list item is selected
10258 * @param {Roo.bootstrap.ComboBox} combo This combo box
10259 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10260 * @param {Number} index The index of the selected item in the dropdown list
10264 * @event beforequery
10265 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10266 * The event object passed has these properties:
10267 * @param {Roo.bootstrap.ComboBox} combo This combo box
10268 * @param {String} query The query
10269 * @param {Boolean} forceAll true to force "all" query
10270 * @param {Boolean} cancel true to cancel the query
10271 * @param {Object} e The query event object
10273 'beforequery': true,
10276 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10277 * @param {Roo.bootstrap.ComboBox} combo This combo box
10282 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10283 * @param {Roo.bootstrap.ComboBox} combo This combo box
10284 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10289 * Fires when the remove value from the combobox array
10290 * @param {Roo.bootstrap.ComboBox} combo This combo box
10297 this.tickItems = [];
10299 this.selectedIndex = -1;
10300 if(this.mode == 'local'){
10301 if(config.queryDelay === undefined){
10302 this.queryDelay = 10;
10304 if(config.minChars === undefined){
10310 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10313 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10314 * rendering into an Roo.Editor, defaults to false)
10317 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10318 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10321 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10324 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10325 * the dropdown list (defaults to undefined, with no header element)
10329 * @cfg {String/Roo.Template} tpl The template to use to render the output
10333 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10335 listWidth: undefined,
10337 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10338 * mode = 'remote' or 'text' if mode = 'local')
10340 displayField: undefined,
10342 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10343 * mode = 'remote' or 'value' if mode = 'local').
10344 * Note: use of a valueField requires the user make a selection
10345 * in order for a value to be mapped.
10347 valueField: undefined,
10351 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10352 * field's data value (defaults to the underlying DOM element's name)
10354 hiddenName: undefined,
10356 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10360 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10362 selectedClass: 'active',
10365 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10369 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10370 * anchor positions (defaults to 'tl-bl')
10372 listAlign: 'tl-bl?',
10374 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10378 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10379 * query specified by the allQuery config option (defaults to 'query')
10381 triggerAction: 'query',
10383 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10384 * (defaults to 4, does not apply if editable = false)
10388 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10389 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10393 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10394 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10398 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10399 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10403 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10404 * when editable = true (defaults to false)
10406 selectOnFocus:false,
10408 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10410 queryParam: 'query',
10412 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10413 * when mode = 'remote' (defaults to 'Loading...')
10415 loadingText: 'Loading...',
10417 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10421 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10425 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10426 * traditional select (defaults to true)
10430 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10434 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10438 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10439 * listWidth has a higher value)
10443 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10444 * allow the user to set arbitrary text into the field (defaults to false)
10446 forceSelection:false,
10448 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10449 * if typeAhead = true (defaults to 250)
10451 typeAheadDelay : 250,
10453 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10454 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10456 valueNotFoundText : undefined,
10458 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10460 blockFocus : false,
10463 * @cfg {Boolean} disableClear Disable showing of clear button.
10465 disableClear : false,
10467 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10469 alwaysQuery : false,
10472 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10486 btnPosition : 'right',
10487 triggerList : true,
10488 showToggleBtn : true,
10489 // element that contains real text value.. (when hidden is used..)
10491 getAutoCreate : function()
10498 if(!this.tickable){
10499 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10504 * ComboBox with tickable selections
10507 var align = this.labelAlign || this.parentLabelAlign();
10510 cls : 'form-group roo-combobox-tickable' //input-group
10516 cls : 'tickable-buttons',
10521 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10528 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10535 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10542 Roo.each(buttons.cn, function(c){
10544 c.cls += ' btn-' + _this.size;
10547 if (_this.disabled) {
10558 cls: 'form-hidden-field'
10562 cls: 'select2-choices',
10566 cls: 'select2-search-field',
10578 cls: 'select2-container input-group select2-container-multi',
10583 // cls: 'typeahead typeahead-long dropdown-menu',
10584 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10589 if (align ==='left' && this.fieldLabel.length) {
10591 Roo.log("left and has label");
10597 cls : 'control-label col-sm-' + this.labelWidth,
10598 html : this.fieldLabel
10602 cls : "col-sm-" + (12 - this.labelWidth),
10609 } else if ( this.fieldLabel.length) {
10615 //cls : 'input-group-addon',
10616 html : this.fieldLabel
10626 Roo.log(" no label && no align");
10633 ['xs','sm','md','lg'].map(function(size){
10634 if (settings[size]) {
10635 cfg.cls += ' col-' + size + '-' + settings[size];
10644 initEvents: function()
10648 throw "can not find store for combo";
10650 this.store = Roo.factory(this.store, Roo.data);
10653 this.initTickableEvents();
10657 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10659 if(this.hiddenName){
10661 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10663 this.hiddenField.dom.value =
10664 this.hiddenValue !== undefined ? this.hiddenValue :
10665 this.value !== undefined ? this.value : '';
10667 // prevent input submission
10668 this.el.dom.removeAttribute('name');
10669 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10674 // this.el.dom.setAttribute('autocomplete', 'off');
10677 var cls = 'x-combo-list';
10679 //this.list = new Roo.Layer({
10680 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10686 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10687 _this.list.setWidth(lw);
10690 this.list.on('mouseover', this.onViewOver, this);
10691 this.list.on('mousemove', this.onViewMove, this);
10693 this.list.on('scroll', this.onViewScroll, this);
10696 this.list.swallowEvent('mousewheel');
10697 this.assetHeight = 0;
10700 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10701 this.assetHeight += this.header.getHeight();
10704 this.innerList = this.list.createChild({cls:cls+'-inner'});
10705 this.innerList.on('mouseover', this.onViewOver, this);
10706 this.innerList.on('mousemove', this.onViewMove, this);
10707 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10709 if(this.allowBlank && !this.pageSize && !this.disableClear){
10710 this.footer = this.list.createChild({cls:cls+'-ft'});
10711 this.pageTb = new Roo.Toolbar(this.footer);
10715 this.footer = this.list.createChild({cls:cls+'-ft'});
10716 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10717 {pageSize: this.pageSize});
10721 if (this.pageTb && this.allowBlank && !this.disableClear) {
10723 this.pageTb.add(new Roo.Toolbar.Fill(), {
10724 cls: 'x-btn-icon x-btn-clear',
10726 handler: function()
10729 _this.clearValue();
10730 _this.onSelect(false, -1);
10735 this.assetHeight += this.footer.getHeight();
10740 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10743 this.view = new Roo.View(this.list, this.tpl, {
10744 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10746 //this.view.wrapEl.setDisplayed(false);
10747 this.view.on('click', this.onViewClick, this);
10751 this.store.on('beforeload', this.onBeforeLoad, this);
10752 this.store.on('load', this.onLoad, this);
10753 this.store.on('loadexception', this.onLoadException, this);
10755 if(this.resizable){
10756 this.resizer = new Roo.Resizable(this.list, {
10757 pinned:true, handles:'se'
10759 this.resizer.on('resize', function(r, w, h){
10760 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10761 this.listWidth = w;
10762 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10763 this.restrictHeight();
10765 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10768 if(!this.editable){
10769 this.editable = true;
10770 this.setEditable(false);
10775 if (typeof(this.events.add.listeners) != 'undefined') {
10777 this.addicon = this.wrap.createChild(
10778 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10780 this.addicon.on('click', function(e) {
10781 this.fireEvent('add', this);
10784 if (typeof(this.events.edit.listeners) != 'undefined') {
10786 this.editicon = this.wrap.createChild(
10787 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10788 if (this.addicon) {
10789 this.editicon.setStyle('margin-left', '40px');
10791 this.editicon.on('click', function(e) {
10793 // we fire even if inothing is selected..
10794 this.fireEvent('edit', this, this.lastData );
10800 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10801 "up" : function(e){
10802 this.inKeyMode = true;
10806 "down" : function(e){
10807 if(!this.isExpanded()){
10808 this.onTriggerClick();
10810 this.inKeyMode = true;
10815 "enter" : function(e){
10816 // this.onViewClick();
10820 if(this.fireEvent("specialkey", this, e)){
10821 this.onViewClick(false);
10827 "esc" : function(e){
10831 "tab" : function(e){
10834 if(this.fireEvent("specialkey", this, e)){
10835 this.onViewClick(false);
10843 doRelay : function(foo, bar, hname){
10844 if(hname == 'down' || this.scope.isExpanded()){
10845 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10854 this.queryDelay = Math.max(this.queryDelay || 10,
10855 this.mode == 'local' ? 10 : 250);
10858 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10860 if(this.typeAhead){
10861 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10863 if(this.editable !== false){
10864 this.inputEl().on("keyup", this.onKeyUp, this);
10866 if(this.forceSelection){
10867 this.inputEl().on('blur', this.doForce, this);
10871 this.choices = this.el.select('ul.select2-choices', true).first();
10872 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10876 initTickableEvents: function()
10880 if(this.hiddenName){
10882 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10884 this.hiddenField.dom.value =
10885 this.hiddenValue !== undefined ? this.hiddenValue :
10886 this.value !== undefined ? this.value : '';
10888 // prevent input submission
10889 this.el.dom.removeAttribute('name');
10890 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10895 // this.list = this.el.select('ul.dropdown-menu',true).first();
10897 this.choices = this.el.select('ul.select2-choices', true).first();
10898 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10899 if(this.triggerList){
10900 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10903 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10904 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10906 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10907 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10909 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10910 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10912 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10913 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10914 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10917 this.cancelBtn.hide();
10922 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10923 _this.list.setWidth(lw);
10926 this.list.on('mouseover', this.onViewOver, this);
10927 this.list.on('mousemove', this.onViewMove, this);
10929 this.list.on('scroll', this.onViewScroll, this);
10932 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>';
10935 this.view = new Roo.View(this.list, this.tpl, {
10936 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10939 //this.view.wrapEl.setDisplayed(false);
10940 this.view.on('click', this.onViewClick, this);
10944 this.store.on('beforeload', this.onBeforeLoad, this);
10945 this.store.on('load', this.onLoad, this);
10946 this.store.on('loadexception', this.onLoadException, this);
10948 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10949 // "up" : function(e){
10950 // this.inKeyMode = true;
10951 // this.selectPrev();
10954 // "down" : function(e){
10955 // if(!this.isExpanded()){
10956 // this.onTriggerClick();
10958 // this.inKeyMode = true;
10959 // this.selectNext();
10963 // "enter" : function(e){
10964 //// this.onViewClick();
10966 // this.collapse();
10968 // if(this.fireEvent("specialkey", this, e)){
10969 // this.onViewClick(false);
10975 // "esc" : function(e){
10976 // this.collapse();
10979 // "tab" : function(e){
10980 // this.collapse();
10982 // if(this.fireEvent("specialkey", this, e)){
10983 // this.onViewClick(false);
10991 // doRelay : function(foo, bar, hname){
10992 // if(hname == 'down' || this.scope.isExpanded()){
10993 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10998 // forceKeyDown: true
11002 this.queryDelay = Math.max(this.queryDelay || 10,
11003 this.mode == 'local' ? 10 : 250);
11006 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11008 if(this.typeAhead){
11009 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11013 onDestroy : function(){
11015 this.view.setStore(null);
11016 this.view.el.removeAllListeners();
11017 this.view.el.remove();
11018 this.view.purgeListeners();
11021 this.list.dom.innerHTML = '';
11025 this.store.un('beforeload', this.onBeforeLoad, this);
11026 this.store.un('load', this.onLoad, this);
11027 this.store.un('loadexception', this.onLoadException, this);
11029 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11033 fireKey : function(e){
11034 if(e.isNavKeyPress() && !this.list.isVisible()){
11035 this.fireEvent("specialkey", this, e);
11040 onResize: function(w, h){
11041 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11043 // if(typeof w != 'number'){
11044 // // we do not handle it!?!?
11047 // var tw = this.trigger.getWidth();
11048 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11049 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11051 // this.inputEl().setWidth( this.adjustWidth('input', x));
11053 // //this.trigger.setStyle('left', x+'px');
11055 // if(this.list && this.listWidth === undefined){
11056 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11057 // this.list.setWidth(lw);
11058 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11066 * Allow or prevent the user from directly editing the field text. If false is passed,
11067 * the user will only be able to select from the items defined in the dropdown list. This method
11068 * is the runtime equivalent of setting the 'editable' config option at config time.
11069 * @param {Boolean} value True to allow the user to directly edit the field text
11071 setEditable : function(value){
11072 if(value == this.editable){
11075 this.editable = value;
11077 this.inputEl().dom.setAttribute('readOnly', true);
11078 this.inputEl().on('mousedown', this.onTriggerClick, this);
11079 this.inputEl().addClass('x-combo-noedit');
11081 this.inputEl().dom.setAttribute('readOnly', false);
11082 this.inputEl().un('mousedown', this.onTriggerClick, this);
11083 this.inputEl().removeClass('x-combo-noedit');
11089 onBeforeLoad : function(combo,opts){
11090 if(!this.hasFocus){
11094 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11096 // this.restrictHeight();
11097 this.selectedIndex = -1;
11101 onLoad : function(){
11103 this.hasQuery = false;
11105 if(!this.hasFocus){
11109 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11110 this.loading.hide();
11113 if(this.store.getCount() > 0){
11115 // this.restrictHeight();
11116 if(this.lastQuery == this.allQuery){
11117 if(this.editable && !this.tickable){
11118 this.inputEl().dom.select();
11122 !this.selectByValue(this.value, true) &&
11123 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11124 this.store.lastOptions.add != true)
11126 this.select(0, true);
11129 if(this.autoFocus){
11132 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11133 this.taTask.delay(this.typeAheadDelay);
11137 this.onEmptyResults();
11143 onLoadException : function()
11145 this.hasQuery = false;
11147 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11148 this.loading.hide();
11152 Roo.log(this.store.reader.jsonData);
11153 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11155 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11161 onTypeAhead : function(){
11162 if(this.store.getCount() > 0){
11163 var r = this.store.getAt(0);
11164 var newValue = r.data[this.displayField];
11165 var len = newValue.length;
11166 var selStart = this.getRawValue().length;
11168 if(selStart != len){
11169 this.setRawValue(newValue);
11170 this.selectText(selStart, newValue.length);
11176 onSelect : function(record, index){
11178 if(this.fireEvent('beforeselect', this, record, index) !== false){
11180 this.setFromData(index > -1 ? record.data : false);
11183 this.fireEvent('select', this, record, index);
11188 * Returns the currently selected field value or empty string if no value is set.
11189 * @return {String} value The selected value
11191 getValue : function(){
11194 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11197 if(this.valueField){
11198 return typeof this.value != 'undefined' ? this.value : '';
11200 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11205 * Clears any text/value currently set in the field
11207 clearValue : function(){
11208 if(this.hiddenField){
11209 this.hiddenField.dom.value = '';
11212 this.setRawValue('');
11213 this.lastSelectionText = '';
11218 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11219 * will be displayed in the field. If the value does not match the data value of an existing item,
11220 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11221 * Otherwise the field will be blank (although the value will still be set).
11222 * @param {String} value The value to match
11224 setValue : function(v){
11231 if(this.valueField){
11232 var r = this.findRecord(this.valueField, v);
11234 text = r.data[this.displayField];
11235 }else if(this.valueNotFoundText !== undefined){
11236 text = this.valueNotFoundText;
11239 this.lastSelectionText = text;
11240 if(this.hiddenField){
11241 this.hiddenField.dom.value = v;
11243 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11247 * @property {Object} the last set data for the element
11252 * Sets the value of the field based on a object which is related to the record format for the store.
11253 * @param {Object} value the value to set as. or false on reset?
11255 setFromData : function(o){
11258 if(typeof o.display_name !== 'string'){
11259 for(var i=0;i<o.display_name.length;i++){
11260 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11268 var dv = ''; // display value
11269 var vv = ''; // value value..
11271 if (this.displayField) {
11272 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11274 // this is an error condition!!!
11275 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11278 if(this.valueField){
11279 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11282 if(this.hiddenField){
11283 this.hiddenField.dom.value = vv;
11285 this.lastSelectionText = dv;
11286 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11290 // no hidden field.. - we store the value in 'value', but still display
11291 // display field!!!!
11292 this.lastSelectionText = dv;
11293 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11299 reset : function(){
11300 // overridden so that last data is reset..
11301 this.setValue(this.originalValue);
11302 this.clearInvalid();
11303 this.lastData = false;
11305 this.view.clearSelections();
11309 findRecord : function(prop, value){
11311 if(this.store.getCount() > 0){
11312 this.store.each(function(r){
11313 if(r.data[prop] == value){
11323 getName: function()
11325 // returns hidden if it's set..
11326 if (!this.rendered) {return ''};
11327 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11331 onViewMove : function(e, t){
11332 this.inKeyMode = false;
11336 onViewOver : function(e, t){
11337 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11340 var item = this.view.findItemFromChild(t);
11343 var index = this.view.indexOf(item);
11344 this.select(index, false);
11349 onViewClick : function(view, doFocus, el, e)
11351 var index = this.view.getSelectedIndexes()[0];
11353 var r = this.store.getAt(index);
11357 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11364 Roo.each(this.tickItems, function(v,k){
11366 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11367 _this.tickItems.splice(k, 1);
11377 this.tickItems.push(r.data);
11382 this.onSelect(r, index);
11384 if(doFocus !== false && !this.blockFocus){
11385 this.inputEl().focus();
11390 restrictHeight : function(){
11391 //this.innerList.dom.style.height = '';
11392 //var inner = this.innerList.dom;
11393 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11394 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11395 //this.list.beginUpdate();
11396 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11397 this.list.alignTo(this.inputEl(), this.listAlign);
11398 this.list.alignTo(this.inputEl(), this.listAlign);
11399 //this.list.endUpdate();
11403 onEmptyResults : function(){
11408 * Returns true if the dropdown list is expanded, else false.
11410 isExpanded : function(){
11411 return this.list.isVisible();
11415 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11416 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11417 * @param {String} value The data value of the item to select
11418 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11419 * selected item if it is not currently in view (defaults to true)
11420 * @return {Boolean} True if the value matched an item in the list, else false
11422 selectByValue : function(v, scrollIntoView){
11423 if(v !== undefined && v !== null){
11424 var r = this.findRecord(this.valueField || this.displayField, v);
11426 this.select(this.store.indexOf(r), scrollIntoView);
11434 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11435 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11436 * @param {Number} index The zero-based index of the list item to select
11437 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11438 * selected item if it is not currently in view (defaults to true)
11440 select : function(index, scrollIntoView){
11441 this.selectedIndex = index;
11442 this.view.select(index);
11443 if(scrollIntoView !== false){
11444 var el = this.view.getNode(index);
11445 if(el && !this.multiple && !this.tickable){
11446 this.list.scrollChildIntoView(el, false);
11452 selectNext : function(){
11453 var ct = this.store.getCount();
11455 if(this.selectedIndex == -1){
11457 }else if(this.selectedIndex < ct-1){
11458 this.select(this.selectedIndex+1);
11464 selectPrev : function(){
11465 var ct = this.store.getCount();
11467 if(this.selectedIndex == -1){
11469 }else if(this.selectedIndex != 0){
11470 this.select(this.selectedIndex-1);
11476 onKeyUp : function(e){
11477 if(this.editable !== false && !e.isSpecialKey()){
11478 this.lastKey = e.getKey();
11479 this.dqTask.delay(this.queryDelay);
11484 validateBlur : function(){
11485 return !this.list || !this.list.isVisible();
11489 initQuery : function(){
11490 this.doQuery(this.getRawValue());
11494 doForce : function(){
11495 if(this.inputEl().dom.value.length > 0){
11496 this.inputEl().dom.value =
11497 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11503 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11504 * query allowing the query action to be canceled if needed.
11505 * @param {String} query The SQL query to execute
11506 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11507 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11508 * saved in the current store (defaults to false)
11510 doQuery : function(q, forceAll){
11512 if(q === undefined || q === null){
11517 forceAll: forceAll,
11521 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11526 forceAll = qe.forceAll;
11527 if(forceAll === true || (q.length >= this.minChars)){
11529 this.hasQuery = true;
11531 if(this.lastQuery != q || this.alwaysQuery){
11532 this.lastQuery = q;
11533 if(this.mode == 'local'){
11534 this.selectedIndex = -1;
11536 this.store.clearFilter();
11538 this.store.filter(this.displayField, q);
11542 this.store.baseParams[this.queryParam] = q;
11544 var options = {params : this.getParams(q)};
11547 options.add = true;
11548 options.params.start = this.page * this.pageSize;
11551 this.store.load(options);
11553 * this code will make the page width larger, at the beginning, the list not align correctly,
11554 * we should expand the list on onLoad
11555 * so command out it
11560 this.selectedIndex = -1;
11565 this.loadNext = false;
11569 getParams : function(q){
11571 //p[this.queryParam] = q;
11575 p.limit = this.pageSize;
11581 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11583 collapse : function(){
11584 if(!this.isExpanded()){
11592 this.cancelBtn.hide();
11593 this.trigger.show();
11596 Roo.get(document).un('mousedown', this.collapseIf, this);
11597 Roo.get(document).un('mousewheel', this.collapseIf, this);
11598 if (!this.editable) {
11599 Roo.get(document).un('keydown', this.listKeyPress, this);
11601 this.fireEvent('collapse', this);
11605 collapseIf : function(e){
11606 var in_combo = e.within(this.el);
11607 var in_list = e.within(this.list);
11608 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11610 if (in_combo || in_list || is_list) {
11611 //e.stopPropagation();
11616 this.onTickableFooterButtonClick(e, false, false);
11624 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11626 expand : function(){
11628 if(this.isExpanded() || !this.hasFocus){
11632 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11633 this.list.setWidth(lw);
11638 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11639 this.list.setWidth(lw);
11643 this.restrictHeight();
11647 this.tickItems = Roo.apply([], this.item);
11650 this.cancelBtn.show();
11651 this.trigger.hide();
11655 Roo.get(document).on('mousedown', this.collapseIf, this);
11656 Roo.get(document).on('mousewheel', this.collapseIf, this);
11657 if (!this.editable) {
11658 Roo.get(document).on('keydown', this.listKeyPress, this);
11661 this.fireEvent('expand', this);
11665 // Implements the default empty TriggerField.onTriggerClick function
11666 onTriggerClick : function(e)
11668 Roo.log('trigger click');
11670 if(this.disabled || !this.triggerList){
11675 this.loadNext = false;
11677 if(this.isExpanded()){
11679 if (!this.blockFocus) {
11680 this.inputEl().focus();
11684 this.hasFocus = true;
11685 if(this.triggerAction == 'all') {
11686 this.doQuery(this.allQuery, true);
11688 this.doQuery(this.getRawValue());
11690 if (!this.blockFocus) {
11691 this.inputEl().focus();
11696 onTickableTriggerClick : function(e)
11703 this.loadNext = false;
11704 this.hasFocus = true;
11706 if(this.triggerAction == 'all') {
11707 this.doQuery(this.allQuery, true);
11709 this.doQuery(this.getRawValue());
11713 onSearchFieldClick : function(e)
11715 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11720 this.loadNext = false;
11721 this.hasFocus = true;
11723 if(this.triggerAction == 'all') {
11724 this.doQuery(this.allQuery, true);
11726 this.doQuery(this.getRawValue());
11730 listKeyPress : function(e)
11732 //Roo.log('listkeypress');
11733 // scroll to first matching element based on key pres..
11734 if (e.isSpecialKey()) {
11737 var k = String.fromCharCode(e.getKey()).toUpperCase();
11740 var csel = this.view.getSelectedNodes();
11741 var cselitem = false;
11743 var ix = this.view.indexOf(csel[0]);
11744 cselitem = this.store.getAt(ix);
11745 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11751 this.store.each(function(v) {
11753 // start at existing selection.
11754 if (cselitem.id == v.id) {
11760 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11761 match = this.store.indexOf(v);
11767 if (match === false) {
11768 return true; // no more action?
11771 this.view.select(match);
11772 var sn = Roo.get(this.view.getSelectedNodes()[0])
11773 //sn.scrollIntoView(sn.dom.parentNode, false);
11776 onViewScroll : function(e, t){
11778 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){
11782 this.hasQuery = true;
11784 this.loading = this.list.select('.loading', true).first();
11786 if(this.loading === null){
11787 this.list.createChild({
11789 cls: 'loading select2-more-results select2-active',
11790 html: 'Loading more results...'
11793 this.loading = this.list.select('.loading', true).first();
11795 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11797 this.loading.hide();
11800 this.loading.show();
11805 this.loadNext = true;
11807 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11812 addItem : function(o)
11814 var dv = ''; // display value
11816 if (this.displayField) {
11817 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11819 // this is an error condition!!!
11820 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11827 var choice = this.choices.createChild({
11829 cls: 'select2-search-choice',
11838 cls: 'select2-search-choice-close',
11843 }, this.searchField);
11845 var close = choice.select('a.select2-search-choice-close', true).first()
11847 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11855 this.inputEl().dom.value = '';
11859 onRemoveItem : function(e, _self, o)
11861 e.preventDefault();
11862 var index = this.item.indexOf(o.data) * 1;
11865 Roo.log('not this item?!');
11869 this.item.splice(index, 1);
11874 this.fireEvent('remove', this, e);
11878 syncValue : function()
11880 if(!this.item.length){
11887 Roo.each(this.item, function(i){
11888 if(_this.valueField){
11889 value.push(i[_this.valueField]);
11896 this.value = value.join(',');
11898 if(this.hiddenField){
11899 this.hiddenField.dom.value = this.value;
11903 clearItem : function()
11905 if(!this.multiple){
11911 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11918 inputEl: function ()
11921 return this.searchField;
11923 return this.el.select('input.form-control',true).first();
11927 onTickableFooterButtonClick : function(e, btn, el)
11929 e.preventDefault();
11931 if(btn && btn.name == 'cancel'){
11932 this.tickItems = Roo.apply([], this.item);
11941 Roo.each(this.tickItems, function(o){
11952 * @cfg {Boolean} grow
11956 * @cfg {Number} growMin
11960 * @cfg {Number} growMax
11970 * Ext JS Library 1.1.1
11971 * Copyright(c) 2006-2007, Ext JS, LLC.
11973 * Originally Released Under LGPL - original licence link has changed is not relivant.
11976 * <script type="text/javascript">
11981 * @extends Roo.util.Observable
11982 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11983 * This class also supports single and multi selection modes. <br>
11984 * Create a data model bound view:
11986 var store = new Roo.data.Store(...);
11988 var view = new Roo.View({
11990 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11992 singleSelect: true,
11993 selectedClass: "ydataview-selected",
11997 // listen for node click?
11998 view.on("click", function(vw, index, node, e){
11999 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12003 dataModel.load("foobar.xml");
12005 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12007 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12008 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12010 * Note: old style constructor is still suported (container, template, config)
12013 * Create a new View
12014 * @param {Object} config The config object
12017 Roo.View = function(config, depreciated_tpl, depreciated_config){
12019 this.parent = false;
12021 if (typeof(depreciated_tpl) == 'undefined') {
12022 // new way.. - universal constructor.
12023 Roo.apply(this, config);
12024 this.el = Roo.get(this.el);
12027 this.el = Roo.get(config);
12028 this.tpl = depreciated_tpl;
12029 Roo.apply(this, depreciated_config);
12031 this.wrapEl = this.el.wrap().wrap();
12032 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12035 if(typeof(this.tpl) == "string"){
12036 this.tpl = new Roo.Template(this.tpl);
12038 // support xtype ctors..
12039 this.tpl = new Roo.factory(this.tpl, Roo);
12043 this.tpl.compile();
12048 * @event beforeclick
12049 * Fires before a click is processed. Returns false to cancel the default action.
12050 * @param {Roo.View} this
12051 * @param {Number} index The index of the target node
12052 * @param {HTMLElement} node The target node
12053 * @param {Roo.EventObject} e The raw event object
12055 "beforeclick" : true,
12058 * Fires when a template node is clicked.
12059 * @param {Roo.View} this
12060 * @param {Number} index The index of the target node
12061 * @param {HTMLElement} node The target node
12062 * @param {Roo.EventObject} e The raw event object
12067 * Fires when a template node is double clicked.
12068 * @param {Roo.View} this
12069 * @param {Number} index The index of the target node
12070 * @param {HTMLElement} node The target node
12071 * @param {Roo.EventObject} e The raw event object
12075 * @event contextmenu
12076 * Fires when a template node is right clicked.
12077 * @param {Roo.View} this
12078 * @param {Number} index The index of the target node
12079 * @param {HTMLElement} node The target node
12080 * @param {Roo.EventObject} e The raw event object
12082 "contextmenu" : true,
12084 * @event selectionchange
12085 * Fires when the selected nodes change.
12086 * @param {Roo.View} this
12087 * @param {Array} selections Array of the selected nodes
12089 "selectionchange" : true,
12092 * @event beforeselect
12093 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12094 * @param {Roo.View} this
12095 * @param {HTMLElement} node The node to be selected
12096 * @param {Array} selections Array of currently selected nodes
12098 "beforeselect" : true,
12100 * @event preparedata
12101 * Fires on every row to render, to allow you to change the data.
12102 * @param {Roo.View} this
12103 * @param {Object} data to be rendered (change this)
12105 "preparedata" : true
12113 "click": this.onClick,
12114 "dblclick": this.onDblClick,
12115 "contextmenu": this.onContextMenu,
12119 this.selections = [];
12121 this.cmp = new Roo.CompositeElementLite([]);
12123 this.store = Roo.factory(this.store, Roo.data);
12124 this.setStore(this.store, true);
12127 if ( this.footer && this.footer.xtype) {
12129 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12131 this.footer.dataSource = this.store
12132 this.footer.container = fctr;
12133 this.footer = Roo.factory(this.footer, Roo);
12134 fctr.insertFirst(this.el);
12136 // this is a bit insane - as the paging toolbar seems to detach the el..
12137 // dom.parentNode.parentNode.parentNode
12138 // they get detached?
12142 Roo.View.superclass.constructor.call(this);
12147 Roo.extend(Roo.View, Roo.util.Observable, {
12150 * @cfg {Roo.data.Store} store Data store to load data from.
12155 * @cfg {String|Roo.Element} el The container element.
12160 * @cfg {String|Roo.Template} tpl The template used by this View
12164 * @cfg {String} dataName the named area of the template to use as the data area
12165 * Works with domtemplates roo-name="name"
12169 * @cfg {String} selectedClass The css class to add to selected nodes
12171 selectedClass : "x-view-selected",
12173 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12178 * @cfg {String} text to display on mask (default Loading)
12182 * @cfg {Boolean} multiSelect Allow multiple selection
12184 multiSelect : false,
12186 * @cfg {Boolean} singleSelect Allow single selection
12188 singleSelect: false,
12191 * @cfg {Boolean} toggleSelect - selecting
12193 toggleSelect : false,
12196 * @cfg {Boolean} tickable - selecting
12201 * Returns the element this view is bound to.
12202 * @return {Roo.Element}
12204 getEl : function(){
12205 return this.wrapEl;
12211 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12213 refresh : function(){
12214 Roo.log('refresh');
12217 // if we are using something like 'domtemplate', then
12218 // the what gets used is:
12219 // t.applySubtemplate(NAME, data, wrapping data..)
12220 // the outer template then get' applied with
12221 // the store 'extra data'
12222 // and the body get's added to the
12223 // roo-name="data" node?
12224 // <span class='roo-tpl-{name}'></span> ?????
12228 this.clearSelections();
12229 this.el.update("");
12231 var records = this.store.getRange();
12232 if(records.length < 1) {
12234 // is this valid?? = should it render a template??
12236 this.el.update(this.emptyText);
12240 if (this.dataName) {
12241 this.el.update(t.apply(this.store.meta)); //????
12242 el = this.el.child('.roo-tpl-' + this.dataName);
12245 for(var i = 0, len = records.length; i < len; i++){
12246 var data = this.prepareData(records[i].data, i, records[i]);
12247 this.fireEvent("preparedata", this, data, i, records[i]);
12249 var d = Roo.apply({}, data);
12252 Roo.apply(d, {'roo-id' : Roo.id()});
12256 Roo.each(this.parent.item, function(item){
12257 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12260 Roo.apply(d, {'roo-data-checked' : 'checked'});
12264 html[html.length] = Roo.util.Format.trim(
12266 t.applySubtemplate(this.dataName, d, this.store.meta) :
12273 el.update(html.join(""));
12274 this.nodes = el.dom.childNodes;
12275 this.updateIndexes(0);
12280 * Function to override to reformat the data that is sent to
12281 * the template for each node.
12282 * DEPRICATED - use the preparedata event handler.
12283 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12284 * a JSON object for an UpdateManager bound view).
12286 prepareData : function(data, index, record)
12288 this.fireEvent("preparedata", this, data, index, record);
12292 onUpdate : function(ds, record){
12293 Roo.log('on update');
12294 this.clearSelections();
12295 var index = this.store.indexOf(record);
12296 var n = this.nodes[index];
12297 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12298 n.parentNode.removeChild(n);
12299 this.updateIndexes(index, index);
12305 onAdd : function(ds, records, index)
12307 Roo.log(['on Add', ds, records, index] );
12308 this.clearSelections();
12309 if(this.nodes.length == 0){
12313 var n = this.nodes[index];
12314 for(var i = 0, len = records.length; i < len; i++){
12315 var d = this.prepareData(records[i].data, i, records[i]);
12317 this.tpl.insertBefore(n, d);
12320 this.tpl.append(this.el, d);
12323 this.updateIndexes(index);
12326 onRemove : function(ds, record, index){
12327 Roo.log('onRemove');
12328 this.clearSelections();
12329 var el = this.dataName ?
12330 this.el.child('.roo-tpl-' + this.dataName) :
12333 el.dom.removeChild(this.nodes[index]);
12334 this.updateIndexes(index);
12338 * Refresh an individual node.
12339 * @param {Number} index
12341 refreshNode : function(index){
12342 this.onUpdate(this.store, this.store.getAt(index));
12345 updateIndexes : function(startIndex, endIndex){
12346 var ns = this.nodes;
12347 startIndex = startIndex || 0;
12348 endIndex = endIndex || ns.length - 1;
12349 for(var i = startIndex; i <= endIndex; i++){
12350 ns[i].nodeIndex = i;
12355 * Changes the data store this view uses and refresh the view.
12356 * @param {Store} store
12358 setStore : function(store, initial){
12359 if(!initial && this.store){
12360 this.store.un("datachanged", this.refresh);
12361 this.store.un("add", this.onAdd);
12362 this.store.un("remove", this.onRemove);
12363 this.store.un("update", this.onUpdate);
12364 this.store.un("clear", this.refresh);
12365 this.store.un("beforeload", this.onBeforeLoad);
12366 this.store.un("load", this.onLoad);
12367 this.store.un("loadexception", this.onLoad);
12371 store.on("datachanged", this.refresh, this);
12372 store.on("add", this.onAdd, this);
12373 store.on("remove", this.onRemove, this);
12374 store.on("update", this.onUpdate, this);
12375 store.on("clear", this.refresh, this);
12376 store.on("beforeload", this.onBeforeLoad, this);
12377 store.on("load", this.onLoad, this);
12378 store.on("loadexception", this.onLoad, this);
12386 * onbeforeLoad - masks the loading area.
12389 onBeforeLoad : function(store,opts)
12391 Roo.log('onBeforeLoad');
12393 this.el.update("");
12395 this.el.mask(this.mask ? this.mask : "Loading" );
12397 onLoad : function ()
12404 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12405 * @param {HTMLElement} node
12406 * @return {HTMLElement} The template node
12408 findItemFromChild : function(node){
12409 var el = this.dataName ?
12410 this.el.child('.roo-tpl-' + this.dataName,true) :
12413 if(!node || node.parentNode == el){
12416 var p = node.parentNode;
12417 while(p && p != el){
12418 if(p.parentNode == el){
12427 onClick : function(e){
12428 var item = this.findItemFromChild(e.getTarget());
12430 var index = this.indexOf(item);
12431 if(this.onItemClick(item, index, e) !== false){
12432 this.fireEvent("click", this, index, item, e);
12435 this.clearSelections();
12440 onContextMenu : function(e){
12441 var item = this.findItemFromChild(e.getTarget());
12443 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12448 onDblClick : function(e){
12449 var item = this.findItemFromChild(e.getTarget());
12451 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12455 onItemClick : function(item, index, e)
12457 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12460 if (this.toggleSelect) {
12461 var m = this.isSelected(item) ? 'unselect' : 'select';
12464 _t[m](item, true, false);
12467 if(this.multiSelect || this.singleSelect){
12468 if(this.multiSelect && e.shiftKey && this.lastSelection){
12469 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12471 this.select(item, this.multiSelect && e.ctrlKey);
12472 this.lastSelection = item;
12475 if(!this.tickable){
12476 e.preventDefault();
12484 * Get the number of selected nodes.
12487 getSelectionCount : function(){
12488 return this.selections.length;
12492 * Get the currently selected nodes.
12493 * @return {Array} An array of HTMLElements
12495 getSelectedNodes : function(){
12496 return this.selections;
12500 * Get the indexes of the selected nodes.
12503 getSelectedIndexes : function(){
12504 var indexes = [], s = this.selections;
12505 for(var i = 0, len = s.length; i < len; i++){
12506 indexes.push(s[i].nodeIndex);
12512 * Clear all selections
12513 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12515 clearSelections : function(suppressEvent){
12516 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12517 this.cmp.elements = this.selections;
12518 this.cmp.removeClass(this.selectedClass);
12519 this.selections = [];
12520 if(!suppressEvent){
12521 this.fireEvent("selectionchange", this, this.selections);
12527 * Returns true if the passed node is selected
12528 * @param {HTMLElement/Number} node The node or node index
12529 * @return {Boolean}
12531 isSelected : function(node){
12532 var s = this.selections;
12536 node = this.getNode(node);
12537 return s.indexOf(node) !== -1;
12542 * @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
12543 * @param {Boolean} keepExisting (optional) true to keep existing selections
12544 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12546 select : function(nodeInfo, keepExisting, suppressEvent){
12547 if(nodeInfo instanceof Array){
12549 this.clearSelections(true);
12551 for(var i = 0, len = nodeInfo.length; i < len; i++){
12552 this.select(nodeInfo[i], true, true);
12556 var node = this.getNode(nodeInfo);
12557 if(!node || this.isSelected(node)){
12558 return; // already selected.
12561 this.clearSelections(true);
12563 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12564 Roo.fly(node).addClass(this.selectedClass);
12565 this.selections.push(node);
12566 if(!suppressEvent){
12567 this.fireEvent("selectionchange", this, this.selections);
12575 * @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
12576 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12577 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12579 unselect : function(nodeInfo, keepExisting, suppressEvent)
12581 if(nodeInfo instanceof Array){
12582 Roo.each(this.selections, function(s) {
12583 this.unselect(s, nodeInfo);
12587 var node = this.getNode(nodeInfo);
12588 if(!node || !this.isSelected(node)){
12589 Roo.log("not selected");
12590 return; // not selected.
12594 Roo.each(this.selections, function(s) {
12596 Roo.fly(node).removeClass(this.selectedClass);
12603 this.selections= ns;
12604 this.fireEvent("selectionchange", this, this.selections);
12608 * Gets a template node.
12609 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12610 * @return {HTMLElement} The node or null if it wasn't found
12612 getNode : function(nodeInfo){
12613 if(typeof nodeInfo == "string"){
12614 return document.getElementById(nodeInfo);
12615 }else if(typeof nodeInfo == "number"){
12616 return this.nodes[nodeInfo];
12622 * Gets a range template nodes.
12623 * @param {Number} startIndex
12624 * @param {Number} endIndex
12625 * @return {Array} An array of nodes
12627 getNodes : function(start, end){
12628 var ns = this.nodes;
12629 start = start || 0;
12630 end = typeof end == "undefined" ? ns.length - 1 : end;
12633 for(var i = start; i <= end; i++){
12637 for(var i = start; i >= end; i--){
12645 * Finds the index of the passed node
12646 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12647 * @return {Number} The index of the node or -1
12649 indexOf : function(node){
12650 node = this.getNode(node);
12651 if(typeof node.nodeIndex == "number"){
12652 return node.nodeIndex;
12654 var ns = this.nodes;
12655 for(var i = 0, len = ns.length; i < len; i++){
12666 * based on jquery fullcalendar
12670 Roo.bootstrap = Roo.bootstrap || {};
12672 * @class Roo.bootstrap.Calendar
12673 * @extends Roo.bootstrap.Component
12674 * Bootstrap Calendar class
12675 * @cfg {Boolean} loadMask (true|false) default false
12676 * @cfg {Object} header generate the user specific header of the calendar, default false
12679 * Create a new Container
12680 * @param {Object} config The config object
12685 Roo.bootstrap.Calendar = function(config){
12686 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12690 * Fires when a date is selected
12691 * @param {DatePicker} this
12692 * @param {Date} date The selected date
12696 * @event monthchange
12697 * Fires when the displayed month changes
12698 * @param {DatePicker} this
12699 * @param {Date} date The selected month
12701 'monthchange': true,
12703 * @event evententer
12704 * Fires when mouse over an event
12705 * @param {Calendar} this
12706 * @param {event} Event
12708 'evententer': true,
12710 * @event eventleave
12711 * Fires when the mouse leaves an
12712 * @param {Calendar} this
12715 'eventleave': true,
12717 * @event eventclick
12718 * Fires when the mouse click an
12719 * @param {Calendar} this
12728 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12731 * @cfg {Number} startDay
12732 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12740 getAutoCreate : function(){
12743 var fc_button = function(name, corner, style, content ) {
12744 return Roo.apply({},{
12746 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12748 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12751 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12762 style : 'width:100%',
12769 cls : 'fc-header-left',
12771 fc_button('prev', 'left', 'arrow', '‹' ),
12772 fc_button('next', 'right', 'arrow', '›' ),
12773 { tag: 'span', cls: 'fc-header-space' },
12774 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12782 cls : 'fc-header-center',
12786 cls: 'fc-header-title',
12789 html : 'month / year'
12797 cls : 'fc-header-right',
12799 /* fc_button('month', 'left', '', 'month' ),
12800 fc_button('week', '', '', 'week' ),
12801 fc_button('day', 'right', '', 'day' )
12813 header = this.header;
12816 var cal_heads = function() {
12818 // fixme - handle this.
12820 for (var i =0; i < Date.dayNames.length; i++) {
12821 var d = Date.dayNames[i];
12824 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12825 html : d.substring(0,3)
12829 ret[0].cls += ' fc-first';
12830 ret[6].cls += ' fc-last';
12833 var cal_cell = function(n) {
12836 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12841 cls: 'fc-day-number',
12845 cls: 'fc-day-content',
12849 style: 'position: relative;' // height: 17px;
12861 var cal_rows = function() {
12864 for (var r = 0; r < 6; r++) {
12871 for (var i =0; i < Date.dayNames.length; i++) {
12872 var d = Date.dayNames[i];
12873 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12876 row.cn[0].cls+=' fc-first';
12877 row.cn[0].cn[0].style = 'min-height:90px';
12878 row.cn[6].cls+=' fc-last';
12882 ret[0].cls += ' fc-first';
12883 ret[4].cls += ' fc-prev-last';
12884 ret[5].cls += ' fc-last';
12891 cls: 'fc-border-separate',
12892 style : 'width:100%',
12900 cls : 'fc-first fc-last',
12918 cls : 'fc-content',
12919 style : "position: relative;",
12922 cls : 'fc-view fc-view-month fc-grid',
12923 style : 'position: relative',
12924 unselectable : 'on',
12927 cls : 'fc-event-container',
12928 style : 'position:absolute;z-index:8;top:0;left:0;'
12946 initEvents : function()
12949 throw "can not find store for calendar";
12955 style: "text-align:center",
12959 style: "background-color:white;width:50%;margin:250 auto",
12963 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12974 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12976 var size = this.el.select('.fc-content', true).first().getSize();
12977 this.maskEl.setSize(size.width, size.height);
12978 this.maskEl.enableDisplayMode("block");
12979 if(!this.loadMask){
12980 this.maskEl.hide();
12983 this.store = Roo.factory(this.store, Roo.data);
12984 this.store.on('load', this.onLoad, this);
12985 this.store.on('beforeload', this.onBeforeLoad, this);
12989 this.cells = this.el.select('.fc-day',true);
12990 //Roo.log(this.cells);
12991 this.textNodes = this.el.query('.fc-day-number');
12992 this.cells.addClassOnOver('fc-state-hover');
12994 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12995 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12996 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12997 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12999 this.on('monthchange', this.onMonthChange, this);
13001 this.update(new Date().clearTime());
13004 resize : function() {
13005 var sz = this.el.getSize();
13007 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13008 this.el.select('.fc-day-content div',true).setHeight(34);
13013 showPrevMonth : function(e){
13014 this.update(this.activeDate.add("mo", -1));
13016 showToday : function(e){
13017 this.update(new Date().clearTime());
13020 showNextMonth : function(e){
13021 this.update(this.activeDate.add("mo", 1));
13025 showPrevYear : function(){
13026 this.update(this.activeDate.add("y", -1));
13030 showNextYear : function(){
13031 this.update(this.activeDate.add("y", 1));
13036 update : function(date)
13038 var vd = this.activeDate;
13039 this.activeDate = date;
13040 // if(vd && this.el){
13041 // var t = date.getTime();
13042 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13043 // Roo.log('using add remove');
13045 // this.fireEvent('monthchange', this, date);
13047 // this.cells.removeClass("fc-state-highlight");
13048 // this.cells.each(function(c){
13049 // if(c.dateValue == t){
13050 // c.addClass("fc-state-highlight");
13051 // setTimeout(function(){
13052 // try{c.dom.firstChild.focus();}catch(e){}
13062 var days = date.getDaysInMonth();
13064 var firstOfMonth = date.getFirstDateOfMonth();
13065 var startingPos = firstOfMonth.getDay()-this.startDay;
13067 if(startingPos < this.startDay){
13071 var pm = date.add(Date.MONTH, -1);
13072 var prevStart = pm.getDaysInMonth()-startingPos;
13074 this.cells = this.el.select('.fc-day',true);
13075 this.textNodes = this.el.query('.fc-day-number');
13076 this.cells.addClassOnOver('fc-state-hover');
13078 var cells = this.cells.elements;
13079 var textEls = this.textNodes;
13081 Roo.each(cells, function(cell){
13082 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13085 days += startingPos;
13087 // convert everything to numbers so it's fast
13088 var day = 86400000;
13089 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13092 //Roo.log(prevStart);
13094 var today = new Date().clearTime().getTime();
13095 var sel = date.clearTime().getTime();
13096 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13097 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13098 var ddMatch = this.disabledDatesRE;
13099 var ddText = this.disabledDatesText;
13100 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13101 var ddaysText = this.disabledDaysText;
13102 var format = this.format;
13104 var setCellClass = function(cal, cell){
13108 //Roo.log('set Cell Class');
13110 var t = d.getTime();
13114 cell.dateValue = t;
13116 cell.className += " fc-today";
13117 cell.className += " fc-state-highlight";
13118 cell.title = cal.todayText;
13121 // disable highlight in other month..
13122 //cell.className += " fc-state-highlight";
13127 cell.className = " fc-state-disabled";
13128 cell.title = cal.minText;
13132 cell.className = " fc-state-disabled";
13133 cell.title = cal.maxText;
13137 if(ddays.indexOf(d.getDay()) != -1){
13138 cell.title = ddaysText;
13139 cell.className = " fc-state-disabled";
13142 if(ddMatch && format){
13143 var fvalue = d.dateFormat(format);
13144 if(ddMatch.test(fvalue)){
13145 cell.title = ddText.replace("%0", fvalue);
13146 cell.className = " fc-state-disabled";
13150 if (!cell.initialClassName) {
13151 cell.initialClassName = cell.dom.className;
13154 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13159 for(; i < startingPos; i++) {
13160 textEls[i].innerHTML = (++prevStart);
13161 d.setDate(d.getDate()+1);
13163 cells[i].className = "fc-past fc-other-month";
13164 setCellClass(this, cells[i]);
13169 for(; i < days; i++){
13170 intDay = i - startingPos + 1;
13171 textEls[i].innerHTML = (intDay);
13172 d.setDate(d.getDate()+1);
13174 cells[i].className = ''; // "x-date-active";
13175 setCellClass(this, cells[i]);
13179 for(; i < 42; i++) {
13180 textEls[i].innerHTML = (++extraDays);
13181 d.setDate(d.getDate()+1);
13183 cells[i].className = "fc-future fc-other-month";
13184 setCellClass(this, cells[i]);
13187 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13189 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13191 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13192 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13194 if(totalRows != 6){
13195 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13196 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13199 this.fireEvent('monthchange', this, date);
13203 if(!this.internalRender){
13204 var main = this.el.dom.firstChild;
13205 var w = main.offsetWidth;
13206 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13207 Roo.fly(main).setWidth(w);
13208 this.internalRender = true;
13209 // opera does not respect the auto grow header center column
13210 // then, after it gets a width opera refuses to recalculate
13211 // without a second pass
13212 if(Roo.isOpera && !this.secondPass){
13213 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13214 this.secondPass = true;
13215 this.update.defer(10, this, [date]);
13222 findCell : function(dt) {
13223 dt = dt.clearTime().getTime();
13225 this.cells.each(function(c){
13226 //Roo.log("check " +c.dateValue + '?=' + dt);
13227 if(c.dateValue == dt){
13237 findCells : function(ev) {
13238 var s = ev.start.clone().clearTime().getTime();
13240 var e= ev.end.clone().clearTime().getTime();
13243 this.cells.each(function(c){
13244 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13246 if(c.dateValue > e){
13249 if(c.dateValue < s){
13258 // findBestRow: function(cells)
13262 // for (var i =0 ; i < cells.length;i++) {
13263 // ret = Math.max(cells[i].rows || 0,ret);
13270 addItem : function(ev)
13272 // look for vertical location slot in
13273 var cells = this.findCells(ev);
13275 // ev.row = this.findBestRow(cells);
13277 // work out the location.
13281 for(var i =0; i < cells.length; i++) {
13283 cells[i].row = cells[0].row;
13286 cells[i].row = cells[i].row + 1;
13296 if (crow.start.getY() == cells[i].getY()) {
13298 crow.end = cells[i];
13315 cells[0].events.push(ev);
13317 this.calevents.push(ev);
13320 clearEvents: function() {
13322 if(!this.calevents){
13326 Roo.each(this.cells.elements, function(c){
13332 Roo.each(this.calevents, function(e) {
13333 Roo.each(e.els, function(el) {
13334 el.un('mouseenter' ,this.onEventEnter, this);
13335 el.un('mouseleave' ,this.onEventLeave, this);
13340 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13346 renderEvents: function()
13350 this.cells.each(function(c) {
13359 if(c.row != c.events.length){
13360 r = 4 - (4 - (c.row - c.events.length));
13363 c.events = ev.slice(0, r);
13364 c.more = ev.slice(r);
13366 if(c.more.length && c.more.length == 1){
13367 c.events.push(c.more.pop());
13370 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13374 this.cells.each(function(c) {
13376 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13379 for (var e = 0; e < c.events.length; e++){
13380 var ev = c.events[e];
13381 var rows = ev.rows;
13383 for(var i = 0; i < rows.length; i++) {
13385 // how many rows should it span..
13388 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13389 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13391 unselectable : "on",
13394 cls: 'fc-event-inner',
13398 // cls: 'fc-event-time',
13399 // html : cells.length > 1 ? '' : ev.time
13403 cls: 'fc-event-title',
13404 html : String.format('{0}', ev.title)
13411 cls: 'ui-resizable-handle ui-resizable-e',
13412 html : '  '
13419 cfg.cls += ' fc-event-start';
13421 if ((i+1) == rows.length) {
13422 cfg.cls += ' fc-event-end';
13425 var ctr = _this.el.select('.fc-event-container',true).first();
13426 var cg = ctr.createChild(cfg);
13428 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13429 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13431 var r = (c.more.length) ? 1 : 0;
13432 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13433 cg.setWidth(ebox.right - sbox.x -2);
13435 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13436 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13437 cg.on('click', _this.onEventClick, _this, ev);
13448 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13449 style : 'position: absolute',
13450 unselectable : "on",
13453 cls: 'fc-event-inner',
13457 cls: 'fc-event-title',
13465 cls: 'ui-resizable-handle ui-resizable-e',
13466 html : '  '
13472 var ctr = _this.el.select('.fc-event-container',true).first();
13473 var cg = ctr.createChild(cfg);
13475 var sbox = c.select('.fc-day-content',true).first().getBox();
13476 var ebox = c.select('.fc-day-content',true).first().getBox();
13478 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13479 cg.setWidth(ebox.right - sbox.x -2);
13481 cg.on('click', _this.onMoreEventClick, _this, c.more);
13491 onEventEnter: function (e, el,event,d) {
13492 this.fireEvent('evententer', this, el, event);
13495 onEventLeave: function (e, el,event,d) {
13496 this.fireEvent('eventleave', this, el, event);
13499 onEventClick: function (e, el,event,d) {
13500 this.fireEvent('eventclick', this, el, event);
13503 onMonthChange: function () {
13507 onMoreEventClick: function(e, el, more)
13511 this.calpopover.placement = 'right';
13512 this.calpopover.setTitle('More');
13514 this.calpopover.setContent('');
13516 var ctr = this.calpopover.el.select('.popover-content', true).first();
13518 Roo.each(more, function(m){
13520 cls : 'fc-event-hori fc-event-draggable',
13523 var cg = ctr.createChild(cfg);
13525 cg.on('click', _this.onEventClick, _this, m);
13528 this.calpopover.show(el);
13533 onLoad: function ()
13535 this.calevents = [];
13538 if(this.store.getCount() > 0){
13539 this.store.data.each(function(d){
13542 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13543 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13544 time : d.data.start_time,
13545 title : d.data.title,
13546 description : d.data.description,
13547 venue : d.data.venue
13552 this.renderEvents();
13554 if(this.calevents.length && this.loadMask){
13555 this.maskEl.hide();
13559 onBeforeLoad: function()
13561 this.clearEvents();
13563 this.maskEl.show();
13577 * @class Roo.bootstrap.Popover
13578 * @extends Roo.bootstrap.Component
13579 * Bootstrap Popover class
13580 * @cfg {String} html contents of the popover (or false to use children..)
13581 * @cfg {String} title of popover (or false to hide)
13582 * @cfg {String} placement how it is placed
13583 * @cfg {String} trigger click || hover (or false to trigger manually)
13584 * @cfg {String} over what (parent or false to trigger manually.)
13587 * Create a new Popover
13588 * @param {Object} config The config object
13591 Roo.bootstrap.Popover = function(config){
13592 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13595 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13597 title: 'Fill in a title',
13600 placement : 'right',
13601 trigger : 'hover', // hover
13605 can_build_overlaid : false,
13607 getChildContainer : function()
13609 return this.el.select('.popover-content',true).first();
13612 getAutoCreate : function(){
13613 Roo.log('make popover?');
13615 cls : 'popover roo-dynamic',
13616 style: 'display:block',
13622 cls : 'popover-inner',
13626 cls: 'popover-title',
13630 cls : 'popover-content',
13641 setTitle: function(str)
13643 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13645 setContent: function(str)
13647 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13649 // as it get's added to the bottom of the page.
13650 onRender : function(ct, position)
13652 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13654 var cfg = Roo.apply({}, this.getAutoCreate());
13658 cfg.cls += ' ' + this.cls;
13661 cfg.style = this.style;
13663 Roo.log("adding to ")
13664 this.el = Roo.get(document.body).createChild(cfg, position);
13670 initEvents : function()
13672 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13673 this.el.enableDisplayMode('block');
13675 if (this.over === false) {
13678 if (this.triggers === false) {
13681 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13682 var triggers = this.trigger ? this.trigger.split(' ') : [];
13683 Roo.each(triggers, function(trigger) {
13685 if (trigger == 'click') {
13686 on_el.on('click', this.toggle, this);
13687 } else if (trigger != 'manual') {
13688 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13689 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13691 on_el.on(eventIn ,this.enter, this);
13692 on_el.on(eventOut, this.leave, this);
13703 toggle : function () {
13704 this.hoverState == 'in' ? this.leave() : this.enter();
13707 enter : function () {
13710 clearTimeout(this.timeout);
13712 this.hoverState = 'in'
13714 if (!this.delay || !this.delay.show) {
13719 this.timeout = setTimeout(function () {
13720 if (_t.hoverState == 'in') {
13723 }, this.delay.show)
13725 leave : function() {
13726 clearTimeout(this.timeout);
13728 this.hoverState = 'out'
13730 if (!this.delay || !this.delay.hide) {
13735 this.timeout = setTimeout(function () {
13736 if (_t.hoverState == 'out') {
13739 }, this.delay.hide)
13742 show : function (on_el)
13745 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13748 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13749 if (this.html !== false) {
13750 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13752 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13753 if (!this.title.length) {
13754 this.el.select('.popover-title',true).hide();
13757 var placement = typeof this.placement == 'function' ?
13758 this.placement.call(this, this.el, on_el) :
13761 var autoToken = /\s?auto?\s?/i;
13762 var autoPlace = autoToken.test(placement);
13764 placement = placement.replace(autoToken, '') || 'top';
13768 //this.el.setXY([0,0]);
13770 this.el.dom.style.display='block';
13771 this.el.addClass(placement);
13773 //this.el.appendTo(on_el);
13775 var p = this.getPosition();
13776 var box = this.el.getBox();
13781 var align = Roo.bootstrap.Popover.alignment[placement]
13782 this.el.alignTo(on_el, align[0],align[1]);
13783 //var arrow = this.el.select('.arrow',true).first();
13784 //arrow.set(align[2],
13786 this.el.addClass('in');
13787 this.hoverState = null;
13789 if (this.el.hasClass('fade')) {
13796 this.el.setXY([0,0]);
13797 this.el.removeClass('in');
13804 Roo.bootstrap.Popover.alignment = {
13805 'left' : ['r-l', [-10,0], 'right'],
13806 'right' : ['l-r', [10,0], 'left'],
13807 'bottom' : ['t-b', [0,10], 'top'],
13808 'top' : [ 'b-t', [0,-10], 'bottom']
13819 * @class Roo.bootstrap.Progress
13820 * @extends Roo.bootstrap.Component
13821 * Bootstrap Progress class
13822 * @cfg {Boolean} striped striped of the progress bar
13823 * @cfg {Boolean} active animated of the progress bar
13827 * Create a new Progress
13828 * @param {Object} config The config object
13831 Roo.bootstrap.Progress = function(config){
13832 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13835 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13840 getAutoCreate : function(){
13848 cfg.cls += ' progress-striped';
13852 cfg.cls += ' active';
13871 * @class Roo.bootstrap.ProgressBar
13872 * @extends Roo.bootstrap.Component
13873 * Bootstrap ProgressBar class
13874 * @cfg {Number} aria_valuenow aria-value now
13875 * @cfg {Number} aria_valuemin aria-value min
13876 * @cfg {Number} aria_valuemax aria-value max
13877 * @cfg {String} label label for the progress bar
13878 * @cfg {String} panel (success | info | warning | danger )
13879 * @cfg {String} role role of the progress bar
13880 * @cfg {String} sr_only text
13884 * Create a new ProgressBar
13885 * @param {Object} config The config object
13888 Roo.bootstrap.ProgressBar = function(config){
13889 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13892 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13896 aria_valuemax : 100,
13902 getAutoCreate : function()
13907 cls: 'progress-bar',
13908 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13920 cfg.role = this.role;
13923 if(this.aria_valuenow){
13924 cfg['aria-valuenow'] = this.aria_valuenow;
13927 if(this.aria_valuemin){
13928 cfg['aria-valuemin'] = this.aria_valuemin;
13931 if(this.aria_valuemax){
13932 cfg['aria-valuemax'] = this.aria_valuemax;
13935 if(this.label && !this.sr_only){
13936 cfg.html = this.label;
13940 cfg.cls += ' progress-bar-' + this.panel;
13946 update : function(aria_valuenow)
13948 this.aria_valuenow = aria_valuenow;
13950 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13965 * @class Roo.bootstrap.TabGroup
13966 * @extends Roo.bootstrap.Column
13967 * Bootstrap Column class
13968 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13969 * @cfg {Boolean} carousel true to make the group behave like a carousel
13972 * Create a new TabGroup
13973 * @param {Object} config The config object
13976 Roo.bootstrap.TabGroup = function(config){
13977 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13979 this.navId = Roo.id();
13982 Roo.bootstrap.TabGroup.register(this);
13986 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13989 transition : false,
13991 getAutoCreate : function()
13993 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13995 cfg.cls += ' tab-content';
13997 if (this.carousel) {
13998 cfg.cls += ' carousel slide';
14000 cls : 'carousel-inner'
14007 getChildContainer : function()
14009 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14013 * register a Navigation item
14014 * @param {Roo.bootstrap.NavItem} the navitem to add
14016 register : function(item)
14018 this.tabs.push( item);
14019 item.navId = this.navId; // not really needed..
14023 getActivePanel : function()
14026 Roo.each(this.tabs, function(t) {
14036 getPanelByName : function(n)
14039 Roo.each(this.tabs, function(t) {
14040 if (t.tabId == n) {
14048 indexOfPanel : function(p)
14051 Roo.each(this.tabs, function(t,i) {
14052 if (t.tabId == p.tabId) {
14061 * show a specific panel
14062 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14063 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14065 showPanel : function (pan)
14068 if (typeof(pan) == 'number') {
14069 pan = this.tabs[pan];
14071 if (typeof(pan) == 'string') {
14072 pan = this.getPanelByName(pan);
14074 if (pan.tabId == this.getActivePanel().tabId) {
14077 var cur = this.getActivePanel();
14079 if (false === cur.fireEvent('beforedeactivate')) {
14083 if (this.carousel) {
14084 this.transition = true;
14085 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14086 var lr = dir == 'next' ? 'left' : 'right';
14087 pan.el.addClass(dir); // or prev
14088 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14089 cur.el.addClass(lr); // or right
14090 pan.el.addClass(lr);
14093 cur.el.on('transitionend', function() {
14094 Roo.log("trans end?");
14096 pan.el.removeClass([lr,dir]);
14097 pan.setActive(true);
14099 cur.el.removeClass([lr]);
14100 cur.setActive(false);
14102 _this.transition = false;
14104 }, this, { single: true } );
14108 cur.setActive(false);
14109 pan.setActive(true);
14113 showPanelNext : function()
14115 var i = this.indexOfPanel(this.getActivePanel());
14116 if (i > this.tabs.length) {
14119 this.showPanel(this.tabs[i+1]);
14121 showPanelPrev : function()
14123 var i = this.indexOfPanel(this.getActivePanel());
14127 this.showPanel(this.tabs[i-1]);
14138 Roo.apply(Roo.bootstrap.TabGroup, {
14142 * register a Navigation Group
14143 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14145 register : function(navgrp)
14147 this.groups[navgrp.navId] = navgrp;
14151 * fetch a Navigation Group based on the navigation ID
14152 * if one does not exist , it will get created.
14153 * @param {string} the navgroup to add
14154 * @returns {Roo.bootstrap.NavGroup} the navgroup
14156 get: function(navId) {
14157 if (typeof(this.groups[navId]) == 'undefined') {
14158 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14160 return this.groups[navId] ;
14175 * @class Roo.bootstrap.TabPanel
14176 * @extends Roo.bootstrap.Component
14177 * Bootstrap TabPanel class
14178 * @cfg {Boolean} active panel active
14179 * @cfg {String} html panel content
14180 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14181 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14185 * Create a new TabPanel
14186 * @param {Object} config The config object
14189 Roo.bootstrap.TabPanel = function(config){
14190 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14194 * Fires when the active status changes
14195 * @param {Roo.bootstrap.TabPanel} this
14196 * @param {Boolean} state the new state
14201 * @event beforedeactivate
14202 * Fires before a tab is de-activated - can be used to do validation on a form.
14203 * @param {Roo.bootstrap.TabPanel} this
14204 * @return {Boolean} false if there is an error
14207 'beforedeactivate': true
14210 this.tabId = this.tabId || Roo.id();
14214 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14221 getAutoCreate : function(){
14224 // item is needed for carousel - not sure if it has any effect otherwise
14225 cls: 'tab-pane item',
14226 html: this.html || ''
14230 cfg.cls += ' active';
14234 cfg.tabId = this.tabId;
14241 initEvents: function()
14243 Roo.log('-------- init events on tab panel ---------');
14245 var p = this.parent();
14246 this.navId = this.navId || p.navId;
14248 if (typeof(this.navId) != 'undefined') {
14249 // not really needed.. but just in case.. parent should be a NavGroup.
14250 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14251 Roo.log(['register', tg, this]);
14257 onRender : function(ct, position)
14259 // Roo.log("Call onRender: " + this.xtype);
14261 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14269 setActive: function(state)
14271 Roo.log("panel - set active " + this.tabId + "=" + state);
14273 this.active = state;
14275 this.el.removeClass('active');
14277 } else if (!this.el.hasClass('active')) {
14278 this.el.addClass('active');
14280 this.fireEvent('changed', this, state);
14297 * @class Roo.bootstrap.DateField
14298 * @extends Roo.bootstrap.Input
14299 * Bootstrap DateField class
14300 * @cfg {Number} weekStart default 0
14301 * @cfg {Number} weekStart default 0
14302 * @cfg {Number} viewMode default empty, (months|years)
14303 * @cfg {Number} minViewMode default empty, (months|years)
14304 * @cfg {Number} startDate default -Infinity
14305 * @cfg {Number} endDate default Infinity
14306 * @cfg {Boolean} todayHighlight default false
14307 * @cfg {Boolean} todayBtn default false
14308 * @cfg {Boolean} calendarWeeks default false
14309 * @cfg {Object} daysOfWeekDisabled default empty
14311 * @cfg {Boolean} keyboardNavigation default true
14312 * @cfg {String} language default en
14315 * Create a new DateField
14316 * @param {Object} config The config object
14319 Roo.bootstrap.DateField = function(config){
14320 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14324 * Fires when this field show.
14325 * @param {Roo.bootstrap.DateField} this
14326 * @param {Mixed} date The date value
14331 * Fires when this field hide.
14332 * @param {Roo.bootstrap.DateField} this
14333 * @param {Mixed} date The date value
14338 * Fires when select a date.
14339 * @param {Roo.bootstrap.DateField} this
14340 * @param {Mixed} date The date value
14346 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14349 * @cfg {String} format
14350 * The default date format string which can be overriden for localization support. The format must be
14351 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14355 * @cfg {String} altFormats
14356 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14357 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14359 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14367 todayHighlight : false,
14373 keyboardNavigation: true,
14375 calendarWeeks: false,
14377 startDate: -Infinity,
14381 daysOfWeekDisabled: [],
14385 UTCDate: function()
14387 return new Date(Date.UTC.apply(Date, arguments));
14390 UTCToday: function()
14392 var today = new Date();
14393 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14396 getDate: function() {
14397 var d = this.getUTCDate();
14398 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14401 getUTCDate: function() {
14405 setDate: function(d) {
14406 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14409 setUTCDate: function(d) {
14411 this.setValue(this.formatDate(this.date));
14414 onRender: function(ct, position)
14417 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14419 this.language = this.language || 'en';
14420 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14421 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14423 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14424 this.format = this.format || 'm/d/y';
14425 this.isInline = false;
14426 this.isInput = true;
14427 this.component = this.el.select('.add-on', true).first() || false;
14428 this.component = (this.component && this.component.length === 0) ? false : this.component;
14429 this.hasInput = this.component && this.inputEL().length;
14431 if (typeof(this.minViewMode === 'string')) {
14432 switch (this.minViewMode) {
14434 this.minViewMode = 1;
14437 this.minViewMode = 2;
14440 this.minViewMode = 0;
14445 if (typeof(this.viewMode === 'string')) {
14446 switch (this.viewMode) {
14459 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14461 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14463 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14465 this.picker().on('mousedown', this.onMousedown, this);
14466 this.picker().on('click', this.onClick, this);
14468 this.picker().addClass('datepicker-dropdown');
14470 this.startViewMode = this.viewMode;
14473 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14474 if(!this.calendarWeeks){
14479 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14480 v.attr('colspan', function(i, val){
14481 return parseInt(val) + 1;
14486 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14488 this.setStartDate(this.startDate);
14489 this.setEndDate(this.endDate);
14491 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14498 if(this.isInline) {
14503 picker : function()
14505 return this.pickerEl;
14506 // return this.el.select('.datepicker', true).first();
14509 fillDow: function()
14511 var dowCnt = this.weekStart;
14520 if(this.calendarWeeks){
14528 while (dowCnt < this.weekStart + 7) {
14532 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14536 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14539 fillMonths: function()
14542 var months = this.picker().select('>.datepicker-months td', true).first();
14544 months.dom.innerHTML = '';
14550 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14553 months.createChild(month);
14560 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;
14562 if (this.date < this.startDate) {
14563 this.viewDate = new Date(this.startDate);
14564 } else if (this.date > this.endDate) {
14565 this.viewDate = new Date(this.endDate);
14567 this.viewDate = new Date(this.date);
14575 var d = new Date(this.viewDate),
14576 year = d.getUTCFullYear(),
14577 month = d.getUTCMonth(),
14578 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14579 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14580 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14581 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14582 currentDate = this.date && this.date.valueOf(),
14583 today = this.UTCToday();
14585 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14587 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14589 // this.picker.select('>tfoot th.today').
14590 // .text(dates[this.language].today)
14591 // .toggle(this.todayBtn !== false);
14593 this.updateNavArrows();
14596 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14598 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14600 prevMonth.setUTCDate(day);
14602 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14604 var nextMonth = new Date(prevMonth);
14606 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14608 nextMonth = nextMonth.valueOf();
14610 var fillMonths = false;
14612 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14614 while(prevMonth.valueOf() < nextMonth) {
14617 if (prevMonth.getUTCDay() === this.weekStart) {
14619 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14627 if(this.calendarWeeks){
14628 // ISO 8601: First week contains first thursday.
14629 // ISO also states week starts on Monday, but we can be more abstract here.
14631 // Start of current week: based on weekstart/current date
14632 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14633 // Thursday of this week
14634 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14635 // First Thursday of year, year from thursday
14636 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14637 // Calendar week: ms between thursdays, div ms per day, div 7 days
14638 calWeek = (th - yth) / 864e5 / 7 + 1;
14640 fillMonths.cn.push({
14648 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14650 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14653 if (this.todayHighlight &&
14654 prevMonth.getUTCFullYear() == today.getFullYear() &&
14655 prevMonth.getUTCMonth() == today.getMonth() &&
14656 prevMonth.getUTCDate() == today.getDate()) {
14657 clsName += ' today';
14660 if (currentDate && prevMonth.valueOf() === currentDate) {
14661 clsName += ' active';
14664 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14665 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14666 clsName += ' disabled';
14669 fillMonths.cn.push({
14671 cls: 'day ' + clsName,
14672 html: prevMonth.getDate()
14675 prevMonth.setDate(prevMonth.getDate()+1);
14678 var currentYear = this.date && this.date.getUTCFullYear();
14679 var currentMonth = this.date && this.date.getUTCMonth();
14681 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14683 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14684 v.removeClass('active');
14686 if(currentYear === year && k === currentMonth){
14687 v.addClass('active');
14690 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14691 v.addClass('disabled');
14697 year = parseInt(year/10, 10) * 10;
14699 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14701 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14704 for (var i = -1; i < 11; i++) {
14705 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14707 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14715 showMode: function(dir)
14718 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14720 Roo.each(this.picker().select('>div',true).elements, function(v){
14721 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14724 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14729 if(this.isInline) return;
14731 this.picker().removeClass(['bottom', 'top']);
14733 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14735 * place to the top of element!
14739 this.picker().addClass('top');
14740 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14745 this.picker().addClass('bottom');
14747 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14750 parseDate : function(value)
14752 if(!value || value instanceof Date){
14755 var v = Date.parseDate(value, this.format);
14756 if (!v && this.useIso) {
14757 v = Date.parseDate(value, 'Y-m-d');
14759 if(!v && this.altFormats){
14760 if(!this.altFormatsArray){
14761 this.altFormatsArray = this.altFormats.split("|");
14763 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14764 v = Date.parseDate(value, this.altFormatsArray[i]);
14770 formatDate : function(date, fmt)
14772 return (!date || !(date instanceof Date)) ?
14773 date : date.dateFormat(fmt || this.format);
14776 onFocus : function()
14778 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14782 onBlur : function()
14784 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14786 var d = this.inputEl().getValue();
14795 this.picker().show();
14799 this.fireEvent('show', this, this.date);
14804 if(this.isInline) return;
14805 this.picker().hide();
14806 this.viewMode = this.startViewMode;
14809 this.fireEvent('hide', this, this.date);
14813 onMousedown: function(e)
14815 e.stopPropagation();
14816 e.preventDefault();
14821 Roo.bootstrap.DateField.superclass.keyup.call(this);
14825 setValue: function(v)
14827 var d = new Date(v).clearTime();
14829 if(isNaN(d.getTime())){
14830 this.date = this.viewDate = '';
14831 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14835 v = this.formatDate(d);
14837 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14839 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14843 this.fireEvent('select', this, this.date);
14847 getValue: function()
14849 return this.formatDate(this.date);
14852 fireKey: function(e)
14854 if (!this.picker().isVisible()){
14855 if (e.keyCode == 27) // allow escape to hide and re-show picker
14860 var dateChanged = false,
14862 newDate, newViewDate;
14867 e.preventDefault();
14871 if (!this.keyboardNavigation) break;
14872 dir = e.keyCode == 37 ? -1 : 1;
14875 newDate = this.moveYear(this.date, dir);
14876 newViewDate = this.moveYear(this.viewDate, dir);
14877 } else if (e.shiftKey){
14878 newDate = this.moveMonth(this.date, dir);
14879 newViewDate = this.moveMonth(this.viewDate, dir);
14881 newDate = new Date(this.date);
14882 newDate.setUTCDate(this.date.getUTCDate() + dir);
14883 newViewDate = new Date(this.viewDate);
14884 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14886 if (this.dateWithinRange(newDate)){
14887 this.date = newDate;
14888 this.viewDate = newViewDate;
14889 this.setValue(this.formatDate(this.date));
14891 e.preventDefault();
14892 dateChanged = true;
14897 if (!this.keyboardNavigation) break;
14898 dir = e.keyCode == 38 ? -1 : 1;
14900 newDate = this.moveYear(this.date, dir);
14901 newViewDate = this.moveYear(this.viewDate, dir);
14902 } else if (e.shiftKey){
14903 newDate = this.moveMonth(this.date, dir);
14904 newViewDate = this.moveMonth(this.viewDate, dir);
14906 newDate = new Date(this.date);
14907 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14908 newViewDate = new Date(this.viewDate);
14909 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14911 if (this.dateWithinRange(newDate)){
14912 this.date = newDate;
14913 this.viewDate = newViewDate;
14914 this.setValue(this.formatDate(this.date));
14916 e.preventDefault();
14917 dateChanged = true;
14921 this.setValue(this.formatDate(this.date));
14923 e.preventDefault();
14926 this.setValue(this.formatDate(this.date));
14940 onClick: function(e)
14942 e.stopPropagation();
14943 e.preventDefault();
14945 var target = e.getTarget();
14947 if(target.nodeName.toLowerCase() === 'i'){
14948 target = Roo.get(target).dom.parentNode;
14951 var nodeName = target.nodeName;
14952 var className = target.className;
14953 var html = target.innerHTML;
14955 switch(nodeName.toLowerCase()) {
14957 switch(className) {
14963 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14964 switch(this.viewMode){
14966 this.viewDate = this.moveMonth(this.viewDate, dir);
14970 this.viewDate = this.moveYear(this.viewDate, dir);
14976 var date = new Date();
14977 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14979 this.setValue(this.formatDate(this.date));
14986 if (className.indexOf('disabled') === -1) {
14987 this.viewDate.setUTCDate(1);
14988 if (className.indexOf('month') !== -1) {
14989 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14991 var year = parseInt(html, 10) || 0;
14992 this.viewDate.setUTCFullYear(year);
15001 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
15002 var day = parseInt(html, 10) || 1;
15003 var year = this.viewDate.getUTCFullYear(),
15004 month = this.viewDate.getUTCMonth();
15006 if (className.indexOf('old') !== -1) {
15013 } else if (className.indexOf('new') !== -1) {
15021 this.date = this.UTCDate(year, month, day,0,0,0,0);
15022 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15024 this.setValue(this.formatDate(this.date));
15031 setStartDate: function(startDate)
15033 this.startDate = startDate || -Infinity;
15034 if (this.startDate !== -Infinity) {
15035 this.startDate = this.parseDate(this.startDate);
15038 this.updateNavArrows();
15041 setEndDate: function(endDate)
15043 this.endDate = endDate || Infinity;
15044 if (this.endDate !== Infinity) {
15045 this.endDate = this.parseDate(this.endDate);
15048 this.updateNavArrows();
15051 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15053 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15054 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15055 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15057 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15058 return parseInt(d, 10);
15061 this.updateNavArrows();
15064 updateNavArrows: function()
15066 var d = new Date(this.viewDate),
15067 year = d.getUTCFullYear(),
15068 month = d.getUTCMonth();
15070 Roo.each(this.picker().select('.prev', true).elements, function(v){
15072 switch (this.viewMode) {
15075 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15081 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15088 Roo.each(this.picker().select('.next', true).elements, function(v){
15090 switch (this.viewMode) {
15093 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15099 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15107 moveMonth: function(date, dir)
15109 if (!dir) return date;
15110 var new_date = new Date(date.valueOf()),
15111 day = new_date.getUTCDate(),
15112 month = new_date.getUTCMonth(),
15113 mag = Math.abs(dir),
15115 dir = dir > 0 ? 1 : -1;
15118 // If going back one month, make sure month is not current month
15119 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15121 return new_date.getUTCMonth() == month;
15123 // If going forward one month, make sure month is as expected
15124 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15126 return new_date.getUTCMonth() != new_month;
15128 new_month = month + dir;
15129 new_date.setUTCMonth(new_month);
15130 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15131 if (new_month < 0 || new_month > 11)
15132 new_month = (new_month + 12) % 12;
15134 // For magnitudes >1, move one month at a time...
15135 for (var i=0; i<mag; i++)
15136 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15137 new_date = this.moveMonth(new_date, dir);
15138 // ...then reset the day, keeping it in the new month
15139 new_month = new_date.getUTCMonth();
15140 new_date.setUTCDate(day);
15142 return new_month != new_date.getUTCMonth();
15145 // Common date-resetting loop -- if date is beyond end of month, make it
15148 new_date.setUTCDate(--day);
15149 new_date.setUTCMonth(new_month);
15154 moveYear: function(date, dir)
15156 return this.moveMonth(date, dir*12);
15159 dateWithinRange: function(date)
15161 return date >= this.startDate && date <= this.endDate;
15167 this.picker().remove();
15172 Roo.apply(Roo.bootstrap.DateField, {
15183 html: '<i class="fa fa-arrow-left"/>'
15193 html: '<i class="fa fa-arrow-right"/>'
15235 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15236 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15237 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15238 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15239 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15252 navFnc: 'FullYear',
15257 navFnc: 'FullYear',
15262 Roo.apply(Roo.bootstrap.DateField, {
15266 cls: 'datepicker dropdown-menu',
15270 cls: 'datepicker-days',
15274 cls: 'table-condensed',
15276 Roo.bootstrap.DateField.head,
15280 Roo.bootstrap.DateField.footer
15287 cls: 'datepicker-months',
15291 cls: 'table-condensed',
15293 Roo.bootstrap.DateField.head,
15294 Roo.bootstrap.DateField.content,
15295 Roo.bootstrap.DateField.footer
15302 cls: 'datepicker-years',
15306 cls: 'table-condensed',
15308 Roo.bootstrap.DateField.head,
15309 Roo.bootstrap.DateField.content,
15310 Roo.bootstrap.DateField.footer
15329 * @class Roo.bootstrap.TimeField
15330 * @extends Roo.bootstrap.Input
15331 * Bootstrap DateField class
15335 * Create a new TimeField
15336 * @param {Object} config The config object
15339 Roo.bootstrap.TimeField = function(config){
15340 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15344 * Fires when this field show.
15345 * @param {Roo.bootstrap.DateField} this
15346 * @param {Mixed} date The date value
15351 * Fires when this field hide.
15352 * @param {Roo.bootstrap.DateField} this
15353 * @param {Mixed} date The date value
15358 * Fires when select a date.
15359 * @param {Roo.bootstrap.DateField} this
15360 * @param {Mixed} date The date value
15366 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15369 * @cfg {String} format
15370 * The default time format string which can be overriden for localization support. The format must be
15371 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15375 onRender: function(ct, position)
15378 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15380 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15382 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15384 this.pop = this.picker().select('>.datepicker-time',true).first();
15385 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15387 this.picker().on('mousedown', this.onMousedown, this);
15388 this.picker().on('click', this.onClick, this);
15390 this.picker().addClass('datepicker-dropdown');
15395 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15396 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15397 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15398 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15399 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15400 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15404 fireKey: function(e){
15405 if (!this.picker().isVisible()){
15406 if (e.keyCode == 27) // allow escape to hide and re-show picker
15411 e.preventDefault();
15419 this.onTogglePeriod();
15422 this.onIncrementMinutes();
15425 this.onDecrementMinutes();
15434 onClick: function(e) {
15435 e.stopPropagation();
15436 e.preventDefault();
15439 picker : function()
15441 return this.el.select('.datepicker', true).first();
15444 fillTime: function()
15446 var time = this.pop.select('tbody', true).first();
15448 time.dom.innerHTML = '';
15463 cls: 'hours-up glyphicon glyphicon-chevron-up'
15483 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15504 cls: 'timepicker-hour',
15519 cls: 'timepicker-minute',
15534 cls: 'btn btn-primary period',
15556 cls: 'hours-down glyphicon glyphicon-chevron-down'
15576 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15594 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15601 var hours = this.time.getHours();
15602 var minutes = this.time.getMinutes();
15615 hours = hours - 12;
15619 hours = '0' + hours;
15623 minutes = '0' + minutes;
15626 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15627 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15628 this.pop.select('button', true).first().dom.innerHTML = period;
15634 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15636 var cls = ['bottom'];
15638 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15645 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15650 this.picker().addClass(cls.join('-'));
15654 Roo.each(cls, function(c){
15656 _this.picker().setTop(_this.inputEl().getHeight());
15660 _this.picker().setTop(0 - _this.picker().getHeight());
15665 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15669 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15676 onFocus : function()
15678 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15682 onBlur : function()
15684 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15690 this.picker().show();
15695 this.fireEvent('show', this, this.date);
15700 this.picker().hide();
15703 this.fireEvent('hide', this, this.date);
15706 setTime : function()
15709 this.setValue(this.time.format(this.format));
15711 this.fireEvent('select', this, this.date);
15716 onMousedown: function(e){
15717 e.stopPropagation();
15718 e.preventDefault();
15721 onIncrementHours: function()
15723 Roo.log('onIncrementHours');
15724 this.time = this.time.add(Date.HOUR, 1);
15729 onDecrementHours: function()
15731 Roo.log('onDecrementHours');
15732 this.time = this.time.add(Date.HOUR, -1);
15736 onIncrementMinutes: function()
15738 Roo.log('onIncrementMinutes');
15739 this.time = this.time.add(Date.MINUTE, 1);
15743 onDecrementMinutes: function()
15745 Roo.log('onDecrementMinutes');
15746 this.time = this.time.add(Date.MINUTE, -1);
15750 onTogglePeriod: function()
15752 Roo.log('onTogglePeriod');
15753 this.time = this.time.add(Date.HOUR, 12);
15760 Roo.apply(Roo.bootstrap.TimeField, {
15790 cls: 'btn btn-info ok',
15802 Roo.apply(Roo.bootstrap.TimeField, {
15806 cls: 'datepicker dropdown-menu',
15810 cls: 'datepicker-time',
15814 cls: 'table-condensed',
15816 Roo.bootstrap.TimeField.content,
15817 Roo.bootstrap.TimeField.footer
15836 * @class Roo.bootstrap.CheckBox
15837 * @extends Roo.bootstrap.Input
15838 * Bootstrap CheckBox class
15840 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15841 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15842 * @cfg {String} boxLabel The text that appears beside the checkbox
15843 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15844 * @cfg {Boolean} checked initnal the element
15848 * Create a new CheckBox
15849 * @param {Object} config The config object
15852 Roo.bootstrap.CheckBox = function(config){
15853 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15858 * Fires when the element is checked or unchecked.
15859 * @param {Roo.bootstrap.CheckBox} this This input
15860 * @param {Boolean} checked The new checked value
15866 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15868 inputType: 'checkbox',
15875 getAutoCreate : function()
15877 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15883 cfg.cls = 'form-group checkbox' //input-group
15891 type : this.inputType,
15892 value : (!this.checked) ? this.valueOff : this.inputValue,
15893 cls : 'roo-checkbox', //'form-box',
15894 placeholder : this.placeholder || ''
15898 if (this.weight) { // Validity check?
15899 cfg.cls += " checkbox-" + this.weight;
15902 if (this.disabled) {
15903 input.disabled=true;
15907 input.checked = this.checked;
15911 input.name = this.name;
15915 input.cls += ' input-' + this.size;
15919 ['xs','sm','md','lg'].map(function(size){
15920 if (settings[size]) {
15921 cfg.cls += ' col-' + size + '-' + settings[size];
15927 var inputblock = input;
15932 if (this.before || this.after) {
15935 cls : 'input-group',
15939 inputblock.cn.push({
15941 cls : 'input-group-addon',
15945 inputblock.cn.push(input);
15947 inputblock.cn.push({
15949 cls : 'input-group-addon',
15956 if (align ==='left' && this.fieldLabel.length) {
15957 Roo.log("left and has label");
15963 cls : 'control-label col-md-' + this.labelWidth,
15964 html : this.fieldLabel
15968 cls : "col-md-" + (12 - this.labelWidth),
15975 } else if ( this.fieldLabel.length) {
15980 tag: this.boxLabel ? 'span' : 'label',
15982 cls: 'control-label box-input-label',
15983 //cls : 'input-group-addon',
15984 html : this.fieldLabel
15994 Roo.log(" no label && no align");
15995 cfg.cn = [ inputblock ] ;
16004 html: this.boxLabel
16016 * return the real input element.
16018 inputEl: function ()
16020 return this.el.select('input.roo-checkbox',true).first();
16025 return this.el.select('label.control-label',true).first();
16028 initEvents : function()
16030 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16032 this.inputEl().on('click', this.onClick, this);
16036 onClick : function()
16038 this.setChecked(!this.checked);
16041 setChecked : function(state,suppressEvent)
16043 this.checked = state;
16045 this.inputEl().dom.checked = state;
16047 if(suppressEvent !== true){
16048 this.fireEvent('check', this, state);
16051 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16055 setValue : function(v,suppressEvent)
16057 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16071 * @class Roo.bootstrap.Radio
16072 * @extends Roo.bootstrap.CheckBox
16073 * Bootstrap Radio class
16076 * Create a new Radio
16077 * @param {Object} config The config object
16080 Roo.bootstrap.Radio = function(config){
16081 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16085 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16087 inputType: 'radio',
16091 getAutoCreate : function()
16093 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16099 cfg.cls = 'form-group radio' //input-group
16104 type : this.inputType,
16105 value : (!this.checked) ? this.valueOff : this.inputValue,
16107 placeholder : this.placeholder || ''
16110 if (this.weight) { // Validity check?
16111 cfg.cls += " radio-" + this.weight;
16113 if (this.disabled) {
16114 input.disabled=true;
16118 input.checked = this.checked;
16122 input.name = this.name;
16126 input.cls += ' input-' + this.size;
16130 ['xs','sm','md','lg'].map(function(size){
16131 if (settings[size]) {
16132 cfg.cls += ' col-' + size + '-' + settings[size];
16136 var inputblock = input;
16138 if (this.before || this.after) {
16141 cls : 'input-group',
16145 inputblock.cn.push({
16147 cls : 'input-group-addon',
16151 inputblock.cn.push(input);
16153 inputblock.cn.push({
16155 cls : 'input-group-addon',
16162 if (align ==='left' && this.fieldLabel.length) {
16163 Roo.log("left and has label");
16169 cls : 'control-label col-md-' + this.labelWidth,
16170 html : this.fieldLabel
16174 cls : "col-md-" + (12 - this.labelWidth),
16181 } else if ( this.fieldLabel.length) {
16188 cls: 'control-label box-input-label',
16189 //cls : 'input-group-addon',
16190 html : this.fieldLabel
16200 Roo.log(" no label && no align");
16215 html: this.boxLabel
16222 inputEl: function ()
16224 return this.el.select('input.roo-radio',true).first();
16226 onClick : function()
16228 this.setChecked(true);
16231 setChecked : function(state,suppressEvent)
16234 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16235 v.dom.checked = false;
16239 this.checked = state;
16240 this.inputEl().dom.checked = state;
16242 if(suppressEvent !== true){
16243 this.fireEvent('check', this, state);
16246 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16250 getGroupValue : function()
16253 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16254 if(v.dom.checked == true){
16255 value = v.dom.value;
16263 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16264 * @return {Mixed} value The field value
16266 getValue : function(){
16267 return this.getGroupValue();
16273 //<script type="text/javascript">
16276 * Based Ext JS Library 1.1.1
16277 * Copyright(c) 2006-2007, Ext JS, LLC.
16283 * @class Roo.HtmlEditorCore
16284 * @extends Roo.Component
16285 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16287 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16290 Roo.HtmlEditorCore = function(config){
16293 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16296 * @event initialize
16297 * Fires when the editor is fully initialized (including the iframe)
16298 * @param {Roo.HtmlEditorCore} this
16303 * Fires when the editor is first receives the focus. Any insertion must wait
16304 * until after this event.
16305 * @param {Roo.HtmlEditorCore} this
16309 * @event beforesync
16310 * Fires before the textarea is updated with content from the editor iframe. Return false
16311 * to cancel the sync.
16312 * @param {Roo.HtmlEditorCore} this
16313 * @param {String} html
16317 * @event beforepush
16318 * Fires before the iframe editor is updated with content from the textarea. Return false
16319 * to cancel the push.
16320 * @param {Roo.HtmlEditorCore} this
16321 * @param {String} html
16326 * Fires when the textarea is updated with content from the editor iframe.
16327 * @param {Roo.HtmlEditorCore} this
16328 * @param {String} html
16333 * Fires when the iframe editor is updated with content from the textarea.
16334 * @param {Roo.HtmlEditorCore} this
16335 * @param {String} html
16340 * @event editorevent
16341 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16342 * @param {Roo.HtmlEditorCore} this
16350 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16354 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16360 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16365 * @cfg {Number} height (in pixels)
16369 * @cfg {Number} width (in pixels)
16374 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16377 stylesheets: false,
16382 // private properties
16383 validationEvent : false,
16385 initialized : false,
16387 sourceEditMode : false,
16388 onFocus : Roo.emptyFn,
16390 hideMode:'offsets',
16398 * Protected method that will not generally be called directly. It
16399 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16400 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16402 getDocMarkup : function(){
16405 Roo.log(this.stylesheets);
16407 // inherit styels from page...??
16408 if (this.stylesheets === false) {
16410 Roo.get(document.head).select('style').each(function(node) {
16411 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16414 Roo.get(document.head).select('link').each(function(node) {
16415 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16418 } else if (!this.stylesheets.length) {
16420 st = '<style type="text/css">' +
16421 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16424 Roo.each(this.stylesheets, function(s) {
16425 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16430 st += '<style type="text/css">' +
16431 'IMG { cursor: pointer } ' +
16435 return '<html><head>' + st +
16436 //<style type="text/css">' +
16437 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16439 ' </head><body class="roo-htmleditor-body"></body></html>';
16443 onRender : function(ct, position)
16446 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16447 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16450 this.el.dom.style.border = '0 none';
16451 this.el.dom.setAttribute('tabIndex', -1);
16452 this.el.addClass('x-hidden hide');
16456 if(Roo.isIE){ // fix IE 1px bogus margin
16457 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16461 this.frameId = Roo.id();
16465 var iframe = this.owner.wrap.createChild({
16467 cls: 'form-control', // bootstrap..
16469 name: this.frameId,
16470 frameBorder : 'no',
16471 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16476 this.iframe = iframe.dom;
16478 this.assignDocWin();
16480 this.doc.designMode = 'on';
16483 this.doc.write(this.getDocMarkup());
16487 var task = { // must defer to wait for browser to be ready
16489 //console.log("run task?" + this.doc.readyState);
16490 this.assignDocWin();
16491 if(this.doc.body || this.doc.readyState == 'complete'){
16493 this.doc.designMode="on";
16497 Roo.TaskMgr.stop(task);
16498 this.initEditor.defer(10, this);
16505 Roo.TaskMgr.start(task);
16512 onResize : function(w, h)
16514 Roo.log('resize: ' +w + ',' + h );
16515 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16519 if(typeof w == 'number'){
16521 this.iframe.style.width = w + 'px';
16523 if(typeof h == 'number'){
16525 this.iframe.style.height = h + 'px';
16527 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16534 * Toggles the editor between standard and source edit mode.
16535 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16537 toggleSourceEdit : function(sourceEditMode){
16539 this.sourceEditMode = sourceEditMode === true;
16541 if(this.sourceEditMode){
16543 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16546 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16547 //this.iframe.className = '';
16550 //this.setSize(this.owner.wrap.getSize());
16551 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16558 * Protected method that will not generally be called directly. If you need/want
16559 * custom HTML cleanup, this is the method you should override.
16560 * @param {String} html The HTML to be cleaned
16561 * return {String} The cleaned HTML
16563 cleanHtml : function(html){
16564 html = String(html);
16565 if(html.length > 5){
16566 if(Roo.isSafari){ // strip safari nonsense
16567 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16570 if(html == ' '){
16577 * HTML Editor -> Textarea
16578 * Protected method that will not generally be called directly. Syncs the contents
16579 * of the editor iframe with the textarea.
16581 syncValue : function(){
16582 if(this.initialized){
16583 var bd = (this.doc.body || this.doc.documentElement);
16584 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16585 var html = bd.innerHTML;
16587 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16588 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16590 html = '<div style="'+m[0]+'">' + html + '</div>';
16593 html = this.cleanHtml(html);
16594 // fix up the special chars.. normaly like back quotes in word...
16595 // however we do not want to do this with chinese..
16596 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16597 var cc = b.charCodeAt();
16599 (cc >= 0x4E00 && cc < 0xA000 ) ||
16600 (cc >= 0x3400 && cc < 0x4E00 ) ||
16601 (cc >= 0xf900 && cc < 0xfb00 )
16607 if(this.owner.fireEvent('beforesync', this, html) !== false){
16608 this.el.dom.value = html;
16609 this.owner.fireEvent('sync', this, html);
16615 * Protected method that will not generally be called directly. Pushes the value of the textarea
16616 * into the iframe editor.
16618 pushValue : function(){
16619 if(this.initialized){
16620 var v = this.el.dom.value.trim();
16622 // if(v.length < 1){
16626 if(this.owner.fireEvent('beforepush', this, v) !== false){
16627 var d = (this.doc.body || this.doc.documentElement);
16629 this.cleanUpPaste();
16630 this.el.dom.value = d.innerHTML;
16631 this.owner.fireEvent('push', this, v);
16637 deferFocus : function(){
16638 this.focus.defer(10, this);
16642 focus : function(){
16643 if(this.win && !this.sourceEditMode){
16650 assignDocWin: function()
16652 var iframe = this.iframe;
16655 this.doc = iframe.contentWindow.document;
16656 this.win = iframe.contentWindow;
16658 // if (!Roo.get(this.frameId)) {
16661 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16662 // this.win = Roo.get(this.frameId).dom.contentWindow;
16664 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16668 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16669 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16674 initEditor : function(){
16675 //console.log("INIT EDITOR");
16676 this.assignDocWin();
16680 this.doc.designMode="on";
16682 this.doc.write(this.getDocMarkup());
16685 var dbody = (this.doc.body || this.doc.documentElement);
16686 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16687 // this copies styles from the containing element into thsi one..
16688 // not sure why we need all of this..
16689 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16691 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16692 //ss['background-attachment'] = 'fixed'; // w3c
16693 dbody.bgProperties = 'fixed'; // ie
16694 //Roo.DomHelper.applyStyles(dbody, ss);
16695 Roo.EventManager.on(this.doc, {
16696 //'mousedown': this.onEditorEvent,
16697 'mouseup': this.onEditorEvent,
16698 'dblclick': this.onEditorEvent,
16699 'click': this.onEditorEvent,
16700 'keyup': this.onEditorEvent,
16705 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16707 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16708 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16710 this.initialized = true;
16712 this.owner.fireEvent('initialize', this);
16717 onDestroy : function(){
16723 //for (var i =0; i < this.toolbars.length;i++) {
16724 // // fixme - ask toolbars for heights?
16725 // this.toolbars[i].onDestroy();
16728 //this.wrap.dom.innerHTML = '';
16729 //this.wrap.remove();
16734 onFirstFocus : function(){
16736 this.assignDocWin();
16739 this.activated = true;
16742 if(Roo.isGecko){ // prevent silly gecko errors
16744 var s = this.win.getSelection();
16745 if(!s.focusNode || s.focusNode.nodeType != 3){
16746 var r = s.getRangeAt(0);
16747 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16752 this.execCmd('useCSS', true);
16753 this.execCmd('styleWithCSS', false);
16756 this.owner.fireEvent('activate', this);
16760 adjustFont: function(btn){
16761 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16762 //if(Roo.isSafari){ // safari
16765 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16766 if(Roo.isSafari){ // safari
16767 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16768 v = (v < 10) ? 10 : v;
16769 v = (v > 48) ? 48 : v;
16770 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16775 v = Math.max(1, v+adjust);
16777 this.execCmd('FontSize', v );
16780 onEditorEvent : function(e){
16781 this.owner.fireEvent('editorevent', this, e);
16782 // this.updateToolbar();
16783 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16786 insertTag : function(tg)
16788 // could be a bit smarter... -> wrap the current selected tRoo..
16789 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16791 range = this.createRange(this.getSelection());
16792 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16793 wrappingNode.appendChild(range.extractContents());
16794 range.insertNode(wrappingNode);
16801 this.execCmd("formatblock", tg);
16805 insertText : function(txt)
16809 var range = this.createRange();
16810 range.deleteContents();
16811 //alert(Sender.getAttribute('label'));
16813 range.insertNode(this.doc.createTextNode(txt));
16819 * Executes a Midas editor command on the editor document and performs necessary focus and
16820 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16821 * @param {String} cmd The Midas command
16822 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16824 relayCmd : function(cmd, value){
16826 this.execCmd(cmd, value);
16827 this.owner.fireEvent('editorevent', this);
16828 //this.updateToolbar();
16829 this.owner.deferFocus();
16833 * Executes a Midas editor command directly on the editor document.
16834 * For visual commands, you should use {@link #relayCmd} instead.
16835 * <b>This should only be called after the editor is initialized.</b>
16836 * @param {String} cmd The Midas command
16837 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16839 execCmd : function(cmd, value){
16840 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16847 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16849 * @param {String} text | dom node..
16851 insertAtCursor : function(text)
16856 if(!this.activated){
16862 var r = this.doc.selection.createRange();
16873 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16877 // from jquery ui (MIT licenced)
16879 var win = this.win;
16881 if (win.getSelection && win.getSelection().getRangeAt) {
16882 range = win.getSelection().getRangeAt(0);
16883 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16884 range.insertNode(node);
16885 } else if (win.document.selection && win.document.selection.createRange) {
16886 // no firefox support
16887 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16888 win.document.selection.createRange().pasteHTML(txt);
16890 // no firefox support
16891 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16892 this.execCmd('InsertHTML', txt);
16901 mozKeyPress : function(e){
16903 var c = e.getCharCode(), cmd;
16906 c = String.fromCharCode(c).toLowerCase();
16920 this.cleanUpPaste.defer(100, this);
16928 e.preventDefault();
16936 fixKeys : function(){ // load time branching for fastest keydown performance
16938 return function(e){
16939 var k = e.getKey(), r;
16942 r = this.doc.selection.createRange();
16945 r.pasteHTML('    ');
16952 r = this.doc.selection.createRange();
16954 var target = r.parentElement();
16955 if(!target || target.tagName.toLowerCase() != 'li'){
16957 r.pasteHTML('<br />');
16963 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16964 this.cleanUpPaste.defer(100, this);
16970 }else if(Roo.isOpera){
16971 return function(e){
16972 var k = e.getKey();
16976 this.execCmd('InsertHTML','    ');
16979 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16980 this.cleanUpPaste.defer(100, this);
16985 }else if(Roo.isSafari){
16986 return function(e){
16987 var k = e.getKey();
16991 this.execCmd('InsertText','\t');
16995 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16996 this.cleanUpPaste.defer(100, this);
17004 getAllAncestors: function()
17006 var p = this.getSelectedNode();
17009 a.push(p); // push blank onto stack..
17010 p = this.getParentElement();
17014 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17018 a.push(this.doc.body);
17022 lastSelNode : false,
17025 getSelection : function()
17027 this.assignDocWin();
17028 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17031 getSelectedNode: function()
17033 // this may only work on Gecko!!!
17035 // should we cache this!!!!
17040 var range = this.createRange(this.getSelection()).cloneRange();
17043 var parent = range.parentElement();
17045 var testRange = range.duplicate();
17046 testRange.moveToElementText(parent);
17047 if (testRange.inRange(range)) {
17050 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17053 parent = parent.parentElement;
17058 // is ancestor a text element.
17059 var ac = range.commonAncestorContainer;
17060 if (ac.nodeType == 3) {
17061 ac = ac.parentNode;
17064 var ar = ac.childNodes;
17067 var other_nodes = [];
17068 var has_other_nodes = false;
17069 for (var i=0;i<ar.length;i++) {
17070 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17073 // fullly contained node.
17075 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17080 // probably selected..
17081 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17082 other_nodes.push(ar[i]);
17086 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17091 has_other_nodes = true;
17093 if (!nodes.length && other_nodes.length) {
17094 nodes= other_nodes;
17096 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17102 createRange: function(sel)
17104 // this has strange effects when using with
17105 // top toolbar - not sure if it's a great idea.
17106 //this.editor.contentWindow.focus();
17107 if (typeof sel != "undefined") {
17109 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17111 return this.doc.createRange();
17114 return this.doc.createRange();
17117 getParentElement: function()
17120 this.assignDocWin();
17121 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17123 var range = this.createRange(sel);
17126 var p = range.commonAncestorContainer;
17127 while (p.nodeType == 3) { // text node
17138 * Range intersection.. the hard stuff...
17142 * [ -- selected range --- ]
17146 * if end is before start or hits it. fail.
17147 * if start is after end or hits it fail.
17149 * if either hits (but other is outside. - then it's not
17155 // @see http://www.thismuchiknow.co.uk/?p=64.
17156 rangeIntersectsNode : function(range, node)
17158 var nodeRange = node.ownerDocument.createRange();
17160 nodeRange.selectNode(node);
17162 nodeRange.selectNodeContents(node);
17165 var rangeStartRange = range.cloneRange();
17166 rangeStartRange.collapse(true);
17168 var rangeEndRange = range.cloneRange();
17169 rangeEndRange.collapse(false);
17171 var nodeStartRange = nodeRange.cloneRange();
17172 nodeStartRange.collapse(true);
17174 var nodeEndRange = nodeRange.cloneRange();
17175 nodeEndRange.collapse(false);
17177 return rangeStartRange.compareBoundaryPoints(
17178 Range.START_TO_START, nodeEndRange) == -1 &&
17179 rangeEndRange.compareBoundaryPoints(
17180 Range.START_TO_START, nodeStartRange) == 1;
17184 rangeCompareNode : function(range, node)
17186 var nodeRange = node.ownerDocument.createRange();
17188 nodeRange.selectNode(node);
17190 nodeRange.selectNodeContents(node);
17194 range.collapse(true);
17196 nodeRange.collapse(true);
17198 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17199 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17201 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17203 var nodeIsBefore = ss == 1;
17204 var nodeIsAfter = ee == -1;
17206 if (nodeIsBefore && nodeIsAfter)
17208 if (!nodeIsBefore && nodeIsAfter)
17209 return 1; //right trailed.
17211 if (nodeIsBefore && !nodeIsAfter)
17212 return 2; // left trailed.
17217 // private? - in a new class?
17218 cleanUpPaste : function()
17220 // cleans up the whole document..
17221 Roo.log('cleanuppaste');
17223 this.cleanUpChildren(this.doc.body);
17224 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17225 if (clean != this.doc.body.innerHTML) {
17226 this.doc.body.innerHTML = clean;
17231 cleanWordChars : function(input) {// change the chars to hex code
17232 var he = Roo.HtmlEditorCore;
17234 var output = input;
17235 Roo.each(he.swapCodes, function(sw) {
17236 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17238 output = output.replace(swapper, sw[1]);
17245 cleanUpChildren : function (n)
17247 if (!n.childNodes.length) {
17250 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17251 this.cleanUpChild(n.childNodes[i]);
17258 cleanUpChild : function (node)
17261 //console.log(node);
17262 if (node.nodeName == "#text") {
17263 // clean up silly Windows -- stuff?
17266 if (node.nodeName == "#comment") {
17267 node.parentNode.removeChild(node);
17268 // clean up silly Windows -- stuff?
17272 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17274 node.parentNode.removeChild(node);
17279 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17281 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17282 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17284 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17285 // remove_keep_children = true;
17288 if (remove_keep_children) {
17289 this.cleanUpChildren(node);
17290 // inserts everything just before this node...
17291 while (node.childNodes.length) {
17292 var cn = node.childNodes[0];
17293 node.removeChild(cn);
17294 node.parentNode.insertBefore(cn, node);
17296 node.parentNode.removeChild(node);
17300 if (!node.attributes || !node.attributes.length) {
17301 this.cleanUpChildren(node);
17305 function cleanAttr(n,v)
17308 if (v.match(/^\./) || v.match(/^\//)) {
17311 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17314 if (v.match(/^#/)) {
17317 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17318 node.removeAttribute(n);
17322 function cleanStyle(n,v)
17324 if (v.match(/expression/)) { //XSS?? should we even bother..
17325 node.removeAttribute(n);
17328 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17329 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17332 var parts = v.split(/;/);
17335 Roo.each(parts, function(p) {
17336 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17340 var l = p.split(':').shift().replace(/\s+/g,'');
17341 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17343 if ( cblack.indexOf(l) > -1) {
17344 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17345 //node.removeAttribute(n);
17349 // only allow 'c whitelisted system attributes'
17350 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17351 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17352 //node.removeAttribute(n);
17362 if (clean.length) {
17363 node.setAttribute(n, clean.join(';'));
17365 node.removeAttribute(n);
17371 for (var i = node.attributes.length-1; i > -1 ; i--) {
17372 var a = node.attributes[i];
17375 if (a.name.toLowerCase().substr(0,2)=='on') {
17376 node.removeAttribute(a.name);
17379 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17380 node.removeAttribute(a.name);
17383 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17384 cleanAttr(a.name,a.value); // fixme..
17387 if (a.name == 'style') {
17388 cleanStyle(a.name,a.value);
17391 /// clean up MS crap..
17392 // tecnically this should be a list of valid class'es..
17395 if (a.name == 'class') {
17396 if (a.value.match(/^Mso/)) {
17397 node.className = '';
17400 if (a.value.match(/body/)) {
17401 node.className = '';
17412 this.cleanUpChildren(node);
17417 * Clean up MS wordisms...
17419 cleanWord : function(node)
17422 var cleanWordChildren = function()
17424 if (!node.childNodes.length) {
17427 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17428 _t.cleanWord(node.childNodes[i]);
17434 this.cleanWord(this.doc.body);
17437 if (node.nodeName == "#text") {
17438 // clean up silly Windows -- stuff?
17441 if (node.nodeName == "#comment") {
17442 node.parentNode.removeChild(node);
17443 // clean up silly Windows -- stuff?
17447 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17448 node.parentNode.removeChild(node);
17452 // remove - but keep children..
17453 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17454 while (node.childNodes.length) {
17455 var cn = node.childNodes[0];
17456 node.removeChild(cn);
17457 node.parentNode.insertBefore(cn, node);
17459 node.parentNode.removeChild(node);
17460 cleanWordChildren();
17464 if (node.className.length) {
17466 var cn = node.className.split(/\W+/);
17468 Roo.each(cn, function(cls) {
17469 if (cls.match(/Mso[a-zA-Z]+/)) {
17474 node.className = cna.length ? cna.join(' ') : '';
17476 node.removeAttribute("class");
17480 if (node.hasAttribute("lang")) {
17481 node.removeAttribute("lang");
17484 if (node.hasAttribute("style")) {
17486 var styles = node.getAttribute("style").split(";");
17488 Roo.each(styles, function(s) {
17489 if (!s.match(/:/)) {
17492 var kv = s.split(":");
17493 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17496 // what ever is left... we allow.
17499 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17500 if (!nstyle.length) {
17501 node.removeAttribute('style');
17505 cleanWordChildren();
17509 domToHTML : function(currentElement, depth, nopadtext) {
17511 depth = depth || 0;
17512 nopadtext = nopadtext || false;
17514 if (!currentElement) {
17515 return this.domToHTML(this.doc.body);
17518 //Roo.log(currentElement);
17520 var allText = false;
17521 var nodeName = currentElement.nodeName;
17522 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17524 if (nodeName == '#text') {
17525 return currentElement.nodeValue;
17530 if (nodeName != 'BODY') {
17533 // Prints the node tagName, such as <A>, <IMG>, etc
17536 for(i = 0; i < currentElement.attributes.length;i++) {
17538 var aname = currentElement.attributes.item(i).name;
17539 if (!currentElement.attributes.item(i).value.length) {
17542 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17545 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17554 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17557 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17562 // Traverse the tree
17564 var currentElementChild = currentElement.childNodes.item(i);
17565 var allText = true;
17566 var innerHTML = '';
17568 while (currentElementChild) {
17569 // Formatting code (indent the tree so it looks nice on the screen)
17570 var nopad = nopadtext;
17571 if (lastnode == 'SPAN') {
17575 if (currentElementChild.nodeName == '#text') {
17576 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17577 if (!nopad && toadd.length > 80) {
17578 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17580 innerHTML += toadd;
17583 currentElementChild = currentElement.childNodes.item(i);
17589 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17591 // Recursively traverse the tree structure of the child node
17592 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17593 lastnode = currentElementChild.nodeName;
17595 currentElementChild=currentElement.childNodes.item(i);
17601 // The remaining code is mostly for formatting the tree
17602 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17607 ret+= "</"+tagName+">";
17613 // hide stuff that is not compatible
17627 * @event specialkey
17631 * @cfg {String} fieldClass @hide
17634 * @cfg {String} focusClass @hide
17637 * @cfg {String} autoCreate @hide
17640 * @cfg {String} inputType @hide
17643 * @cfg {String} invalidClass @hide
17646 * @cfg {String} invalidText @hide
17649 * @cfg {String} msgFx @hide
17652 * @cfg {String} validateOnBlur @hide
17656 Roo.HtmlEditorCore.white = [
17657 'area', 'br', 'img', 'input', 'hr', 'wbr',
17659 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17660 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17661 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17662 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17663 'table', 'ul', 'xmp',
17665 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17668 'dir', 'menu', 'ol', 'ul', 'dl',
17674 Roo.HtmlEditorCore.black = [
17675 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17677 'base', 'basefont', 'bgsound', 'blink', 'body',
17678 'frame', 'frameset', 'head', 'html', 'ilayer',
17679 'iframe', 'layer', 'link', 'meta', 'object',
17680 'script', 'style' ,'title', 'xml' // clean later..
17682 Roo.HtmlEditorCore.clean = [
17683 'script', 'style', 'title', 'xml'
17685 Roo.HtmlEditorCore.remove = [
17690 Roo.HtmlEditorCore.ablack = [
17694 Roo.HtmlEditorCore.aclean = [
17695 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17699 Roo.HtmlEditorCore.pwhite= [
17700 'http', 'https', 'mailto'
17703 // white listed style attributes.
17704 Roo.HtmlEditorCore.cwhite= [
17705 // 'text-align', /// default is to allow most things..
17711 // black listed style attributes.
17712 Roo.HtmlEditorCore.cblack= [
17713 // 'font-size' -- this can be set by the project
17717 Roo.HtmlEditorCore.swapCodes =[
17736 * @class Roo.bootstrap.HtmlEditor
17737 * @extends Roo.bootstrap.TextArea
17738 * Bootstrap HtmlEditor class
17741 * Create a new HtmlEditor
17742 * @param {Object} config The config object
17745 Roo.bootstrap.HtmlEditor = function(config){
17746 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17747 if (!this.toolbars) {
17748 this.toolbars = [];
17750 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17753 * @event initialize
17754 * Fires when the editor is fully initialized (including the iframe)
17755 * @param {HtmlEditor} this
17760 * Fires when the editor is first receives the focus. Any insertion must wait
17761 * until after this event.
17762 * @param {HtmlEditor} this
17766 * @event beforesync
17767 * Fires before the textarea is updated with content from the editor iframe. Return false
17768 * to cancel the sync.
17769 * @param {HtmlEditor} this
17770 * @param {String} html
17774 * @event beforepush
17775 * Fires before the iframe editor is updated with content from the textarea. Return false
17776 * to cancel the push.
17777 * @param {HtmlEditor} this
17778 * @param {String} html
17783 * Fires when the textarea is updated with content from the editor iframe.
17784 * @param {HtmlEditor} this
17785 * @param {String} html
17790 * Fires when the iframe editor is updated with content from the textarea.
17791 * @param {HtmlEditor} this
17792 * @param {String} html
17796 * @event editmodechange
17797 * Fires when the editor switches edit modes
17798 * @param {HtmlEditor} this
17799 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17801 editmodechange: true,
17803 * @event editorevent
17804 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17805 * @param {HtmlEditor} this
17809 * @event firstfocus
17810 * Fires when on first focus - needed by toolbars..
17811 * @param {HtmlEditor} this
17816 * Auto save the htmlEditor value as a file into Events
17817 * @param {HtmlEditor} this
17821 * @event savedpreview
17822 * preview the saved version of htmlEditor
17823 * @param {HtmlEditor} this
17830 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17834 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17839 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17844 * @cfg {Number} height (in pixels)
17848 * @cfg {Number} width (in pixels)
17853 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17856 stylesheets: false,
17861 // private properties
17862 validationEvent : false,
17864 initialized : false,
17867 onFocus : Roo.emptyFn,
17869 hideMode:'offsets',
17872 tbContainer : false,
17874 toolbarContainer :function() {
17875 return this.wrap.select('.x-html-editor-tb',true).first();
17879 * Protected method that will not generally be called directly. It
17880 * is called when the editor creates its toolbar. Override this method if you need to
17881 * add custom toolbar buttons.
17882 * @param {HtmlEditor} editor
17884 createToolbar : function(){
17886 Roo.log("create toolbars");
17888 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17889 this.toolbars[0].render(this.toolbarContainer());
17893 // if (!editor.toolbars || !editor.toolbars.length) {
17894 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17897 // for (var i =0 ; i < editor.toolbars.length;i++) {
17898 // editor.toolbars[i] = Roo.factory(
17899 // typeof(editor.toolbars[i]) == 'string' ?
17900 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17901 // Roo.bootstrap.HtmlEditor);
17902 // editor.toolbars[i].init(editor);
17908 onRender : function(ct, position)
17910 // Roo.log("Call onRender: " + this.xtype);
17912 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17914 this.wrap = this.inputEl().wrap({
17915 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17918 this.editorcore.onRender(ct, position);
17920 if (this.resizable) {
17921 this.resizeEl = new Roo.Resizable(this.wrap, {
17925 minHeight : this.height,
17926 height: this.height,
17927 handles : this.resizable,
17930 resize : function(r, w, h) {
17931 _t.onResize(w,h); // -something
17937 this.createToolbar(this);
17940 if(!this.width && this.resizable){
17941 this.setSize(this.wrap.getSize());
17943 if (this.resizeEl) {
17944 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17945 // should trigger onReize..
17951 onResize : function(w, h)
17953 Roo.log('resize: ' +w + ',' + h );
17954 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17958 if(this.inputEl() ){
17959 if(typeof w == 'number'){
17960 var aw = w - this.wrap.getFrameWidth('lr');
17961 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17964 if(typeof h == 'number'){
17965 var tbh = -11; // fixme it needs to tool bar size!
17966 for (var i =0; i < this.toolbars.length;i++) {
17967 // fixme - ask toolbars for heights?
17968 tbh += this.toolbars[i].el.getHeight();
17969 //if (this.toolbars[i].footer) {
17970 // tbh += this.toolbars[i].footer.el.getHeight();
17978 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17979 ah -= 5; // knock a few pixes off for look..
17980 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17984 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17985 this.editorcore.onResize(ew,eh);
17990 * Toggles the editor between standard and source edit mode.
17991 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17993 toggleSourceEdit : function(sourceEditMode)
17995 this.editorcore.toggleSourceEdit(sourceEditMode);
17997 if(this.editorcore.sourceEditMode){
17998 Roo.log('editor - showing textarea');
18001 // Roo.log(this.syncValue());
18003 this.inputEl().removeClass(['hide', 'x-hidden']);
18004 this.inputEl().dom.removeAttribute('tabIndex');
18005 this.inputEl().focus();
18007 Roo.log('editor - hiding textarea');
18009 // Roo.log(this.pushValue());
18012 this.inputEl().addClass(['hide', 'x-hidden']);
18013 this.inputEl().dom.setAttribute('tabIndex', -1);
18014 //this.deferFocus();
18017 if(this.resizable){
18018 this.setSize(this.wrap.getSize());
18021 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18024 // private (for BoxComponent)
18025 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18027 // private (for BoxComponent)
18028 getResizeEl : function(){
18032 // private (for BoxComponent)
18033 getPositionEl : function(){
18038 initEvents : function(){
18039 this.originalValue = this.getValue();
18043 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18046 // markInvalid : Roo.emptyFn,
18048 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18051 // clearInvalid : Roo.emptyFn,
18053 setValue : function(v){
18054 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18055 this.editorcore.pushValue();
18060 deferFocus : function(){
18061 this.focus.defer(10, this);
18065 focus : function(){
18066 this.editorcore.focus();
18072 onDestroy : function(){
18078 for (var i =0; i < this.toolbars.length;i++) {
18079 // fixme - ask toolbars for heights?
18080 this.toolbars[i].onDestroy();
18083 this.wrap.dom.innerHTML = '';
18084 this.wrap.remove();
18089 onFirstFocus : function(){
18090 //Roo.log("onFirstFocus");
18091 this.editorcore.onFirstFocus();
18092 for (var i =0; i < this.toolbars.length;i++) {
18093 this.toolbars[i].onFirstFocus();
18099 syncValue : function()
18101 this.editorcore.syncValue();
18104 pushValue : function()
18106 this.editorcore.pushValue();
18110 // hide stuff that is not compatible
18124 * @event specialkey
18128 * @cfg {String} fieldClass @hide
18131 * @cfg {String} focusClass @hide
18134 * @cfg {String} autoCreate @hide
18137 * @cfg {String} inputType @hide
18140 * @cfg {String} invalidClass @hide
18143 * @cfg {String} invalidText @hide
18146 * @cfg {String} msgFx @hide
18149 * @cfg {String} validateOnBlur @hide
18158 Roo.namespace('Roo.bootstrap.htmleditor');
18160 * @class Roo.bootstrap.HtmlEditorToolbar1
18165 new Roo.bootstrap.HtmlEditor({
18168 new Roo.bootstrap.HtmlEditorToolbar1({
18169 disable : { fonts: 1 , format: 1, ..., ... , ...],
18175 * @cfg {Object} disable List of elements to disable..
18176 * @cfg {Array} btns List of additional buttons.
18180 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18183 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18186 Roo.apply(this, config);
18188 // default disabled, based on 'good practice'..
18189 this.disable = this.disable || {};
18190 Roo.applyIf(this.disable, {
18193 specialElements : true
18195 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18197 this.editor = config.editor;
18198 this.editorcore = config.editor.editorcore;
18200 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18202 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18203 // dont call parent... till later.
18205 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18210 editorcore : false,
18215 "h1","h2","h3","h4","h5","h6",
18217 "abbr", "acronym", "address", "cite", "samp", "var",
18221 onRender : function(ct, position)
18223 // Roo.log("Call onRender: " + this.xtype);
18225 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18227 this.el.dom.style.marginBottom = '0';
18229 var editorcore = this.editorcore;
18230 var editor= this.editor;
18233 var btn = function(id,cmd , toggle, handler){
18235 var event = toggle ? 'toggle' : 'click';
18240 xns: Roo.bootstrap,
18243 enableToggle:toggle !== false,
18245 pressed : toggle ? false : null,
18248 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18249 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18258 xns: Roo.bootstrap,
18259 glyphicon : 'font',
18263 xns: Roo.bootstrap,
18267 Roo.each(this.formats, function(f) {
18268 style.menu.items.push({
18270 xns: Roo.bootstrap,
18271 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18276 editorcore.insertTag(this.tagname);
18283 children.push(style);
18286 btn('bold',false,true);
18287 btn('italic',false,true);
18288 btn('align-left', 'justifyleft',true);
18289 btn('align-center', 'justifycenter',true);
18290 btn('align-right' , 'justifyright',true);
18291 btn('link', false, false, function(btn) {
18292 //Roo.log("create link?");
18293 var url = prompt(this.createLinkText, this.defaultLinkValue);
18294 if(url && url != 'http:/'+'/'){
18295 this.editorcore.relayCmd('createlink', url);
18298 btn('list','insertunorderedlist',true);
18299 btn('pencil', false,true, function(btn){
18302 this.toggleSourceEdit(btn.pressed);
18308 xns: Roo.bootstrap,
18313 xns: Roo.bootstrap,
18318 cog.menu.items.push({
18320 xns: Roo.bootstrap,
18321 html : Clean styles,
18326 editorcore.insertTag(this.tagname);
18335 this.xtype = 'NavSimplebar';
18337 for(var i=0;i< children.length;i++) {
18339 this.buttons.add(this.addxtypeChild(children[i]));
18343 editor.on('editorevent', this.updateToolbar, this);
18345 onBtnClick : function(id)
18347 this.editorcore.relayCmd(id);
18348 this.editorcore.focus();
18352 * Protected method that will not generally be called directly. It triggers
18353 * a toolbar update by reading the markup state of the current selection in the editor.
18355 updateToolbar: function(){
18357 if(!this.editorcore.activated){
18358 this.editor.onFirstFocus(); // is this neeed?
18362 var btns = this.buttons;
18363 var doc = this.editorcore.doc;
18364 btns.get('bold').setActive(doc.queryCommandState('bold'));
18365 btns.get('italic').setActive(doc.queryCommandState('italic'));
18366 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18368 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18369 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18370 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18372 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18373 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18376 var ans = this.editorcore.getAllAncestors();
18377 if (this.formatCombo) {
18380 var store = this.formatCombo.store;
18381 this.formatCombo.setValue("");
18382 for (var i =0; i < ans.length;i++) {
18383 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18385 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18393 // hides menus... - so this cant be on a menu...
18394 Roo.bootstrap.MenuMgr.hideAll();
18396 Roo.bootstrap.MenuMgr.hideAll();
18397 //this.editorsyncValue();
18399 onFirstFocus: function() {
18400 this.buttons.each(function(item){
18404 toggleSourceEdit : function(sourceEditMode){
18407 if(sourceEditMode){
18408 Roo.log("disabling buttons");
18409 this.buttons.each( function(item){
18410 if(item.cmd != 'pencil'){
18416 Roo.log("enabling buttons");
18417 if(this.editorcore.initialized){
18418 this.buttons.each( function(item){
18424 Roo.log("calling toggole on editor");
18425 // tell the editor that it's been pressed..
18426 this.editor.toggleSourceEdit(sourceEditMode);
18436 * @class Roo.bootstrap.Table.AbstractSelectionModel
18437 * @extends Roo.util.Observable
18438 * Abstract base class for grid SelectionModels. It provides the interface that should be
18439 * implemented by descendant classes. This class should not be directly instantiated.
18442 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18443 this.locked = false;
18444 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18448 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18449 /** @ignore Called by the grid automatically. Do not call directly. */
18450 init : function(grid){
18456 * Locks the selections.
18459 this.locked = true;
18463 * Unlocks the selections.
18465 unlock : function(){
18466 this.locked = false;
18470 * Returns true if the selections are locked.
18471 * @return {Boolean}
18473 isLocked : function(){
18474 return this.locked;
18478 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18479 * @class Roo.bootstrap.Table.RowSelectionModel
18480 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18481 * It supports multiple selections and keyboard selection/navigation.
18483 * @param {Object} config
18486 Roo.bootstrap.Table.RowSelectionModel = function(config){
18487 Roo.apply(this, config);
18488 this.selections = new Roo.util.MixedCollection(false, function(o){
18493 this.lastActive = false;
18497 * @event selectionchange
18498 * Fires when the selection changes
18499 * @param {SelectionModel} this
18501 "selectionchange" : true,
18503 * @event afterselectionchange
18504 * Fires after the selection changes (eg. by key press or clicking)
18505 * @param {SelectionModel} this
18507 "afterselectionchange" : true,
18509 * @event beforerowselect
18510 * Fires when a row is selected being selected, return false to cancel.
18511 * @param {SelectionModel} this
18512 * @param {Number} rowIndex The selected index
18513 * @param {Boolean} keepExisting False if other selections will be cleared
18515 "beforerowselect" : true,
18518 * Fires when a row is selected.
18519 * @param {SelectionModel} this
18520 * @param {Number} rowIndex The selected index
18521 * @param {Roo.data.Record} r The record
18523 "rowselect" : true,
18525 * @event rowdeselect
18526 * Fires when a row is deselected.
18527 * @param {SelectionModel} this
18528 * @param {Number} rowIndex The selected index
18530 "rowdeselect" : true
18532 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18533 this.locked = false;
18536 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18538 * @cfg {Boolean} singleSelect
18539 * True to allow selection of only one row at a time (defaults to false)
18541 singleSelect : false,
18544 initEvents : function(){
18546 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18547 this.grid.on("mousedown", this.handleMouseDown, this);
18548 }else{ // allow click to work like normal
18549 this.grid.on("rowclick", this.handleDragableRowClick, this);
18552 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18553 "up" : function(e){
18555 this.selectPrevious(e.shiftKey);
18556 }else if(this.last !== false && this.lastActive !== false){
18557 var last = this.last;
18558 this.selectRange(this.last, this.lastActive-1);
18559 this.grid.getView().focusRow(this.lastActive);
18560 if(last !== false){
18564 this.selectFirstRow();
18566 this.fireEvent("afterselectionchange", this);
18568 "down" : function(e){
18570 this.selectNext(e.shiftKey);
18571 }else if(this.last !== false && this.lastActive !== false){
18572 var last = this.last;
18573 this.selectRange(this.last, this.lastActive+1);
18574 this.grid.getView().focusRow(this.lastActive);
18575 if(last !== false){
18579 this.selectFirstRow();
18581 this.fireEvent("afterselectionchange", this);
18586 var view = this.grid.view;
18587 view.on("refresh", this.onRefresh, this);
18588 view.on("rowupdated", this.onRowUpdated, this);
18589 view.on("rowremoved", this.onRemove, this);
18593 onRefresh : function(){
18594 var ds = this.grid.dataSource, i, v = this.grid.view;
18595 var s = this.selections;
18596 s.each(function(r){
18597 if((i = ds.indexOfId(r.id)) != -1){
18606 onRemove : function(v, index, r){
18607 this.selections.remove(r);
18611 onRowUpdated : function(v, index, r){
18612 if(this.isSelected(r)){
18613 v.onRowSelect(index);
18619 * @param {Array} records The records to select
18620 * @param {Boolean} keepExisting (optional) True to keep existing selections
18622 selectRecords : function(records, keepExisting){
18624 this.clearSelections();
18626 var ds = this.grid.dataSource;
18627 for(var i = 0, len = records.length; i < len; i++){
18628 this.selectRow(ds.indexOf(records[i]), true);
18633 * Gets the number of selected rows.
18636 getCount : function(){
18637 return this.selections.length;
18641 * Selects the first row in the grid.
18643 selectFirstRow : function(){
18648 * Select the last row.
18649 * @param {Boolean} keepExisting (optional) True to keep existing selections
18651 selectLastRow : function(keepExisting){
18652 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18656 * Selects the row immediately following the last selected row.
18657 * @param {Boolean} keepExisting (optional) True to keep existing selections
18659 selectNext : function(keepExisting){
18660 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18661 this.selectRow(this.last+1, keepExisting);
18662 this.grid.getView().focusRow(this.last);
18667 * Selects the row that precedes the last selected row.
18668 * @param {Boolean} keepExisting (optional) True to keep existing selections
18670 selectPrevious : function(keepExisting){
18672 this.selectRow(this.last-1, keepExisting);
18673 this.grid.getView().focusRow(this.last);
18678 * Returns the selected records
18679 * @return {Array} Array of selected records
18681 getSelections : function(){
18682 return [].concat(this.selections.items);
18686 * Returns the first selected record.
18689 getSelected : function(){
18690 return this.selections.itemAt(0);
18695 * Clears all selections.
18697 clearSelections : function(fast){
18698 if(this.locked) return;
18700 var ds = this.grid.dataSource;
18701 var s = this.selections;
18702 s.each(function(r){
18703 this.deselectRow(ds.indexOfId(r.id));
18707 this.selections.clear();
18714 * Selects all rows.
18716 selectAll : function(){
18717 if(this.locked) return;
18718 this.selections.clear();
18719 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18720 this.selectRow(i, true);
18725 * Returns True if there is a selection.
18726 * @return {Boolean}
18728 hasSelection : function(){
18729 return this.selections.length > 0;
18733 * Returns True if the specified row is selected.
18734 * @param {Number/Record} record The record or index of the record to check
18735 * @return {Boolean}
18737 isSelected : function(index){
18738 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18739 return (r && this.selections.key(r.id) ? true : false);
18743 * Returns True if the specified record id is selected.
18744 * @param {String} id The id of record to check
18745 * @return {Boolean}
18747 isIdSelected : function(id){
18748 return (this.selections.key(id) ? true : false);
18752 handleMouseDown : function(e, t){
18753 var view = this.grid.getView(), rowIndex;
18754 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18757 if(e.shiftKey && this.last !== false){
18758 var last = this.last;
18759 this.selectRange(last, rowIndex, e.ctrlKey);
18760 this.last = last; // reset the last
18761 view.focusRow(rowIndex);
18763 var isSelected = this.isSelected(rowIndex);
18764 if(e.button !== 0 && isSelected){
18765 view.focusRow(rowIndex);
18766 }else if(e.ctrlKey && isSelected){
18767 this.deselectRow(rowIndex);
18768 }else if(!isSelected){
18769 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18770 view.focusRow(rowIndex);
18773 this.fireEvent("afterselectionchange", this);
18776 handleDragableRowClick : function(grid, rowIndex, e)
18778 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18779 this.selectRow(rowIndex, false);
18780 grid.view.focusRow(rowIndex);
18781 this.fireEvent("afterselectionchange", this);
18786 * Selects multiple rows.
18787 * @param {Array} rows Array of the indexes of the row to select
18788 * @param {Boolean} keepExisting (optional) True to keep existing selections
18790 selectRows : function(rows, keepExisting){
18792 this.clearSelections();
18794 for(var i = 0, len = rows.length; i < len; i++){
18795 this.selectRow(rows[i], true);
18800 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18801 * @param {Number} startRow The index of the first row in the range
18802 * @param {Number} endRow The index of the last row in the range
18803 * @param {Boolean} keepExisting (optional) True to retain existing selections
18805 selectRange : function(startRow, endRow, keepExisting){
18806 if(this.locked) return;
18808 this.clearSelections();
18810 if(startRow <= endRow){
18811 for(var i = startRow; i <= endRow; i++){
18812 this.selectRow(i, true);
18815 for(var i = startRow; i >= endRow; i--){
18816 this.selectRow(i, true);
18822 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18823 * @param {Number} startRow The index of the first row in the range
18824 * @param {Number} endRow The index of the last row in the range
18826 deselectRange : function(startRow, endRow, preventViewNotify){
18827 if(this.locked) return;
18828 for(var i = startRow; i <= endRow; i++){
18829 this.deselectRow(i, preventViewNotify);
18835 * @param {Number} row The index of the row to select
18836 * @param {Boolean} keepExisting (optional) True to keep existing selections
18838 selectRow : function(index, keepExisting, preventViewNotify){
18839 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18840 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18841 if(!keepExisting || this.singleSelect){
18842 this.clearSelections();
18844 var r = this.grid.dataSource.getAt(index);
18845 this.selections.add(r);
18846 this.last = this.lastActive = index;
18847 if(!preventViewNotify){
18848 this.grid.getView().onRowSelect(index);
18850 this.fireEvent("rowselect", this, index, r);
18851 this.fireEvent("selectionchange", this);
18857 * @param {Number} row The index of the row to deselect
18859 deselectRow : function(index, preventViewNotify){
18860 if(this.locked) return;
18861 if(this.last == index){
18864 if(this.lastActive == index){
18865 this.lastActive = false;
18867 var r = this.grid.dataSource.getAt(index);
18868 this.selections.remove(r);
18869 if(!preventViewNotify){
18870 this.grid.getView().onRowDeselect(index);
18872 this.fireEvent("rowdeselect", this, index);
18873 this.fireEvent("selectionchange", this);
18877 restoreLast : function(){
18879 this.last = this._last;
18884 acceptsNav : function(row, col, cm){
18885 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18889 onEditorKey : function(field, e){
18890 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18895 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18897 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18899 }else if(k == e.ENTER && !e.ctrlKey){
18903 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18905 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18907 }else if(k == e.ESC){
18911 g.startEditing(newCell[0], newCell[1]);
18916 * Ext JS Library 1.1.1
18917 * Copyright(c) 2006-2007, Ext JS, LLC.
18919 * Originally Released Under LGPL - original licence link has changed is not relivant.
18922 * <script type="text/javascript">
18926 * @class Roo.bootstrap.PagingToolbar
18928 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18930 * Create a new PagingToolbar
18931 * @param {Object} config The config object
18933 Roo.bootstrap.PagingToolbar = function(config)
18935 // old args format still supported... - xtype is prefered..
18936 // created from xtype...
18937 var ds = config.dataSource;
18938 this.toolbarItems = [];
18939 if (config.items) {
18940 this.toolbarItems = config.items;
18941 // config.items = [];
18944 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18951 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18955 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18957 * @cfg {Roo.data.Store} dataSource
18958 * The underlying data store providing the paged data
18961 * @cfg {String/HTMLElement/Element} container
18962 * container The id or element that will contain the toolbar
18965 * @cfg {Boolean} displayInfo
18966 * True to display the displayMsg (defaults to false)
18969 * @cfg {Number} pageSize
18970 * The number of records to display per page (defaults to 20)
18974 * @cfg {String} displayMsg
18975 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18977 displayMsg : 'Displaying {0} - {1} of {2}',
18979 * @cfg {String} emptyMsg
18980 * The message to display when no records are found (defaults to "No data to display")
18982 emptyMsg : 'No data to display',
18984 * Customizable piece of the default paging text (defaults to "Page")
18987 beforePageText : "Page",
18989 * Customizable piece of the default paging text (defaults to "of %0")
18992 afterPageText : "of {0}",
18994 * Customizable piece of the default paging text (defaults to "First Page")
18997 firstText : "First Page",
18999 * Customizable piece of the default paging text (defaults to "Previous Page")
19002 prevText : "Previous Page",
19004 * Customizable piece of the default paging text (defaults to "Next Page")
19007 nextText : "Next Page",
19009 * Customizable piece of the default paging text (defaults to "Last Page")
19012 lastText : "Last Page",
19014 * Customizable piece of the default paging text (defaults to "Refresh")
19017 refreshText : "Refresh",
19021 onRender : function(ct, position)
19023 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19024 this.navgroup.parentId = this.id;
19025 this.navgroup.onRender(this.el, null);
19026 // add the buttons to the navgroup
19028 if(this.displayInfo){
19029 Roo.log(this.el.select('ul.navbar-nav',true).first());
19030 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19031 this.displayEl = this.el.select('.x-paging-info', true).first();
19032 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19033 // this.displayEl = navel.el.select('span',true).first();
19039 Roo.each(_this.buttons, function(e){
19040 Roo.factory(e).onRender(_this.el, null);
19044 Roo.each(_this.toolbarItems, function(e) {
19045 _this.navgroup.addItem(e);
19048 this.first = this.navgroup.addItem({
19049 tooltip: this.firstText,
19051 icon : 'fa fa-backward',
19053 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19056 this.prev = this.navgroup.addItem({
19057 tooltip: this.prevText,
19059 icon : 'fa fa-step-backward',
19061 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19063 //this.addSeparator();
19066 var field = this.navgroup.addItem( {
19068 cls : 'x-paging-position',
19070 html : this.beforePageText +
19071 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19072 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19075 this.field = field.el.select('input', true).first();
19076 this.field.on("keydown", this.onPagingKeydown, this);
19077 this.field.on("focus", function(){this.dom.select();});
19080 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19081 //this.field.setHeight(18);
19082 //this.addSeparator();
19083 this.next = this.navgroup.addItem({
19084 tooltip: this.nextText,
19086 html : ' <i class="fa fa-step-forward">',
19088 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19090 this.last = this.navgroup.addItem({
19091 tooltip: this.lastText,
19092 icon : 'fa fa-forward',
19095 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19097 //this.addSeparator();
19098 this.loading = this.navgroup.addItem({
19099 tooltip: this.refreshText,
19100 icon: 'fa fa-refresh',
19102 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19108 updateInfo : function(){
19109 if(this.displayEl){
19110 var count = this.ds.getCount();
19111 var msg = count == 0 ?
19115 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19117 this.displayEl.update(msg);
19122 onLoad : function(ds, r, o){
19123 this.cursor = o.params ? o.params.start : 0;
19124 var d = this.getPageData(),
19128 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19129 this.field.dom.value = ap;
19130 this.first.setDisabled(ap == 1);
19131 this.prev.setDisabled(ap == 1);
19132 this.next.setDisabled(ap == ps);
19133 this.last.setDisabled(ap == ps);
19134 this.loading.enable();
19139 getPageData : function(){
19140 var total = this.ds.getTotalCount();
19143 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19144 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19149 onLoadError : function(){
19150 this.loading.enable();
19154 onPagingKeydown : function(e){
19155 var k = e.getKey();
19156 var d = this.getPageData();
19158 var v = this.field.dom.value, pageNum;
19159 if(!v || isNaN(pageNum = parseInt(v, 10))){
19160 this.field.dom.value = d.activePage;
19163 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19164 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19167 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))
19169 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19170 this.field.dom.value = pageNum;
19171 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19174 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19176 var v = this.field.dom.value, pageNum;
19177 var increment = (e.shiftKey) ? 10 : 1;
19178 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19180 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19181 this.field.dom.value = d.activePage;
19184 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19186 this.field.dom.value = parseInt(v, 10) + increment;
19187 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19188 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19195 beforeLoad : function(){
19197 this.loading.disable();
19202 onClick : function(which){
19209 ds.load({params:{start: 0, limit: this.pageSize}});
19212 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19215 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19218 var total = ds.getTotalCount();
19219 var extra = total % this.pageSize;
19220 var lastStart = extra ? (total - extra) : total-this.pageSize;
19221 ds.load({params:{start: lastStart, limit: this.pageSize}});
19224 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19230 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19231 * @param {Roo.data.Store} store The data store to unbind
19233 unbind : function(ds){
19234 ds.un("beforeload", this.beforeLoad, this);
19235 ds.un("load", this.onLoad, this);
19236 ds.un("loadexception", this.onLoadError, this);
19237 ds.un("remove", this.updateInfo, this);
19238 ds.un("add", this.updateInfo, this);
19239 this.ds = undefined;
19243 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19244 * @param {Roo.data.Store} store The data store to bind
19246 bind : function(ds){
19247 ds.on("beforeload", this.beforeLoad, this);
19248 ds.on("load", this.onLoad, this);
19249 ds.on("loadexception", this.onLoadError, this);
19250 ds.on("remove", this.updateInfo, this);
19251 ds.on("add", this.updateInfo, this);
19262 * @class Roo.bootstrap.MessageBar
19263 * @extends Roo.bootstrap.Component
19264 * Bootstrap MessageBar class
19265 * @cfg {String} html contents of the MessageBar
19266 * @cfg {String} weight (info | success | warning | danger) default info
19267 * @cfg {String} beforeClass insert the bar before the given class
19268 * @cfg {Boolean} closable (true | false) default false
19269 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19272 * Create a new Element
19273 * @param {Object} config The config object
19276 Roo.bootstrap.MessageBar = function(config){
19277 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19280 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19286 beforeClass: 'bootstrap-sticky-wrap',
19288 getAutoCreate : function(){
19292 cls: 'alert alert-dismissable alert-' + this.weight,
19297 html: this.html || ''
19303 cfg.cls += ' alert-messages-fixed';
19317 onRender : function(ct, position)
19319 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19322 var cfg = Roo.apply({}, this.getAutoCreate());
19326 cfg.cls += ' ' + this.cls;
19329 cfg.style = this.style;
19331 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19333 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19336 this.el.select('>button.close').on('click', this.hide, this);
19342 if (!this.rendered) {
19348 this.fireEvent('show', this);
19354 if (!this.rendered) {
19360 this.fireEvent('hide', this);
19363 update : function()
19365 // var e = this.el.dom.firstChild;
19367 // if(this.closable){
19368 // e = e.nextSibling;
19371 // e.data = this.html || '';
19373 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19389 * @class Roo.bootstrap.Graph
19390 * @extends Roo.bootstrap.Component
19391 * Bootstrap Graph class
19395 @cfg {String} graphtype bar | vbar | pie
19396 @cfg {number} g_x coodinator | centre x (pie)
19397 @cfg {number} g_y coodinator | centre y (pie)
19398 @cfg {number} g_r radius (pie)
19399 @cfg {number} g_height height of the chart (respected by all elements in the set)
19400 @cfg {number} g_width width of the chart (respected by all elements in the set)
19401 @cfg {Object} title The title of the chart
19404 -opts (object) options for the chart
19406 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19407 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19409 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.
19410 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19412 o stretch (boolean)
19414 -opts (object) options for the pie
19417 o startAngle (number)
19418 o endAngle (number)
19422 * Create a new Input
19423 * @param {Object} config The config object
19426 Roo.bootstrap.Graph = function(config){
19427 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19433 * The img click event for the img.
19434 * @param {Roo.EventObject} e
19440 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19451 //g_colors: this.colors,
19458 getAutoCreate : function(){
19469 onRender : function(ct,position){
19470 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19471 this.raphael = Raphael(this.el.dom);
19473 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19474 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19475 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19476 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19478 r.text(160, 10, "Single Series Chart").attr(txtattr);
19479 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19480 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19481 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19483 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19484 r.barchart(330, 10, 300, 220, data1);
19485 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19486 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19489 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19490 // r.barchart(30, 30, 560, 250, xdata, {
19491 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19492 // axis : "0 0 1 1",
19493 // axisxlabels : xdata
19494 // //yvalues : cols,
19497 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19499 // this.load(null,xdata,{
19500 // axis : "0 0 1 1",
19501 // axisxlabels : xdata
19506 load : function(graphtype,xdata,opts){
19507 this.raphael.clear();
19509 graphtype = this.graphtype;
19514 var r = this.raphael,
19515 fin = function () {
19516 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19518 fout = function () {
19519 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19521 pfin = function() {
19522 this.sector.stop();
19523 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19526 this.label[0].stop();
19527 this.label[0].attr({ r: 7.5 });
19528 this.label[1].attr({ "font-weight": 800 });
19531 pfout = function() {
19532 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19535 this.label[0].animate({ r: 5 }, 500, "bounce");
19536 this.label[1].attr({ "font-weight": 400 });
19542 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19545 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19548 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19549 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19551 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19558 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19563 setTitle: function(o)
19568 initEvents: function() {
19571 this.el.on('click', this.onClick, this);
19575 onClick : function(e)
19577 Roo.log('img onclick');
19578 this.fireEvent('click', this, e);
19590 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19593 * @class Roo.bootstrap.dash.NumberBox
19594 * @extends Roo.bootstrap.Component
19595 * Bootstrap NumberBox class
19596 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19597 * @cfg {String} headline Box headline
19598 * @cfg {String} content Box content
19599 * @cfg {String} icon Box icon
19600 * @cfg {String} footer Footer text
19601 * @cfg {String} fhref Footer href
19604 * Create a new NumberBox
19605 * @param {Object} config The config object
19609 Roo.bootstrap.dash.NumberBox = function(config){
19610 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19614 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19624 getAutoCreate : function(){
19628 cls : 'small-box bg-' + this.bgcolor,
19636 cls : 'roo-headline',
19637 html : this.headline
19641 cls : 'roo-content',
19642 html : this.content
19656 cls : 'ion ' + this.icon
19665 cls : 'small-box-footer',
19666 href : this.fhref || '#',
19670 cfg.cn.push(footer);
19677 onRender : function(ct,position){
19678 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19685 setHeadline: function (value)
19687 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19690 setFooter: function (value, href)
19692 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19695 this.el.select('a.small-box-footer',true).first().attr('href', href);
19700 setContent: function (value)
19702 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19705 initEvents: function()
19719 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19722 * @class Roo.bootstrap.dash.TabBox
19723 * @extends Roo.bootstrap.Component
19724 * Bootstrap TabBox class
19725 * @cfg {String} title Title of the TabBox
19726 * @cfg {String} icon Icon of the TabBox
19727 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19730 * Create a new TabBox
19731 * @param {Object} config The config object
19735 Roo.bootstrap.dash.TabBox = function(config){
19736 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19741 * When a pane is added
19742 * @param {Roo.bootstrap.dash.TabPane} pane
19749 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19755 getChildContainer : function()
19757 return this.el.select('.tab-content', true).first();
19760 getAutoCreate : function(){
19764 cls: 'pull-left header',
19772 cls: 'fa ' + this.icon
19779 cls: 'nav-tabs-custom',
19783 cls: 'nav nav-tabs pull-right',
19790 cls: 'tab-content no-padding',
19798 initEvents : function()
19800 //Roo.log('add add pane handler');
19801 this.on('addpane', this.onAddPane, this);
19804 * Updates the box title
19805 * @param {String} html to set the title to.
19807 setTitle : function(value)
19809 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19811 onAddPane : function(pane)
19813 //Roo.log('addpane');
19815 // tabs are rendere left to right..
19816 if(!this.showtabs){
19820 var ctr = this.el.select('.nav-tabs', true).first();
19823 var existing = ctr.select('.nav-tab',true);
19824 var qty = existing.getCount();;
19827 var tab = ctr.createChild({
19829 cls : 'nav-tab' + (qty ? '' : ' active'),
19837 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19840 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19842 pane.el.addClass('active');
19847 onTabClick : function(ev,un,ob,pane)
19849 //Roo.log('tab - prev default');
19850 ev.preventDefault();
19853 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19854 pane.tab.addClass('active');
19855 //Roo.log(pane.title);
19856 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19857 // technically we should have a deactivate event.. but maybe add later.
19858 // and it should not de-activate the selected tab...
19860 pane.el.addClass('active');
19861 pane.fireEvent('activate');
19876 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19878 * @class Roo.bootstrap.TabPane
19879 * @extends Roo.bootstrap.Component
19880 * Bootstrap TabPane class
19881 * @cfg {Boolean} active (false | true) Default false
19882 * @cfg {String} title title of panel
19886 * Create a new TabPane
19887 * @param {Object} config The config object
19890 Roo.bootstrap.dash.TabPane = function(config){
19891 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19897 * When a pane is activated
19898 * @param {Roo.bootstrap.dash.TabPane} pane
19905 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19910 // the tabBox that this is attached to.
19913 getAutoCreate : function()
19921 cfg.cls += ' active';
19926 initEvents : function()
19928 //Roo.log('trigger add pane handler');
19929 this.parent().fireEvent('addpane', this)
19933 * Updates the tab title
19934 * @param {String} html to set the title to.
19936 setTitle: function(str)
19942 this.tab.select('a', true).first().dom.innerHTML = str;
19959 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19962 * @class Roo.bootstrap.menu.Menu
19963 * @extends Roo.bootstrap.Component
19964 * Bootstrap Menu class - container for Menu
19965 * @cfg {String} html Text of the menu
19966 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19967 * @cfg {String} icon Font awesome icon
19968 * @cfg {String} pos Menu align to (top | bottom) default bottom
19972 * Create a new Menu
19973 * @param {Object} config The config object
19977 Roo.bootstrap.menu.Menu = function(config){
19978 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19982 * @event beforeshow
19983 * Fires before this menu is displayed
19984 * @param {Roo.bootstrap.menu.Menu} this
19988 * @event beforehide
19989 * Fires before this menu is hidden
19990 * @param {Roo.bootstrap.menu.Menu} this
19995 * Fires after this menu is displayed
19996 * @param {Roo.bootstrap.menu.Menu} this
20001 * Fires after this menu is hidden
20002 * @param {Roo.bootstrap.menu.Menu} this
20007 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20008 * @param {Roo.bootstrap.menu.Menu} this
20009 * @param {Roo.EventObject} e
20016 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20020 weight : 'default',
20025 getChildContainer : function() {
20026 if(this.isSubMenu){
20030 return this.el.select('ul.dropdown-menu', true).first();
20033 getAutoCreate : function()
20038 cls : 'roo-menu-text',
20046 cls : 'fa ' + this.icon
20057 cls : 'dropdown-button btn btn-' + this.weight,
20062 cls : 'dropdown-toggle btn btn-' + this.weight,
20072 cls : 'dropdown-menu'
20078 if(this.pos == 'top'){
20079 cfg.cls += ' dropup';
20082 if(this.isSubMenu){
20085 cls : 'dropdown-menu'
20092 onRender : function(ct, position)
20094 this.isSubMenu = ct.hasClass('dropdown-submenu');
20096 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20099 initEvents : function()
20101 if(this.isSubMenu){
20105 this.hidden = true;
20107 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20108 this.triggerEl.on('click', this.onTriggerPress, this);
20110 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20111 this.buttonEl.on('click', this.onClick, this);
20117 if(this.isSubMenu){
20121 return this.el.select('ul.dropdown-menu', true).first();
20124 onClick : function(e)
20126 this.fireEvent("click", this, e);
20129 onTriggerPress : function(e)
20131 if (this.isVisible()) {
20138 isVisible : function(){
20139 return !this.hidden;
20144 this.fireEvent("beforeshow", this);
20146 this.hidden = false;
20147 this.el.addClass('open');
20149 Roo.get(document).on("mouseup", this.onMouseUp, this);
20151 this.fireEvent("show", this);
20158 this.fireEvent("beforehide", this);
20160 this.hidden = true;
20161 this.el.removeClass('open');
20163 Roo.get(document).un("mouseup", this.onMouseUp);
20165 this.fireEvent("hide", this);
20168 onMouseUp : function()
20182 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20185 * @class Roo.bootstrap.menu.Item
20186 * @extends Roo.bootstrap.Component
20187 * Bootstrap MenuItem class
20188 * @cfg {Boolean} submenu (true | false) default false
20189 * @cfg {String} html text of the item
20190 * @cfg {String} href the link
20191 * @cfg {Boolean} disable (true | false) default false
20192 * @cfg {Boolean} preventDefault (true | false) default true
20193 * @cfg {String} icon Font awesome icon
20194 * @cfg {String} pos Submenu align to (left | right) default right
20198 * Create a new Item
20199 * @param {Object} config The config object
20203 Roo.bootstrap.menu.Item = function(config){
20204 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20208 * Fires when the mouse is hovering over this menu
20209 * @param {Roo.bootstrap.menu.Item} this
20210 * @param {Roo.EventObject} e
20215 * Fires when the mouse exits this menu
20216 * @param {Roo.bootstrap.menu.Item} this
20217 * @param {Roo.EventObject} e
20223 * The raw click event for the entire grid.
20224 * @param {Roo.EventObject} e
20230 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20235 preventDefault: true,
20240 getAutoCreate : function()
20245 cls : 'roo-menu-item-text',
20253 cls : 'fa ' + this.icon
20262 href : this.href || '#',
20269 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20273 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20275 if(this.pos == 'left'){
20276 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20283 initEvents : function()
20285 this.el.on('mouseover', this.onMouseOver, this);
20286 this.el.on('mouseout', this.onMouseOut, this);
20288 this.el.select('a', true).first().on('click', this.onClick, this);
20292 onClick : function(e)
20294 if(this.preventDefault){
20295 e.preventDefault();
20298 this.fireEvent("click", this, e);
20301 onMouseOver : function(e)
20303 if(this.submenu && this.pos == 'left'){
20304 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20307 this.fireEvent("mouseover", this, e);
20310 onMouseOut : function(e)
20312 this.fireEvent("mouseout", this, e);
20324 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20327 * @class Roo.bootstrap.menu.Separator
20328 * @extends Roo.bootstrap.Component
20329 * Bootstrap Separator class
20332 * Create a new Separator
20333 * @param {Object} config The config object
20337 Roo.bootstrap.menu.Separator = function(config){
20338 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20341 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20343 getAutoCreate : function(){