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'));
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');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @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
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
775 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
777 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
778 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
779 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
780 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
783 * @cfg {Boolean} hidden (true|false) hide the element
784 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
785 * @cfg {String} fa (ban|check|...) font awesome icon
786 * @cfg {Number} fasize (1|2|....) font awsome size
788 * @cfg {String} icon (info-sign|check|...) glyphicon name
790 * @cfg {String} html content of column.
793 * Create a new Column
794 * @param {Object} config The config object
797 Roo.bootstrap.Column = function(config){
798 Roo.bootstrap.Column.superclass.constructor.call(this, config);
801 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
819 getAutoCreate : function(){
820 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
828 ['xs','sm','md','lg'].map(function(size){
829 //Roo.log( size + ':' + settings[size]);
831 if (settings[size+'off'] !== false) {
832 cfg.cls += ' col-' + settings[size+'off'] + '-offset';
835 if (settings[size] === false) {
838 Roo.log(settings[size]);
839 if (!settings[size]) { // 0 = hidden
840 cfg.cls += ' hidden-' + size;
843 cfg.cls += ' col-' + size + '-' + settings[size];
848 cfg.cls += ' hidden';
851 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
852 cfg.cls +=' alert alert-' + this.alert;
856 if (this.html.length) {
857 cfg.html = this.html;
861 if (this.fasize > 1) {
862 fasize = ' fa-' + this.fasize + 'x';
864 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
869 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
888 * @class Roo.bootstrap.Container
889 * @extends Roo.bootstrap.Component
890 * Bootstrap Container class
891 * @cfg {Boolean} jumbotron is it a jumbotron element
892 * @cfg {String} html content of element
893 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
894 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
895 * @cfg {String} header content of header (for panel)
896 * @cfg {String} footer content of footer (for panel)
897 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
898 * @cfg {String} tag (header|aside|section) type of HTML tag.
899 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
900 * @cfg {String} fa (ban|check|...) font awesome icon
901 * @cfg {String} icon (info-sign|check|...) glyphicon name
902 * @cfg {Boolean} hidden (true|false) hide the element
906 * Create a new Container
907 * @param {Object} config The config object
910 Roo.bootstrap.Container = function(config){
911 Roo.bootstrap.Container.superclass.constructor.call(this, config);
914 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
928 getChildContainer : function() {
934 if (this.panel.length) {
935 return this.el.select('.panel-body',true).first();
942 getAutoCreate : function(){
945 tag : this.tag || 'div',
949 if (this.jumbotron) {
950 cfg.cls = 'jumbotron';
955 // - this is applied by the parent..
957 // cfg.cls = this.cls + '';
960 if (this.sticky.length) {
962 var bd = Roo.get(document.body);
963 if (!bd.hasClass('bootstrap-sticky')) {
964 bd.addClass('bootstrap-sticky');
965 Roo.select('html',true).setStyle('height', '100%');
968 cfg.cls += 'bootstrap-sticky-' + this.sticky;
972 if (this.well.length) {
976 cfg.cls +=' well well-' +this.well;
985 cfg.cls += ' hidden';
989 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
990 cfg.cls +=' alert alert-' + this.alert;
995 if (this.panel.length) {
996 cfg.cls += ' panel panel-' + this.panel;
998 if (this.header.length) {
1001 cls : 'panel-heading',
1004 cls : 'panel-title',
1017 if (this.footer.length) {
1019 cls : 'panel-footer',
1028 body.html = this.html || cfg.html;
1029 // prefix with the icons..
1031 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1034 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1039 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1040 cfg.cls = 'container';
1046 titleEl : function()
1048 if(!this.el || !this.panel.length || !this.header.length){
1052 return this.el.select('.panel-title',true).first();
1055 setTitle : function(v)
1057 var titleEl = this.titleEl();
1063 titleEl.dom.innerHTML = v;
1066 getTitle : function()
1069 var titleEl = this.titleEl();
1075 return titleEl.dom.innerHTML;
1089 * @class Roo.bootstrap.Img
1090 * @extends Roo.bootstrap.Component
1091 * Bootstrap Img class
1092 * @cfg {Boolean} imgResponsive false | true
1093 * @cfg {String} border rounded | circle | thumbnail
1094 * @cfg {String} src image source
1095 * @cfg {String} alt image alternative text
1096 * @cfg {String} href a tag href
1097 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1100 * Create a new Input
1101 * @param {Object} config The config object
1104 Roo.bootstrap.Img = function(config){
1105 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1111 * The img click event for the img.
1112 * @param {Roo.EventObject} e
1118 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1120 imgResponsive: true,
1126 getAutoCreate : function(){
1130 cls: (this.imgResponsive) ? 'img-responsive' : '',
1134 cfg.html = this.html || cfg.html;
1136 cfg.src = this.src || cfg.src;
1138 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1139 cfg.cls += ' img-' + this.border;
1156 a.target = this.target;
1162 return (this.href) ? a : cfg;
1165 initEvents: function() {
1168 this.el.on('click', this.onClick, this);
1172 onClick : function(e)
1174 Roo.log('img onclick');
1175 this.fireEvent('click', this, e);
1189 * @class Roo.bootstrap.Link
1190 * @extends Roo.bootstrap.Component
1191 * Bootstrap Link Class
1192 * @cfg {String} alt image alternative text
1193 * @cfg {String} href a tag href
1194 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1195 * @cfg {String} html the content of the link.
1196 * @cfg {String} anchor name for the anchor link
1198 * @cfg {Boolean} preventDefault (true | false) default false
1202 * Create a new Input
1203 * @param {Object} config The config object
1206 Roo.bootstrap.Link = function(config){
1207 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1213 * The img click event for the img.
1214 * @param {Roo.EventObject} e
1220 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1224 preventDefault: false,
1228 getAutoCreate : function()
1234 // anchor's do not require html/href...
1235 if (this.anchor === false) {
1236 cfg.html = this.html || 'html-missing';
1237 cfg.href = this.href || '#';
1239 cfg.name = this.anchor;
1240 if (this.html !== false) {
1241 cfg.html = this.html;
1243 if (this.href !== false) {
1244 cfg.href = this.href;
1248 if(this.alt !== false){
1253 if(this.target !== false) {
1254 cfg.target = this.target;
1260 initEvents: function() {
1262 if(!this.href || this.preventDefault){
1263 this.el.on('click', this.onClick, this);
1267 onClick : function(e)
1269 if(this.preventDefault){
1272 //Roo.log('img onclick');
1273 this.fireEvent('click', this, e);
1286 * @class Roo.bootstrap.Header
1287 * @extends Roo.bootstrap.Component
1288 * Bootstrap Header class
1289 * @cfg {String} html content of header
1290 * @cfg {Number} level (1|2|3|4|5|6) default 1
1293 * Create a new Header
1294 * @param {Object} config The config object
1298 Roo.bootstrap.Header = function(config){
1299 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1302 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1310 getAutoCreate : function(){
1313 tag: 'h' + (1 *this.level),
1314 html: this.html || 'fill in html'
1326 * Ext JS Library 1.1.1
1327 * Copyright(c) 2006-2007, Ext JS, LLC.
1329 * Originally Released Under LGPL - original licence link has changed is not relivant.
1332 * <script type="text/javascript">
1336 * @class Roo.bootstrap.MenuMgr
1337 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1340 Roo.bootstrap.MenuMgr = function(){
1341 var menus, active, groups = {}, attached = false, lastShow = new Date();
1343 // private - called when first menu is created
1346 active = new Roo.util.MixedCollection();
1347 Roo.get(document).addKeyListener(27, function(){
1348 if(active.length > 0){
1356 if(active && active.length > 0){
1357 var c = active.clone();
1367 if(active.length < 1){
1368 Roo.get(document).un("mouseup", onMouseDown);
1376 var last = active.last();
1377 lastShow = new Date();
1380 Roo.get(document).on("mouseup", onMouseDown);
1385 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1386 m.parentMenu.activeChild = m;
1387 }else if(last && last.isVisible()){
1388 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1393 function onBeforeHide(m){
1395 m.activeChild.hide();
1397 if(m.autoHideTimer){
1398 clearTimeout(m.autoHideTimer);
1399 delete m.autoHideTimer;
1404 function onBeforeShow(m){
1405 var pm = m.parentMenu;
1406 if(!pm && !m.allowOtherMenus){
1408 }else if(pm && pm.activeChild && active != m){
1409 pm.activeChild.hide();
1414 function onMouseDown(e){
1415 Roo.log("on MouseDown");
1416 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1424 function onBeforeCheck(mi, state){
1426 var g = groups[mi.group];
1427 for(var i = 0, l = g.length; i < l; i++){
1429 g[i].setChecked(false);
1438 * Hides all menus that are currently visible
1440 hideAll : function(){
1445 register : function(menu){
1449 menus[menu.id] = menu;
1450 menu.on("beforehide", onBeforeHide);
1451 menu.on("hide", onHide);
1452 menu.on("beforeshow", onBeforeShow);
1453 menu.on("show", onShow);
1455 if(g && menu.events["checkchange"]){
1459 groups[g].push(menu);
1460 menu.on("checkchange", onCheck);
1465 * Returns a {@link Roo.menu.Menu} object
1466 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1467 * be used to generate and return a new Menu instance.
1469 get : function(menu){
1470 if(typeof menu == "string"){ // menu id
1472 }else if(menu.events){ // menu instance
1475 /*else if(typeof menu.length == 'number'){ // array of menu items?
1476 return new Roo.bootstrap.Menu({items:menu});
1477 }else{ // otherwise, must be a config
1478 return new Roo.bootstrap.Menu(menu);
1485 unregister : function(menu){
1486 delete menus[menu.id];
1487 menu.un("beforehide", onBeforeHide);
1488 menu.un("hide", onHide);
1489 menu.un("beforeshow", onBeforeShow);
1490 menu.un("show", onShow);
1492 if(g && menu.events["checkchange"]){
1493 groups[g].remove(menu);
1494 menu.un("checkchange", onCheck);
1499 registerCheckable : function(menuItem){
1500 var g = menuItem.group;
1505 groups[g].push(menuItem);
1506 menuItem.on("beforecheckchange", onBeforeCheck);
1511 unregisterCheckable : function(menuItem){
1512 var g = menuItem.group;
1514 groups[g].remove(menuItem);
1515 menuItem.un("beforecheckchange", onBeforeCheck);
1527 * @class Roo.bootstrap.Menu
1528 * @extends Roo.bootstrap.Component
1529 * Bootstrap Menu class - container for MenuItems
1530 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1534 * @param {Object} config The config object
1538 Roo.bootstrap.Menu = function(config){
1539 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1540 if (this.registerMenu) {
1541 Roo.bootstrap.MenuMgr.register(this);
1546 * Fires before this menu is displayed
1547 * @param {Roo.menu.Menu} this
1552 * Fires before this menu is hidden
1553 * @param {Roo.menu.Menu} this
1558 * Fires after this menu is displayed
1559 * @param {Roo.menu.Menu} this
1564 * Fires after this menu is hidden
1565 * @param {Roo.menu.Menu} this
1570 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1571 * @param {Roo.menu.Menu} this
1572 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1573 * @param {Roo.EventObject} e
1578 * Fires when the mouse is hovering over this menu
1579 * @param {Roo.menu.Menu} this
1580 * @param {Roo.EventObject} e
1581 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1586 * Fires when the mouse exits this menu
1587 * @param {Roo.menu.Menu} this
1588 * @param {Roo.EventObject} e
1589 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1594 * Fires when a menu item contained in this menu is clicked
1595 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1596 * @param {Roo.EventObject} e
1600 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1603 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1607 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1610 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1612 registerMenu : true,
1614 menuItems :false, // stores the menu items..
1620 getChildContainer : function() {
1624 getAutoCreate : function(){
1626 //if (['right'].indexOf(this.align)!==-1) {
1627 // cfg.cn[1].cls += ' pull-right'
1633 cls : 'dropdown-menu' ,
1634 style : 'z-index:1000'
1638 if (this.type === 'submenu') {
1639 cfg.cls = 'submenu active';
1641 if (this.type === 'treeview') {
1642 cfg.cls = 'treeview-menu';
1647 initEvents : function() {
1649 // Roo.log("ADD event");
1650 // Roo.log(this.triggerEl.dom);
1651 this.triggerEl.on('click', this.onTriggerPress, this);
1652 this.triggerEl.addClass('dropdown-toggle');
1653 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1655 this.el.on("mouseover", this.onMouseOver, this);
1656 this.el.on("mouseout", this.onMouseOut, this);
1660 findTargetItem : function(e){
1661 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1665 //Roo.log(t); Roo.log(t.id);
1667 //Roo.log(this.menuitems);
1668 return this.menuitems.get(t.id);
1670 //return this.items.get(t.menuItemId);
1675 onClick : function(e){
1676 Roo.log("menu.onClick");
1677 var t = this.findTargetItem(e);
1683 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1684 if(t == this.activeItem && t.shouldDeactivate(e)){
1685 this.activeItem.deactivate();
1686 delete this.activeItem;
1690 this.setActiveItem(t, true);
1697 Roo.log('pass click event');
1701 this.fireEvent("click", this, t, e);
1705 onMouseOver : function(e){
1706 var t = this.findTargetItem(e);
1709 // if(t.canActivate && !t.disabled){
1710 // this.setActiveItem(t, true);
1714 this.fireEvent("mouseover", this, e, t);
1716 isVisible : function(){
1717 return !this.hidden;
1719 onMouseOut : function(e){
1720 var t = this.findTargetItem(e);
1723 // if(t == this.activeItem && t.shouldDeactivate(e)){
1724 // this.activeItem.deactivate();
1725 // delete this.activeItem;
1728 this.fireEvent("mouseout", this, e, t);
1733 * Displays this menu relative to another element
1734 * @param {String/HTMLElement/Roo.Element} element The element to align to
1735 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1736 * the element (defaults to this.defaultAlign)
1737 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1739 show : function(el, pos, parentMenu){
1740 this.parentMenu = parentMenu;
1744 this.fireEvent("beforeshow", this);
1745 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1748 * Displays this menu at a specific xy position
1749 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1750 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1752 showAt : function(xy, parentMenu, /* private: */_e){
1753 this.parentMenu = parentMenu;
1758 this.fireEvent("beforeshow", this);
1760 //xy = this.el.adjustForConstraints(xy);
1762 //this.el.setXY(xy);
1764 this.hideMenuItems();
1765 this.hidden = false;
1766 this.triggerEl.addClass('open');
1768 this.fireEvent("show", this);
1774 this.doFocus.defer(50, this);
1778 doFocus : function(){
1780 this.focusEl.focus();
1785 * Hides this menu and optionally all parent menus
1786 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1788 hide : function(deep){
1790 this.hideMenuItems();
1791 if(this.el && this.isVisible()){
1792 this.fireEvent("beforehide", this);
1793 if(this.activeItem){
1794 this.activeItem.deactivate();
1795 this.activeItem = null;
1797 this.triggerEl.removeClass('open');;
1799 this.fireEvent("hide", this);
1801 if(deep === true && this.parentMenu){
1802 this.parentMenu.hide(true);
1806 onTriggerPress : function(e)
1809 Roo.log('trigger press');
1810 //Roo.log(e.getTarget());
1811 // Roo.log(this.triggerEl.dom);
1812 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1815 if (this.isVisible()) {
1819 this.show(this.triggerEl, false, false);
1828 hideMenuItems : function()
1830 //$(backdrop).remove()
1831 Roo.select('.open',true).each(function(aa) {
1833 aa.removeClass('open');
1834 //var parent = getParent($(this))
1835 //var relatedTarget = { relatedTarget: this }
1837 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1838 //if (e.isDefaultPrevented()) return
1839 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1842 addxtypeChild : function (tree, cntr) {
1843 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1845 this.menuitems.add(comp);
1866 * @class Roo.bootstrap.MenuItem
1867 * @extends Roo.bootstrap.Component
1868 * Bootstrap MenuItem class
1869 * @cfg {String} html the menu label
1870 * @cfg {String} href the link
1871 * @cfg {Boolean} preventDefault (true | false) default true
1875 * Create a new MenuItem
1876 * @param {Object} config The config object
1880 Roo.bootstrap.MenuItem = function(config){
1881 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1886 * The raw click event for the entire grid.
1887 * @param {Roo.EventObject} e
1893 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1897 preventDefault: true,
1899 getAutoCreate : function(){
1902 cls: 'dropdown-menu-item',
1911 if (this.parent().type == 'treeview') {
1912 cfg.cls = 'treeview-menu';
1915 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1916 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1920 initEvents: function() {
1922 //this.el.select('a').on('click', this.onClick, this);
1925 onClick : function(e)
1927 Roo.log('item on click ');
1928 //if(this.preventDefault){
1929 // e.preventDefault();
1931 //this.parent().hideMenuItems();
1933 this.fireEvent('click', this, e);
1952 * @class Roo.bootstrap.MenuSeparator
1953 * @extends Roo.bootstrap.Component
1954 * Bootstrap MenuSeparator class
1957 * Create a new MenuItem
1958 * @param {Object} config The config object
1962 Roo.bootstrap.MenuSeparator = function(config){
1963 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1966 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1968 getAutoCreate : function(){
1983 <div class="modal fade">
1984 <div class="modal-dialog">
1985 <div class="modal-content">
1986 <div class="modal-header">
1987 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1988 <h4 class="modal-title">Modal title</h4>
1990 <div class="modal-body">
1991 <p>One fine body…</p>
1993 <div class="modal-footer">
1994 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1995 <button type="button" class="btn btn-primary">Save changes</button>
1997 </div><!-- /.modal-content -->
1998 </div><!-- /.modal-dialog -->
1999 </div><!-- /.modal -->
2009 * @class Roo.bootstrap.Modal
2010 * @extends Roo.bootstrap.Component
2011 * Bootstrap Modal class
2012 * @cfg {String} title Title of dialog
2013 * @cfg {Boolean} specificTitle (true|false) default false
2014 * @cfg {Array} buttons Array of buttons or standard button set..
2015 * @cfg {String} buttonPosition (left|right|center) default right
2018 * Create a new Modal Dialog
2019 * @param {Object} config The config object
2022 Roo.bootstrap.Modal = function(config){
2023 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2028 * The raw btnclick event for the button
2029 * @param {Roo.EventObject} e
2033 this.buttons = this.buttons || [];
2036 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2038 title : 'test dialog',
2045 specificTitle: false,
2047 buttonPosition: 'right',
2049 onRender : function(ct, position)
2051 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2054 var cfg = Roo.apply({}, this.getAutoCreate());
2057 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2059 //if (!cfg.name.length) {
2063 cfg.cls += ' ' + this.cls;
2066 cfg.style = this.style;
2068 this.el = Roo.get(document.body).createChild(cfg, position);
2070 //var type = this.el.dom.type;
2072 if(this.tabIndex !== undefined){
2073 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2078 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2079 this.maskEl.enableDisplayMode("block");
2081 //this.el.addClass("x-dlg-modal");
2083 if (this.buttons.length) {
2084 Roo.each(this.buttons, function(bb) {
2085 b = Roo.apply({}, bb);
2086 b.xns = b.xns || Roo.bootstrap;
2087 b.xtype = b.xtype || 'Button';
2088 if (typeof(b.listeners) == 'undefined') {
2089 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2092 var btn = Roo.factory(b);
2094 btn.onRender(this.el.select('.modal-footer div').first());
2098 // render the children.
2101 if(typeof(this.items) != 'undefined'){
2102 var items = this.items;
2105 for(var i =0;i < items.length;i++) {
2106 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2110 this.items = nitems;
2112 this.body = this.el.select('.modal-body',true).first();
2113 this.close = this.el.select('.modal-header .close', true).first();
2114 this.footer = this.el.select('.modal-footer',true).first();
2116 //this.el.addClass([this.fieldClass, this.cls]);
2119 getAutoCreate : function(){
2124 html : this.html || ''
2129 cls : 'modal-title',
2133 if(this.specificTitle){
2139 style : 'display: none',
2142 cls: "modal-dialog",
2145 cls : "modal-content",
2148 cls : 'modal-header',
2160 cls : 'modal-footer',
2164 cls: 'btn-' + this.buttonPosition
2183 getChildContainer : function() {
2185 return this.el.select('.modal-body',true).first();
2188 getButtonContainer : function() {
2189 return this.el.select('.modal-footer div',true).first();
2192 initEvents : function()
2194 this.el.select('.modal-header .close').on('click', this.hide, this);
2196 // this.addxtype(this);
2200 if (!this.rendered) {
2204 this.el.addClass('on');
2205 this.el.removeClass('fade');
2206 this.el.setStyle('display', 'block');
2207 Roo.get(document.body).addClass("x-body-masked");
2208 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2210 this.el.setStyle('zIndex', '10001');
2211 this.fireEvent('show', this);
2217 Roo.log('Modal hide?!');
2219 Roo.get(document.body).removeClass("x-body-masked");
2220 this.el.removeClass('on');
2221 this.el.addClass('fade');
2222 this.el.setStyle('display', 'none');
2223 this.fireEvent('hide', this);
2226 addButton : function(str, cb)
2230 var b = Roo.apply({}, { html : str } );
2231 b.xns = b.xns || Roo.bootstrap;
2232 b.xtype = b.xtype || 'Button';
2233 if (typeof(b.listeners) == 'undefined') {
2234 b.listeners = { click : cb.createDelegate(this) };
2237 var btn = Roo.factory(b);
2239 btn.onRender(this.el.select('.modal-footer div').first());
2245 setDefaultButton : function(btn)
2247 //this.el.select('.modal-footer').()
2249 resizeTo: function(w,h)
2253 setContentSize : function(w, h)
2257 onButtonClick: function(btn,e)
2260 this.fireEvent('btnclick', btn.name, e);
2262 setTitle: function(str) {
2263 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2269 Roo.apply(Roo.bootstrap.Modal, {
2271 * Button config that displays a single OK button
2280 * Button config that displays Yes and No buttons
2296 * Button config that displays OK and Cancel buttons
2311 * Button config that displays Yes, No and Cancel buttons
2333 * messagebox - can be used as a replace
2337 * @class Roo.MessageBox
2338 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2342 Roo.Msg.alert('Status', 'Changes saved successfully.');
2344 // Prompt for user data:
2345 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2347 // process text value...
2351 // Show a dialog using config options:
2353 title:'Save Changes?',
2354 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2355 buttons: Roo.Msg.YESNOCANCEL,
2362 Roo.bootstrap.MessageBox = function(){
2363 var dlg, opt, mask, waitTimer;
2364 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2365 var buttons, activeTextEl, bwidth;
2369 var handleButton = function(button){
2371 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2375 var handleHide = function(){
2377 dlg.el.removeClass(opt.cls);
2380 // Roo.TaskMgr.stop(waitTimer);
2381 // waitTimer = null;
2386 var updateButtons = function(b){
2389 buttons["ok"].hide();
2390 buttons["cancel"].hide();
2391 buttons["yes"].hide();
2392 buttons["no"].hide();
2393 //dlg.footer.dom.style.display = 'none';
2396 dlg.footer.dom.style.display = '';
2397 for(var k in buttons){
2398 if(typeof buttons[k] != "function"){
2401 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2402 width += buttons[k].el.getWidth()+15;
2412 var handleEsc = function(d, k, e){
2413 if(opt && opt.closable !== false){
2423 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2424 * @return {Roo.BasicDialog} The BasicDialog element
2426 getDialog : function(){
2428 dlg = new Roo.bootstrap.Modal( {
2431 //constraintoviewport:false,
2433 //collapsible : false,
2438 //buttonAlign:"center",
2439 closeClick : function(){
2440 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2443 handleButton("cancel");
2448 dlg.on("hide", handleHide);
2450 //dlg.addKeyListener(27, handleEsc);
2452 this.buttons = buttons;
2453 var bt = this.buttonText;
2454 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2455 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2456 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2457 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2459 bodyEl = dlg.body.createChild({
2461 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2462 '<textarea class="roo-mb-textarea"></textarea>' +
2463 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2465 msgEl = bodyEl.dom.firstChild;
2466 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2467 textboxEl.enableDisplayMode();
2468 textboxEl.addKeyListener([10,13], function(){
2469 if(dlg.isVisible() && opt && opt.buttons){
2472 }else if(opt.buttons.yes){
2473 handleButton("yes");
2477 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2478 textareaEl.enableDisplayMode();
2479 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2480 progressEl.enableDisplayMode();
2481 var pf = progressEl.dom.firstChild;
2483 pp = Roo.get(pf.firstChild);
2484 pp.setHeight(pf.offsetHeight);
2492 * Updates the message box body text
2493 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2494 * the XHTML-compliant non-breaking space character '&#160;')
2495 * @return {Roo.MessageBox} This message box
2497 updateText : function(text){
2498 if(!dlg.isVisible() && !opt.width){
2499 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2501 msgEl.innerHTML = text || ' ';
2503 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2504 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2506 Math.min(opt.width || cw , this.maxWidth),
2507 Math.max(opt.minWidth || this.minWidth, bwidth)
2510 activeTextEl.setWidth(w);
2512 if(dlg.isVisible()){
2513 dlg.fixedcenter = false;
2515 // to big, make it scroll. = But as usual stupid IE does not support
2518 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2519 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2520 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2522 bodyEl.dom.style.height = '';
2523 bodyEl.dom.style.overflowY = '';
2526 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2528 bodyEl.dom.style.overflowX = '';
2531 dlg.setContentSize(w, bodyEl.getHeight());
2532 if(dlg.isVisible()){
2533 dlg.fixedcenter = true;
2539 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2540 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2541 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2542 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2543 * @return {Roo.MessageBox} This message box
2545 updateProgress : function(value, text){
2547 this.updateText(text);
2549 if (pp) { // weird bug on my firefox - for some reason this is not defined
2550 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2556 * Returns true if the message box is currently displayed
2557 * @return {Boolean} True if the message box is visible, else false
2559 isVisible : function(){
2560 return dlg && dlg.isVisible();
2564 * Hides the message box if it is displayed
2567 if(this.isVisible()){
2573 * Displays a new message box, or reinitializes an existing message box, based on the config options
2574 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2575 * The following config object properties are supported:
2577 Property Type Description
2578 ---------- --------------- ------------------------------------------------------------------------------------
2579 animEl String/Element An id or Element from which the message box should animate as it opens and
2580 closes (defaults to undefined)
2581 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2582 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2583 closable Boolean False to hide the top-right close button (defaults to true). Note that
2584 progress and wait dialogs will ignore this property and always hide the
2585 close button as they can only be closed programmatically.
2586 cls String A custom CSS class to apply to the message box element
2587 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2588 displayed (defaults to 75)
2589 fn Function A callback function to execute after closing the dialog. The arguments to the
2590 function will be btn (the name of the button that was clicked, if applicable,
2591 e.g. "ok"), and text (the value of the active text field, if applicable).
2592 Progress and wait dialogs will ignore this option since they do not respond to
2593 user actions and can only be closed programmatically, so any required function
2594 should be called by the same code after it closes the dialog.
2595 icon String A CSS class that provides a background image to be used as an icon for
2596 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2597 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2598 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2599 modal Boolean False to allow user interaction with the page while the message box is
2600 displayed (defaults to true)
2601 msg String A string that will replace the existing message box body text (defaults
2602 to the XHTML-compliant non-breaking space character ' ')
2603 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2604 progress Boolean True to display a progress bar (defaults to false)
2605 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2606 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2607 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2608 title String The title text
2609 value String The string value to set into the active textbox element if displayed
2610 wait Boolean True to display a progress bar (defaults to false)
2611 width Number The width of the dialog in pixels
2618 msg: 'Please enter your address:',
2620 buttons: Roo.MessageBox.OKCANCEL,
2623 animEl: 'addAddressBtn'
2626 * @param {Object} config Configuration options
2627 * @return {Roo.MessageBox} This message box
2629 show : function(options)
2632 // this causes nightmares if you show one dialog after another
2633 // especially on callbacks..
2635 if(this.isVisible()){
2638 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2639 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2640 Roo.log("New Dialog Message:" + options.msg )
2641 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2642 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2645 var d = this.getDialog();
2647 d.setTitle(opt.title || " ");
2648 d.close.setDisplayed(opt.closable !== false);
2649 activeTextEl = textboxEl;
2650 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2655 textareaEl.setHeight(typeof opt.multiline == "number" ?
2656 opt.multiline : this.defaultTextHeight);
2657 activeTextEl = textareaEl;
2666 progressEl.setDisplayed(opt.progress === true);
2667 this.updateProgress(0);
2668 activeTextEl.dom.value = opt.value || "";
2670 dlg.setDefaultButton(activeTextEl);
2672 var bs = opt.buttons;
2676 }else if(bs && bs.yes){
2677 db = buttons["yes"];
2679 dlg.setDefaultButton(db);
2681 bwidth = updateButtons(opt.buttons);
2682 this.updateText(opt.msg);
2684 d.el.addClass(opt.cls);
2686 d.proxyDrag = opt.proxyDrag === true;
2687 d.modal = opt.modal !== false;
2688 d.mask = opt.modal !== false ? mask : false;
2690 // force it to the end of the z-index stack so it gets a cursor in FF
2691 document.body.appendChild(dlg.el.dom);
2692 d.animateTarget = null;
2693 d.show(options.animEl);
2699 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2700 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2701 * and closing the message box when the process is complete.
2702 * @param {String} title The title bar text
2703 * @param {String} msg The message box body text
2704 * @return {Roo.MessageBox} This message box
2706 progress : function(title, msg){
2713 minWidth: this.minProgressWidth,
2720 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2721 * If a callback function is passed it will be called after the user clicks the button, and the
2722 * id of the button that was clicked will be passed as the only parameter to the callback
2723 * (could also be the top-right close button).
2724 * @param {String} title The title bar text
2725 * @param {String} msg The message box body text
2726 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2727 * @param {Object} scope (optional) The scope of the callback function
2728 * @return {Roo.MessageBox} This message box
2730 alert : function(title, msg, fn, scope){
2743 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2744 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2745 * You are responsible for closing the message box when the process is complete.
2746 * @param {String} msg The message box body text
2747 * @param {String} title (optional) The title bar text
2748 * @return {Roo.MessageBox} This message box
2750 wait : function(msg, title){
2761 waitTimer = Roo.TaskMgr.start({
2763 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2771 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2772 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2773 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2774 * @param {String} title The title bar text
2775 * @param {String} msg The message box body text
2776 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2777 * @param {Object} scope (optional) The scope of the callback function
2778 * @return {Roo.MessageBox} This message box
2780 confirm : function(title, msg, fn, scope){
2784 buttons: this.YESNO,
2793 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2794 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2795 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2796 * (could also be the top-right close button) and the text that was entered will be passed as the two
2797 * parameters to the callback.
2798 * @param {String} title The title bar text
2799 * @param {String} msg The message box body text
2800 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2801 * @param {Object} scope (optional) The scope of the callback function
2802 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2803 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2804 * @return {Roo.MessageBox} This message box
2806 prompt : function(title, msg, fn, scope, multiline){
2810 buttons: this.OKCANCEL,
2815 multiline: multiline,
2822 * Button config that displays a single OK button
2827 * Button config that displays Yes and No buttons
2830 YESNO : {yes:true, no:true},
2832 * Button config that displays OK and Cancel buttons
2835 OKCANCEL : {ok:true, cancel:true},
2837 * Button config that displays Yes, No and Cancel buttons
2840 YESNOCANCEL : {yes:true, no:true, cancel:true},
2843 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2846 defaultTextHeight : 75,
2848 * The maximum width in pixels of the message box (defaults to 600)
2853 * The minimum width in pixels of the message box (defaults to 100)
2858 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2859 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2862 minProgressWidth : 250,
2864 * An object containing the default button text strings that can be overriden for localized language support.
2865 * Supported properties are: ok, cancel, yes and no.
2866 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2879 * Shorthand for {@link Roo.MessageBox}
2881 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2882 Roo.Msg = Roo.Msg || Roo.MessageBox;
2891 * @class Roo.bootstrap.Navbar
2892 * @extends Roo.bootstrap.Component
2893 * Bootstrap Navbar class
2896 * Create a new Navbar
2897 * @param {Object} config The config object
2901 Roo.bootstrap.Navbar = function(config){
2902 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2906 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2915 getAutoCreate : function(){
2918 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2922 initEvents :function ()
2924 //Roo.log(this.el.select('.navbar-toggle',true));
2925 this.el.select('.navbar-toggle',true).on('click', function() {
2926 // Roo.log('click');
2927 this.el.select('.navbar-collapse',true).toggleClass('in');
2935 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2937 var size = this.el.getSize();
2938 this.maskEl.setSize(size.width, size.height);
2939 this.maskEl.enableDisplayMode("block");
2948 getChildContainer : function()
2950 if (this.el.select('.collapse').getCount()) {
2951 return this.el.select('.collapse',true).first();
2984 * @class Roo.bootstrap.NavSimplebar
2985 * @extends Roo.bootstrap.Navbar
2986 * Bootstrap Sidebar class
2988 * @cfg {Boolean} inverse is inverted color
2990 * @cfg {String} type (nav | pills | tabs)
2991 * @cfg {Boolean} arrangement stacked | justified
2992 * @cfg {String} align (left | right) alignment
2994 * @cfg {Boolean} main (true|false) main nav bar? default false
2995 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2997 * @cfg {String} tag (header|footer|nav|div) default is nav
3003 * Create a new Sidebar
3004 * @param {Object} config The config object
3008 Roo.bootstrap.NavSimplebar = function(config){
3009 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3012 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3028 getAutoCreate : function(){
3032 tag : this.tag || 'div',
3045 this.type = this.type || 'nav';
3046 if (['tabs','pills'].indexOf(this.type)!==-1) {
3047 cfg.cn[0].cls += ' nav-' + this.type
3051 if (this.type!=='nav') {
3052 Roo.log('nav type must be nav/tabs/pills')
3054 cfg.cn[0].cls += ' navbar-nav'
3060 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3061 cfg.cn[0].cls += ' nav-' + this.arrangement;
3065 if (this.align === 'right') {
3066 cfg.cn[0].cls += ' navbar-right';
3070 cfg.cls += ' navbar-inverse';
3097 * @class Roo.bootstrap.NavHeaderbar
3098 * @extends Roo.bootstrap.NavSimplebar
3099 * Bootstrap Sidebar class
3101 * @cfg {String} brand what is brand
3102 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3103 * @cfg {String} brand_href href of the brand
3104 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3105 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3108 * Create a new Sidebar
3109 * @param {Object} config The config object
3113 Roo.bootstrap.NavHeaderbar = function(config){
3114 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3117 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3125 getAutoCreate : function(){
3128 tag: this.nav || 'nav',
3137 cls: 'navbar-header',
3142 cls: 'navbar-toggle',
3143 'data-toggle': 'collapse',
3148 html: 'Toggle navigation'
3170 cls: 'collapse navbar-collapse',
3174 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3176 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3177 cfg.cls += ' navbar-' + this.position;
3179 // tag can override this..
3181 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3184 if (this.brand !== '') {
3187 href: this.brand_href ? this.brand_href : '#',
3188 cls: 'navbar-brand',
3196 cfg.cls += ' main-nav';
3204 initEvents : function()
3206 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3208 if (this.autohide) {
3213 Roo.get(document).on('scroll',function(e) {
3214 var ns = Roo.get(document).getScroll().top;
3215 var os = prevScroll;
3219 ft.removeClass('slideDown');
3220 ft.addClass('slideUp');
3223 ft.removeClass('slideUp');
3224 ft.addClass('slideDown');
3248 * @class Roo.bootstrap.NavSidebar
3249 * @extends Roo.bootstrap.Navbar
3250 * Bootstrap Sidebar class
3253 * Create a new Sidebar
3254 * @param {Object} config The config object
3258 Roo.bootstrap.NavSidebar = function(config){
3259 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3262 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3264 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3266 getAutoCreate : function(){
3271 cls: 'sidebar sidebar-nav'
3293 * @class Roo.bootstrap.NavGroup
3294 * @extends Roo.bootstrap.Component
3295 * Bootstrap NavGroup class
3296 * @cfg {String} align left | right
3297 * @cfg {Boolean} inverse false | true
3298 * @cfg {String} type (nav|pills|tab) default nav
3299 * @cfg {String} navId - reference Id for navbar.
3303 * Create a new nav group
3304 * @param {Object} config The config object
3307 Roo.bootstrap.NavGroup = function(config){
3308 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3311 Roo.bootstrap.NavGroup.register(this);
3315 * Fires when the active item changes
3316 * @param {Roo.bootstrap.NavGroup} this
3317 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3318 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3325 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3336 getAutoCreate : function()
3338 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3345 if (['tabs','pills'].indexOf(this.type)!==-1) {
3346 cfg.cls += ' nav-' + this.type
3348 if (this.type!=='nav') {
3349 Roo.log('nav type must be nav/tabs/pills')
3351 cfg.cls += ' navbar-nav'
3354 if (this.parent().sidebar) {
3357 cls: 'dashboard-menu sidebar-menu'
3363 if (this.form === true) {
3369 if (this.align === 'right') {
3370 cfg.cls += ' navbar-right';
3372 cfg.cls += ' navbar-left';
3376 if (this.align === 'right') {
3377 cfg.cls += ' navbar-right';
3381 cfg.cls += ' navbar-inverse';
3389 * sets the active Navigation item
3390 * @param {Roo.bootstrap.NavItem} the new current navitem
3392 setActiveItem : function(item)
3395 Roo.each(this.navItems, function(v){
3400 v.setActive(false, true);
3407 item.setActive(true, true);
3408 this.fireEvent('changed', this, item, prev);
3413 * gets the active Navigation item
3414 * @return {Roo.bootstrap.NavItem} the current navitem
3416 getActive : function()
3420 Roo.each(this.navItems, function(v){
3431 indexOfNav : function()
3435 Roo.each(this.navItems, function(v,i){
3446 * adds a Navigation item
3447 * @param {Roo.bootstrap.NavItem} the navitem to add
3449 addItem : function(cfg)
3451 var cn = new Roo.bootstrap.NavItem(cfg);
3453 cn.parentId = this.id;
3454 cn.onRender(this.el, null);
3458 * register a Navigation item
3459 * @param {Roo.bootstrap.NavItem} the navitem to add
3461 register : function(item)
3463 this.navItems.push( item);
3464 item.navId = this.navId;
3469 getNavItem: function(tabId)
3472 Roo.each(this.navItems, function(e) {
3473 if (e.tabId == tabId) {
3483 setActiveNext : function()
3485 var i = this.indexOfNav(this.getActive());
3486 if (i > this.navItems.length) {
3489 this.setActiveItem(this.navItems[i+1]);
3491 setActivePrev : function()
3493 var i = this.indexOfNav(this.getActive());
3497 this.setActiveItem(this.navItems[i-1]);
3499 clearWasActive : function(except) {
3500 Roo.each(this.navItems, function(e) {
3501 if (e.tabId != except.tabId && e.was_active) {
3502 e.was_active = false;
3509 getWasActive : function ()
3512 Roo.each(this.navItems, function(e) {
3527 Roo.apply(Roo.bootstrap.NavGroup, {
3531 * register a Navigation Group
3532 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3534 register : function(navgrp)
3536 this.groups[navgrp.navId] = navgrp;
3540 * fetch a Navigation Group based on the navigation ID
3541 * @param {string} the navgroup to add
3542 * @returns {Roo.bootstrap.NavGroup} the navgroup
3544 get: function(navId) {
3545 if (typeof(this.groups[navId]) == 'undefined') {
3547 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3549 return this.groups[navId] ;
3564 * @class Roo.bootstrap.NavItem
3565 * @extends Roo.bootstrap.Component
3566 * Bootstrap Navbar.NavItem class
3567 * @cfg {String} href link to
3568 * @cfg {String} html content of button
3569 * @cfg {String} badge text inside badge
3570 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3571 * @cfg {String} glyphicon name of glyphicon
3572 * @cfg {String} icon name of font awesome icon
3573 * @cfg {Boolean} active Is item active
3574 * @cfg {Boolean} disabled Is item disabled
3576 * @cfg {Boolean} preventDefault (true | false) default false
3577 * @cfg {String} tabId the tab that this item activates.
3578 * @cfg {String} tagtype (a|span) render as a href or span?
3581 * Create a new Navbar Item
3582 * @param {Object} config The config object
3584 Roo.bootstrap.NavItem = function(config){
3585 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3590 * The raw click event for the entire grid.
3591 * @param {Roo.EventObject} e
3596 * Fires when the active item active state changes
3597 * @param {Roo.bootstrap.NavItem} this
3598 * @param {boolean} state the new state
3606 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3614 preventDefault : false,
3621 getAutoCreate : function(){
3629 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3631 if (this.disabled) {
3632 cfg.cls += ' disabled';
3635 if (this.href || this.html || this.glyphicon || this.icon) {
3639 href : this.href || "#",
3640 html: this.html || ''
3645 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3648 if(this.glyphicon) {
3649 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3654 cfg.cn[0].html += " <span class='caret'></span>";
3658 if (this.badge !== '') {
3660 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3668 initEvents: function() {
3669 // Roo.log('init events?');
3670 // Roo.log(this.el.dom);
3671 if (typeof (this.menu) != 'undefined') {
3672 this.menu.parentType = this.xtype;
3673 this.menu.triggerEl = this.el;
3674 this.addxtype(Roo.apply({}, this.menu));
3678 this.el.select('a',true).on('click', this.onClick, this);
3679 // at this point parent should be available..
3680 this.parent().register(this);
3683 onClick : function(e)
3686 if(this.preventDefault){
3689 if (this.disabled) {
3693 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3694 if (tg && tg.transition) {
3695 Roo.log("waiting for the transitionend");
3699 Roo.log("fire event clicked");
3700 if(this.fireEvent('click', this, e) === false){
3703 var p = this.parent();
3704 if (['tabs','pills'].indexOf(p.type)!==-1) {
3705 if (typeof(p.setActiveItem) !== 'undefined') {
3706 p.setActiveItem(this);
3709 // if parent is a navbarheader....
3710 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3711 // remove the collapsed menu expand...
3712 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3717 isActive: function () {
3720 setActive : function(state, fire, is_was_active)
3722 if (this.active && !state & this.navId) {
3723 this.was_active = true;
3724 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3726 nv.clearWasActive(this);
3730 this.active = state;
3733 this.el.removeClass('active');
3734 } else if (!this.el.hasClass('active')) {
3735 this.el.addClass('active');
3738 this.fireEvent('changed', this, state);
3741 // show a panel if it's registered and related..
3743 if (!this.navId || !this.tabId || !state || is_was_active) {
3747 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3751 var pan = tg.getPanelByName(this.tabId);
3755 // if we can not flip to new panel - go back to old nav highlight..
3756 if (false == tg.showPanel(pan)) {
3757 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3759 var onav = nv.getWasActive();
3761 onav.setActive(true, false, true);
3770 // this should not be here...
3771 setDisabled : function(state)
3773 this.disabled = state;
3775 this.el.removeClass('disabled');
3776 } else if (!this.el.hasClass('disabled')) {
3777 this.el.addClass('disabled');
3790 * <span> icon </span>
3791 * <span> text </span>
3792 * <span>badge </span>
3796 * @class Roo.bootstrap.NavSidebarItem
3797 * @extends Roo.bootstrap.NavItem
3798 * Bootstrap Navbar.NavSidebarItem class
3800 * Create a new Navbar Button
3801 * @param {Object} config The config object
3803 Roo.bootstrap.NavSidebarItem = function(config){
3804 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3809 * The raw click event for the entire grid.
3810 * @param {Roo.EventObject} e
3815 * Fires when the active item active state changes
3816 * @param {Roo.bootstrap.NavSidebarItem} this
3817 * @param {boolean} state the new state
3825 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3828 getAutoCreate : function(){
3833 href : this.href || '#',
3845 html : this.html || ''
3850 cfg.cls += ' active';
3854 if (this.glyphicon || this.icon) {
3855 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3856 a.cn.push({ tag : 'i', cls : c }) ;
3861 if (this.badge !== '') {
3862 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3866 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3867 a.cls += 'dropdown-toggle treeview' ;
3891 * @class Roo.bootstrap.Row
3892 * @extends Roo.bootstrap.Component
3893 * Bootstrap Row class (contains columns...)
3897 * @param {Object} config The config object
3900 Roo.bootstrap.Row = function(config){
3901 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3904 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3906 getAutoCreate : function(){
3925 * @class Roo.bootstrap.Element
3926 * @extends Roo.bootstrap.Component
3927 * Bootstrap Element class
3928 * @cfg {String} html contents of the element
3929 * @cfg {String} tag tag of the element
3930 * @cfg {String} cls class of the element
3933 * Create a new Element
3934 * @param {Object} config The config object
3937 Roo.bootstrap.Element = function(config){
3938 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3941 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3948 getAutoCreate : function(){
3973 * @class Roo.bootstrap.Pagination
3974 * @extends Roo.bootstrap.Component
3975 * Bootstrap Pagination class
3976 * @cfg {String} size xs | sm | md | lg
3977 * @cfg {Boolean} inverse false | true
3980 * Create a new Pagination
3981 * @param {Object} config The config object
3984 Roo.bootstrap.Pagination = function(config){
3985 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3988 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3994 getAutoCreate : function(){
4000 cfg.cls += ' inverse';
4006 cfg.cls += " " + this.cls;
4024 * @class Roo.bootstrap.PaginationItem
4025 * @extends Roo.bootstrap.Component
4026 * Bootstrap PaginationItem class
4027 * @cfg {String} html text
4028 * @cfg {String} href the link
4029 * @cfg {Boolean} preventDefault (true | false) default true
4030 * @cfg {Boolean} active (true | false) default false
4034 * Create a new PaginationItem
4035 * @param {Object} config The config object
4039 Roo.bootstrap.PaginationItem = function(config){
4040 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4045 * The raw click event for the entire grid.
4046 * @param {Roo.EventObject} e
4052 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4056 preventDefault: true,
4060 getAutoCreate : function(){
4066 href : this.href ? this.href : '#',
4067 html : this.html ? this.html : ''
4077 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4083 initEvents: function() {
4085 this.el.on('click', this.onClick, this);
4088 onClick : function(e)
4090 Roo.log('PaginationItem on click ');
4091 if(this.preventDefault){
4095 this.fireEvent('click', this, e);
4111 * @class Roo.bootstrap.Slider
4112 * @extends Roo.bootstrap.Component
4113 * Bootstrap Slider class
4116 * Create a new Slider
4117 * @param {Object} config The config object
4120 Roo.bootstrap.Slider = function(config){
4121 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4124 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4126 getAutoCreate : function(){
4130 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4134 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4146 * Ext JS Library 1.1.1
4147 * Copyright(c) 2006-2007, Ext JS, LLC.
4149 * Originally Released Under LGPL - original licence link has changed is not relivant.
4152 * <script type="text/javascript">
4157 * @class Roo.grid.ColumnModel
4158 * @extends Roo.util.Observable
4159 * This is the default implementation of a ColumnModel used by the Grid. It defines
4160 * the columns in the grid.
4163 var colModel = new Roo.grid.ColumnModel([
4164 {header: "Ticker", width: 60, sortable: true, locked: true},
4165 {header: "Company Name", width: 150, sortable: true},
4166 {header: "Market Cap.", width: 100, sortable: true},
4167 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4168 {header: "Employees", width: 100, sortable: true, resizable: false}
4173 * The config options listed for this class are options which may appear in each
4174 * individual column definition.
4175 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4177 * @param {Object} config An Array of column config objects. See this class's
4178 * config objects for details.
4180 Roo.grid.ColumnModel = function(config){
4182 * The config passed into the constructor
4184 this.config = config;
4187 // if no id, create one
4188 // if the column does not have a dataIndex mapping,
4189 // map it to the order it is in the config
4190 for(var i = 0, len = config.length; i < len; i++){
4192 if(typeof c.dataIndex == "undefined"){
4195 if(typeof c.renderer == "string"){
4196 c.renderer = Roo.util.Format[c.renderer];
4198 if(typeof c.id == "undefined"){
4201 if(c.editor && c.editor.xtype){
4202 c.editor = Roo.factory(c.editor, Roo.grid);
4204 if(c.editor && c.editor.isFormField){
4205 c.editor = new Roo.grid.GridEditor(c.editor);
4207 this.lookup[c.id] = c;
4211 * The width of columns which have no width specified (defaults to 100)
4214 this.defaultWidth = 100;
4217 * Default sortable of columns which have no sortable specified (defaults to false)
4220 this.defaultSortable = false;
4224 * @event widthchange
4225 * Fires when the width of a column changes.
4226 * @param {ColumnModel} this
4227 * @param {Number} columnIndex The column index
4228 * @param {Number} newWidth The new width
4230 "widthchange": true,
4232 * @event headerchange
4233 * Fires when the text of a header changes.
4234 * @param {ColumnModel} this
4235 * @param {Number} columnIndex The column index
4236 * @param {Number} newText The new header text
4238 "headerchange": true,
4240 * @event hiddenchange
4241 * Fires when a column is hidden or "unhidden".
4242 * @param {ColumnModel} this
4243 * @param {Number} columnIndex The column index
4244 * @param {Boolean} hidden true if hidden, false otherwise
4246 "hiddenchange": true,
4248 * @event columnmoved
4249 * Fires when a column is moved.
4250 * @param {ColumnModel} this
4251 * @param {Number} oldIndex
4252 * @param {Number} newIndex
4254 "columnmoved" : true,
4256 * @event columlockchange
4257 * Fires when a column's locked state is changed
4258 * @param {ColumnModel} this
4259 * @param {Number} colIndex
4260 * @param {Boolean} locked true if locked
4262 "columnlockchange" : true
4264 Roo.grid.ColumnModel.superclass.constructor.call(this);
4266 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4268 * @cfg {String} header The header text to display in the Grid view.
4271 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4272 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4273 * specified, the column's index is used as an index into the Record's data Array.
4276 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4277 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4280 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4281 * Defaults to the value of the {@link #defaultSortable} property.
4282 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4285 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4288 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4291 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4294 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4297 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4298 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4299 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4300 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4303 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4306 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4310 * Returns the id of the column at the specified index.
4311 * @param {Number} index The column index
4312 * @return {String} the id
4314 getColumnId : function(index){
4315 return this.config[index].id;
4319 * Returns the column for a specified id.
4320 * @param {String} id The column id
4321 * @return {Object} the column
4323 getColumnById : function(id){
4324 return this.lookup[id];
4329 * Returns the column for a specified dataIndex.
4330 * @param {String} dataIndex The column dataIndex
4331 * @return {Object|Boolean} the column or false if not found
4333 getColumnByDataIndex: function(dataIndex){
4334 var index = this.findColumnIndex(dataIndex);
4335 return index > -1 ? this.config[index] : false;
4339 * Returns the index for a specified column id.
4340 * @param {String} id The column id
4341 * @return {Number} the index, or -1 if not found
4343 getIndexById : function(id){
4344 for(var i = 0, len = this.config.length; i < len; i++){
4345 if(this.config[i].id == id){
4353 * Returns the index for a specified column dataIndex.
4354 * @param {String} dataIndex The column dataIndex
4355 * @return {Number} the index, or -1 if not found
4358 findColumnIndex : function(dataIndex){
4359 for(var i = 0, len = this.config.length; i < len; i++){
4360 if(this.config[i].dataIndex == dataIndex){
4368 moveColumn : function(oldIndex, newIndex){
4369 var c = this.config[oldIndex];
4370 this.config.splice(oldIndex, 1);
4371 this.config.splice(newIndex, 0, c);
4372 this.dataMap = null;
4373 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4376 isLocked : function(colIndex){
4377 return this.config[colIndex].locked === true;
4380 setLocked : function(colIndex, value, suppressEvent){
4381 if(this.isLocked(colIndex) == value){
4384 this.config[colIndex].locked = value;
4386 this.fireEvent("columnlockchange", this, colIndex, value);
4390 getTotalLockedWidth : function(){
4392 for(var i = 0; i < this.config.length; i++){
4393 if(this.isLocked(i) && !this.isHidden(i)){
4394 this.totalWidth += this.getColumnWidth(i);
4400 getLockedCount : function(){
4401 for(var i = 0, len = this.config.length; i < len; i++){
4402 if(!this.isLocked(i)){
4409 * Returns the number of columns.
4412 getColumnCount : function(visibleOnly){
4413 if(visibleOnly === true){
4415 for(var i = 0, len = this.config.length; i < len; i++){
4416 if(!this.isHidden(i)){
4422 return this.config.length;
4426 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4427 * @param {Function} fn
4428 * @param {Object} scope (optional)
4429 * @return {Array} result
4431 getColumnsBy : function(fn, scope){
4433 for(var i = 0, len = this.config.length; i < len; i++){
4434 var c = this.config[i];
4435 if(fn.call(scope||this, c, i) === true){
4443 * Returns true if the specified column is sortable.
4444 * @param {Number} col The column index
4447 isSortable : function(col){
4448 if(typeof this.config[col].sortable == "undefined"){
4449 return this.defaultSortable;
4451 return this.config[col].sortable;
4455 * Returns the rendering (formatting) function defined for the column.
4456 * @param {Number} col The column index.
4457 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4459 getRenderer : function(col){
4460 if(!this.config[col].renderer){
4461 return Roo.grid.ColumnModel.defaultRenderer;
4463 return this.config[col].renderer;
4467 * Sets the rendering (formatting) function for a column.
4468 * @param {Number} col The column index
4469 * @param {Function} fn The function to use to process the cell's raw data
4470 * to return HTML markup for the grid view. The render function is called with
4471 * the following parameters:<ul>
4472 * <li>Data value.</li>
4473 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4474 * <li>css A CSS style string to apply to the table cell.</li>
4475 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4476 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4477 * <li>Row index</li>
4478 * <li>Column index</li>
4479 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4481 setRenderer : function(col, fn){
4482 this.config[col].renderer = fn;
4486 * Returns the width for the specified column.
4487 * @param {Number} col The column index
4490 getColumnWidth : function(col){
4491 return this.config[col].width * 1 || this.defaultWidth;
4495 * Sets the width for a column.
4496 * @param {Number} col The column index
4497 * @param {Number} width The new width
4499 setColumnWidth : function(col, width, suppressEvent){
4500 this.config[col].width = width;
4501 this.totalWidth = null;
4503 this.fireEvent("widthchange", this, col, width);
4508 * Returns the total width of all columns.
4509 * @param {Boolean} includeHidden True to include hidden column widths
4512 getTotalWidth : function(includeHidden){
4513 if(!this.totalWidth){
4514 this.totalWidth = 0;
4515 for(var i = 0, len = this.config.length; i < len; i++){
4516 if(includeHidden || !this.isHidden(i)){
4517 this.totalWidth += this.getColumnWidth(i);
4521 return this.totalWidth;
4525 * Returns the header for the specified column.
4526 * @param {Number} col The column index
4529 getColumnHeader : function(col){
4530 return this.config[col].header;
4534 * Sets the header for a column.
4535 * @param {Number} col The column index
4536 * @param {String} header The new header
4538 setColumnHeader : function(col, header){
4539 this.config[col].header = header;
4540 this.fireEvent("headerchange", this, col, header);
4544 * Returns the tooltip for the specified column.
4545 * @param {Number} col The column index
4548 getColumnTooltip : function(col){
4549 return this.config[col].tooltip;
4552 * Sets the tooltip for a column.
4553 * @param {Number} col The column index
4554 * @param {String} tooltip The new tooltip
4556 setColumnTooltip : function(col, tooltip){
4557 this.config[col].tooltip = tooltip;
4561 * Returns the dataIndex for the specified column.
4562 * @param {Number} col The column index
4565 getDataIndex : function(col){
4566 return this.config[col].dataIndex;
4570 * Sets the dataIndex for a column.
4571 * @param {Number} col The column index
4572 * @param {Number} dataIndex The new dataIndex
4574 setDataIndex : function(col, dataIndex){
4575 this.config[col].dataIndex = dataIndex;
4581 * Returns true if the cell is editable.
4582 * @param {Number} colIndex The column index
4583 * @param {Number} rowIndex The row index
4586 isCellEditable : function(colIndex, rowIndex){
4587 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4591 * Returns the editor defined for the cell/column.
4592 * return false or null to disable editing.
4593 * @param {Number} colIndex The column index
4594 * @param {Number} rowIndex The row index
4597 getCellEditor : function(colIndex, rowIndex){
4598 return this.config[colIndex].editor;
4602 * Sets if a column is editable.
4603 * @param {Number} col The column index
4604 * @param {Boolean} editable True if the column is editable
4606 setEditable : function(col, editable){
4607 this.config[col].editable = editable;
4612 * Returns true if the column is hidden.
4613 * @param {Number} colIndex The column index
4616 isHidden : function(colIndex){
4617 return this.config[colIndex].hidden;
4622 * Returns true if the column width cannot be changed
4624 isFixed : function(colIndex){
4625 return this.config[colIndex].fixed;
4629 * Returns true if the column can be resized
4632 isResizable : function(colIndex){
4633 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4636 * Sets if a column is hidden.
4637 * @param {Number} colIndex The column index
4638 * @param {Boolean} hidden True if the column is hidden
4640 setHidden : function(colIndex, hidden){
4641 this.config[colIndex].hidden = hidden;
4642 this.totalWidth = null;
4643 this.fireEvent("hiddenchange", this, colIndex, hidden);
4647 * Sets the editor for a column.
4648 * @param {Number} col The column index
4649 * @param {Object} editor The editor object
4651 setEditor : function(col, editor){
4652 this.config[col].editor = editor;
4656 Roo.grid.ColumnModel.defaultRenderer = function(value){
4657 if(typeof value == "string" && value.length < 1){
4663 // Alias for backwards compatibility
4664 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4667 * Ext JS Library 1.1.1
4668 * Copyright(c) 2006-2007, Ext JS, LLC.
4670 * Originally Released Under LGPL - original licence link has changed is not relivant.
4673 * <script type="text/javascript">
4677 * @class Roo.LoadMask
4678 * A simple utility class for generically masking elements while loading data. If the element being masked has
4679 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4680 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4681 * element's UpdateManager load indicator and will be destroyed after the initial load.
4683 * Create a new LoadMask
4684 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4685 * @param {Object} config The config object
4687 Roo.LoadMask = function(el, config){
4688 this.el = Roo.get(el);
4689 Roo.apply(this, config);
4691 this.store.on('beforeload', this.onBeforeLoad, this);
4692 this.store.on('load', this.onLoad, this);
4693 this.store.on('loadexception', this.onLoadException, this);
4694 this.removeMask = false;
4696 var um = this.el.getUpdateManager();
4697 um.showLoadIndicator = false; // disable the default indicator
4698 um.on('beforeupdate', this.onBeforeLoad, this);
4699 um.on('update', this.onLoad, this);
4700 um.on('failure', this.onLoad, this);
4701 this.removeMask = true;
4705 Roo.LoadMask.prototype = {
4707 * @cfg {Boolean} removeMask
4708 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4709 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4713 * The text to display in a centered loading message box (defaults to 'Loading...')
4717 * @cfg {String} msgCls
4718 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4720 msgCls : 'x-mask-loading',
4723 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4729 * Disables the mask to prevent it from being displayed
4731 disable : function(){
4732 this.disabled = true;
4736 * Enables the mask so that it can be displayed
4738 enable : function(){
4739 this.disabled = false;
4742 onLoadException : function()
4746 if (typeof(arguments[3]) != 'undefined') {
4747 Roo.MessageBox.alert("Error loading",arguments[3]);
4751 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4752 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4761 this.el.unmask(this.removeMask);
4766 this.el.unmask(this.removeMask);
4770 onBeforeLoad : function(){
4772 this.el.mask(this.msg, this.msgCls);
4777 destroy : function(){
4779 this.store.un('beforeload', this.onBeforeLoad, this);
4780 this.store.un('load', this.onLoad, this);
4781 this.store.un('loadexception', this.onLoadException, this);
4783 var um = this.el.getUpdateManager();
4784 um.un('beforeupdate', this.onBeforeLoad, this);
4785 um.un('update', this.onLoad, this);
4786 um.un('failure', this.onLoad, this);
4797 * @class Roo.bootstrap.Table
4798 * @extends Roo.bootstrap.Component
4799 * Bootstrap Table class
4800 * @cfg {String} cls table class
4801 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4802 * @cfg {String} bgcolor Specifies the background color for a table
4803 * @cfg {Number} border Specifies whether the table cells should have borders or not
4804 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4805 * @cfg {Number} cellspacing Specifies the space between cells
4806 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4807 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4808 * @cfg {String} sortable Specifies that the table should be sortable
4809 * @cfg {String} summary Specifies a summary of the content of a table
4810 * @cfg {Number} width Specifies the width of a table
4811 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4813 * @cfg {boolean} striped Should the rows be alternative striped
4814 * @cfg {boolean} bordered Add borders to the table
4815 * @cfg {boolean} hover Add hover highlighting
4816 * @cfg {boolean} condensed Format condensed
4817 * @cfg {boolean} responsive Format condensed
4818 * @cfg {Boolean} loadMask (true|false) default false
4819 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4820 * @cfg {Boolean} thead (true|false) generate thead, default true
4821 * @cfg {Boolean} RowSelection (true|false) default false
4822 * @cfg {Boolean} CellSelection (true|false) default false
4824 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4828 * Create a new Table
4829 * @param {Object} config The config object
4832 Roo.bootstrap.Table = function(config){
4833 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4836 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4837 this.sm = this.selModel;
4838 this.sm.xmodule = this.xmodule || false;
4840 if (this.cm && typeof(this.cm.config) == 'undefined') {
4841 this.colModel = new Roo.grid.ColumnModel(this.cm);
4842 this.cm = this.colModel;
4843 this.cm.xmodule = this.xmodule || false;
4846 this.store= Roo.factory(this.store, Roo.data);
4847 this.ds = this.store;
4848 this.ds.xmodule = this.xmodule || false;
4851 if (this.footer && this.store) {
4852 this.footer.dataSource = this.ds;
4853 this.footer = Roo.factory(this.footer);
4860 * Fires when a cell is clicked
4861 * @param {Roo.bootstrap.Table} this
4862 * @param {Roo.Element} el
4863 * @param {Number} rowIndex
4864 * @param {Number} columnIndex
4865 * @param {Roo.EventObject} e
4869 * @event celldblclick
4870 * Fires when a cell is double clicked
4871 * @param {Roo.bootstrap.Table} this
4872 * @param {Roo.Element} el
4873 * @param {Number} rowIndex
4874 * @param {Number} columnIndex
4875 * @param {Roo.EventObject} e
4877 "celldblclick" : true,
4880 * Fires when a row is clicked
4881 * @param {Roo.bootstrap.Table} this
4882 * @param {Roo.Element} el
4883 * @param {Number} rowIndex
4884 * @param {Roo.EventObject} e
4888 * @event rowdblclick
4889 * Fires when a row is double clicked
4890 * @param {Roo.bootstrap.Table} this
4891 * @param {Roo.Element} el
4892 * @param {Number} rowIndex
4893 * @param {Roo.EventObject} e
4895 "rowdblclick" : true,
4898 * Fires when a mouseover occur
4899 * @param {Roo.bootstrap.Table} this
4900 * @param {Roo.Element} el
4901 * @param {Number} rowIndex
4902 * @param {Number} columnIndex
4903 * @param {Roo.EventObject} e
4908 * Fires when a mouseout occur
4909 * @param {Roo.bootstrap.Table} this
4910 * @param {Roo.Element} el
4911 * @param {Number} rowIndex
4912 * @param {Number} columnIndex
4913 * @param {Roo.EventObject} e
4918 * Fires when a row is rendered, so you can change add a style to it.
4919 * @param {Roo.bootstrap.Table} this
4920 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4927 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4951 RowSelection : false,
4952 CellSelection : false,
4955 // Roo.Element - the tbody
4958 getAutoCreate : function(){
4959 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4968 cfg.cls += ' table-striped';
4972 cfg.cls += ' table-hover';
4974 if (this.bordered) {
4975 cfg.cls += ' table-bordered';
4977 if (this.condensed) {
4978 cfg.cls += ' table-condensed';
4980 if (this.responsive) {
4981 cfg.cls += ' table-responsive';
4985 cfg.cls+= ' ' +this.cls;
4988 // this lot should be simplifed...
4991 cfg.align=this.align;
4994 cfg.bgcolor=this.bgcolor;
4997 cfg.border=this.border;
4999 if (this.cellpadding) {
5000 cfg.cellpadding=this.cellpadding;
5002 if (this.cellspacing) {
5003 cfg.cellspacing=this.cellspacing;
5006 cfg.frame=this.frame;
5009 cfg.rules=this.rules;
5011 if (this.sortable) {
5012 cfg.sortable=this.sortable;
5015 cfg.summary=this.summary;
5018 cfg.width=this.width;
5021 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5024 if(this.store || this.cm){
5026 cfg.cn.push(this.renderHeader());
5029 cfg.cn.push(this.renderBody());
5032 cfg.cn.push(this.renderFooter());
5035 cfg.cls+= ' TableGrid';
5038 return { cn : [ cfg ] };
5041 initEvents : function()
5043 if(!this.store || !this.cm){
5047 //Roo.log('initEvents with ds!!!!');
5049 this.mainBody = this.el.select('tbody', true).first();
5054 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5055 e.on('click', _this.sort, _this);
5058 this.el.on("click", this.onClick, this);
5059 this.el.on("dblclick", this.onDblClick, this);
5061 this.parent().el.setStyle('position', 'relative');
5063 this.footer.parentId = this.id;
5064 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5067 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5069 this.store.on('load', this.onLoad, this);
5070 this.store.on('beforeload', this.onBeforeLoad, this);
5071 this.store.on('update', this.onUpdate, this);
5075 onMouseover : function(e, el)
5077 var cell = Roo.get(el);
5083 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5084 cell = cell.findParent('td', false, true);
5087 var row = cell.findParent('tr', false, true);
5088 var cellIndex = cell.dom.cellIndex;
5089 var rowIndex = row.dom.rowIndex - 1; // start from 0
5091 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5095 onMouseout : function(e, el)
5097 var cell = Roo.get(el);
5103 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5104 cell = cell.findParent('td', false, true);
5107 var row = cell.findParent('tr', false, true);
5108 var cellIndex = cell.dom.cellIndex;
5109 var rowIndex = row.dom.rowIndex - 1; // start from 0
5111 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5115 onClick : function(e, el)
5117 var cell = Roo.get(el);
5119 if(!cell || (!this.CellSelection && !this.RowSelection)){
5124 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5125 cell = cell.findParent('td', false, true);
5128 var row = cell.findParent('tr', false, true);
5129 var cellIndex = cell.dom.cellIndex;
5130 var rowIndex = row.dom.rowIndex - 1;
5132 if(this.CellSelection){
5133 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5136 if(this.RowSelection){
5137 this.fireEvent('rowclick', this, row, rowIndex, e);
5143 onDblClick : function(e,el)
5145 var cell = Roo.get(el);
5147 if(!cell || (!this.CellSelection && !this.RowSelection)){
5151 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5152 cell = cell.findParent('td', false, true);
5155 var row = cell.findParent('tr', false, true);
5156 var cellIndex = cell.dom.cellIndex;
5157 var rowIndex = row.dom.rowIndex - 1;
5159 if(this.CellSelection){
5160 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5163 if(this.RowSelection){
5164 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5168 sort : function(e,el)
5170 var col = Roo.get(el)
5172 if(!col.hasClass('sortable')){
5176 var sort = col.attr('sort');
5179 if(col.hasClass('glyphicon-arrow-up')){
5183 this.store.sortInfo = {field : sort, direction : dir};
5186 Roo.log("calling footer first");
5187 this.footer.onClick('first');
5190 this.store.load({ params : { start : 0 } });
5194 renderHeader : function()
5203 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5205 var config = cm.config[i];
5210 html: cm.getColumnHeader(i)
5213 if(typeof(config.hidden) != 'undefined' && config.hidden){
5214 c.style += ' display:none;';
5217 if(typeof(config.dataIndex) != 'undefined'){
5218 c.sort = config.dataIndex;
5221 if(typeof(config.sortable) != 'undefined' && config.sortable){
5225 if(typeof(config.align) != 'undefined' && config.align.length){
5226 c.style += ' text-align:' + config.align + ';';
5229 if(typeof(config.width) != 'undefined'){
5230 c.style += ' width:' + config.width + 'px;';
5239 renderBody : function()
5249 colspan : this.cm.getColumnCount()
5259 renderFooter : function()
5269 colspan : this.cm.getColumnCount()
5283 Roo.log('ds onload');
5288 var ds = this.store;
5290 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5291 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5293 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5294 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5297 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5298 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5302 var tbody = this.mainBody;
5304 if(ds.getCount() > 0){
5305 ds.data.each(function(d,rowIndex){
5306 var row = this.renderRow(cm, ds, rowIndex);
5308 tbody.createChild(row);
5312 if(row.cellObjects.length){
5313 Roo.each(row.cellObjects, function(r){
5314 _this.renderCellObject(r);
5321 Roo.each(this.el.select('tbody td', true).elements, function(e){
5322 e.on('mouseover', _this.onMouseover, _this);
5325 Roo.each(this.el.select('tbody td', true).elements, function(e){
5326 e.on('mouseout', _this.onMouseout, _this);
5329 //if(this.loadMask){
5330 // this.maskEl.hide();
5335 onUpdate : function(ds,record)
5337 this.refreshRow(record);
5339 onRemove : function(ds, record, index, isUpdate){
5340 if(isUpdate !== true){
5341 this.fireEvent("beforerowremoved", this, index, record);
5343 var bt = this.mainBody.dom;
5345 bt.removeChild(bt.rows[index]);
5348 if(isUpdate !== true){
5349 //this.stripeRows(index);
5350 //this.syncRowHeights(index, index);
5352 this.fireEvent("rowremoved", this, index, record);
5357 refreshRow : function(record){
5358 var ds = this.store, index;
5359 if(typeof record == 'number'){
5361 record = ds.getAt(index);
5363 index = ds.indexOf(record);
5365 this.insertRow(ds, index, true);
5366 this.onRemove(ds, record, index+1, true);
5367 //this.syncRowHeights(index, index);
5369 this.fireEvent("rowupdated", this, index, record);
5372 insertRow : function(dm, rowIndex, isUpdate){
5375 this.fireEvent("beforerowsinserted", this, rowIndex);
5377 //var s = this.getScrollState();
5378 var row = this.renderRow(this.cm, this.store, rowIndex);
5379 // insert before rowIndex..
5380 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5384 if(row.cellObjects.length){
5385 Roo.each(row.cellObjects, function(r){
5386 _this.renderCellObject(r);
5391 this.fireEvent("rowsinserted", this, rowIndex);
5392 //this.syncRowHeights(firstRow, lastRow);
5393 //this.stripeRows(firstRow);
5400 getRowDom : function(rowIndex)
5402 // not sure if I need to check this.. but let's do it anyway..
5403 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5404 this.mainBody.dom.rows[rowIndex] : false
5406 // returns the object tree for a tr..
5409 renderRow : function(cm, ds, rowIndex) {
5411 var d = ds.getAt(rowIndex);
5418 var cellObjects = [];
5420 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5421 var config = cm.config[i];
5423 var renderer = cm.getRenderer(i);
5427 if(typeof(renderer) !== 'undefined'){
5428 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5430 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5431 // and are rendered into the cells after the row is rendered - using the id for the element.
5433 if(typeof(value) === 'object'){
5443 rowIndex : rowIndex,
5448 this.fireEvent('rowclass', this, rowcfg);
5452 cls : rowcfg.rowClass,
5454 html: (typeof(value) === 'object') ? '' : value
5461 if(typeof(config.hidden) != 'undefined' && config.hidden){
5462 td.style += ' display:none;';
5465 if(typeof(config.align) != 'undefined' && config.align.length){
5466 td.style += ' text-align:' + config.align + ';';
5469 if(typeof(config.width) != 'undefined'){
5470 td.style += ' width:' + config.width + 'px;';
5477 row.cellObjects = cellObjects;
5485 onBeforeLoad : function()
5487 //Roo.log('ds onBeforeLoad');
5491 //if(this.loadMask){
5492 // this.maskEl.show();
5498 this.el.select('tbody', true).first().dom.innerHTML = '';
5501 getSelectionModel : function(){
5503 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5505 return this.selModel;
5508 * Render the Roo.bootstrap object from renderder
5510 renderCellObject : function(r)
5514 var t = r.cfg.render(r.container);
5517 Roo.each(r.cfg.cn, function(c){
5519 container: t.getChildContainer(),
5522 _this.renderCellObject(child);
5539 * @class Roo.bootstrap.TableCell
5540 * @extends Roo.bootstrap.Component
5541 * Bootstrap TableCell class
5542 * @cfg {String} html cell contain text
5543 * @cfg {String} cls cell class
5544 * @cfg {String} tag cell tag (td|th) default td
5545 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5546 * @cfg {String} align Aligns the content in a cell
5547 * @cfg {String} axis Categorizes cells
5548 * @cfg {String} bgcolor Specifies the background color of a cell
5549 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5550 * @cfg {Number} colspan Specifies the number of columns a cell should span
5551 * @cfg {String} headers Specifies one or more header cells a cell is related to
5552 * @cfg {Number} height Sets the height of a cell
5553 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5554 * @cfg {Number} rowspan Sets the number of rows a cell should span
5555 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5556 * @cfg {String} valign Vertical aligns the content in a cell
5557 * @cfg {Number} width Specifies the width of a cell
5560 * Create a new TableCell
5561 * @param {Object} config The config object
5564 Roo.bootstrap.TableCell = function(config){
5565 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5568 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5588 getAutoCreate : function(){
5589 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5609 cfg.align=this.align
5615 cfg.bgcolor=this.bgcolor
5618 cfg.charoff=this.charoff
5621 cfg.colspan=this.colspan
5624 cfg.headers=this.headers
5627 cfg.height=this.height
5630 cfg.nowrap=this.nowrap
5633 cfg.rowspan=this.rowspan
5636 cfg.scope=this.scope
5639 cfg.valign=this.valign
5642 cfg.width=this.width
5661 * @class Roo.bootstrap.TableRow
5662 * @extends Roo.bootstrap.Component
5663 * Bootstrap TableRow class
5664 * @cfg {String} cls row class
5665 * @cfg {String} align Aligns the content in a table row
5666 * @cfg {String} bgcolor Specifies a background color for a table row
5667 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5668 * @cfg {String} valign Vertical aligns the content in a table row
5671 * Create a new TableRow
5672 * @param {Object} config The config object
5675 Roo.bootstrap.TableRow = function(config){
5676 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5679 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5687 getAutoCreate : function(){
5688 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5698 cfg.align = this.align;
5701 cfg.bgcolor = this.bgcolor;
5704 cfg.charoff = this.charoff;
5707 cfg.valign = this.valign;
5725 * @class Roo.bootstrap.TableBody
5726 * @extends Roo.bootstrap.Component
5727 * Bootstrap TableBody class
5728 * @cfg {String} cls element class
5729 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5730 * @cfg {String} align Aligns the content inside the element
5731 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5732 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5735 * Create a new TableBody
5736 * @param {Object} config The config object
5739 Roo.bootstrap.TableBody = function(config){
5740 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5743 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5751 getAutoCreate : function(){
5752 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5766 cfg.align = this.align;
5769 cfg.charoff = this.charoff;
5772 cfg.valign = this.valign;
5779 // initEvents : function()
5786 // this.store = Roo.factory(this.store, Roo.data);
5787 // this.store.on('load', this.onLoad, this);
5789 // this.store.load();
5793 // onLoad: function ()
5795 // this.fireEvent('load', this);
5805 * Ext JS Library 1.1.1
5806 * Copyright(c) 2006-2007, Ext JS, LLC.
5808 * Originally Released Under LGPL - original licence link has changed is not relivant.
5811 * <script type="text/javascript">
5814 // as we use this in bootstrap.
5815 Roo.namespace('Roo.form');
5817 * @class Roo.form.Action
5818 * Internal Class used to handle form actions
5820 * @param {Roo.form.BasicForm} el The form element or its id
5821 * @param {Object} config Configuration options
5826 // define the action interface
5827 Roo.form.Action = function(form, options){
5829 this.options = options || {};
5832 * Client Validation Failed
5835 Roo.form.Action.CLIENT_INVALID = 'client';
5837 * Server Validation Failed
5840 Roo.form.Action.SERVER_INVALID = 'server';
5842 * Connect to Server Failed
5845 Roo.form.Action.CONNECT_FAILURE = 'connect';
5847 * Reading Data from Server Failed
5850 Roo.form.Action.LOAD_FAILURE = 'load';
5852 Roo.form.Action.prototype = {
5854 failureType : undefined,
5855 response : undefined,
5859 run : function(options){
5864 success : function(response){
5869 handleResponse : function(response){
5873 // default connection failure
5874 failure : function(response){
5876 this.response = response;
5877 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5878 this.form.afterAction(this, false);
5881 processResponse : function(response){
5882 this.response = response;
5883 if(!response.responseText){
5886 this.result = this.handleResponse(response);
5890 // utility functions used internally
5891 getUrl : function(appendParams){
5892 var url = this.options.url || this.form.url || this.form.el.dom.action;
5894 var p = this.getParams();
5896 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5902 getMethod : function(){
5903 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5906 getParams : function(){
5907 var bp = this.form.baseParams;
5908 var p = this.options.params;
5910 if(typeof p == "object"){
5911 p = Roo.urlEncode(Roo.applyIf(p, bp));
5912 }else if(typeof p == 'string' && bp){
5913 p += '&' + Roo.urlEncode(bp);
5916 p = Roo.urlEncode(bp);
5921 createCallback : function(){
5923 success: this.success,
5924 failure: this.failure,
5926 timeout: (this.form.timeout*1000),
5927 upload: this.form.fileUpload ? this.success : undefined
5932 Roo.form.Action.Submit = function(form, options){
5933 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5936 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5939 haveProgress : false,
5940 uploadComplete : false,
5942 // uploadProgress indicator.
5943 uploadProgress : function()
5945 if (!this.form.progressUrl) {
5949 if (!this.haveProgress) {
5950 Roo.MessageBox.progress("Uploading", "Uploading");
5952 if (this.uploadComplete) {
5953 Roo.MessageBox.hide();
5957 this.haveProgress = true;
5959 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5961 var c = new Roo.data.Connection();
5963 url : this.form.progressUrl,
5968 success : function(req){
5969 //console.log(data);
5973 rdata = Roo.decode(req.responseText)
5975 Roo.log("Invalid data from server..");
5979 if (!rdata || !rdata.success) {
5981 Roo.MessageBox.alert(Roo.encode(rdata));
5984 var data = rdata.data;
5986 if (this.uploadComplete) {
5987 Roo.MessageBox.hide();
5992 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5993 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5996 this.uploadProgress.defer(2000,this);
5999 failure: function(data) {
6000 Roo.log('progress url failed ');
6011 // run get Values on the form, so it syncs any secondary forms.
6012 this.form.getValues();
6014 var o = this.options;
6015 var method = this.getMethod();
6016 var isPost = method == 'POST';
6017 if(o.clientValidation === false || this.form.isValid()){
6019 if (this.form.progressUrl) {
6020 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6021 (new Date() * 1) + '' + Math.random());
6026 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6027 form:this.form.el.dom,
6028 url:this.getUrl(!isPost),
6030 params:isPost ? this.getParams() : null,
6031 isUpload: this.form.fileUpload
6034 this.uploadProgress();
6036 }else if (o.clientValidation !== false){ // client validation failed
6037 this.failureType = Roo.form.Action.CLIENT_INVALID;
6038 this.form.afterAction(this, false);
6042 success : function(response)
6044 this.uploadComplete= true;
6045 if (this.haveProgress) {
6046 Roo.MessageBox.hide();
6050 var result = this.processResponse(response);
6051 if(result === true || result.success){
6052 this.form.afterAction(this, true);
6056 this.form.markInvalid(result.errors);
6057 this.failureType = Roo.form.Action.SERVER_INVALID;
6059 this.form.afterAction(this, false);
6061 failure : function(response)
6063 this.uploadComplete= true;
6064 if (this.haveProgress) {
6065 Roo.MessageBox.hide();
6068 this.response = response;
6069 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6070 this.form.afterAction(this, false);
6073 handleResponse : function(response){
6074 if(this.form.errorReader){
6075 var rs = this.form.errorReader.read(response);
6078 for(var i = 0, len = rs.records.length; i < len; i++) {
6079 var r = rs.records[i];
6083 if(errors.length < 1){
6087 success : rs.success,
6093 ret = Roo.decode(response.responseText);
6097 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6107 Roo.form.Action.Load = function(form, options){
6108 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6109 this.reader = this.form.reader;
6112 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6117 Roo.Ajax.request(Roo.apply(
6118 this.createCallback(), {
6119 method:this.getMethod(),
6120 url:this.getUrl(false),
6121 params:this.getParams()
6125 success : function(response){
6127 var result = this.processResponse(response);
6128 if(result === true || !result.success || !result.data){
6129 this.failureType = Roo.form.Action.LOAD_FAILURE;
6130 this.form.afterAction(this, false);
6133 this.form.clearInvalid();
6134 this.form.setValues(result.data);
6135 this.form.afterAction(this, true);
6138 handleResponse : function(response){
6139 if(this.form.reader){
6140 var rs = this.form.reader.read(response);
6141 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6143 success : rs.success,
6147 return Roo.decode(response.responseText);
6151 Roo.form.Action.ACTION_TYPES = {
6152 'load' : Roo.form.Action.Load,
6153 'submit' : Roo.form.Action.Submit
6162 * @class Roo.bootstrap.Form
6163 * @extends Roo.bootstrap.Component
6164 * Bootstrap Form class
6165 * @cfg {String} method GET | POST (default POST)
6166 * @cfg {String} labelAlign top | left (default top)
6167 * @cfg {String} align left | right - for navbars
6168 * @cfg {Boolean} loadMask load mask when submit (default true)
6173 * @param {Object} config The config object
6177 Roo.bootstrap.Form = function(config){
6178 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6181 * @event clientvalidation
6182 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6183 * @param {Form} this
6184 * @param {Boolean} valid true if the form has passed client-side validation
6186 clientvalidation: true,
6188 * @event beforeaction
6189 * Fires before any action is performed. Return false to cancel the action.
6190 * @param {Form} this
6191 * @param {Action} action The action to be performed
6195 * @event actionfailed
6196 * Fires when an action fails.
6197 * @param {Form} this
6198 * @param {Action} action The action that failed
6200 actionfailed : true,
6202 * @event actioncomplete
6203 * Fires when an action is completed.
6204 * @param {Form} this
6205 * @param {Action} action The action that completed
6207 actioncomplete : true
6212 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6215 * @cfg {String} method
6216 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6221 * The URL to use for form actions if one isn't supplied in the action options.
6224 * @cfg {Boolean} fileUpload
6225 * Set to true if this form is a file upload.
6229 * @cfg {Object} baseParams
6230 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6234 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6238 * @cfg {Sting} align (left|right) for navbar forms
6243 activeAction : null,
6246 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6247 * element by passing it or its id or mask the form itself by passing in true.
6250 waitMsgTarget : false,
6254 getAutoCreate : function(){
6258 method : this.method || 'POST',
6259 id : this.id || Roo.id(),
6262 if (this.parent().xtype.match(/^Nav/)) {
6263 cfg.cls = 'navbar-form navbar-' + this.align;
6267 if (this.labelAlign == 'left' ) {
6268 cfg.cls += ' form-horizontal';
6274 initEvents : function()
6276 this.el.on('submit', this.onSubmit, this);
6277 // this was added as random key presses on the form where triggering form submit.
6278 this.el.on('keypress', function(e) {
6279 if (e.getCharCode() != 13) {
6282 // we might need to allow it for textareas.. and some other items.
6283 // check e.getTarget().
6285 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6289 Roo.log("keypress blocked");
6297 onSubmit : function(e){
6302 * Returns true if client-side validation on the form is successful.
6305 isValid : function(){
6306 var items = this.getItems();
6308 items.each(function(f){
6317 * Returns true if any fields in this form have changed since their original load.
6320 isDirty : function(){
6322 var items = this.getItems();
6323 items.each(function(f){
6333 * Performs a predefined action (submit or load) or custom actions you define on this form.
6334 * @param {String} actionName The name of the action type
6335 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6336 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6337 * accept other config options):
6339 Property Type Description
6340 ---------------- --------------- ----------------------------------------------------------------------------------
6341 url String The url for the action (defaults to the form's url)
6342 method String The form method to use (defaults to the form's method, or POST if not defined)
6343 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6344 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6345 validate the form on the client (defaults to false)
6347 * @return {BasicForm} this
6349 doAction : function(action, options){
6350 if(typeof action == 'string'){
6351 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6353 if(this.fireEvent('beforeaction', this, action) !== false){
6354 this.beforeAction(action);
6355 action.run.defer(100, action);
6361 beforeAction : function(action){
6362 var o = action.options;
6365 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6367 // not really supported yet.. ??
6369 //if(this.waitMsgTarget === true){
6370 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6371 //}else if(this.waitMsgTarget){
6372 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6373 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6375 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6381 afterAction : function(action, success){
6382 this.activeAction = null;
6383 var o = action.options;
6385 //if(this.waitMsgTarget === true){
6387 //}else if(this.waitMsgTarget){
6388 // this.waitMsgTarget.unmask();
6390 // Roo.MessageBox.updateProgress(1);
6391 // Roo.MessageBox.hide();
6398 Roo.callback(o.success, o.scope, [this, action]);
6399 this.fireEvent('actioncomplete', this, action);
6403 // failure condition..
6404 // we have a scenario where updates need confirming.
6405 // eg. if a locking scenario exists..
6406 // we look for { errors : { needs_confirm : true }} in the response.
6408 (typeof(action.result) != 'undefined') &&
6409 (typeof(action.result.errors) != 'undefined') &&
6410 (typeof(action.result.errors.needs_confirm) != 'undefined')
6413 Roo.log("not supported yet");
6416 Roo.MessageBox.confirm(
6417 "Change requires confirmation",
6418 action.result.errorMsg,
6423 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6433 Roo.callback(o.failure, o.scope, [this, action]);
6434 // show an error message if no failed handler is set..
6435 if (!this.hasListener('actionfailed')) {
6436 Roo.log("need to add dialog support");
6438 Roo.MessageBox.alert("Error",
6439 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6440 action.result.errorMsg :
6441 "Saving Failed, please check your entries or try again"
6446 this.fireEvent('actionfailed', this, action);
6451 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6452 * @param {String} id The value to search for
6455 findField : function(id){
6456 var items = this.getItems();
6457 var field = items.get(id);
6459 items.each(function(f){
6460 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6467 return field || null;
6470 * Mark fields in this form invalid in bulk.
6471 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6472 * @return {BasicForm} this
6474 markInvalid : function(errors){
6475 if(errors instanceof Array){
6476 for(var i = 0, len = errors.length; i < len; i++){
6477 var fieldError = errors[i];
6478 var f = this.findField(fieldError.id);
6480 f.markInvalid(fieldError.msg);
6486 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6487 field.markInvalid(errors[id]);
6491 //Roo.each(this.childForms || [], function (f) {
6492 // f.markInvalid(errors);
6499 * Set values for fields in this form in bulk.
6500 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6501 * @return {BasicForm} this
6503 setValues : function(values){
6504 if(values instanceof Array){ // array of objects
6505 for(var i = 0, len = values.length; i < len; i++){
6507 var f = this.findField(v.id);
6509 f.setValue(v.value);
6510 if(this.trackResetOnLoad){
6511 f.originalValue = f.getValue();
6515 }else{ // object hash
6518 if(typeof values[id] != 'function' && (field = this.findField(id))){
6520 if (field.setFromData &&
6522 field.displayField &&
6523 // combos' with local stores can
6524 // be queried via setValue()
6525 // to set their value..
6526 (field.store && !field.store.isLocal)
6530 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6531 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6532 field.setFromData(sd);
6535 field.setValue(values[id]);
6539 if(this.trackResetOnLoad){
6540 field.originalValue = field.getValue();
6546 //Roo.each(this.childForms || [], function (f) {
6547 // f.setValues(values);
6554 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6555 * they are returned as an array.
6556 * @param {Boolean} asString
6559 getValues : function(asString){
6560 //if (this.childForms) {
6561 // copy values from the child forms
6562 // Roo.each(this.childForms, function (f) {
6563 // this.setValues(f.getValues());
6569 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6570 if(asString === true){
6573 return Roo.urlDecode(fs);
6577 * Returns the fields in this form as an object with key/value pairs.
6578 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6581 getFieldValues : function(with_hidden)
6583 var items = this.getItems();
6585 items.each(function(f){
6589 var v = f.getValue();
6590 if (f.inputType =='radio') {
6591 if (typeof(ret[f.getName()]) == 'undefined') {
6592 ret[f.getName()] = ''; // empty..
6595 if (!f.el.dom.checked) {
6603 // not sure if this supported any more..
6604 if ((typeof(v) == 'object') && f.getRawValue) {
6605 v = f.getRawValue() ; // dates..
6607 // combo boxes where name != hiddenName...
6608 if (f.name != f.getName()) {
6609 ret[f.name] = f.getRawValue();
6611 ret[f.getName()] = v;
6618 * Clears all invalid messages in this form.
6619 * @return {BasicForm} this
6621 clearInvalid : function(){
6622 var items = this.getItems();
6624 items.each(function(f){
6635 * @return {BasicForm} this
6638 var items = this.getItems();
6639 items.each(function(f){
6643 Roo.each(this.childForms || [], function (f) {
6650 getItems : function()
6652 var r=new Roo.util.MixedCollection(false, function(o){
6653 return o.id || (o.id = Roo.id());
6655 var iter = function(el) {
6662 Roo.each(el.items,function(e) {
6681 * Ext JS Library 1.1.1
6682 * Copyright(c) 2006-2007, Ext JS, LLC.
6684 * Originally Released Under LGPL - original licence link has changed is not relivant.
6687 * <script type="text/javascript">
6690 * @class Roo.form.VTypes
6691 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6694 Roo.form.VTypes = function(){
6695 // closure these in so they are only created once.
6696 var alpha = /^[a-zA-Z_]+$/;
6697 var alphanum = /^[a-zA-Z0-9_]+$/;
6698 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6699 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6701 // All these messages and functions are configurable
6704 * The function used to validate email addresses
6705 * @param {String} value The email address
6707 'email' : function(v){
6708 return email.test(v);
6711 * The error text to display when the email validation function returns false
6714 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6716 * The keystroke filter mask to be applied on email input
6719 'emailMask' : /[a-z0-9_\.\-@]/i,
6722 * The function used to validate URLs
6723 * @param {String} value The URL
6725 'url' : function(v){
6729 * The error text to display when the url validation function returns false
6732 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6735 * The function used to validate alpha values
6736 * @param {String} value The value
6738 'alpha' : function(v){
6739 return alpha.test(v);
6742 * The error text to display when the alpha validation function returns false
6745 'alphaText' : 'This field should only contain letters and _',
6747 * The keystroke filter mask to be applied on alpha input
6750 'alphaMask' : /[a-z_]/i,
6753 * The function used to validate alphanumeric values
6754 * @param {String} value The value
6756 'alphanum' : function(v){
6757 return alphanum.test(v);
6760 * The error text to display when the alphanumeric validation function returns false
6763 'alphanumText' : 'This field should only contain letters, numbers and _',
6765 * The keystroke filter mask to be applied on alphanumeric input
6768 'alphanumMask' : /[a-z0-9_]/i
6778 * @class Roo.bootstrap.Input
6779 * @extends Roo.bootstrap.Component
6780 * Bootstrap Input class
6781 * @cfg {Boolean} disabled is it disabled
6782 * @cfg {String} fieldLabel - the label associated
6783 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6784 * @cfg {String} name name of the input
6785 * @cfg {string} fieldLabel - the label associated
6786 * @cfg {string} inputType - input / file submit ...
6787 * @cfg {string} placeholder - placeholder to put in text.
6788 * @cfg {string} before - input group add on before
6789 * @cfg {string} after - input group add on after
6790 * @cfg {string} size - (lg|sm) or leave empty..
6791 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6792 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6793 * @cfg {Number} md colspan out of 12 for computer-sized screens
6794 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6795 * @cfg {string} value default value of the input
6796 * @cfg {Number} labelWidth set the width of label (0-12)
6797 * @cfg {String} labelAlign (top|left)
6798 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6799 * @cfg {String} align (left|center|right) Default left
6803 * Create a new Input
6804 * @param {Object} config The config object
6807 Roo.bootstrap.Input = function(config){
6808 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6813 * Fires when this field receives input focus.
6814 * @param {Roo.form.Field} this
6819 * Fires when this field loses input focus.
6820 * @param {Roo.form.Field} this
6825 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6826 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6827 * @param {Roo.form.Field} this
6828 * @param {Roo.EventObject} e The event object
6833 * Fires just before the field blurs if the field value has changed.
6834 * @param {Roo.form.Field} this
6835 * @param {Mixed} newValue The new value
6836 * @param {Mixed} oldValue The original value
6841 * Fires after the field has been marked as invalid.
6842 * @param {Roo.form.Field} this
6843 * @param {String} msg The validation message
6848 * Fires after the field has been validated with no errors.
6849 * @param {Roo.form.Field} this
6854 * Fires after the key up
6855 * @param {Roo.form.Field} this
6856 * @param {Roo.EventObject} e The event Object
6862 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6864 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6865 automatic validation (defaults to "keyup").
6867 validationEvent : "keyup",
6869 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6871 validateOnBlur : true,
6873 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6875 validationDelay : 250,
6877 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6879 focusClass : "x-form-focus", // not needed???
6883 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6885 invalidClass : "has-error",
6888 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6890 selectOnFocus : false,
6893 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6897 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6902 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6904 disableKeyFilter : false,
6907 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6911 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6915 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6917 blankText : "This field is required",
6920 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6924 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6926 maxLength : Number.MAX_VALUE,
6928 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6930 minLengthText : "The minimum length for this field is {0}",
6932 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6934 maxLengthText : "The maximum length for this field is {0}",
6938 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6939 * If available, this function will be called only after the basic validators all return true, and will be passed the
6940 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6944 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6945 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6946 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6950 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6973 formatedValue : false,
6975 parentLabelAlign : function()
6978 while (parent.parent()) {
6979 parent = parent.parent();
6980 if (typeof(parent.labelAlign) !='undefined') {
6981 return parent.labelAlign;
6988 getAutoCreate : function(){
6990 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6996 if(this.inputType != 'hidden'){
6997 cfg.cls = 'form-group' //input-group
7003 type : this.inputType,
7005 cls : 'form-control',
7006 placeholder : this.placeholder || ''
7011 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7014 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7015 input.maxLength = this.maxLength;
7018 if (this.disabled) {
7019 input.disabled=true;
7022 if (this.readOnly) {
7023 input.readonly=true;
7027 input.name = this.name;
7030 input.cls += ' input-' + this.size;
7033 ['xs','sm','md','lg'].map(function(size){
7034 if (settings[size]) {
7035 cfg.cls += ' col-' + size + '-' + settings[size];
7039 var inputblock = input;
7041 if (this.before || this.after) {
7044 cls : 'input-group',
7047 if (this.before && typeof(this.before) == 'string') {
7049 inputblock.cn.push({
7051 cls : 'roo-input-before input-group-addon',
7055 if (this.before && typeof(this.before) == 'object') {
7056 this.before = Roo.factory(this.before);
7057 Roo.log(this.before);
7058 inputblock.cn.push({
7060 cls : 'roo-input-before input-group-' +
7061 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7065 inputblock.cn.push(input);
7067 if (this.after && typeof(this.after) == 'string') {
7068 inputblock.cn.push({
7070 cls : 'roo-input-after input-group-addon',
7074 if (this.after && typeof(this.after) == 'object') {
7075 this.after = Roo.factory(this.after);
7076 Roo.log(this.after);
7077 inputblock.cn.push({
7079 cls : 'roo-input-after input-group-' +
7080 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7085 if (align ==='left' && this.fieldLabel.length) {
7086 Roo.log("left and has label");
7092 cls : 'control-label col-sm-' + this.labelWidth,
7093 html : this.fieldLabel
7097 cls : "col-sm-" + (12 - this.labelWidth),
7104 } else if ( this.fieldLabel.length) {
7110 //cls : 'input-group-addon',
7111 html : this.fieldLabel
7121 Roo.log(" no label && no align");
7130 Roo.log('input-parentType: ' + this.parentType);
7132 if (this.parentType === 'Navbar' && this.parent().bar) {
7133 cfg.cls += ' navbar-form';
7141 * return the real input element.
7143 inputEl: function ()
7145 return this.el.select('input.form-control',true).first();
7147 setDisabled : function(v)
7149 var i = this.inputEl().dom;
7151 i.removeAttribute('disabled');
7155 i.setAttribute('disabled','true');
7157 initEvents : function()
7160 this.inputEl().on("keydown" , this.fireKey, this);
7161 this.inputEl().on("focus", this.onFocus, this);
7162 this.inputEl().on("blur", this.onBlur, this);
7164 this.inputEl().relayEvent('keyup', this);
7166 // reference to original value for reset
7167 this.originalValue = this.getValue();
7168 //Roo.form.TextField.superclass.initEvents.call(this);
7169 if(this.validationEvent == 'keyup'){
7170 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7171 this.inputEl().on('keyup', this.filterValidation, this);
7173 else if(this.validationEvent !== false){
7174 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7177 if(this.selectOnFocus){
7178 this.on("focus", this.preFocus, this);
7181 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7182 this.inputEl().on("keypress", this.filterKeys, this);
7185 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7186 this.el.on("click", this.autoSize, this);
7189 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7190 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7193 if (typeof(this.before) == 'object') {
7194 this.before.render(this.el.select('.roo-input-before',true).first());
7196 if (typeof(this.after) == 'object') {
7197 this.after.render(this.el.select('.roo-input-after',true).first());
7202 filterValidation : function(e){
7203 if(!e.isNavKeyPress()){
7204 this.validationTask.delay(this.validationDelay);
7208 * Validates the field value
7209 * @return {Boolean} True if the value is valid, else false
7211 validate : function(){
7212 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7213 if(this.disabled || this.validateValue(this.getRawValue())){
7214 this.clearInvalid();
7222 * Validates a value according to the field's validation rules and marks the field as invalid
7223 * if the validation fails
7224 * @param {Mixed} value The value to validate
7225 * @return {Boolean} True if the value is valid, else false
7227 validateValue : function(value){
7228 if(value.length < 1) { // if it's blank
7229 if(this.allowBlank){
7230 this.clearInvalid();
7233 this.markInvalid(this.blankText);
7237 if(value.length < this.minLength){
7238 this.markInvalid(String.format(this.minLengthText, this.minLength));
7241 if(value.length > this.maxLength){
7242 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7246 var vt = Roo.form.VTypes;
7247 if(!vt[this.vtype](value, this)){
7248 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7252 if(typeof this.validator == "function"){
7253 var msg = this.validator(value);
7255 this.markInvalid(msg);
7259 if(this.regex && !this.regex.test(value)){
7260 this.markInvalid(this.regexText);
7269 fireKey : function(e){
7270 //Roo.log('field ' + e.getKey());
7271 if(e.isNavKeyPress()){
7272 this.fireEvent("specialkey", this, e);
7275 focus : function (selectText){
7277 this.inputEl().focus();
7278 if(selectText === true){
7279 this.inputEl().dom.select();
7285 onFocus : function(){
7286 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7287 // this.el.addClass(this.focusClass);
7290 this.hasFocus = true;
7291 this.startValue = this.getValue();
7292 this.fireEvent("focus", this);
7296 beforeBlur : Roo.emptyFn,
7300 onBlur : function(){
7302 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7303 //this.el.removeClass(this.focusClass);
7305 this.hasFocus = false;
7306 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7309 var v = this.getValue();
7310 if(String(v) !== String(this.startValue)){
7311 this.fireEvent('change', this, v, this.startValue);
7313 this.fireEvent("blur", this);
7317 * Resets the current field value to the originally loaded value and clears any validation messages
7320 this.setValue(this.originalValue);
7321 this.clearInvalid();
7324 * Returns the name of the field
7325 * @return {Mixed} name The name field
7327 getName: function(){
7331 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7332 * @return {Mixed} value The field value
7334 getValue : function(){
7336 var v = this.inputEl().getValue();
7341 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7342 * @return {Mixed} value The field value
7344 getRawValue : function(){
7345 var v = this.inputEl().getValue();
7351 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7352 * @param {Mixed} value The value to set
7354 setRawValue : function(v){
7355 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7358 selectText : function(start, end){
7359 var v = this.getRawValue();
7361 start = start === undefined ? 0 : start;
7362 end = end === undefined ? v.length : end;
7363 var d = this.inputEl().dom;
7364 if(d.setSelectionRange){
7365 d.setSelectionRange(start, end);
7366 }else if(d.createTextRange){
7367 var range = d.createTextRange();
7368 range.moveStart("character", start);
7369 range.moveEnd("character", v.length-end);
7376 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7377 * @param {Mixed} value The value to set
7379 setValue : function(v){
7382 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7388 processValue : function(value){
7389 if(this.stripCharsRe){
7390 var newValue = value.replace(this.stripCharsRe, '');
7391 if(newValue !== value){
7392 this.setRawValue(newValue);
7399 preFocus : function(){
7401 if(this.selectOnFocus){
7402 this.inputEl().dom.select();
7405 filterKeys : function(e){
7407 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7410 var c = e.getCharCode(), cc = String.fromCharCode(c);
7411 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7414 if(!this.maskRe.test(cc)){
7419 * Clear any invalid styles/messages for this field
7421 clearInvalid : function(){
7423 if(!this.el || this.preventMark){ // not rendered
7426 this.el.removeClass(this.invalidClass);
7428 switch(this.msgTarget){
7430 this.el.dom.qtip = '';
7433 this.el.dom.title = '';
7437 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7442 this.errorIcon.dom.qtip = '';
7443 this.errorIcon.hide();
7444 this.un('resize', this.alignErrorIcon, this);
7448 var t = Roo.getDom(this.msgTarget);
7450 t.style.display = 'none';
7454 this.fireEvent('valid', this);
7457 * Mark this field as invalid
7458 * @param {String} msg The validation message
7460 markInvalid : function(msg){
7461 if(!this.el || this.preventMark){ // not rendered
7464 this.el.addClass(this.invalidClass);
7466 msg = msg || this.invalidText;
7467 switch(this.msgTarget){
7469 this.el.dom.qtip = msg;
7470 this.el.dom.qclass = 'x-form-invalid-tip';
7471 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7472 Roo.QuickTips.enable();
7476 this.el.dom.title = msg;
7480 var elp = this.el.findParent('.x-form-element', 5, true);
7481 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7482 this.errorEl.setWidth(elp.getWidth(true)-20);
7484 this.errorEl.update(msg);
7485 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7488 if(!this.errorIcon){
7489 var elp = this.el.findParent('.x-form-element', 5, true);
7490 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7492 this.alignErrorIcon();
7493 this.errorIcon.dom.qtip = msg;
7494 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7495 this.errorIcon.show();
7496 this.on('resize', this.alignErrorIcon, this);
7499 var t = Roo.getDom(this.msgTarget);
7501 t.style.display = this.msgDisplay;
7505 this.fireEvent('invalid', this, msg);
7508 SafariOnKeyDown : function(event)
7510 // this is a workaround for a password hang bug on chrome/ webkit.
7512 var isSelectAll = false;
7514 if(this.inputEl().dom.selectionEnd > 0){
7515 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7517 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7518 event.preventDefault();
7523 if(isSelectAll){ // backspace and delete key
7525 event.preventDefault();
7526 // this is very hacky as keydown always get's upper case.
7528 var cc = String.fromCharCode(event.getCharCode());
7529 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7533 adjustWidth : function(tag, w){
7534 tag = tag.toLowerCase();
7535 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7536 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7540 if(tag == 'textarea'){
7543 }else if(Roo.isOpera){
7547 if(tag == 'textarea'){
7566 * @class Roo.bootstrap.TextArea
7567 * @extends Roo.bootstrap.Input
7568 * Bootstrap TextArea class
7569 * @cfg {Number} cols Specifies the visible width of a text area
7570 * @cfg {Number} rows Specifies the visible number of lines in a text area
7571 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7572 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7573 * @cfg {string} html text
7576 * Create a new TextArea
7577 * @param {Object} config The config object
7580 Roo.bootstrap.TextArea = function(config){
7581 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7585 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7595 getAutoCreate : function(){
7597 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7608 value : this.value || '',
7609 html: this.html || '',
7610 cls : 'form-control',
7611 placeholder : this.placeholder || ''
7615 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7616 input.maxLength = this.maxLength;
7620 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7624 input.cols = this.cols;
7627 if (this.readOnly) {
7628 input.readonly = true;
7632 input.name = this.name;
7636 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7640 ['xs','sm','md','lg'].map(function(size){
7641 if (settings[size]) {
7642 cfg.cls += ' col-' + size + '-' + settings[size];
7646 var inputblock = input;
7648 if (this.before || this.after) {
7651 cls : 'input-group',
7655 inputblock.cn.push({
7657 cls : 'input-group-addon',
7661 inputblock.cn.push(input);
7663 inputblock.cn.push({
7665 cls : 'input-group-addon',
7672 if (align ==='left' && this.fieldLabel.length) {
7673 Roo.log("left and has label");
7679 cls : 'control-label col-sm-' + this.labelWidth,
7680 html : this.fieldLabel
7684 cls : "col-sm-" + (12 - this.labelWidth),
7691 } else if ( this.fieldLabel.length) {
7697 //cls : 'input-group-addon',
7698 html : this.fieldLabel
7708 Roo.log(" no label && no align");
7718 if (this.disabled) {
7719 input.disabled=true;
7726 * return the real textarea element.
7728 inputEl: function ()
7730 return this.el.select('textarea.form-control',true).first();
7738 * trigger field - base class for combo..
7743 * @class Roo.bootstrap.TriggerField
7744 * @extends Roo.bootstrap.Input
7745 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7746 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7747 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7748 * for which you can provide a custom implementation. For example:
7750 var trigger = new Roo.bootstrap.TriggerField();
7751 trigger.onTriggerClick = myTriggerFn;
7752 trigger.applyTo('my-field');
7755 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7756 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7757 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7758 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7760 * Create a new TriggerField.
7761 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7762 * to the base TextField)
7764 Roo.bootstrap.TriggerField = function(config){
7765 this.mimicing = false;
7766 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7769 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7771 * @cfg {String} triggerClass A CSS class to apply to the trigger
7774 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7778 /** @cfg {Boolean} grow @hide */
7779 /** @cfg {Number} growMin @hide */
7780 /** @cfg {Number} growMax @hide */
7786 autoSize: Roo.emptyFn,
7793 actionMode : 'wrap',
7797 getAutoCreate : function(){
7799 var align = this.labelAlign || this.parentLabelAlign();
7804 cls: 'form-group' //input-group
7811 type : this.inputType,
7812 cls : 'form-control',
7813 autocomplete: 'off',
7814 placeholder : this.placeholder || ''
7818 input.name = this.name;
7821 input.cls += ' input-' + this.size;
7824 if (this.disabled) {
7825 input.disabled=true;
7828 var inputblock = input;
7830 if (this.before || this.after) {
7833 cls : 'input-group',
7837 inputblock.cn.push({
7839 cls : 'input-group-addon',
7843 inputblock.cn.push(input);
7845 inputblock.cn.push({
7847 cls : 'input-group-addon',
7860 cls: 'form-hidden-field'
7868 Roo.log('multiple');
7876 cls: 'form-hidden-field'
7880 cls: 'select2-choices',
7884 cls: 'select2-search-field',
7897 cls: 'select2-container input-group',
7902 // cls: 'typeahead typeahead-long dropdown-menu',
7903 // style: 'display:none'
7908 if(!this.multiple && this.showToggleBtn){
7911 cls : 'input-group-addon btn dropdown-toggle',
7919 cls: 'combobox-clear',
7933 combobox.cls += ' select2-container-multi';
7936 if (align ==='left' && this.fieldLabel.length) {
7938 Roo.log("left and has label");
7944 cls : 'control-label col-sm-' + this.labelWidth,
7945 html : this.fieldLabel
7949 cls : "col-sm-" + (12 - this.labelWidth),
7956 } else if ( this.fieldLabel.length) {
7962 //cls : 'input-group-addon',
7963 html : this.fieldLabel
7973 Roo.log(" no label && no align");
7980 ['xs','sm','md','lg'].map(function(size){
7981 if (settings[size]) {
7982 cfg.cls += ' col-' + size + '-' + settings[size];
7993 onResize : function(w, h){
7994 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7995 // if(typeof w == 'number'){
7996 // var x = w - this.trigger.getWidth();
7997 // this.inputEl().setWidth(this.adjustWidth('input', x));
7998 // this.trigger.setStyle('left', x+'px');
8003 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8006 getResizeEl : function(){
8007 return this.inputEl();
8011 getPositionEl : function(){
8012 return this.inputEl();
8016 alignErrorIcon : function(){
8017 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8021 initEvents : function(){
8025 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8026 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8027 if(!this.multiple && this.showToggleBtn){
8028 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8029 if(this.hideTrigger){
8030 this.trigger.setDisplayed(false);
8032 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8036 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8039 //this.trigger.addClassOnOver('x-form-trigger-over');
8040 //this.trigger.addClassOnClick('x-form-trigger-click');
8043 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8047 createList : function()
8049 this.list = Roo.get(document.body).createChild({
8051 cls: 'typeahead typeahead-long dropdown-menu',
8052 style: 'display:none'
8055 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8060 initTrigger : function(){
8065 onDestroy : function(){
8067 this.trigger.removeAllListeners();
8068 // this.trigger.remove();
8071 // this.wrap.remove();
8073 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8077 onFocus : function(){
8078 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8081 this.wrap.addClass('x-trigger-wrap-focus');
8082 this.mimicing = true;
8083 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8084 if(this.monitorTab){
8085 this.el.on("keydown", this.checkTab, this);
8092 checkTab : function(e){
8093 if(e.getKey() == e.TAB){
8099 onBlur : function(){
8104 mimicBlur : function(e, t){
8106 if(!this.wrap.contains(t) && this.validateBlur()){
8113 triggerBlur : function(){
8114 this.mimicing = false;
8115 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8116 if(this.monitorTab){
8117 this.el.un("keydown", this.checkTab, this);
8119 //this.wrap.removeClass('x-trigger-wrap-focus');
8120 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8124 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8125 validateBlur : function(e, t){
8130 onDisable : function(){
8131 this.inputEl().dom.disabled = true;
8132 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8134 // this.wrap.addClass('x-item-disabled');
8139 onEnable : function(){
8140 this.inputEl().dom.disabled = false;
8141 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8143 // this.el.removeClass('x-item-disabled');
8148 onShow : function(){
8149 var ae = this.getActionEl();
8152 ae.dom.style.display = '';
8153 ae.dom.style.visibility = 'visible';
8159 onHide : function(){
8160 var ae = this.getActionEl();
8161 ae.dom.style.display = 'none';
8165 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8166 * by an implementing function.
8168 * @param {EventObject} e
8170 onTriggerClick : Roo.emptyFn
8174 * Ext JS Library 1.1.1
8175 * Copyright(c) 2006-2007, Ext JS, LLC.
8177 * Originally Released Under LGPL - original licence link has changed is not relivant.
8180 * <script type="text/javascript">
8185 * @class Roo.data.SortTypes
8187 * Defines the default sorting (casting?) comparison functions used when sorting data.
8189 Roo.data.SortTypes = {
8191 * Default sort that does nothing
8192 * @param {Mixed} s The value being converted
8193 * @return {Mixed} The comparison value
8200 * The regular expression used to strip tags
8204 stripTagsRE : /<\/?[^>]+>/gi,
8207 * Strips all HTML tags to sort on text only
8208 * @param {Mixed} s The value being converted
8209 * @return {String} The comparison value
8211 asText : function(s){
8212 return String(s).replace(this.stripTagsRE, "");
8216 * Strips all HTML tags to sort on text only - Case insensitive
8217 * @param {Mixed} s The value being converted
8218 * @return {String} The comparison value
8220 asUCText : function(s){
8221 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8225 * Case insensitive string
8226 * @param {Mixed} s The value being converted
8227 * @return {String} The comparison value
8229 asUCString : function(s) {
8230 return String(s).toUpperCase();
8235 * @param {Mixed} s The value being converted
8236 * @return {Number} The comparison value
8238 asDate : function(s) {
8242 if(s instanceof Date){
8245 return Date.parse(String(s));
8250 * @param {Mixed} s The value being converted
8251 * @return {Float} The comparison value
8253 asFloat : function(s) {
8254 var val = parseFloat(String(s).replace(/,/g, ""));
8255 if(isNaN(val)) val = 0;
8261 * @param {Mixed} s The value being converted
8262 * @return {Number} The comparison value
8264 asInt : function(s) {
8265 var val = parseInt(String(s).replace(/,/g, ""));
8266 if(isNaN(val)) val = 0;
8271 * Ext JS Library 1.1.1
8272 * Copyright(c) 2006-2007, Ext JS, LLC.
8274 * Originally Released Under LGPL - original licence link has changed is not relivant.
8277 * <script type="text/javascript">
8281 * @class Roo.data.Record
8282 * Instances of this class encapsulate both record <em>definition</em> information, and record
8283 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8284 * to access Records cached in an {@link Roo.data.Store} object.<br>
8286 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8287 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8290 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8292 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8293 * {@link #create}. The parameters are the same.
8294 * @param {Array} data An associative Array of data values keyed by the field name.
8295 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8296 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8297 * not specified an integer id is generated.
8299 Roo.data.Record = function(data, id){
8300 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8305 * Generate a constructor for a specific record layout.
8306 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8307 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8308 * Each field definition object may contain the following properties: <ul>
8309 * <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,
8310 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8311 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8312 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8313 * is being used, then this is a string containing the javascript expression to reference the data relative to
8314 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8315 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8316 * this may be omitted.</p></li>
8317 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8318 * <ul><li>auto (Default, implies no conversion)</li>
8323 * <li>date</li></ul></p></li>
8324 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8325 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8326 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8327 * by the Reader into an object that will be stored in the Record. It is passed the
8328 * following parameters:<ul>
8329 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8331 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8333 * <br>usage:<br><pre><code>
8334 var TopicRecord = Roo.data.Record.create(
8335 {name: 'title', mapping: 'topic_title'},
8336 {name: 'author', mapping: 'username'},
8337 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8338 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8339 {name: 'lastPoster', mapping: 'user2'},
8340 {name: 'excerpt', mapping: 'post_text'}
8343 var myNewRecord = new TopicRecord({
8344 title: 'Do my job please',
8347 lastPost: new Date(),
8348 lastPoster: 'Animal',
8349 excerpt: 'No way dude!'
8351 myStore.add(myNewRecord);
8356 Roo.data.Record.create = function(o){
8358 f.superclass.constructor.apply(this, arguments);
8360 Roo.extend(f, Roo.data.Record);
8361 var p = f.prototype;
8362 p.fields = new Roo.util.MixedCollection(false, function(field){
8365 for(var i = 0, len = o.length; i < len; i++){
8366 p.fields.add(new Roo.data.Field(o[i]));
8368 f.getField = function(name){
8369 return p.fields.get(name);
8374 Roo.data.Record.AUTO_ID = 1000;
8375 Roo.data.Record.EDIT = 'edit';
8376 Roo.data.Record.REJECT = 'reject';
8377 Roo.data.Record.COMMIT = 'commit';
8379 Roo.data.Record.prototype = {
8381 * Readonly flag - true if this record has been modified.
8390 join : function(store){
8395 * Set the named field to the specified value.
8396 * @param {String} name The name of the field to set.
8397 * @param {Object} value The value to set the field to.
8399 set : function(name, value){
8400 if(this.data[name] == value){
8407 if(typeof this.modified[name] == 'undefined'){
8408 this.modified[name] = this.data[name];
8410 this.data[name] = value;
8411 if(!this.editing && this.store){
8412 this.store.afterEdit(this);
8417 * Get the value of the named field.
8418 * @param {String} name The name of the field to get the value of.
8419 * @return {Object} The value of the field.
8421 get : function(name){
8422 return this.data[name];
8426 beginEdit : function(){
8427 this.editing = true;
8432 cancelEdit : function(){
8433 this.editing = false;
8434 delete this.modified;
8438 endEdit : function(){
8439 this.editing = false;
8440 if(this.dirty && this.store){
8441 this.store.afterEdit(this);
8446 * Usually called by the {@link Roo.data.Store} which owns the Record.
8447 * Rejects all changes made to the Record since either creation, or the last commit operation.
8448 * Modified fields are reverted to their original values.
8450 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8451 * of reject operations.
8453 reject : function(){
8454 var m = this.modified;
8456 if(typeof m[n] != "function"){
8457 this.data[n] = m[n];
8461 delete this.modified;
8462 this.editing = false;
8464 this.store.afterReject(this);
8469 * Usually called by the {@link Roo.data.Store} which owns the Record.
8470 * Commits all changes made to the Record since either creation, or the last commit operation.
8472 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8473 * of commit operations.
8475 commit : function(){
8477 delete this.modified;
8478 this.editing = false;
8480 this.store.afterCommit(this);
8485 hasError : function(){
8486 return this.error != null;
8490 clearError : function(){
8495 * Creates a copy of this record.
8496 * @param {String} id (optional) A new record id if you don't want to use this record's id
8499 copy : function(newId) {
8500 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8504 * Ext JS Library 1.1.1
8505 * Copyright(c) 2006-2007, Ext JS, LLC.
8507 * Originally Released Under LGPL - original licence link has changed is not relivant.
8510 * <script type="text/javascript">
8516 * @class Roo.data.Store
8517 * @extends Roo.util.Observable
8518 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8519 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8521 * 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
8522 * has no knowledge of the format of the data returned by the Proxy.<br>
8524 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8525 * instances from the data object. These records are cached and made available through accessor functions.
8527 * Creates a new Store.
8528 * @param {Object} config A config object containing the objects needed for the Store to access data,
8529 * and read the data into Records.
8531 Roo.data.Store = function(config){
8532 this.data = new Roo.util.MixedCollection(false);
8533 this.data.getKey = function(o){
8536 this.baseParams = {};
8543 "multisort" : "_multisort"
8546 if(config && config.data){
8547 this.inlineData = config.data;
8551 Roo.apply(this, config);
8553 if(this.reader){ // reader passed
8554 this.reader = Roo.factory(this.reader, Roo.data);
8555 this.reader.xmodule = this.xmodule || false;
8556 if(!this.recordType){
8557 this.recordType = this.reader.recordType;
8559 if(this.reader.onMetaChange){
8560 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8564 if(this.recordType){
8565 this.fields = this.recordType.prototype.fields;
8571 * @event datachanged
8572 * Fires when the data cache has changed, and a widget which is using this Store
8573 * as a Record cache should refresh its view.
8574 * @param {Store} this
8579 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8580 * @param {Store} this
8581 * @param {Object} meta The JSON metadata
8586 * Fires when Records have been added to the Store
8587 * @param {Store} this
8588 * @param {Roo.data.Record[]} records The array of Records added
8589 * @param {Number} index The index at which the record(s) were added
8594 * Fires when a Record has been removed from the Store
8595 * @param {Store} this
8596 * @param {Roo.data.Record} record The Record that was removed
8597 * @param {Number} index The index at which the record was removed
8602 * Fires when a Record has been updated
8603 * @param {Store} this
8604 * @param {Roo.data.Record} record The Record that was updated
8605 * @param {String} operation The update operation being performed. Value may be one of:
8607 Roo.data.Record.EDIT
8608 Roo.data.Record.REJECT
8609 Roo.data.Record.COMMIT
8615 * Fires when the data cache has been cleared.
8616 * @param {Store} this
8621 * Fires before a request is made for a new data object. If the beforeload handler returns false
8622 * the load action will be canceled.
8623 * @param {Store} this
8624 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8628 * @event beforeloadadd
8629 * Fires after a new set of Records has been loaded.
8630 * @param {Store} this
8631 * @param {Roo.data.Record[]} records The Records that were loaded
8632 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8634 beforeloadadd : true,
8637 * Fires after a new set of Records has been loaded, before they are added to the store.
8638 * @param {Store} this
8639 * @param {Roo.data.Record[]} records The Records that were loaded
8640 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8641 * @params {Object} return from reader
8645 * @event loadexception
8646 * Fires if an exception occurs in the Proxy during loading.
8647 * Called with the signature of the Proxy's "loadexception" event.
8648 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8651 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8652 * @param {Object} load options
8653 * @param {Object} jsonData from your request (normally this contains the Exception)
8655 loadexception : true
8659 this.proxy = Roo.factory(this.proxy, Roo.data);
8660 this.proxy.xmodule = this.xmodule || false;
8661 this.relayEvents(this.proxy, ["loadexception"]);
8663 this.sortToggle = {};
8664 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8666 Roo.data.Store.superclass.constructor.call(this);
8668 if(this.inlineData){
8669 this.loadData(this.inlineData);
8670 delete this.inlineData;
8674 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8676 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8677 * without a remote query - used by combo/forms at present.
8681 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8684 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8687 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8688 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8691 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8692 * on any HTTP request
8695 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8698 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8702 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8703 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8708 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8709 * loaded or when a record is removed. (defaults to false).
8711 pruneModifiedRecords : false,
8717 * Add Records to the Store and fires the add event.
8718 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8720 add : function(records){
8721 records = [].concat(records);
8722 for(var i = 0, len = records.length; i < len; i++){
8723 records[i].join(this);
8725 var index = this.data.length;
8726 this.data.addAll(records);
8727 this.fireEvent("add", this, records, index);
8731 * Remove a Record from the Store and fires the remove event.
8732 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8734 remove : function(record){
8735 var index = this.data.indexOf(record);
8736 this.data.removeAt(index);
8737 if(this.pruneModifiedRecords){
8738 this.modified.remove(record);
8740 this.fireEvent("remove", this, record, index);
8744 * Remove all Records from the Store and fires the clear event.
8746 removeAll : function(){
8748 if(this.pruneModifiedRecords){
8751 this.fireEvent("clear", this);
8755 * Inserts Records to the Store at the given index and fires the add event.
8756 * @param {Number} index The start index at which to insert the passed Records.
8757 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8759 insert : function(index, records){
8760 records = [].concat(records);
8761 for(var i = 0, len = records.length; i < len; i++){
8762 this.data.insert(index, records[i]);
8763 records[i].join(this);
8765 this.fireEvent("add", this, records, index);
8769 * Get the index within the cache of the passed Record.
8770 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8771 * @return {Number} The index of the passed Record. Returns -1 if not found.
8773 indexOf : function(record){
8774 return this.data.indexOf(record);
8778 * Get the index within the cache of the Record with the passed id.
8779 * @param {String} id The id of the Record to find.
8780 * @return {Number} The index of the Record. Returns -1 if not found.
8782 indexOfId : function(id){
8783 return this.data.indexOfKey(id);
8787 * Get the Record with the specified id.
8788 * @param {String} id The id of the Record to find.
8789 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8791 getById : function(id){
8792 return this.data.key(id);
8796 * Get the Record at the specified index.
8797 * @param {Number} index The index of the Record to find.
8798 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8800 getAt : function(index){
8801 return this.data.itemAt(index);
8805 * Returns a range of Records between specified indices.
8806 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8807 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8808 * @return {Roo.data.Record[]} An array of Records
8810 getRange : function(start, end){
8811 return this.data.getRange(start, end);
8815 storeOptions : function(o){
8816 o = Roo.apply({}, o);
8819 this.lastOptions = o;
8823 * Loads the Record cache from the configured Proxy using the configured Reader.
8825 * If using remote paging, then the first load call must specify the <em>start</em>
8826 * and <em>limit</em> properties in the options.params property to establish the initial
8827 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8829 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8830 * and this call will return before the new data has been loaded. Perform any post-processing
8831 * in a callback function, or in a "load" event handler.</strong>
8833 * @param {Object} options An object containing properties which control loading options:<ul>
8834 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8835 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8836 * passed the following arguments:<ul>
8837 * <li>r : Roo.data.Record[]</li>
8838 * <li>options: Options object from the load call</li>
8839 * <li>success: Boolean success indicator</li></ul></li>
8840 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8841 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8844 load : function(options){
8845 options = options || {};
8846 if(this.fireEvent("beforeload", this, options) !== false){
8847 this.storeOptions(options);
8848 var p = Roo.apply(options.params || {}, this.baseParams);
8849 // if meta was not loaded from remote source.. try requesting it.
8850 if (!this.reader.metaFromRemote) {
8853 if(this.sortInfo && this.remoteSort){
8854 var pn = this.paramNames;
8855 p[pn["sort"]] = this.sortInfo.field;
8856 p[pn["dir"]] = this.sortInfo.direction;
8858 if (this.multiSort) {
8859 var pn = this.paramNames;
8860 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8863 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8868 * Reloads the Record cache from the configured Proxy using the configured Reader and
8869 * the options from the last load operation performed.
8870 * @param {Object} options (optional) An object containing properties which may override the options
8871 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8872 * the most recently used options are reused).
8874 reload : function(options){
8875 this.load(Roo.applyIf(options||{}, this.lastOptions));
8879 // Called as a callback by the Reader during a load operation.
8880 loadRecords : function(o, options, success){
8881 if(!o || success === false){
8882 if(success !== false){
8883 this.fireEvent("load", this, [], options, o);
8885 if(options.callback){
8886 options.callback.call(options.scope || this, [], options, false);
8890 // if data returned failure - throw an exception.
8891 if (o.success === false) {
8892 // show a message if no listener is registered.
8893 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8894 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8896 // loadmask wil be hooked into this..
8897 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8900 var r = o.records, t = o.totalRecords || r.length;
8902 this.fireEvent("beforeloadadd", this, r, options, o);
8904 if(!options || options.add !== true){
8905 if(this.pruneModifiedRecords){
8908 for(var i = 0, len = r.length; i < len; i++){
8912 this.data = this.snapshot;
8913 delete this.snapshot;
8916 this.data.addAll(r);
8917 this.totalLength = t;
8919 this.fireEvent("datachanged", this);
8921 this.totalLength = Math.max(t, this.data.length+r.length);
8924 this.fireEvent("load", this, r, options, o);
8925 if(options.callback){
8926 options.callback.call(options.scope || this, r, options, true);
8932 * Loads data from a passed data block. A Reader which understands the format of the data
8933 * must have been configured in the constructor.
8934 * @param {Object} data The data block from which to read the Records. The format of the data expected
8935 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8936 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8938 loadData : function(o, append){
8939 var r = this.reader.readRecords(o);
8940 this.loadRecords(r, {add: append}, true);
8944 * Gets the number of cached records.
8946 * <em>If using paging, this may not be the total size of the dataset. If the data object
8947 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8948 * the data set size</em>
8950 getCount : function(){
8951 return this.data.length || 0;
8955 * Gets the total number of records in the dataset as returned by the server.
8957 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8958 * the dataset size</em>
8960 getTotalCount : function(){
8961 return this.totalLength || 0;
8965 * Returns the sort state of the Store as an object with two properties:
8967 field {String} The name of the field by which the Records are sorted
8968 direction {String} The sort order, "ASC" or "DESC"
8971 getSortState : function(){
8972 return this.sortInfo;
8976 applySort : function(){
8977 if(this.sortInfo && !this.remoteSort){
8978 var s = this.sortInfo, f = s.field;
8979 var st = this.fields.get(f).sortType;
8980 var fn = function(r1, r2){
8981 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8982 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8984 this.data.sort(s.direction, fn);
8985 if(this.snapshot && this.snapshot != this.data){
8986 this.snapshot.sort(s.direction, fn);
8992 * Sets the default sort column and order to be used by the next load operation.
8993 * @param {String} fieldName The name of the field to sort by.
8994 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8996 setDefaultSort : function(field, dir){
8997 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9002 * If remote sorting is used, the sort is performed on the server, and the cache is
9003 * reloaded. If local sorting is used, the cache is sorted internally.
9004 * @param {String} fieldName The name of the field to sort by.
9005 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9007 sort : function(fieldName, dir){
9008 var f = this.fields.get(fieldName);
9010 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9012 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9013 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9018 this.sortToggle[f.name] = dir;
9019 this.sortInfo = {field: f.name, direction: dir};
9020 if(!this.remoteSort){
9022 this.fireEvent("datachanged", this);
9024 this.load(this.lastOptions);
9029 * Calls the specified function for each of the Records in the cache.
9030 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9031 * Returning <em>false</em> aborts and exits the iteration.
9032 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9034 each : function(fn, scope){
9035 this.data.each(fn, scope);
9039 * Gets all records modified since the last commit. Modified records are persisted across load operations
9040 * (e.g., during paging).
9041 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9043 getModifiedRecords : function(){
9044 return this.modified;
9048 createFilterFn : function(property, value, anyMatch){
9049 if(!value.exec){ // not a regex
9050 value = String(value);
9051 if(value.length == 0){
9054 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9057 return value.test(r.data[property]);
9062 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9063 * @param {String} property A field on your records
9064 * @param {Number} start The record index to start at (defaults to 0)
9065 * @param {Number} end The last record index to include (defaults to length - 1)
9066 * @return {Number} The sum
9068 sum : function(property, start, end){
9069 var rs = this.data.items, v = 0;
9071 end = (end || end === 0) ? end : rs.length-1;
9073 for(var i = start; i <= end; i++){
9074 v += (rs[i].data[property] || 0);
9080 * Filter the records by a specified property.
9081 * @param {String} field A field on your records
9082 * @param {String/RegExp} value Either a string that the field
9083 * should start with or a RegExp to test against the field
9084 * @param {Boolean} anyMatch True to match any part not just the beginning
9086 filter : function(property, value, anyMatch){
9087 var fn = this.createFilterFn(property, value, anyMatch);
9088 return fn ? this.filterBy(fn) : this.clearFilter();
9092 * Filter by a function. The specified function will be called with each
9093 * record in this data source. If the function returns true the record is included,
9094 * otherwise it is filtered.
9095 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9096 * @param {Object} scope (optional) The scope of the function (defaults to this)
9098 filterBy : function(fn, scope){
9099 this.snapshot = this.snapshot || this.data;
9100 this.data = this.queryBy(fn, scope||this);
9101 this.fireEvent("datachanged", this);
9105 * Query the records by a specified property.
9106 * @param {String} field A field on your records
9107 * @param {String/RegExp} value Either a string that the field
9108 * should start with or a RegExp to test against the field
9109 * @param {Boolean} anyMatch True to match any part not just the beginning
9110 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9112 query : function(property, value, anyMatch){
9113 var fn = this.createFilterFn(property, value, anyMatch);
9114 return fn ? this.queryBy(fn) : this.data.clone();
9118 * Query by a function. The specified function will be called with each
9119 * record in this data source. If the function returns true the record is included
9121 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9122 * @param {Object} scope (optional) The scope of the function (defaults to this)
9123 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9125 queryBy : function(fn, scope){
9126 var data = this.snapshot || this.data;
9127 return data.filterBy(fn, scope||this);
9131 * Collects unique values for a particular dataIndex from this store.
9132 * @param {String} dataIndex The property to collect
9133 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9134 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9135 * @return {Array} An array of the unique values
9137 collect : function(dataIndex, allowNull, bypassFilter){
9138 var d = (bypassFilter === true && this.snapshot) ?
9139 this.snapshot.items : this.data.items;
9140 var v, sv, r = [], l = {};
9141 for(var i = 0, len = d.length; i < len; i++){
9142 v = d[i].data[dataIndex];
9144 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9153 * Revert to a view of the Record cache with no filtering applied.
9154 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9156 clearFilter : function(suppressEvent){
9157 if(this.snapshot && this.snapshot != this.data){
9158 this.data = this.snapshot;
9159 delete this.snapshot;
9160 if(suppressEvent !== true){
9161 this.fireEvent("datachanged", this);
9167 afterEdit : function(record){
9168 if(this.modified.indexOf(record) == -1){
9169 this.modified.push(record);
9171 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9175 afterReject : function(record){
9176 this.modified.remove(record);
9177 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9181 afterCommit : function(record){
9182 this.modified.remove(record);
9183 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9187 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9188 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9190 commitChanges : function(){
9191 var m = this.modified.slice(0);
9193 for(var i = 0, len = m.length; i < len; i++){
9199 * Cancel outstanding changes on all changed records.
9201 rejectChanges : function(){
9202 var m = this.modified.slice(0);
9204 for(var i = 0, len = m.length; i < len; i++){
9209 onMetaChange : function(meta, rtype, o){
9210 this.recordType = rtype;
9211 this.fields = rtype.prototype.fields;
9212 delete this.snapshot;
9213 this.sortInfo = meta.sortInfo || this.sortInfo;
9215 this.fireEvent('metachange', this, this.reader.meta);
9218 moveIndex : function(data, type)
9220 var index = this.indexOf(data);
9222 var newIndex = index + type;
9226 this.insert(newIndex, data);
9231 * Ext JS Library 1.1.1
9232 * Copyright(c) 2006-2007, Ext JS, LLC.
9234 * Originally Released Under LGPL - original licence link has changed is not relivant.
9237 * <script type="text/javascript">
9241 * @class Roo.data.SimpleStore
9242 * @extends Roo.data.Store
9243 * Small helper class to make creating Stores from Array data easier.
9244 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9245 * @cfg {Array} fields An array of field definition objects, or field name strings.
9246 * @cfg {Array} data The multi-dimensional array of data
9248 * @param {Object} config
9250 Roo.data.SimpleStore = function(config){
9251 Roo.data.SimpleStore.superclass.constructor.call(this, {
9253 reader: new Roo.data.ArrayReader({
9256 Roo.data.Record.create(config.fields)
9258 proxy : new Roo.data.MemoryProxy(config.data)
9262 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9264 * Ext JS Library 1.1.1
9265 * Copyright(c) 2006-2007, Ext JS, LLC.
9267 * Originally Released Under LGPL - original licence link has changed is not relivant.
9270 * <script type="text/javascript">
9275 * @extends Roo.data.Store
9276 * @class Roo.data.JsonStore
9277 * Small helper class to make creating Stores for JSON data easier. <br/>
9279 var store = new Roo.data.JsonStore({
9280 url: 'get-images.php',
9282 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9285 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9286 * JsonReader and HttpProxy (unless inline data is provided).</b>
9287 * @cfg {Array} fields An array of field definition objects, or field name strings.
9289 * @param {Object} config
9291 Roo.data.JsonStore = function(c){
9292 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9293 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9294 reader: new Roo.data.JsonReader(c, c.fields)
9297 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9299 * Ext JS Library 1.1.1
9300 * Copyright(c) 2006-2007, Ext JS, LLC.
9302 * Originally Released Under LGPL - original licence link has changed is not relivant.
9305 * <script type="text/javascript">
9309 Roo.data.Field = function(config){
9310 if(typeof config == "string"){
9311 config = {name: config};
9313 Roo.apply(this, config);
9319 var st = Roo.data.SortTypes;
9320 // named sortTypes are supported, here we look them up
9321 if(typeof this.sortType == "string"){
9322 this.sortType = st[this.sortType];
9325 // set default sortType for strings and dates
9329 this.sortType = st.asUCString;
9332 this.sortType = st.asDate;
9335 this.sortType = st.none;
9340 var stripRe = /[\$,%]/g;
9342 // prebuilt conversion function for this field, instead of
9343 // switching every time we're reading a value
9345 var cv, dateFormat = this.dateFormat;
9350 cv = function(v){ return v; };
9353 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9357 return v !== undefined && v !== null && v !== '' ?
9358 parseInt(String(v).replace(stripRe, ""), 10) : '';
9363 return v !== undefined && v !== null && v !== '' ?
9364 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9369 cv = function(v){ return v === true || v === "true" || v == 1; };
9376 if(v instanceof Date){
9380 if(dateFormat == "timestamp"){
9381 return new Date(v*1000);
9383 return Date.parseDate(v, dateFormat);
9385 var parsed = Date.parse(v);
9386 return parsed ? new Date(parsed) : null;
9395 Roo.data.Field.prototype = {
9403 * Ext JS Library 1.1.1
9404 * Copyright(c) 2006-2007, Ext JS, LLC.
9406 * Originally Released Under LGPL - original licence link has changed is not relivant.
9409 * <script type="text/javascript">
9412 // Base class for reading structured data from a data source. This class is intended to be
9413 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9416 * @class Roo.data.DataReader
9417 * Base class for reading structured data from a data source. This class is intended to be
9418 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9421 Roo.data.DataReader = function(meta, recordType){
9425 this.recordType = recordType instanceof Array ?
9426 Roo.data.Record.create(recordType) : recordType;
9429 Roo.data.DataReader.prototype = {
9431 * Create an empty record
9432 * @param {Object} data (optional) - overlay some values
9433 * @return {Roo.data.Record} record created.
9435 newRow : function(d) {
9437 this.recordType.prototype.fields.each(function(c) {
9439 case 'int' : da[c.name] = 0; break;
9440 case 'date' : da[c.name] = new Date(); break;
9441 case 'float' : da[c.name] = 0.0; break;
9442 case 'boolean' : da[c.name] = false; break;
9443 default : da[c.name] = ""; break;
9447 return new this.recordType(Roo.apply(da, d));
9452 * Ext JS Library 1.1.1
9453 * Copyright(c) 2006-2007, Ext JS, LLC.
9455 * Originally Released Under LGPL - original licence link has changed is not relivant.
9458 * <script type="text/javascript">
9462 * @class Roo.data.DataProxy
9463 * @extends Roo.data.Observable
9464 * This class is an abstract base class for implementations which provide retrieval of
9465 * unformatted data objects.<br>
9467 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9468 * (of the appropriate type which knows how to parse the data object) to provide a block of
9469 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9471 * Custom implementations must implement the load method as described in
9472 * {@link Roo.data.HttpProxy#load}.
9474 Roo.data.DataProxy = function(){
9478 * Fires before a network request is made to retrieve a data object.
9479 * @param {Object} This DataProxy object.
9480 * @param {Object} params The params parameter to the load function.
9485 * Fires before the load method's callback is called.
9486 * @param {Object} This DataProxy object.
9487 * @param {Object} o The data object.
9488 * @param {Object} arg The callback argument object passed to the load function.
9492 * @event loadexception
9493 * Fires if an Exception occurs during data retrieval.
9494 * @param {Object} This DataProxy object.
9495 * @param {Object} o The data object.
9496 * @param {Object} arg The callback argument object passed to the load function.
9497 * @param {Object} e The Exception.
9499 loadexception : true
9501 Roo.data.DataProxy.superclass.constructor.call(this);
9504 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9507 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9511 * Ext JS Library 1.1.1
9512 * Copyright(c) 2006-2007, Ext JS, LLC.
9514 * Originally Released Under LGPL - original licence link has changed is not relivant.
9517 * <script type="text/javascript">
9520 * @class Roo.data.MemoryProxy
9521 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9522 * to the Reader when its load method is called.
9524 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9526 Roo.data.MemoryProxy = function(data){
9530 Roo.data.MemoryProxy.superclass.constructor.call(this);
9534 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9536 * Load data from the requested source (in this case an in-memory
9537 * data object passed to the constructor), read the data object into
9538 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9539 * process that block using the passed callback.
9540 * @param {Object} params This parameter is not used by the MemoryProxy class.
9541 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9542 * object into a block of Roo.data.Records.
9543 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9544 * The function must be passed <ul>
9545 * <li>The Record block object</li>
9546 * <li>The "arg" argument from the load function</li>
9547 * <li>A boolean success indicator</li>
9549 * @param {Object} scope The scope in which to call the callback
9550 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9552 load : function(params, reader, callback, scope, arg){
9553 params = params || {};
9556 result = reader.readRecords(this.data);
9558 this.fireEvent("loadexception", this, arg, null, e);
9559 callback.call(scope, null, arg, false);
9562 callback.call(scope, result, arg, true);
9566 update : function(params, records){
9571 * Ext JS Library 1.1.1
9572 * Copyright(c) 2006-2007, Ext JS, LLC.
9574 * Originally Released Under LGPL - original licence link has changed is not relivant.
9577 * <script type="text/javascript">
9580 * @class Roo.data.HttpProxy
9581 * @extends Roo.data.DataProxy
9582 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9583 * configured to reference a certain URL.<br><br>
9585 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9586 * from which the running page was served.<br><br>
9588 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9590 * Be aware that to enable the browser to parse an XML document, the server must set
9591 * the Content-Type header in the HTTP response to "text/xml".
9593 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9594 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9595 * will be used to make the request.
9597 Roo.data.HttpProxy = function(conn){
9598 Roo.data.HttpProxy.superclass.constructor.call(this);
9599 // is conn a conn config or a real conn?
9601 this.useAjax = !conn || !conn.events;
9605 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9606 // thse are take from connection...
9609 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9612 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9613 * extra parameters to each request made by this object. (defaults to undefined)
9616 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9617 * to each request made by this object. (defaults to undefined)
9620 * @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)
9623 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9626 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9632 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9636 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9637 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9638 * a finer-grained basis than the DataProxy events.
9640 getConnection : function(){
9641 return this.useAjax ? Roo.Ajax : this.conn;
9645 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9646 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9647 * process that block using the passed callback.
9648 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9649 * for the request to the remote server.
9650 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9651 * object into a block of Roo.data.Records.
9652 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9653 * The function must be passed <ul>
9654 * <li>The Record block object</li>
9655 * <li>The "arg" argument from the load function</li>
9656 * <li>A boolean success indicator</li>
9658 * @param {Object} scope The scope in which to call the callback
9659 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9661 load : function(params, reader, callback, scope, arg){
9662 if(this.fireEvent("beforeload", this, params) !== false){
9664 params : params || {},
9666 callback : callback,
9671 callback : this.loadResponse,
9675 Roo.applyIf(o, this.conn);
9676 if(this.activeRequest){
9677 Roo.Ajax.abort(this.activeRequest);
9679 this.activeRequest = Roo.Ajax.request(o);
9681 this.conn.request(o);
9684 callback.call(scope||this, null, arg, false);
9689 loadResponse : function(o, success, response){
9690 delete this.activeRequest;
9692 this.fireEvent("loadexception", this, o, response);
9693 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9698 result = o.reader.read(response);
9700 this.fireEvent("loadexception", this, o, response, e);
9701 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9705 this.fireEvent("load", this, o, o.request.arg);
9706 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9710 update : function(dataSet){
9715 updateResponse : function(dataSet){
9720 * Ext JS Library 1.1.1
9721 * Copyright(c) 2006-2007, Ext JS, LLC.
9723 * Originally Released Under LGPL - original licence link has changed is not relivant.
9726 * <script type="text/javascript">
9730 * @class Roo.data.ScriptTagProxy
9731 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9732 * other than the originating domain of the running page.<br><br>
9734 * <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
9735 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9737 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9738 * source code that is used as the source inside a <script> tag.<br><br>
9740 * In order for the browser to process the returned data, the server must wrap the data object
9741 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9742 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9743 * depending on whether the callback name was passed:
9746 boolean scriptTag = false;
9747 String cb = request.getParameter("callback");
9750 response.setContentType("text/javascript");
9752 response.setContentType("application/x-json");
9754 Writer out = response.getWriter();
9756 out.write(cb + "(");
9758 out.print(dataBlock.toJsonString());
9765 * @param {Object} config A configuration object.
9767 Roo.data.ScriptTagProxy = function(config){
9768 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9769 Roo.apply(this, config);
9770 this.head = document.getElementsByTagName("head")[0];
9773 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9775 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9777 * @cfg {String} url The URL from which to request the data object.
9780 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9784 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9785 * the server the name of the callback function set up by the load call to process the returned data object.
9786 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9787 * javascript output which calls this named function passing the data object as its only parameter.
9789 callbackParam : "callback",
9791 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9792 * name to the request.
9797 * Load data from the configured URL, read the data object into
9798 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9799 * process that block using the passed callback.
9800 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9801 * for the request to the remote server.
9802 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9803 * object into a block of Roo.data.Records.
9804 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9805 * The function must be passed <ul>
9806 * <li>The Record block object</li>
9807 * <li>The "arg" argument from the load function</li>
9808 * <li>A boolean success indicator</li>
9810 * @param {Object} scope The scope in which to call the callback
9811 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9813 load : function(params, reader, callback, scope, arg){
9814 if(this.fireEvent("beforeload", this, params) !== false){
9816 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9819 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9821 url += "&_dc=" + (new Date().getTime());
9823 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9826 cb : "stcCallback"+transId,
9827 scriptId : "stcScript"+transId,
9831 callback : callback,
9837 window[trans.cb] = function(o){
9838 conn.handleResponse(o, trans);
9841 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9843 if(this.autoAbort !== false){
9847 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9849 var script = document.createElement("script");
9850 script.setAttribute("src", url);
9851 script.setAttribute("type", "text/javascript");
9852 script.setAttribute("id", trans.scriptId);
9853 this.head.appendChild(script);
9857 callback.call(scope||this, null, arg, false);
9862 isLoading : function(){
9863 return this.trans ? true : false;
9867 * Abort the current server request.
9870 if(this.isLoading()){
9871 this.destroyTrans(this.trans);
9876 destroyTrans : function(trans, isLoaded){
9877 this.head.removeChild(document.getElementById(trans.scriptId));
9878 clearTimeout(trans.timeoutId);
9880 window[trans.cb] = undefined;
9882 delete window[trans.cb];
9885 // if hasn't been loaded, wait for load to remove it to prevent script error
9886 window[trans.cb] = function(){
9887 window[trans.cb] = undefined;
9889 delete window[trans.cb];
9896 handleResponse : function(o, trans){
9898 this.destroyTrans(trans, true);
9901 result = trans.reader.readRecords(o);
9903 this.fireEvent("loadexception", this, o, trans.arg, e);
9904 trans.callback.call(trans.scope||window, null, trans.arg, false);
9907 this.fireEvent("load", this, o, trans.arg);
9908 trans.callback.call(trans.scope||window, result, trans.arg, true);
9912 handleFailure : function(trans){
9914 this.destroyTrans(trans, false);
9915 this.fireEvent("loadexception", this, null, trans.arg);
9916 trans.callback.call(trans.scope||window, null, trans.arg, false);
9920 * Ext JS Library 1.1.1
9921 * Copyright(c) 2006-2007, Ext JS, LLC.
9923 * Originally Released Under LGPL - original licence link has changed is not relivant.
9926 * <script type="text/javascript">
9930 * @class Roo.data.JsonReader
9931 * @extends Roo.data.DataReader
9932 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9933 * based on mappings in a provided Roo.data.Record constructor.
9935 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9936 * in the reply previously.
9941 var RecordDef = Roo.data.Record.create([
9942 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9943 {name: 'occupation'} // This field will use "occupation" as the mapping.
9945 var myReader = new Roo.data.JsonReader({
9946 totalProperty: "results", // The property which contains the total dataset size (optional)
9947 root: "rows", // The property which contains an Array of row objects
9948 id: "id" // The property within each row object that provides an ID for the record (optional)
9952 * This would consume a JSON file like this:
9954 { 'results': 2, 'rows': [
9955 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9956 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9959 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9960 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9961 * paged from the remote server.
9962 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9963 * @cfg {String} root name of the property which contains the Array of row objects.
9964 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9966 * Create a new JsonReader
9967 * @param {Object} meta Metadata configuration options
9968 * @param {Object} recordType Either an Array of field definition objects,
9969 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9971 Roo.data.JsonReader = function(meta, recordType){
9974 // set some defaults:
9976 totalProperty: 'total',
9977 successProperty : 'success',
9982 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9984 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9987 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9988 * Used by Store query builder to append _requestMeta to params.
9991 metaFromRemote : false,
9993 * This method is only used by a DataProxy which has retrieved data from a remote server.
9994 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9995 * @return {Object} data A data block which is used by an Roo.data.Store object as
9996 * a cache of Roo.data.Records.
9998 read : function(response){
9999 var json = response.responseText;
10001 var o = /* eval:var:o */ eval("("+json+")");
10003 throw {message: "JsonReader.read: Json object not found"};
10009 this.metaFromRemote = true;
10010 this.meta = o.metaData;
10011 this.recordType = Roo.data.Record.create(o.metaData.fields);
10012 this.onMetaChange(this.meta, this.recordType, o);
10014 return this.readRecords(o);
10017 // private function a store will implement
10018 onMetaChange : function(meta, recordType, o){
10025 simpleAccess: function(obj, subsc) {
10032 getJsonAccessor: function(){
10034 return function(expr) {
10036 return(re.test(expr))
10037 ? new Function("obj", "return obj." + expr)
10042 return Roo.emptyFn;
10047 * Create a data block containing Roo.data.Records from an XML document.
10048 * @param {Object} o An object which contains an Array of row objects in the property specified
10049 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10050 * which contains the total size of the dataset.
10051 * @return {Object} data A data block which is used by an Roo.data.Store object as
10052 * a cache of Roo.data.Records.
10054 readRecords : function(o){
10056 * After any data loads, the raw JSON data is available for further custom processing.
10060 var s = this.meta, Record = this.recordType,
10061 f = Record.prototype.fields, fi = f.items, fl = f.length;
10063 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10065 if(s.totalProperty) {
10066 this.getTotal = this.getJsonAccessor(s.totalProperty);
10068 if(s.successProperty) {
10069 this.getSuccess = this.getJsonAccessor(s.successProperty);
10071 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10073 var g = this.getJsonAccessor(s.id);
10074 this.getId = function(rec) {
10076 return (r === undefined || r === "") ? null : r;
10079 this.getId = function(){return null;};
10082 for(var jj = 0; jj < fl; jj++){
10084 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10085 this.ef[jj] = this.getJsonAccessor(map);
10089 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10090 if(s.totalProperty){
10091 var vt = parseInt(this.getTotal(o), 10);
10096 if(s.successProperty){
10097 var vs = this.getSuccess(o);
10098 if(vs === false || vs === 'false'){
10103 for(var i = 0; i < c; i++){
10106 var id = this.getId(n);
10107 for(var j = 0; j < fl; j++){
10109 var v = this.ef[j](n);
10111 Roo.log('missing convert for ' + f.name);
10115 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10117 var record = new Record(values, id);
10119 records[i] = record;
10125 totalRecords : totalRecords
10130 * Ext JS Library 1.1.1
10131 * Copyright(c) 2006-2007, Ext JS, LLC.
10133 * Originally Released Under LGPL - original licence link has changed is not relivant.
10136 * <script type="text/javascript">
10140 * @class Roo.data.ArrayReader
10141 * @extends Roo.data.DataReader
10142 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10143 * Each element of that Array represents a row of data fields. The
10144 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10145 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10149 var RecordDef = Roo.data.Record.create([
10150 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10151 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10153 var myReader = new Roo.data.ArrayReader({
10154 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10158 * This would consume an Array like this:
10160 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10162 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10164 * Create a new JsonReader
10165 * @param {Object} meta Metadata configuration options.
10166 * @param {Object} recordType Either an Array of field definition objects
10167 * as specified to {@link Roo.data.Record#create},
10168 * or an {@link Roo.data.Record} object
10169 * created using {@link Roo.data.Record#create}.
10171 Roo.data.ArrayReader = function(meta, recordType){
10172 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10175 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10177 * Create a data block containing Roo.data.Records from an XML document.
10178 * @param {Object} o An Array of row objects which represents the dataset.
10179 * @return {Object} data A data block which is used by an Roo.data.Store object as
10180 * a cache of Roo.data.Records.
10182 readRecords : function(o){
10183 var sid = this.meta ? this.meta.id : null;
10184 var recordType = this.recordType, fields = recordType.prototype.fields;
10187 for(var i = 0; i < root.length; i++){
10190 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10191 for(var j = 0, jlen = fields.length; j < jlen; j++){
10192 var f = fields.items[j];
10193 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10194 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10196 values[f.name] = v;
10198 var record = new recordType(values, id);
10200 records[records.length] = record;
10204 totalRecords : records.length
10213 * @class Roo.bootstrap.ComboBox
10214 * @extends Roo.bootstrap.TriggerField
10215 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10216 * @cfg {Boolean} append (true|false) default false
10217 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10218 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10219 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10220 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10221 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10223 * Create a new ComboBox.
10224 * @param {Object} config Configuration options
10226 Roo.bootstrap.ComboBox = function(config){
10227 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10231 * Fires when the dropdown list is expanded
10232 * @param {Roo.bootstrap.ComboBox} combo This combo box
10237 * Fires when the dropdown list is collapsed
10238 * @param {Roo.bootstrap.ComboBox} combo This combo box
10242 * @event beforeselect
10243 * Fires before a list item is selected. Return false to cancel the selection.
10244 * @param {Roo.bootstrap.ComboBox} combo This combo box
10245 * @param {Roo.data.Record} record The data record returned from the underlying store
10246 * @param {Number} index The index of the selected item in the dropdown list
10248 'beforeselect' : true,
10251 * Fires when a list item is selected
10252 * @param {Roo.bootstrap.ComboBox} combo This combo box
10253 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10254 * @param {Number} index The index of the selected item in the dropdown list
10258 * @event beforequery
10259 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10260 * The event object passed has these properties:
10261 * @param {Roo.bootstrap.ComboBox} combo This combo box
10262 * @param {String} query The query
10263 * @param {Boolean} forceAll true to force "all" query
10264 * @param {Boolean} cancel true to cancel the query
10265 * @param {Object} e The query event object
10267 'beforequery': true,
10270 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10271 * @param {Roo.bootstrap.ComboBox} combo This combo box
10276 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10277 * @param {Roo.bootstrap.ComboBox} combo This combo box
10278 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10283 * Fires when the remove value from the combobox array
10284 * @param {Roo.bootstrap.ComboBox} combo This combo box
10291 this.tickItems = [];
10293 this.selectedIndex = -1;
10294 if(this.mode == 'local'){
10295 if(config.queryDelay === undefined){
10296 this.queryDelay = 10;
10298 if(config.minChars === undefined){
10304 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10307 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10308 * rendering into an Roo.Editor, defaults to false)
10311 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10312 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10315 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10318 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10319 * the dropdown list (defaults to undefined, with no header element)
10323 * @cfg {String/Roo.Template} tpl The template to use to render the output
10327 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10329 listWidth: undefined,
10331 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10332 * mode = 'remote' or 'text' if mode = 'local')
10334 displayField: undefined,
10336 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10337 * mode = 'remote' or 'value' if mode = 'local').
10338 * Note: use of a valueField requires the user make a selection
10339 * in order for a value to be mapped.
10341 valueField: undefined,
10345 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10346 * field's data value (defaults to the underlying DOM element's name)
10348 hiddenName: undefined,
10350 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10354 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10356 selectedClass: 'active',
10359 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10363 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10364 * anchor positions (defaults to 'tl-bl')
10366 listAlign: 'tl-bl?',
10368 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10372 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10373 * query specified by the allQuery config option (defaults to 'query')
10375 triggerAction: 'query',
10377 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10378 * (defaults to 4, does not apply if editable = false)
10382 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10383 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10387 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10388 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10392 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10393 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10397 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10398 * when editable = true (defaults to false)
10400 selectOnFocus:false,
10402 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10404 queryParam: 'query',
10406 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10407 * when mode = 'remote' (defaults to 'Loading...')
10409 loadingText: 'Loading...',
10411 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10415 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10419 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10420 * traditional select (defaults to true)
10424 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10428 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10432 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10433 * listWidth has a higher value)
10437 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10438 * allow the user to set arbitrary text into the field (defaults to false)
10440 forceSelection:false,
10442 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10443 * if typeAhead = true (defaults to 250)
10445 typeAheadDelay : 250,
10447 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10448 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10450 valueNotFoundText : undefined,
10452 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10454 blockFocus : false,
10457 * @cfg {Boolean} disableClear Disable showing of clear button.
10459 disableClear : false,
10461 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10463 alwaysQuery : false,
10466 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10480 btnPosition : 'right',
10481 triggerList : true,
10482 showToggleBtn : true,
10483 // element that contains real text value.. (when hidden is used..)
10485 getAutoCreate : function()
10492 if(!this.tickable){
10493 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10498 * ComboBox with tickable selections
10501 var align = this.labelAlign || this.parentLabelAlign();
10504 cls : 'form-group roo-combobox-tickable' //input-group
10510 cls : 'tickable-buttons',
10515 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10522 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10529 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10536 Roo.each(buttons.cn, function(c){
10538 c.cls += ' btn-' + _this.size;
10541 if (_this.disabled) {
10552 cls: 'form-hidden-field'
10556 cls: 'select2-choices',
10560 cls: 'select2-search-field',
10572 cls: 'select2-container input-group select2-container-multi',
10577 // cls: 'typeahead typeahead-long dropdown-menu',
10578 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10583 if (align ==='left' && this.fieldLabel.length) {
10585 Roo.log("left and has label");
10591 cls : 'control-label col-sm-' + this.labelWidth,
10592 html : this.fieldLabel
10596 cls : "col-sm-" + (12 - this.labelWidth),
10603 } else if ( this.fieldLabel.length) {
10609 //cls : 'input-group-addon',
10610 html : this.fieldLabel
10620 Roo.log(" no label && no align");
10627 ['xs','sm','md','lg'].map(function(size){
10628 if (settings[size]) {
10629 cfg.cls += ' col-' + size + '-' + settings[size];
10638 initEvents: function()
10642 throw "can not find store for combo";
10644 this.store = Roo.factory(this.store, Roo.data);
10647 this.initTickableEvents();
10651 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10653 if(this.hiddenName){
10655 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10657 this.hiddenField.dom.value =
10658 this.hiddenValue !== undefined ? this.hiddenValue :
10659 this.value !== undefined ? this.value : '';
10661 // prevent input submission
10662 this.el.dom.removeAttribute('name');
10663 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10668 // this.el.dom.setAttribute('autocomplete', 'off');
10671 var cls = 'x-combo-list';
10673 //this.list = new Roo.Layer({
10674 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10680 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10681 _this.list.setWidth(lw);
10684 this.list.on('mouseover', this.onViewOver, this);
10685 this.list.on('mousemove', this.onViewMove, this);
10687 this.list.on('scroll', this.onViewScroll, this);
10690 this.list.swallowEvent('mousewheel');
10691 this.assetHeight = 0;
10694 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10695 this.assetHeight += this.header.getHeight();
10698 this.innerList = this.list.createChild({cls:cls+'-inner'});
10699 this.innerList.on('mouseover', this.onViewOver, this);
10700 this.innerList.on('mousemove', this.onViewMove, this);
10701 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10703 if(this.allowBlank && !this.pageSize && !this.disableClear){
10704 this.footer = this.list.createChild({cls:cls+'-ft'});
10705 this.pageTb = new Roo.Toolbar(this.footer);
10709 this.footer = this.list.createChild({cls:cls+'-ft'});
10710 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10711 {pageSize: this.pageSize});
10715 if (this.pageTb && this.allowBlank && !this.disableClear) {
10717 this.pageTb.add(new Roo.Toolbar.Fill(), {
10718 cls: 'x-btn-icon x-btn-clear',
10720 handler: function()
10723 _this.clearValue();
10724 _this.onSelect(false, -1);
10729 this.assetHeight += this.footer.getHeight();
10734 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10737 this.view = new Roo.View(this.list, this.tpl, {
10738 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10740 //this.view.wrapEl.setDisplayed(false);
10741 this.view.on('click', this.onViewClick, this);
10745 this.store.on('beforeload', this.onBeforeLoad, this);
10746 this.store.on('load', this.onLoad, this);
10747 this.store.on('loadexception', this.onLoadException, this);
10749 if(this.resizable){
10750 this.resizer = new Roo.Resizable(this.list, {
10751 pinned:true, handles:'se'
10753 this.resizer.on('resize', function(r, w, h){
10754 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10755 this.listWidth = w;
10756 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10757 this.restrictHeight();
10759 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10762 if(!this.editable){
10763 this.editable = true;
10764 this.setEditable(false);
10769 if (typeof(this.events.add.listeners) != 'undefined') {
10771 this.addicon = this.wrap.createChild(
10772 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10774 this.addicon.on('click', function(e) {
10775 this.fireEvent('add', this);
10778 if (typeof(this.events.edit.listeners) != 'undefined') {
10780 this.editicon = this.wrap.createChild(
10781 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10782 if (this.addicon) {
10783 this.editicon.setStyle('margin-left', '40px');
10785 this.editicon.on('click', function(e) {
10787 // we fire even if inothing is selected..
10788 this.fireEvent('edit', this, this.lastData );
10794 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10795 "up" : function(e){
10796 this.inKeyMode = true;
10800 "down" : function(e){
10801 if(!this.isExpanded()){
10802 this.onTriggerClick();
10804 this.inKeyMode = true;
10809 "enter" : function(e){
10810 // this.onViewClick();
10814 if(this.fireEvent("specialkey", this, e)){
10815 this.onViewClick(false);
10821 "esc" : function(e){
10825 "tab" : function(e){
10828 if(this.fireEvent("specialkey", this, e)){
10829 this.onViewClick(false);
10837 doRelay : function(foo, bar, hname){
10838 if(hname == 'down' || this.scope.isExpanded()){
10839 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10848 this.queryDelay = Math.max(this.queryDelay || 10,
10849 this.mode == 'local' ? 10 : 250);
10852 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10854 if(this.typeAhead){
10855 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10857 if(this.editable !== false){
10858 this.inputEl().on("keyup", this.onKeyUp, this);
10860 if(this.forceSelection){
10861 this.inputEl().on('blur', this.doForce, this);
10865 this.choices = this.el.select('ul.select2-choices', true).first();
10866 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10870 initTickableEvents: function()
10874 if(this.hiddenName){
10876 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10878 this.hiddenField.dom.value =
10879 this.hiddenValue !== undefined ? this.hiddenValue :
10880 this.value !== undefined ? this.value : '';
10882 // prevent input submission
10883 this.el.dom.removeAttribute('name');
10884 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10889 // this.list = this.el.select('ul.dropdown-menu',true).first();
10891 this.choices = this.el.select('ul.select2-choices', true).first();
10892 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10893 if(this.triggerList){
10894 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10897 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10898 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10900 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10901 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10903 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10904 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10906 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10907 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10908 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10911 this.cancelBtn.hide();
10916 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10917 _this.list.setWidth(lw);
10920 this.list.on('mouseover', this.onViewOver, this);
10921 this.list.on('mousemove', this.onViewMove, this);
10923 this.list.on('scroll', this.onViewScroll, this);
10926 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>';
10929 this.view = new Roo.View(this.list, this.tpl, {
10930 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10933 //this.view.wrapEl.setDisplayed(false);
10934 this.view.on('click', this.onViewClick, this);
10938 this.store.on('beforeload', this.onBeforeLoad, this);
10939 this.store.on('load', this.onLoad, this);
10940 this.store.on('loadexception', this.onLoadException, this);
10942 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10943 // "up" : function(e){
10944 // this.inKeyMode = true;
10945 // this.selectPrev();
10948 // "down" : function(e){
10949 // if(!this.isExpanded()){
10950 // this.onTriggerClick();
10952 // this.inKeyMode = true;
10953 // this.selectNext();
10957 // "enter" : function(e){
10958 //// this.onViewClick();
10960 // this.collapse();
10962 // if(this.fireEvent("specialkey", this, e)){
10963 // this.onViewClick(false);
10969 // "esc" : function(e){
10970 // this.collapse();
10973 // "tab" : function(e){
10974 // this.collapse();
10976 // if(this.fireEvent("specialkey", this, e)){
10977 // this.onViewClick(false);
10985 // doRelay : function(foo, bar, hname){
10986 // if(hname == 'down' || this.scope.isExpanded()){
10987 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10992 // forceKeyDown: true
10996 this.queryDelay = Math.max(this.queryDelay || 10,
10997 this.mode == 'local' ? 10 : 250);
11000 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11002 if(this.typeAhead){
11003 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11007 onDestroy : function(){
11009 this.view.setStore(null);
11010 this.view.el.removeAllListeners();
11011 this.view.el.remove();
11012 this.view.purgeListeners();
11015 this.list.dom.innerHTML = '';
11019 this.store.un('beforeload', this.onBeforeLoad, this);
11020 this.store.un('load', this.onLoad, this);
11021 this.store.un('loadexception', this.onLoadException, this);
11023 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11027 fireKey : function(e){
11028 if(e.isNavKeyPress() && !this.list.isVisible()){
11029 this.fireEvent("specialkey", this, e);
11034 onResize: function(w, h){
11035 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11037 // if(typeof w != 'number'){
11038 // // we do not handle it!?!?
11041 // var tw = this.trigger.getWidth();
11042 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11043 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11045 // this.inputEl().setWidth( this.adjustWidth('input', x));
11047 // //this.trigger.setStyle('left', x+'px');
11049 // if(this.list && this.listWidth === undefined){
11050 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11051 // this.list.setWidth(lw);
11052 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11060 * Allow or prevent the user from directly editing the field text. If false is passed,
11061 * the user will only be able to select from the items defined in the dropdown list. This method
11062 * is the runtime equivalent of setting the 'editable' config option at config time.
11063 * @param {Boolean} value True to allow the user to directly edit the field text
11065 setEditable : function(value){
11066 if(value == this.editable){
11069 this.editable = value;
11071 this.inputEl().dom.setAttribute('readOnly', true);
11072 this.inputEl().on('mousedown', this.onTriggerClick, this);
11073 this.inputEl().addClass('x-combo-noedit');
11075 this.inputEl().dom.setAttribute('readOnly', false);
11076 this.inputEl().un('mousedown', this.onTriggerClick, this);
11077 this.inputEl().removeClass('x-combo-noedit');
11083 onBeforeLoad : function(combo,opts){
11084 if(!this.hasFocus){
11088 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11090 // this.restrictHeight();
11091 this.selectedIndex = -1;
11095 onLoad : function(){
11097 this.hasQuery = false;
11099 if(!this.hasFocus){
11103 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11104 this.loading.hide();
11107 if(this.store.getCount() > 0){
11109 // this.restrictHeight();
11110 if(this.lastQuery == this.allQuery){
11111 if(this.editable && !this.tickable){
11112 this.inputEl().dom.select();
11116 !this.selectByValue(this.value, true) &&
11117 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11118 this.store.lastOptions.add != true)
11120 this.select(0, true);
11123 if(this.autoFocus){
11126 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11127 this.taTask.delay(this.typeAheadDelay);
11131 this.onEmptyResults();
11137 onLoadException : function()
11139 this.hasQuery = false;
11141 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11142 this.loading.hide();
11146 Roo.log(this.store.reader.jsonData);
11147 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11149 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11155 onTypeAhead : function(){
11156 if(this.store.getCount() > 0){
11157 var r = this.store.getAt(0);
11158 var newValue = r.data[this.displayField];
11159 var len = newValue.length;
11160 var selStart = this.getRawValue().length;
11162 if(selStart != len){
11163 this.setRawValue(newValue);
11164 this.selectText(selStart, newValue.length);
11170 onSelect : function(record, index){
11172 if(this.fireEvent('beforeselect', this, record, index) !== false){
11174 this.setFromData(index > -1 ? record.data : false);
11177 this.fireEvent('select', this, record, index);
11182 * Returns the currently selected field value or empty string if no value is set.
11183 * @return {String} value The selected value
11185 getValue : function(){
11188 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11191 if(this.valueField){
11192 return typeof this.value != 'undefined' ? this.value : '';
11194 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11199 * Clears any text/value currently set in the field
11201 clearValue : function(){
11202 if(this.hiddenField){
11203 this.hiddenField.dom.value = '';
11206 this.setRawValue('');
11207 this.lastSelectionText = '';
11212 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11213 * will be displayed in the field. If the value does not match the data value of an existing item,
11214 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11215 * Otherwise the field will be blank (although the value will still be set).
11216 * @param {String} value The value to match
11218 setValue : function(v){
11225 if(this.valueField){
11226 var r = this.findRecord(this.valueField, v);
11228 text = r.data[this.displayField];
11229 }else if(this.valueNotFoundText !== undefined){
11230 text = this.valueNotFoundText;
11233 this.lastSelectionText = text;
11234 if(this.hiddenField){
11235 this.hiddenField.dom.value = v;
11237 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11241 * @property {Object} the last set data for the element
11246 * Sets the value of the field based on a object which is related to the record format for the store.
11247 * @param {Object} value the value to set as. or false on reset?
11249 setFromData : function(o){
11252 if(typeof o.display_name !== 'string'){
11253 for(var i=0;i<o.display_name.length;i++){
11254 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11262 var dv = ''; // display value
11263 var vv = ''; // value value..
11265 if (this.displayField) {
11266 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11268 // this is an error condition!!!
11269 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11272 if(this.valueField){
11273 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11276 if(this.hiddenField){
11277 this.hiddenField.dom.value = vv;
11279 this.lastSelectionText = dv;
11280 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11284 // no hidden field.. - we store the value in 'value', but still display
11285 // display field!!!!
11286 this.lastSelectionText = dv;
11287 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11293 reset : function(){
11294 // overridden so that last data is reset..
11295 this.setValue(this.originalValue);
11296 this.clearInvalid();
11297 this.lastData = false;
11299 this.view.clearSelections();
11303 findRecord : function(prop, value){
11305 if(this.store.getCount() > 0){
11306 this.store.each(function(r){
11307 if(r.data[prop] == value){
11317 getName: function()
11319 // returns hidden if it's set..
11320 if (!this.rendered) {return ''};
11321 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11325 onViewMove : function(e, t){
11326 this.inKeyMode = false;
11330 onViewOver : function(e, t){
11331 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11334 var item = this.view.findItemFromChild(t);
11337 var index = this.view.indexOf(item);
11338 this.select(index, false);
11343 onViewClick : function(view, doFocus, el, e)
11345 var index = this.view.getSelectedIndexes()[0];
11347 var r = this.store.getAt(index);
11351 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11358 Roo.each(this.tickItems, function(v,k){
11360 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11361 _this.tickItems.splice(k, 1);
11371 this.tickItems.push(r.data);
11376 this.onSelect(r, index);
11378 if(doFocus !== false && !this.blockFocus){
11379 this.inputEl().focus();
11384 restrictHeight : function(){
11385 //this.innerList.dom.style.height = '';
11386 //var inner = this.innerList.dom;
11387 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11388 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11389 //this.list.beginUpdate();
11390 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11391 this.list.alignTo(this.inputEl(), this.listAlign);
11392 this.list.alignTo(this.inputEl(), this.listAlign);
11393 //this.list.endUpdate();
11397 onEmptyResults : function(){
11402 * Returns true if the dropdown list is expanded, else false.
11404 isExpanded : function(){
11405 return this.list.isVisible();
11409 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11410 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11411 * @param {String} value The data value of the item to select
11412 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11413 * selected item if it is not currently in view (defaults to true)
11414 * @return {Boolean} True if the value matched an item in the list, else false
11416 selectByValue : function(v, scrollIntoView){
11417 if(v !== undefined && v !== null){
11418 var r = this.findRecord(this.valueField || this.displayField, v);
11420 this.select(this.store.indexOf(r), scrollIntoView);
11428 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11429 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11430 * @param {Number} index The zero-based index of the list item to select
11431 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11432 * selected item if it is not currently in view (defaults to true)
11434 select : function(index, scrollIntoView){
11435 this.selectedIndex = index;
11436 this.view.select(index);
11437 if(scrollIntoView !== false){
11438 var el = this.view.getNode(index);
11439 if(el && !this.multiple && !this.tickable){
11440 this.list.scrollChildIntoView(el, false);
11446 selectNext : function(){
11447 var ct = this.store.getCount();
11449 if(this.selectedIndex == -1){
11451 }else if(this.selectedIndex < ct-1){
11452 this.select(this.selectedIndex+1);
11458 selectPrev : function(){
11459 var ct = this.store.getCount();
11461 if(this.selectedIndex == -1){
11463 }else if(this.selectedIndex != 0){
11464 this.select(this.selectedIndex-1);
11470 onKeyUp : function(e){
11471 if(this.editable !== false && !e.isSpecialKey()){
11472 this.lastKey = e.getKey();
11473 this.dqTask.delay(this.queryDelay);
11478 validateBlur : function(){
11479 return !this.list || !this.list.isVisible();
11483 initQuery : function(){
11484 this.doQuery(this.getRawValue());
11488 doForce : function(){
11489 if(this.inputEl().dom.value.length > 0){
11490 this.inputEl().dom.value =
11491 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11497 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11498 * query allowing the query action to be canceled if needed.
11499 * @param {String} query The SQL query to execute
11500 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11501 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11502 * saved in the current store (defaults to false)
11504 doQuery : function(q, forceAll){
11506 if(q === undefined || q === null){
11511 forceAll: forceAll,
11515 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11520 forceAll = qe.forceAll;
11521 if(forceAll === true || (q.length >= this.minChars)){
11523 this.hasQuery = true;
11525 if(this.lastQuery != q || this.alwaysQuery){
11526 this.lastQuery = q;
11527 if(this.mode == 'local'){
11528 this.selectedIndex = -1;
11530 this.store.clearFilter();
11532 this.store.filter(this.displayField, q);
11536 this.store.baseParams[this.queryParam] = q;
11538 var options = {params : this.getParams(q)};
11541 options.add = true;
11542 options.params.start = this.page * this.pageSize;
11545 this.store.load(options);
11547 * this code will make the page width larger, at the beginning, the list not align correctly,
11548 * we should expand the list on onLoad
11549 * so command out it
11554 this.selectedIndex = -1;
11559 this.loadNext = false;
11563 getParams : function(q){
11565 //p[this.queryParam] = q;
11569 p.limit = this.pageSize;
11575 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11577 collapse : function(){
11578 if(!this.isExpanded()){
11586 this.cancelBtn.hide();
11587 this.trigger.show();
11590 Roo.get(document).un('mousedown', this.collapseIf, this);
11591 Roo.get(document).un('mousewheel', this.collapseIf, this);
11592 if (!this.editable) {
11593 Roo.get(document).un('keydown', this.listKeyPress, this);
11595 this.fireEvent('collapse', this);
11599 collapseIf : function(e){
11600 var in_combo = e.within(this.el);
11601 var in_list = e.within(this.list);
11602 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11604 if (in_combo || in_list || is_list) {
11605 //e.stopPropagation();
11610 this.onTickableFooterButtonClick(e, false, false);
11618 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11620 expand : function(){
11622 if(this.isExpanded() || !this.hasFocus){
11626 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11627 this.list.setWidth(lw);
11632 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11633 this.list.setWidth(lw);
11637 this.restrictHeight();
11641 this.tickItems = Roo.apply([], this.item);
11644 this.cancelBtn.show();
11645 this.trigger.hide();
11649 Roo.get(document).on('mousedown', this.collapseIf, this);
11650 Roo.get(document).on('mousewheel', this.collapseIf, this);
11651 if (!this.editable) {
11652 Roo.get(document).on('keydown', this.listKeyPress, this);
11655 this.fireEvent('expand', this);
11659 // Implements the default empty TriggerField.onTriggerClick function
11660 onTriggerClick : function(e)
11662 Roo.log('trigger click');
11664 if(this.disabled || !this.triggerList){
11669 this.loadNext = false;
11671 if(this.isExpanded()){
11673 if (!this.blockFocus) {
11674 this.inputEl().focus();
11678 this.hasFocus = true;
11679 if(this.triggerAction == 'all') {
11680 this.doQuery(this.allQuery, true);
11682 this.doQuery(this.getRawValue());
11684 if (!this.blockFocus) {
11685 this.inputEl().focus();
11690 onTickableTriggerClick : function(e)
11697 this.loadNext = false;
11698 this.hasFocus = true;
11700 if(this.triggerAction == 'all') {
11701 this.doQuery(this.allQuery, true);
11703 this.doQuery(this.getRawValue());
11707 onSearchFieldClick : function(e)
11709 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11714 this.loadNext = false;
11715 this.hasFocus = true;
11717 if(this.triggerAction == 'all') {
11718 this.doQuery(this.allQuery, true);
11720 this.doQuery(this.getRawValue());
11724 listKeyPress : function(e)
11726 //Roo.log('listkeypress');
11727 // scroll to first matching element based on key pres..
11728 if (e.isSpecialKey()) {
11731 var k = String.fromCharCode(e.getKey()).toUpperCase();
11734 var csel = this.view.getSelectedNodes();
11735 var cselitem = false;
11737 var ix = this.view.indexOf(csel[0]);
11738 cselitem = this.store.getAt(ix);
11739 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11745 this.store.each(function(v) {
11747 // start at existing selection.
11748 if (cselitem.id == v.id) {
11754 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11755 match = this.store.indexOf(v);
11761 if (match === false) {
11762 return true; // no more action?
11765 this.view.select(match);
11766 var sn = Roo.get(this.view.getSelectedNodes()[0])
11767 //sn.scrollIntoView(sn.dom.parentNode, false);
11770 onViewScroll : function(e, t){
11772 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){
11776 this.hasQuery = true;
11778 this.loading = this.list.select('.loading', true).first();
11780 if(this.loading === null){
11781 this.list.createChild({
11783 cls: 'loading select2-more-results select2-active',
11784 html: 'Loading more results...'
11787 this.loading = this.list.select('.loading', true).first();
11789 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11791 this.loading.hide();
11794 this.loading.show();
11799 this.loadNext = true;
11801 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11806 addItem : function(o)
11808 var dv = ''; // display value
11810 if (this.displayField) {
11811 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11813 // this is an error condition!!!
11814 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11821 var choice = this.choices.createChild({
11823 cls: 'select2-search-choice',
11832 cls: 'select2-search-choice-close',
11837 }, this.searchField);
11839 var close = choice.select('a.select2-search-choice-close', true).first()
11841 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11849 this.inputEl().dom.value = '';
11853 onRemoveItem : function(e, _self, o)
11855 e.preventDefault();
11856 var index = this.item.indexOf(o.data) * 1;
11859 Roo.log('not this item?!');
11863 this.item.splice(index, 1);
11868 this.fireEvent('remove', this, e);
11872 syncValue : function()
11874 if(!this.item.length){
11881 Roo.each(this.item, function(i){
11882 if(_this.valueField){
11883 value.push(i[_this.valueField]);
11890 this.value = value.join(',');
11892 if(this.hiddenField){
11893 this.hiddenField.dom.value = this.value;
11897 clearItem : function()
11899 if(!this.multiple){
11905 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11912 inputEl: function ()
11915 return this.searchField;
11917 return this.el.select('input.form-control',true).first();
11921 onTickableFooterButtonClick : function(e, btn, el)
11923 e.preventDefault();
11925 if(btn && btn.name == 'cancel'){
11926 this.tickItems = Roo.apply([], this.item);
11935 Roo.each(this.tickItems, function(o){
11946 * @cfg {Boolean} grow
11950 * @cfg {Number} growMin
11954 * @cfg {Number} growMax
11964 * Ext JS Library 1.1.1
11965 * Copyright(c) 2006-2007, Ext JS, LLC.
11967 * Originally Released Under LGPL - original licence link has changed is not relivant.
11970 * <script type="text/javascript">
11975 * @extends Roo.util.Observable
11976 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11977 * This class also supports single and multi selection modes. <br>
11978 * Create a data model bound view:
11980 var store = new Roo.data.Store(...);
11982 var view = new Roo.View({
11984 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11986 singleSelect: true,
11987 selectedClass: "ydataview-selected",
11991 // listen for node click?
11992 view.on("click", function(vw, index, node, e){
11993 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11997 dataModel.load("foobar.xml");
11999 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12001 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12002 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12004 * Note: old style constructor is still suported (container, template, config)
12007 * Create a new View
12008 * @param {Object} config The config object
12011 Roo.View = function(config, depreciated_tpl, depreciated_config){
12013 this.parent = false;
12015 if (typeof(depreciated_tpl) == 'undefined') {
12016 // new way.. - universal constructor.
12017 Roo.apply(this, config);
12018 this.el = Roo.get(this.el);
12021 this.el = Roo.get(config);
12022 this.tpl = depreciated_tpl;
12023 Roo.apply(this, depreciated_config);
12025 this.wrapEl = this.el.wrap().wrap();
12026 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12029 if(typeof(this.tpl) == "string"){
12030 this.tpl = new Roo.Template(this.tpl);
12032 // support xtype ctors..
12033 this.tpl = new Roo.factory(this.tpl, Roo);
12037 this.tpl.compile();
12042 * @event beforeclick
12043 * Fires before a click is processed. Returns false to cancel the default action.
12044 * @param {Roo.View} this
12045 * @param {Number} index The index of the target node
12046 * @param {HTMLElement} node The target node
12047 * @param {Roo.EventObject} e The raw event object
12049 "beforeclick" : true,
12052 * Fires when a template node is clicked.
12053 * @param {Roo.View} this
12054 * @param {Number} index The index of the target node
12055 * @param {HTMLElement} node The target node
12056 * @param {Roo.EventObject} e The raw event object
12061 * Fires when a template node is double clicked.
12062 * @param {Roo.View} this
12063 * @param {Number} index The index of the target node
12064 * @param {HTMLElement} node The target node
12065 * @param {Roo.EventObject} e The raw event object
12069 * @event contextmenu
12070 * Fires when a template node is right clicked.
12071 * @param {Roo.View} this
12072 * @param {Number} index The index of the target node
12073 * @param {HTMLElement} node The target node
12074 * @param {Roo.EventObject} e The raw event object
12076 "contextmenu" : true,
12078 * @event selectionchange
12079 * Fires when the selected nodes change.
12080 * @param {Roo.View} this
12081 * @param {Array} selections Array of the selected nodes
12083 "selectionchange" : true,
12086 * @event beforeselect
12087 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12088 * @param {Roo.View} this
12089 * @param {HTMLElement} node The node to be selected
12090 * @param {Array} selections Array of currently selected nodes
12092 "beforeselect" : true,
12094 * @event preparedata
12095 * Fires on every row to render, to allow you to change the data.
12096 * @param {Roo.View} this
12097 * @param {Object} data to be rendered (change this)
12099 "preparedata" : true
12107 "click": this.onClick,
12108 "dblclick": this.onDblClick,
12109 "contextmenu": this.onContextMenu,
12113 this.selections = [];
12115 this.cmp = new Roo.CompositeElementLite([]);
12117 this.store = Roo.factory(this.store, Roo.data);
12118 this.setStore(this.store, true);
12121 if ( this.footer && this.footer.xtype) {
12123 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12125 this.footer.dataSource = this.store
12126 this.footer.container = fctr;
12127 this.footer = Roo.factory(this.footer, Roo);
12128 fctr.insertFirst(this.el);
12130 // this is a bit insane - as the paging toolbar seems to detach the el..
12131 // dom.parentNode.parentNode.parentNode
12132 // they get detached?
12136 Roo.View.superclass.constructor.call(this);
12141 Roo.extend(Roo.View, Roo.util.Observable, {
12144 * @cfg {Roo.data.Store} store Data store to load data from.
12149 * @cfg {String|Roo.Element} el The container element.
12154 * @cfg {String|Roo.Template} tpl The template used by this View
12158 * @cfg {String} dataName the named area of the template to use as the data area
12159 * Works with domtemplates roo-name="name"
12163 * @cfg {String} selectedClass The css class to add to selected nodes
12165 selectedClass : "x-view-selected",
12167 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12172 * @cfg {String} text to display on mask (default Loading)
12176 * @cfg {Boolean} multiSelect Allow multiple selection
12178 multiSelect : false,
12180 * @cfg {Boolean} singleSelect Allow single selection
12182 singleSelect: false,
12185 * @cfg {Boolean} toggleSelect - selecting
12187 toggleSelect : false,
12190 * @cfg {Boolean} tickable - selecting
12195 * Returns the element this view is bound to.
12196 * @return {Roo.Element}
12198 getEl : function(){
12199 return this.wrapEl;
12205 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12207 refresh : function(){
12208 Roo.log('refresh');
12211 // if we are using something like 'domtemplate', then
12212 // the what gets used is:
12213 // t.applySubtemplate(NAME, data, wrapping data..)
12214 // the outer template then get' applied with
12215 // the store 'extra data'
12216 // and the body get's added to the
12217 // roo-name="data" node?
12218 // <span class='roo-tpl-{name}'></span> ?????
12222 this.clearSelections();
12223 this.el.update("");
12225 var records = this.store.getRange();
12226 if(records.length < 1) {
12228 // is this valid?? = should it render a template??
12230 this.el.update(this.emptyText);
12234 if (this.dataName) {
12235 this.el.update(t.apply(this.store.meta)); //????
12236 el = this.el.child('.roo-tpl-' + this.dataName);
12239 for(var i = 0, len = records.length; i < len; i++){
12240 var data = this.prepareData(records[i].data, i, records[i]);
12241 this.fireEvent("preparedata", this, data, i, records[i]);
12243 var d = Roo.apply({}, data);
12246 Roo.apply(d, {'roo-id' : Roo.id()});
12250 Roo.each(this.parent.item, function(item){
12251 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12254 Roo.apply(d, {'roo-data-checked' : 'checked'});
12258 html[html.length] = Roo.util.Format.trim(
12260 t.applySubtemplate(this.dataName, d, this.store.meta) :
12267 el.update(html.join(""));
12268 this.nodes = el.dom.childNodes;
12269 this.updateIndexes(0);
12274 * Function to override to reformat the data that is sent to
12275 * the template for each node.
12276 * DEPRICATED - use the preparedata event handler.
12277 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12278 * a JSON object for an UpdateManager bound view).
12280 prepareData : function(data, index, record)
12282 this.fireEvent("preparedata", this, data, index, record);
12286 onUpdate : function(ds, record){
12287 Roo.log('on update');
12288 this.clearSelections();
12289 var index = this.store.indexOf(record);
12290 var n = this.nodes[index];
12291 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12292 n.parentNode.removeChild(n);
12293 this.updateIndexes(index, index);
12299 onAdd : function(ds, records, index)
12301 Roo.log(['on Add', ds, records, index] );
12302 this.clearSelections();
12303 if(this.nodes.length == 0){
12307 var n = this.nodes[index];
12308 for(var i = 0, len = records.length; i < len; i++){
12309 var d = this.prepareData(records[i].data, i, records[i]);
12311 this.tpl.insertBefore(n, d);
12314 this.tpl.append(this.el, d);
12317 this.updateIndexes(index);
12320 onRemove : function(ds, record, index){
12321 Roo.log('onRemove');
12322 this.clearSelections();
12323 var el = this.dataName ?
12324 this.el.child('.roo-tpl-' + this.dataName) :
12327 el.dom.removeChild(this.nodes[index]);
12328 this.updateIndexes(index);
12332 * Refresh an individual node.
12333 * @param {Number} index
12335 refreshNode : function(index){
12336 this.onUpdate(this.store, this.store.getAt(index));
12339 updateIndexes : function(startIndex, endIndex){
12340 var ns = this.nodes;
12341 startIndex = startIndex || 0;
12342 endIndex = endIndex || ns.length - 1;
12343 for(var i = startIndex; i <= endIndex; i++){
12344 ns[i].nodeIndex = i;
12349 * Changes the data store this view uses and refresh the view.
12350 * @param {Store} store
12352 setStore : function(store, initial){
12353 if(!initial && this.store){
12354 this.store.un("datachanged", this.refresh);
12355 this.store.un("add", this.onAdd);
12356 this.store.un("remove", this.onRemove);
12357 this.store.un("update", this.onUpdate);
12358 this.store.un("clear", this.refresh);
12359 this.store.un("beforeload", this.onBeforeLoad);
12360 this.store.un("load", this.onLoad);
12361 this.store.un("loadexception", this.onLoad);
12365 store.on("datachanged", this.refresh, this);
12366 store.on("add", this.onAdd, this);
12367 store.on("remove", this.onRemove, this);
12368 store.on("update", this.onUpdate, this);
12369 store.on("clear", this.refresh, this);
12370 store.on("beforeload", this.onBeforeLoad, this);
12371 store.on("load", this.onLoad, this);
12372 store.on("loadexception", this.onLoad, this);
12380 * onbeforeLoad - masks the loading area.
12383 onBeforeLoad : function(store,opts)
12385 Roo.log('onBeforeLoad');
12387 this.el.update("");
12389 this.el.mask(this.mask ? this.mask : "Loading" );
12391 onLoad : function ()
12398 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12399 * @param {HTMLElement} node
12400 * @return {HTMLElement} The template node
12402 findItemFromChild : function(node){
12403 var el = this.dataName ?
12404 this.el.child('.roo-tpl-' + this.dataName,true) :
12407 if(!node || node.parentNode == el){
12410 var p = node.parentNode;
12411 while(p && p != el){
12412 if(p.parentNode == el){
12421 onClick : function(e){
12422 var item = this.findItemFromChild(e.getTarget());
12424 var index = this.indexOf(item);
12425 if(this.onItemClick(item, index, e) !== false){
12426 this.fireEvent("click", this, index, item, e);
12429 this.clearSelections();
12434 onContextMenu : function(e){
12435 var item = this.findItemFromChild(e.getTarget());
12437 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12442 onDblClick : function(e){
12443 var item = this.findItemFromChild(e.getTarget());
12445 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12449 onItemClick : function(item, index, e)
12451 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12454 if (this.toggleSelect) {
12455 var m = this.isSelected(item) ? 'unselect' : 'select';
12458 _t[m](item, true, false);
12461 if(this.multiSelect || this.singleSelect){
12462 if(this.multiSelect && e.shiftKey && this.lastSelection){
12463 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12465 this.select(item, this.multiSelect && e.ctrlKey);
12466 this.lastSelection = item;
12469 if(!this.tickable){
12470 e.preventDefault();
12478 * Get the number of selected nodes.
12481 getSelectionCount : function(){
12482 return this.selections.length;
12486 * Get the currently selected nodes.
12487 * @return {Array} An array of HTMLElements
12489 getSelectedNodes : function(){
12490 return this.selections;
12494 * Get the indexes of the selected nodes.
12497 getSelectedIndexes : function(){
12498 var indexes = [], s = this.selections;
12499 for(var i = 0, len = s.length; i < len; i++){
12500 indexes.push(s[i].nodeIndex);
12506 * Clear all selections
12507 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12509 clearSelections : function(suppressEvent){
12510 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12511 this.cmp.elements = this.selections;
12512 this.cmp.removeClass(this.selectedClass);
12513 this.selections = [];
12514 if(!suppressEvent){
12515 this.fireEvent("selectionchange", this, this.selections);
12521 * Returns true if the passed node is selected
12522 * @param {HTMLElement/Number} node The node or node index
12523 * @return {Boolean}
12525 isSelected : function(node){
12526 var s = this.selections;
12530 node = this.getNode(node);
12531 return s.indexOf(node) !== -1;
12536 * @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
12537 * @param {Boolean} keepExisting (optional) true to keep existing selections
12538 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12540 select : function(nodeInfo, keepExisting, suppressEvent){
12541 if(nodeInfo instanceof Array){
12543 this.clearSelections(true);
12545 for(var i = 0, len = nodeInfo.length; i < len; i++){
12546 this.select(nodeInfo[i], true, true);
12550 var node = this.getNode(nodeInfo);
12551 if(!node || this.isSelected(node)){
12552 return; // already selected.
12555 this.clearSelections(true);
12557 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12558 Roo.fly(node).addClass(this.selectedClass);
12559 this.selections.push(node);
12560 if(!suppressEvent){
12561 this.fireEvent("selectionchange", this, this.selections);
12569 * @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
12570 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12571 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12573 unselect : function(nodeInfo, keepExisting, suppressEvent)
12575 if(nodeInfo instanceof Array){
12576 Roo.each(this.selections, function(s) {
12577 this.unselect(s, nodeInfo);
12581 var node = this.getNode(nodeInfo);
12582 if(!node || !this.isSelected(node)){
12583 Roo.log("not selected");
12584 return; // not selected.
12588 Roo.each(this.selections, function(s) {
12590 Roo.fly(node).removeClass(this.selectedClass);
12597 this.selections= ns;
12598 this.fireEvent("selectionchange", this, this.selections);
12602 * Gets a template node.
12603 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12604 * @return {HTMLElement} The node or null if it wasn't found
12606 getNode : function(nodeInfo){
12607 if(typeof nodeInfo == "string"){
12608 return document.getElementById(nodeInfo);
12609 }else if(typeof nodeInfo == "number"){
12610 return this.nodes[nodeInfo];
12616 * Gets a range template nodes.
12617 * @param {Number} startIndex
12618 * @param {Number} endIndex
12619 * @return {Array} An array of nodes
12621 getNodes : function(start, end){
12622 var ns = this.nodes;
12623 start = start || 0;
12624 end = typeof end == "undefined" ? ns.length - 1 : end;
12627 for(var i = start; i <= end; i++){
12631 for(var i = start; i >= end; i--){
12639 * Finds the index of the passed node
12640 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12641 * @return {Number} The index of the node or -1
12643 indexOf : function(node){
12644 node = this.getNode(node);
12645 if(typeof node.nodeIndex == "number"){
12646 return node.nodeIndex;
12648 var ns = this.nodes;
12649 for(var i = 0, len = ns.length; i < len; i++){
12660 * based on jquery fullcalendar
12664 Roo.bootstrap = Roo.bootstrap || {};
12666 * @class Roo.bootstrap.Calendar
12667 * @extends Roo.bootstrap.Component
12668 * Bootstrap Calendar class
12669 * @cfg {Boolean} loadMask (true|false) default false
12670 * @cfg {Object} header generate the user specific header of the calendar, default false
12673 * Create a new Container
12674 * @param {Object} config The config object
12679 Roo.bootstrap.Calendar = function(config){
12680 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12684 * Fires when a date is selected
12685 * @param {DatePicker} this
12686 * @param {Date} date The selected date
12690 * @event monthchange
12691 * Fires when the displayed month changes
12692 * @param {DatePicker} this
12693 * @param {Date} date The selected month
12695 'monthchange': true,
12697 * @event evententer
12698 * Fires when mouse over an event
12699 * @param {Calendar} this
12700 * @param {event} Event
12702 'evententer': true,
12704 * @event eventleave
12705 * Fires when the mouse leaves an
12706 * @param {Calendar} this
12709 'eventleave': true,
12711 * @event eventclick
12712 * Fires when the mouse click an
12713 * @param {Calendar} this
12722 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12725 * @cfg {Number} startDay
12726 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12734 getAutoCreate : function(){
12737 var fc_button = function(name, corner, style, content ) {
12738 return Roo.apply({},{
12740 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12742 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12745 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12756 style : 'width:100%',
12763 cls : 'fc-header-left',
12765 fc_button('prev', 'left', 'arrow', '‹' ),
12766 fc_button('next', 'right', 'arrow', '›' ),
12767 { tag: 'span', cls: 'fc-header-space' },
12768 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12776 cls : 'fc-header-center',
12780 cls: 'fc-header-title',
12783 html : 'month / year'
12791 cls : 'fc-header-right',
12793 /* fc_button('month', 'left', '', 'month' ),
12794 fc_button('week', '', '', 'week' ),
12795 fc_button('day', 'right', '', 'day' )
12807 header = this.header;
12810 var cal_heads = function() {
12812 // fixme - handle this.
12814 for (var i =0; i < Date.dayNames.length; i++) {
12815 var d = Date.dayNames[i];
12818 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12819 html : d.substring(0,3)
12823 ret[0].cls += ' fc-first';
12824 ret[6].cls += ' fc-last';
12827 var cal_cell = function(n) {
12830 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12835 cls: 'fc-day-number',
12839 cls: 'fc-day-content',
12843 style: 'position: relative;' // height: 17px;
12855 var cal_rows = function() {
12858 for (var r = 0; r < 6; r++) {
12865 for (var i =0; i < Date.dayNames.length; i++) {
12866 var d = Date.dayNames[i];
12867 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12870 row.cn[0].cls+=' fc-first';
12871 row.cn[0].cn[0].style = 'min-height:90px';
12872 row.cn[6].cls+=' fc-last';
12876 ret[0].cls += ' fc-first';
12877 ret[4].cls += ' fc-prev-last';
12878 ret[5].cls += ' fc-last';
12885 cls: 'fc-border-separate',
12886 style : 'width:100%',
12894 cls : 'fc-first fc-last',
12912 cls : 'fc-content',
12913 style : "position: relative;",
12916 cls : 'fc-view fc-view-month fc-grid',
12917 style : 'position: relative',
12918 unselectable : 'on',
12921 cls : 'fc-event-container',
12922 style : 'position:absolute;z-index:8;top:0;left:0;'
12940 initEvents : function()
12943 throw "can not find store for calendar";
12949 style: "text-align:center",
12953 style: "background-color:white;width:50%;margin:250 auto",
12957 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12968 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12970 var size = this.el.select('.fc-content', true).first().getSize();
12971 this.maskEl.setSize(size.width, size.height);
12972 this.maskEl.enableDisplayMode("block");
12973 if(!this.loadMask){
12974 this.maskEl.hide();
12977 this.store = Roo.factory(this.store, Roo.data);
12978 this.store.on('load', this.onLoad, this);
12979 this.store.on('beforeload', this.onBeforeLoad, this);
12983 this.cells = this.el.select('.fc-day',true);
12984 //Roo.log(this.cells);
12985 this.textNodes = this.el.query('.fc-day-number');
12986 this.cells.addClassOnOver('fc-state-hover');
12988 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12989 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12990 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12991 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12993 this.on('monthchange', this.onMonthChange, this);
12995 this.update(new Date().clearTime());
12998 resize : function() {
12999 var sz = this.el.getSize();
13001 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13002 this.el.select('.fc-day-content div',true).setHeight(34);
13007 showPrevMonth : function(e){
13008 this.update(this.activeDate.add("mo", -1));
13010 showToday : function(e){
13011 this.update(new Date().clearTime());
13014 showNextMonth : function(e){
13015 this.update(this.activeDate.add("mo", 1));
13019 showPrevYear : function(){
13020 this.update(this.activeDate.add("y", -1));
13024 showNextYear : function(){
13025 this.update(this.activeDate.add("y", 1));
13030 update : function(date)
13032 var vd = this.activeDate;
13033 this.activeDate = date;
13034 // if(vd && this.el){
13035 // var t = date.getTime();
13036 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13037 // Roo.log('using add remove');
13039 // this.fireEvent('monthchange', this, date);
13041 // this.cells.removeClass("fc-state-highlight");
13042 // this.cells.each(function(c){
13043 // if(c.dateValue == t){
13044 // c.addClass("fc-state-highlight");
13045 // setTimeout(function(){
13046 // try{c.dom.firstChild.focus();}catch(e){}
13056 var days = date.getDaysInMonth();
13058 var firstOfMonth = date.getFirstDateOfMonth();
13059 var startingPos = firstOfMonth.getDay()-this.startDay;
13061 if(startingPos < this.startDay){
13065 var pm = date.add(Date.MONTH, -1);
13066 var prevStart = pm.getDaysInMonth()-startingPos;
13068 this.cells = this.el.select('.fc-day',true);
13069 this.textNodes = this.el.query('.fc-day-number');
13070 this.cells.addClassOnOver('fc-state-hover');
13072 var cells = this.cells.elements;
13073 var textEls = this.textNodes;
13075 Roo.each(cells, function(cell){
13076 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13079 days += startingPos;
13081 // convert everything to numbers so it's fast
13082 var day = 86400000;
13083 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13086 //Roo.log(prevStart);
13088 var today = new Date().clearTime().getTime();
13089 var sel = date.clearTime().getTime();
13090 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13091 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13092 var ddMatch = this.disabledDatesRE;
13093 var ddText = this.disabledDatesText;
13094 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13095 var ddaysText = this.disabledDaysText;
13096 var format = this.format;
13098 var setCellClass = function(cal, cell){
13102 //Roo.log('set Cell Class');
13104 var t = d.getTime();
13108 cell.dateValue = t;
13110 cell.className += " fc-today";
13111 cell.className += " fc-state-highlight";
13112 cell.title = cal.todayText;
13115 // disable highlight in other month..
13116 //cell.className += " fc-state-highlight";
13121 cell.className = " fc-state-disabled";
13122 cell.title = cal.minText;
13126 cell.className = " fc-state-disabled";
13127 cell.title = cal.maxText;
13131 if(ddays.indexOf(d.getDay()) != -1){
13132 cell.title = ddaysText;
13133 cell.className = " fc-state-disabled";
13136 if(ddMatch && format){
13137 var fvalue = d.dateFormat(format);
13138 if(ddMatch.test(fvalue)){
13139 cell.title = ddText.replace("%0", fvalue);
13140 cell.className = " fc-state-disabled";
13144 if (!cell.initialClassName) {
13145 cell.initialClassName = cell.dom.className;
13148 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13153 for(; i < startingPos; i++) {
13154 textEls[i].innerHTML = (++prevStart);
13155 d.setDate(d.getDate()+1);
13157 cells[i].className = "fc-past fc-other-month";
13158 setCellClass(this, cells[i]);
13163 for(; i < days; i++){
13164 intDay = i - startingPos + 1;
13165 textEls[i].innerHTML = (intDay);
13166 d.setDate(d.getDate()+1);
13168 cells[i].className = ''; // "x-date-active";
13169 setCellClass(this, cells[i]);
13173 for(; i < 42; i++) {
13174 textEls[i].innerHTML = (++extraDays);
13175 d.setDate(d.getDate()+1);
13177 cells[i].className = "fc-future fc-other-month";
13178 setCellClass(this, cells[i]);
13181 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13183 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13185 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13186 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13188 if(totalRows != 6){
13189 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13190 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13193 this.fireEvent('monthchange', this, date);
13197 if(!this.internalRender){
13198 var main = this.el.dom.firstChild;
13199 var w = main.offsetWidth;
13200 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13201 Roo.fly(main).setWidth(w);
13202 this.internalRender = true;
13203 // opera does not respect the auto grow header center column
13204 // then, after it gets a width opera refuses to recalculate
13205 // without a second pass
13206 if(Roo.isOpera && !this.secondPass){
13207 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13208 this.secondPass = true;
13209 this.update.defer(10, this, [date]);
13216 findCell : function(dt) {
13217 dt = dt.clearTime().getTime();
13219 this.cells.each(function(c){
13220 //Roo.log("check " +c.dateValue + '?=' + dt);
13221 if(c.dateValue == dt){
13231 findCells : function(ev) {
13232 var s = ev.start.clone().clearTime().getTime();
13234 var e= ev.end.clone().clearTime().getTime();
13237 this.cells.each(function(c){
13238 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13240 if(c.dateValue > e){
13243 if(c.dateValue < s){
13252 // findBestRow: function(cells)
13256 // for (var i =0 ; i < cells.length;i++) {
13257 // ret = Math.max(cells[i].rows || 0,ret);
13264 addItem : function(ev)
13266 // look for vertical location slot in
13267 var cells = this.findCells(ev);
13269 // ev.row = this.findBestRow(cells);
13271 // work out the location.
13275 for(var i =0; i < cells.length; i++) {
13277 cells[i].row = cells[0].row;
13280 cells[i].row = cells[i].row + 1;
13290 if (crow.start.getY() == cells[i].getY()) {
13292 crow.end = cells[i];
13309 cells[0].events.push(ev);
13311 this.calevents.push(ev);
13314 clearEvents: function() {
13316 if(!this.calevents){
13320 Roo.each(this.cells.elements, function(c){
13326 Roo.each(this.calevents, function(e) {
13327 Roo.each(e.els, function(el) {
13328 el.un('mouseenter' ,this.onEventEnter, this);
13329 el.un('mouseleave' ,this.onEventLeave, this);
13334 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13340 renderEvents: function()
13344 this.cells.each(function(c) {
13353 if(c.row != c.events.length){
13354 r = 4 - (4 - (c.row - c.events.length));
13357 c.events = ev.slice(0, r);
13358 c.more = ev.slice(r);
13360 if(c.more.length && c.more.length == 1){
13361 c.events.push(c.more.pop());
13364 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13368 this.cells.each(function(c) {
13370 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13373 for (var e = 0; e < c.events.length; e++){
13374 var ev = c.events[e];
13375 var rows = ev.rows;
13377 for(var i = 0; i < rows.length; i++) {
13379 // how many rows should it span..
13382 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13383 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13385 unselectable : "on",
13388 cls: 'fc-event-inner',
13392 // cls: 'fc-event-time',
13393 // html : cells.length > 1 ? '' : ev.time
13397 cls: 'fc-event-title',
13398 html : String.format('{0}', ev.title)
13405 cls: 'ui-resizable-handle ui-resizable-e',
13406 html : '  '
13413 cfg.cls += ' fc-event-start';
13415 if ((i+1) == rows.length) {
13416 cfg.cls += ' fc-event-end';
13419 var ctr = _this.el.select('.fc-event-container',true).first();
13420 var cg = ctr.createChild(cfg);
13422 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13423 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13425 var r = (c.more.length) ? 1 : 0;
13426 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13427 cg.setWidth(ebox.right - sbox.x -2);
13429 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13430 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13431 cg.on('click', _this.onEventClick, _this, ev);
13442 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13443 style : 'position: absolute',
13444 unselectable : "on",
13447 cls: 'fc-event-inner',
13451 cls: 'fc-event-title',
13459 cls: 'ui-resizable-handle ui-resizable-e',
13460 html : '  '
13466 var ctr = _this.el.select('.fc-event-container',true).first();
13467 var cg = ctr.createChild(cfg);
13469 var sbox = c.select('.fc-day-content',true).first().getBox();
13470 var ebox = c.select('.fc-day-content',true).first().getBox();
13472 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13473 cg.setWidth(ebox.right - sbox.x -2);
13475 cg.on('click', _this.onMoreEventClick, _this, c.more);
13485 onEventEnter: function (e, el,event,d) {
13486 this.fireEvent('evententer', this, el, event);
13489 onEventLeave: function (e, el,event,d) {
13490 this.fireEvent('eventleave', this, el, event);
13493 onEventClick: function (e, el,event,d) {
13494 this.fireEvent('eventclick', this, el, event);
13497 onMonthChange: function () {
13501 onMoreEventClick: function(e, el, more)
13505 this.calpopover.placement = 'right';
13506 this.calpopover.setTitle('More');
13508 this.calpopover.setContent('');
13510 var ctr = this.calpopover.el.select('.popover-content', true).first();
13512 Roo.each(more, function(m){
13514 cls : 'fc-event-hori fc-event-draggable',
13517 var cg = ctr.createChild(cfg);
13519 cg.on('click', _this.onEventClick, _this, m);
13522 this.calpopover.show(el);
13527 onLoad: function ()
13529 this.calevents = [];
13532 if(this.store.getCount() > 0){
13533 this.store.data.each(function(d){
13536 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13537 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13538 time : d.data.start_time,
13539 title : d.data.title,
13540 description : d.data.description,
13541 venue : d.data.venue
13546 this.renderEvents();
13548 if(this.calevents.length && this.loadMask){
13549 this.maskEl.hide();
13553 onBeforeLoad: function()
13555 this.clearEvents();
13557 this.maskEl.show();
13571 * @class Roo.bootstrap.Popover
13572 * @extends Roo.bootstrap.Component
13573 * Bootstrap Popover class
13574 * @cfg {String} html contents of the popover (or false to use children..)
13575 * @cfg {String} title of popover (or false to hide)
13576 * @cfg {String} placement how it is placed
13577 * @cfg {String} trigger click || hover (or false to trigger manually)
13578 * @cfg {String} over what (parent or false to trigger manually.)
13581 * Create a new Popover
13582 * @param {Object} config The config object
13585 Roo.bootstrap.Popover = function(config){
13586 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13589 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13591 title: 'Fill in a title',
13594 placement : 'right',
13595 trigger : 'hover', // hover
13599 can_build_overlaid : false,
13601 getChildContainer : function()
13603 return this.el.select('.popover-content',true).first();
13606 getAutoCreate : function(){
13607 Roo.log('make popover?');
13609 cls : 'popover roo-dynamic',
13610 style: 'display:block',
13616 cls : 'popover-inner',
13620 cls: 'popover-title',
13624 cls : 'popover-content',
13635 setTitle: function(str)
13637 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13639 setContent: function(str)
13641 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13643 // as it get's added to the bottom of the page.
13644 onRender : function(ct, position)
13646 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13648 var cfg = Roo.apply({}, this.getAutoCreate());
13652 cfg.cls += ' ' + this.cls;
13655 cfg.style = this.style;
13657 Roo.log("adding to ")
13658 this.el = Roo.get(document.body).createChild(cfg, position);
13664 initEvents : function()
13666 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13667 this.el.enableDisplayMode('block');
13669 if (this.over === false) {
13672 if (this.triggers === false) {
13675 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13676 var triggers = this.trigger ? this.trigger.split(' ') : [];
13677 Roo.each(triggers, function(trigger) {
13679 if (trigger == 'click') {
13680 on_el.on('click', this.toggle, this);
13681 } else if (trigger != 'manual') {
13682 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13683 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13685 on_el.on(eventIn ,this.enter, this);
13686 on_el.on(eventOut, this.leave, this);
13697 toggle : function () {
13698 this.hoverState == 'in' ? this.leave() : this.enter();
13701 enter : function () {
13704 clearTimeout(this.timeout);
13706 this.hoverState = 'in'
13708 if (!this.delay || !this.delay.show) {
13713 this.timeout = setTimeout(function () {
13714 if (_t.hoverState == 'in') {
13717 }, this.delay.show)
13719 leave : function() {
13720 clearTimeout(this.timeout);
13722 this.hoverState = 'out'
13724 if (!this.delay || !this.delay.hide) {
13729 this.timeout = setTimeout(function () {
13730 if (_t.hoverState == 'out') {
13733 }, this.delay.hide)
13736 show : function (on_el)
13739 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13742 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13743 if (this.html !== false) {
13744 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13746 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13747 if (!this.title.length) {
13748 this.el.select('.popover-title',true).hide();
13751 var placement = typeof this.placement == 'function' ?
13752 this.placement.call(this, this.el, on_el) :
13755 var autoToken = /\s?auto?\s?/i;
13756 var autoPlace = autoToken.test(placement);
13758 placement = placement.replace(autoToken, '') || 'top';
13762 //this.el.setXY([0,0]);
13764 this.el.dom.style.display='block';
13765 this.el.addClass(placement);
13767 //this.el.appendTo(on_el);
13769 var p = this.getPosition();
13770 var box = this.el.getBox();
13775 var align = Roo.bootstrap.Popover.alignment[placement]
13776 this.el.alignTo(on_el, align[0],align[1]);
13777 //var arrow = this.el.select('.arrow',true).first();
13778 //arrow.set(align[2],
13780 this.el.addClass('in');
13781 this.hoverState = null;
13783 if (this.el.hasClass('fade')) {
13790 this.el.setXY([0,0]);
13791 this.el.removeClass('in');
13798 Roo.bootstrap.Popover.alignment = {
13799 'left' : ['r-l', [-10,0], 'right'],
13800 'right' : ['l-r', [10,0], 'left'],
13801 'bottom' : ['t-b', [0,10], 'top'],
13802 'top' : [ 'b-t', [0,-10], 'bottom']
13813 * @class Roo.bootstrap.Progress
13814 * @extends Roo.bootstrap.Component
13815 * Bootstrap Progress class
13816 * @cfg {Boolean} striped striped of the progress bar
13817 * @cfg {Boolean} active animated of the progress bar
13821 * Create a new Progress
13822 * @param {Object} config The config object
13825 Roo.bootstrap.Progress = function(config){
13826 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13829 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13834 getAutoCreate : function(){
13842 cfg.cls += ' progress-striped';
13846 cfg.cls += ' active';
13865 * @class Roo.bootstrap.ProgressBar
13866 * @extends Roo.bootstrap.Component
13867 * Bootstrap ProgressBar class
13868 * @cfg {Number} aria_valuenow aria-value now
13869 * @cfg {Number} aria_valuemin aria-value min
13870 * @cfg {Number} aria_valuemax aria-value max
13871 * @cfg {String} label label for the progress bar
13872 * @cfg {String} panel (success | info | warning | danger )
13873 * @cfg {String} role role of the progress bar
13874 * @cfg {String} sr_only text
13878 * Create a new ProgressBar
13879 * @param {Object} config The config object
13882 Roo.bootstrap.ProgressBar = function(config){
13883 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13886 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13890 aria_valuemax : 100,
13896 getAutoCreate : function()
13901 cls: 'progress-bar',
13902 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13914 cfg.role = this.role;
13917 if(this.aria_valuenow){
13918 cfg['aria-valuenow'] = this.aria_valuenow;
13921 if(this.aria_valuemin){
13922 cfg['aria-valuemin'] = this.aria_valuemin;
13925 if(this.aria_valuemax){
13926 cfg['aria-valuemax'] = this.aria_valuemax;
13929 if(this.label && !this.sr_only){
13930 cfg.html = this.label;
13934 cfg.cls += ' progress-bar-' + this.panel;
13940 update : function(aria_valuenow)
13942 this.aria_valuenow = aria_valuenow;
13944 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13959 * @class Roo.bootstrap.TabGroup
13960 * @extends Roo.bootstrap.Column
13961 * Bootstrap Column class
13962 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13963 * @cfg {Boolean} carousel true to make the group behave like a carousel
13966 * Create a new TabGroup
13967 * @param {Object} config The config object
13970 Roo.bootstrap.TabGroup = function(config){
13971 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13973 this.navId = Roo.id();
13976 Roo.bootstrap.TabGroup.register(this);
13980 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13983 transition : false,
13985 getAutoCreate : function()
13987 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13989 cfg.cls += ' tab-content';
13991 if (this.carousel) {
13992 cfg.cls += ' carousel slide';
13994 cls : 'carousel-inner'
14001 getChildContainer : function()
14003 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14007 * register a Navigation item
14008 * @param {Roo.bootstrap.NavItem} the navitem to add
14010 register : function(item)
14012 this.tabs.push( item);
14013 item.navId = this.navId; // not really needed..
14017 getActivePanel : function()
14020 Roo.each(this.tabs, function(t) {
14030 getPanelByName : function(n)
14033 Roo.each(this.tabs, function(t) {
14034 if (t.tabId == n) {
14042 indexOfPanel : function(p)
14045 Roo.each(this.tabs, function(t,i) {
14046 if (t.tabId == p.tabId) {
14055 * show a specific panel
14056 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14057 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14059 showPanel : function (pan)
14062 if (typeof(pan) == 'number') {
14063 pan = this.tabs[pan];
14065 if (typeof(pan) == 'string') {
14066 pan = this.getPanelByName(pan);
14068 if (pan.tabId == this.getActivePanel().tabId) {
14071 var cur = this.getActivePanel();
14073 if (false === cur.fireEvent('beforedeactivate')) {
14077 if (this.carousel) {
14078 this.transition = true;
14079 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14080 var lr = dir == 'next' ? 'left' : 'right';
14081 pan.el.addClass(dir); // or prev
14082 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14083 cur.el.addClass(lr); // or right
14084 pan.el.addClass(lr);
14087 cur.el.on('transitionend', function() {
14088 Roo.log("trans end?");
14090 pan.el.removeClass([lr,dir]);
14091 pan.setActive(true);
14093 cur.el.removeClass([lr]);
14094 cur.setActive(false);
14096 _this.transition = false;
14098 }, this, { single: true } );
14102 cur.setActive(false);
14103 pan.setActive(true);
14107 showPanelNext : function()
14109 var i = this.indexOfPanel(this.getActivePanel());
14110 if (i > this.tabs.length) {
14113 this.showPanel(this.tabs[i+1]);
14115 showPanelPrev : function()
14117 var i = this.indexOfPanel(this.getActivePanel());
14121 this.showPanel(this.tabs[i-1]);
14132 Roo.apply(Roo.bootstrap.TabGroup, {
14136 * register a Navigation Group
14137 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14139 register : function(navgrp)
14141 this.groups[navgrp.navId] = navgrp;
14145 * fetch a Navigation Group based on the navigation ID
14146 * if one does not exist , it will get created.
14147 * @param {string} the navgroup to add
14148 * @returns {Roo.bootstrap.NavGroup} the navgroup
14150 get: function(navId) {
14151 if (typeof(this.groups[navId]) == 'undefined') {
14152 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14154 return this.groups[navId] ;
14169 * @class Roo.bootstrap.TabPanel
14170 * @extends Roo.bootstrap.Component
14171 * Bootstrap TabPanel class
14172 * @cfg {Boolean} active panel active
14173 * @cfg {String} html panel content
14174 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14175 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14179 * Create a new TabPanel
14180 * @param {Object} config The config object
14183 Roo.bootstrap.TabPanel = function(config){
14184 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14188 * Fires when the active status changes
14189 * @param {Roo.bootstrap.TabPanel} this
14190 * @param {Boolean} state the new state
14195 * @event beforedeactivate
14196 * Fires before a tab is de-activated - can be used to do validation on a form.
14197 * @param {Roo.bootstrap.TabPanel} this
14198 * @return {Boolean} false if there is an error
14201 'beforedeactivate': true
14204 this.tabId = this.tabId || Roo.id();
14208 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14215 getAutoCreate : function(){
14218 // item is needed for carousel - not sure if it has any effect otherwise
14219 cls: 'tab-pane item',
14220 html: this.html || ''
14224 cfg.cls += ' active';
14228 cfg.tabId = this.tabId;
14235 initEvents: function()
14237 Roo.log('-------- init events on tab panel ---------');
14239 var p = this.parent();
14240 this.navId = this.navId || p.navId;
14242 if (typeof(this.navId) != 'undefined') {
14243 // not really needed.. but just in case.. parent should be a NavGroup.
14244 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14245 Roo.log(['register', tg, this]);
14251 onRender : function(ct, position)
14253 // Roo.log("Call onRender: " + this.xtype);
14255 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14263 setActive: function(state)
14265 Roo.log("panel - set active " + this.tabId + "=" + state);
14267 this.active = state;
14269 this.el.removeClass('active');
14271 } else if (!this.el.hasClass('active')) {
14272 this.el.addClass('active');
14274 this.fireEvent('changed', this, state);
14291 * @class Roo.bootstrap.DateField
14292 * @extends Roo.bootstrap.Input
14293 * Bootstrap DateField class
14294 * @cfg {Number} weekStart default 0
14295 * @cfg {Number} weekStart default 0
14296 * @cfg {Number} viewMode default empty, (months|years)
14297 * @cfg {Number} minViewMode default empty, (months|years)
14298 * @cfg {Number} startDate default -Infinity
14299 * @cfg {Number} endDate default Infinity
14300 * @cfg {Boolean} todayHighlight default false
14301 * @cfg {Boolean} todayBtn default false
14302 * @cfg {Boolean} calendarWeeks default false
14303 * @cfg {Object} daysOfWeekDisabled default empty
14305 * @cfg {Boolean} keyboardNavigation default true
14306 * @cfg {String} language default en
14309 * Create a new DateField
14310 * @param {Object} config The config object
14313 Roo.bootstrap.DateField = function(config){
14314 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14318 * Fires when this field show.
14319 * @param {Roo.bootstrap.DateField} this
14320 * @param {Mixed} date The date value
14325 * Fires when this field hide.
14326 * @param {Roo.bootstrap.DateField} this
14327 * @param {Mixed} date The date value
14332 * Fires when select a date.
14333 * @param {Roo.bootstrap.DateField} this
14334 * @param {Mixed} date The date value
14340 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14343 * @cfg {String} format
14344 * The default date format string which can be overriden for localization support. The format must be
14345 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14349 * @cfg {String} altFormats
14350 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14351 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14353 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14361 todayHighlight : false,
14367 keyboardNavigation: true,
14369 calendarWeeks: false,
14371 startDate: -Infinity,
14375 daysOfWeekDisabled: [],
14379 UTCDate: function()
14381 return new Date(Date.UTC.apply(Date, arguments));
14384 UTCToday: function()
14386 var today = new Date();
14387 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14390 getDate: function() {
14391 var d = this.getUTCDate();
14392 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14395 getUTCDate: function() {
14399 setDate: function(d) {
14400 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14403 setUTCDate: function(d) {
14405 this.setValue(this.formatDate(this.date));
14408 onRender: function(ct, position)
14411 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14413 this.language = this.language || 'en';
14414 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14415 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14417 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14418 this.format = this.format || 'm/d/y';
14419 this.isInline = false;
14420 this.isInput = true;
14421 this.component = this.el.select('.add-on', true).first() || false;
14422 this.component = (this.component && this.component.length === 0) ? false : this.component;
14423 this.hasInput = this.component && this.inputEL().length;
14425 if (typeof(this.minViewMode === 'string')) {
14426 switch (this.minViewMode) {
14428 this.minViewMode = 1;
14431 this.minViewMode = 2;
14434 this.minViewMode = 0;
14439 if (typeof(this.viewMode === 'string')) {
14440 switch (this.viewMode) {
14453 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14455 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14457 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14459 this.picker().on('mousedown', this.onMousedown, this);
14460 this.picker().on('click', this.onClick, this);
14462 this.picker().addClass('datepicker-dropdown');
14464 this.startViewMode = this.viewMode;
14467 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14468 if(!this.calendarWeeks){
14473 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14474 v.attr('colspan', function(i, val){
14475 return parseInt(val) + 1;
14480 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14482 this.setStartDate(this.startDate);
14483 this.setEndDate(this.endDate);
14485 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14492 if(this.isInline) {
14497 picker : function()
14499 return this.pickerEl;
14500 // return this.el.select('.datepicker', true).first();
14503 fillDow: function()
14505 var dowCnt = this.weekStart;
14514 if(this.calendarWeeks){
14522 while (dowCnt < this.weekStart + 7) {
14526 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14530 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14533 fillMonths: function()
14536 var months = this.picker().select('>.datepicker-months td', true).first();
14538 months.dom.innerHTML = '';
14544 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14547 months.createChild(month);
14554 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;
14556 if (this.date < this.startDate) {
14557 this.viewDate = new Date(this.startDate);
14558 } else if (this.date > this.endDate) {
14559 this.viewDate = new Date(this.endDate);
14561 this.viewDate = new Date(this.date);
14569 var d = new Date(this.viewDate),
14570 year = d.getUTCFullYear(),
14571 month = d.getUTCMonth(),
14572 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14573 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14574 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14575 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14576 currentDate = this.date && this.date.valueOf(),
14577 today = this.UTCToday();
14579 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14581 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14583 // this.picker.select('>tfoot th.today').
14584 // .text(dates[this.language].today)
14585 // .toggle(this.todayBtn !== false);
14587 this.updateNavArrows();
14590 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14592 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14594 prevMonth.setUTCDate(day);
14596 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14598 var nextMonth = new Date(prevMonth);
14600 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14602 nextMonth = nextMonth.valueOf();
14604 var fillMonths = false;
14606 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14608 while(prevMonth.valueOf() < nextMonth) {
14611 if (prevMonth.getUTCDay() === this.weekStart) {
14613 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14621 if(this.calendarWeeks){
14622 // ISO 8601: First week contains first thursday.
14623 // ISO also states week starts on Monday, but we can be more abstract here.
14625 // Start of current week: based on weekstart/current date
14626 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14627 // Thursday of this week
14628 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14629 // First Thursday of year, year from thursday
14630 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14631 // Calendar week: ms between thursdays, div ms per day, div 7 days
14632 calWeek = (th - yth) / 864e5 / 7 + 1;
14634 fillMonths.cn.push({
14642 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14644 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14647 if (this.todayHighlight &&
14648 prevMonth.getUTCFullYear() == today.getFullYear() &&
14649 prevMonth.getUTCMonth() == today.getMonth() &&
14650 prevMonth.getUTCDate() == today.getDate()) {
14651 clsName += ' today';
14654 if (currentDate && prevMonth.valueOf() === currentDate) {
14655 clsName += ' active';
14658 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14659 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14660 clsName += ' disabled';
14663 fillMonths.cn.push({
14665 cls: 'day ' + clsName,
14666 html: prevMonth.getDate()
14669 prevMonth.setDate(prevMonth.getDate()+1);
14672 var currentYear = this.date && this.date.getUTCFullYear();
14673 var currentMonth = this.date && this.date.getUTCMonth();
14675 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14677 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14678 v.removeClass('active');
14680 if(currentYear === year && k === currentMonth){
14681 v.addClass('active');
14684 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14685 v.addClass('disabled');
14691 year = parseInt(year/10, 10) * 10;
14693 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14695 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14698 for (var i = -1; i < 11; i++) {
14699 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14701 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14709 showMode: function(dir)
14712 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14714 Roo.each(this.picker().select('>div',true).elements, function(v){
14715 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14718 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14723 if(this.isInline) return;
14725 this.picker().removeClass(['bottom', 'top']);
14727 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14729 * place to the top of element!
14733 this.picker().addClass('top');
14734 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14739 this.picker().addClass('bottom');
14741 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14744 parseDate : function(value)
14746 if(!value || value instanceof Date){
14749 var v = Date.parseDate(value, this.format);
14750 if (!v && this.useIso) {
14751 v = Date.parseDate(value, 'Y-m-d');
14753 if(!v && this.altFormats){
14754 if(!this.altFormatsArray){
14755 this.altFormatsArray = this.altFormats.split("|");
14757 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14758 v = Date.parseDate(value, this.altFormatsArray[i]);
14764 formatDate : function(date, fmt)
14766 return (!date || !(date instanceof Date)) ?
14767 date : date.dateFormat(fmt || this.format);
14770 onFocus : function()
14772 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14776 onBlur : function()
14778 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14780 var d = this.inputEl().getValue();
14789 this.picker().show();
14793 this.fireEvent('show', this, this.date);
14798 if(this.isInline) return;
14799 this.picker().hide();
14800 this.viewMode = this.startViewMode;
14803 this.fireEvent('hide', this, this.date);
14807 onMousedown: function(e)
14809 e.stopPropagation();
14810 e.preventDefault();
14815 Roo.bootstrap.DateField.superclass.keyup.call(this);
14819 setValue: function(v)
14821 var d = new Date(v).clearTime();
14823 if(isNaN(d.getTime())){
14824 this.date = this.viewDate = '';
14825 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14829 v = this.formatDate(d);
14831 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14833 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14837 this.fireEvent('select', this, this.date);
14841 getValue: function()
14843 return this.formatDate(this.date);
14846 fireKey: function(e)
14848 if (!this.picker().isVisible()){
14849 if (e.keyCode == 27) // allow escape to hide and re-show picker
14854 var dateChanged = false,
14856 newDate, newViewDate;
14861 e.preventDefault();
14865 if (!this.keyboardNavigation) break;
14866 dir = e.keyCode == 37 ? -1 : 1;
14869 newDate = this.moveYear(this.date, dir);
14870 newViewDate = this.moveYear(this.viewDate, dir);
14871 } else if (e.shiftKey){
14872 newDate = this.moveMonth(this.date, dir);
14873 newViewDate = this.moveMonth(this.viewDate, dir);
14875 newDate = new Date(this.date);
14876 newDate.setUTCDate(this.date.getUTCDate() + dir);
14877 newViewDate = new Date(this.viewDate);
14878 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14880 if (this.dateWithinRange(newDate)){
14881 this.date = newDate;
14882 this.viewDate = newViewDate;
14883 this.setValue(this.formatDate(this.date));
14885 e.preventDefault();
14886 dateChanged = true;
14891 if (!this.keyboardNavigation) break;
14892 dir = e.keyCode == 38 ? -1 : 1;
14894 newDate = this.moveYear(this.date, dir);
14895 newViewDate = this.moveYear(this.viewDate, dir);
14896 } else if (e.shiftKey){
14897 newDate = this.moveMonth(this.date, dir);
14898 newViewDate = this.moveMonth(this.viewDate, dir);
14900 newDate = new Date(this.date);
14901 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14902 newViewDate = new Date(this.viewDate);
14903 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14905 if (this.dateWithinRange(newDate)){
14906 this.date = newDate;
14907 this.viewDate = newViewDate;
14908 this.setValue(this.formatDate(this.date));
14910 e.preventDefault();
14911 dateChanged = true;
14915 this.setValue(this.formatDate(this.date));
14917 e.preventDefault();
14920 this.setValue(this.formatDate(this.date));
14934 onClick: function(e)
14936 e.stopPropagation();
14937 e.preventDefault();
14939 var target = e.getTarget();
14941 if(target.nodeName.toLowerCase() === 'i'){
14942 target = Roo.get(target).dom.parentNode;
14945 var nodeName = target.nodeName;
14946 var className = target.className;
14947 var html = target.innerHTML;
14949 switch(nodeName.toLowerCase()) {
14951 switch(className) {
14957 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14958 switch(this.viewMode){
14960 this.viewDate = this.moveMonth(this.viewDate, dir);
14964 this.viewDate = this.moveYear(this.viewDate, dir);
14970 var date = new Date();
14971 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14973 this.setValue(this.formatDate(this.date));
14980 if (className.indexOf('disabled') === -1) {
14981 this.viewDate.setUTCDate(1);
14982 if (className.indexOf('month') !== -1) {
14983 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14985 var year = parseInt(html, 10) || 0;
14986 this.viewDate.setUTCFullYear(year);
14995 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14996 var day = parseInt(html, 10) || 1;
14997 var year = this.viewDate.getUTCFullYear(),
14998 month = this.viewDate.getUTCMonth();
15000 if (className.indexOf('old') !== -1) {
15007 } else if (className.indexOf('new') !== -1) {
15015 this.date = this.UTCDate(year, month, day,0,0,0,0);
15016 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15018 this.setValue(this.formatDate(this.date));
15025 setStartDate: function(startDate)
15027 this.startDate = startDate || -Infinity;
15028 if (this.startDate !== -Infinity) {
15029 this.startDate = this.parseDate(this.startDate);
15032 this.updateNavArrows();
15035 setEndDate: function(endDate)
15037 this.endDate = endDate || Infinity;
15038 if (this.endDate !== Infinity) {
15039 this.endDate = this.parseDate(this.endDate);
15042 this.updateNavArrows();
15045 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15047 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15048 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15049 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15051 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15052 return parseInt(d, 10);
15055 this.updateNavArrows();
15058 updateNavArrows: function()
15060 var d = new Date(this.viewDate),
15061 year = d.getUTCFullYear(),
15062 month = d.getUTCMonth();
15064 Roo.each(this.picker().select('.prev', true).elements, function(v){
15066 switch (this.viewMode) {
15069 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15075 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15082 Roo.each(this.picker().select('.next', true).elements, function(v){
15084 switch (this.viewMode) {
15087 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15093 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15101 moveMonth: function(date, dir)
15103 if (!dir) return date;
15104 var new_date = new Date(date.valueOf()),
15105 day = new_date.getUTCDate(),
15106 month = new_date.getUTCMonth(),
15107 mag = Math.abs(dir),
15109 dir = dir > 0 ? 1 : -1;
15112 // If going back one month, make sure month is not current month
15113 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15115 return new_date.getUTCMonth() == month;
15117 // If going forward one month, make sure month is as expected
15118 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15120 return new_date.getUTCMonth() != new_month;
15122 new_month = month + dir;
15123 new_date.setUTCMonth(new_month);
15124 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15125 if (new_month < 0 || new_month > 11)
15126 new_month = (new_month + 12) % 12;
15128 // For magnitudes >1, move one month at a time...
15129 for (var i=0; i<mag; i++)
15130 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15131 new_date = this.moveMonth(new_date, dir);
15132 // ...then reset the day, keeping it in the new month
15133 new_month = new_date.getUTCMonth();
15134 new_date.setUTCDate(day);
15136 return new_month != new_date.getUTCMonth();
15139 // Common date-resetting loop -- if date is beyond end of month, make it
15142 new_date.setUTCDate(--day);
15143 new_date.setUTCMonth(new_month);
15148 moveYear: function(date, dir)
15150 return this.moveMonth(date, dir*12);
15153 dateWithinRange: function(date)
15155 return date >= this.startDate && date <= this.endDate;
15161 this.picker().remove();
15166 Roo.apply(Roo.bootstrap.DateField, {
15177 html: '<i class="fa fa-arrow-left"/>'
15187 html: '<i class="fa fa-arrow-right"/>'
15229 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15230 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15231 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15232 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15233 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15246 navFnc: 'FullYear',
15251 navFnc: 'FullYear',
15256 Roo.apply(Roo.bootstrap.DateField, {
15260 cls: 'datepicker dropdown-menu',
15264 cls: 'datepicker-days',
15268 cls: 'table-condensed',
15270 Roo.bootstrap.DateField.head,
15274 Roo.bootstrap.DateField.footer
15281 cls: 'datepicker-months',
15285 cls: 'table-condensed',
15287 Roo.bootstrap.DateField.head,
15288 Roo.bootstrap.DateField.content,
15289 Roo.bootstrap.DateField.footer
15296 cls: 'datepicker-years',
15300 cls: 'table-condensed',
15302 Roo.bootstrap.DateField.head,
15303 Roo.bootstrap.DateField.content,
15304 Roo.bootstrap.DateField.footer
15323 * @class Roo.bootstrap.TimeField
15324 * @extends Roo.bootstrap.Input
15325 * Bootstrap DateField class
15329 * Create a new TimeField
15330 * @param {Object} config The config object
15333 Roo.bootstrap.TimeField = function(config){
15334 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15338 * Fires when this field show.
15339 * @param {Roo.bootstrap.DateField} this
15340 * @param {Mixed} date The date value
15345 * Fires when this field hide.
15346 * @param {Roo.bootstrap.DateField} this
15347 * @param {Mixed} date The date value
15352 * Fires when select a date.
15353 * @param {Roo.bootstrap.DateField} this
15354 * @param {Mixed} date The date value
15360 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15363 * @cfg {String} format
15364 * The default time format string which can be overriden for localization support. The format must be
15365 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15369 onRender: function(ct, position)
15372 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15374 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15376 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15378 this.pop = this.picker().select('>.datepicker-time',true).first();
15379 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15381 this.picker().on('mousedown', this.onMousedown, this);
15382 this.picker().on('click', this.onClick, this);
15384 this.picker().addClass('datepicker-dropdown');
15389 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15390 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15391 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15392 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15393 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15394 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15398 fireKey: function(e){
15399 if (!this.picker().isVisible()){
15400 if (e.keyCode == 27) // allow escape to hide and re-show picker
15405 e.preventDefault();
15413 this.onTogglePeriod();
15416 this.onIncrementMinutes();
15419 this.onDecrementMinutes();
15428 onClick: function(e) {
15429 e.stopPropagation();
15430 e.preventDefault();
15433 picker : function()
15435 return this.el.select('.datepicker', true).first();
15438 fillTime: function()
15440 var time = this.pop.select('tbody', true).first();
15442 time.dom.innerHTML = '';
15457 cls: 'hours-up glyphicon glyphicon-chevron-up'
15477 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15498 cls: 'timepicker-hour',
15513 cls: 'timepicker-minute',
15528 cls: 'btn btn-primary period',
15550 cls: 'hours-down glyphicon glyphicon-chevron-down'
15570 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15588 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15595 var hours = this.time.getHours();
15596 var minutes = this.time.getMinutes();
15609 hours = hours - 12;
15613 hours = '0' + hours;
15617 minutes = '0' + minutes;
15620 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15621 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15622 this.pop.select('button', true).first().dom.innerHTML = period;
15628 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15630 var cls = ['bottom'];
15632 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15639 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15644 this.picker().addClass(cls.join('-'));
15648 Roo.each(cls, function(c){
15650 _this.picker().setTop(_this.inputEl().getHeight());
15654 _this.picker().setTop(0 - _this.picker().getHeight());
15659 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15663 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15670 onFocus : function()
15672 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15676 onBlur : function()
15678 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15684 this.picker().show();
15689 this.fireEvent('show', this, this.date);
15694 this.picker().hide();
15697 this.fireEvent('hide', this, this.date);
15700 setTime : function()
15703 this.setValue(this.time.format(this.format));
15705 this.fireEvent('select', this, this.date);
15710 onMousedown: function(e){
15711 e.stopPropagation();
15712 e.preventDefault();
15715 onIncrementHours: function()
15717 Roo.log('onIncrementHours');
15718 this.time = this.time.add(Date.HOUR, 1);
15723 onDecrementHours: function()
15725 Roo.log('onDecrementHours');
15726 this.time = this.time.add(Date.HOUR, -1);
15730 onIncrementMinutes: function()
15732 Roo.log('onIncrementMinutes');
15733 this.time = this.time.add(Date.MINUTE, 1);
15737 onDecrementMinutes: function()
15739 Roo.log('onDecrementMinutes');
15740 this.time = this.time.add(Date.MINUTE, -1);
15744 onTogglePeriod: function()
15746 Roo.log('onTogglePeriod');
15747 this.time = this.time.add(Date.HOUR, 12);
15754 Roo.apply(Roo.bootstrap.TimeField, {
15784 cls: 'btn btn-info ok',
15796 Roo.apply(Roo.bootstrap.TimeField, {
15800 cls: 'datepicker dropdown-menu',
15804 cls: 'datepicker-time',
15808 cls: 'table-condensed',
15810 Roo.bootstrap.TimeField.content,
15811 Roo.bootstrap.TimeField.footer
15830 * @class Roo.bootstrap.CheckBox
15831 * @extends Roo.bootstrap.Input
15832 * Bootstrap CheckBox class
15834 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15835 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15836 * @cfg {String} boxLabel The text that appears beside the checkbox
15837 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15838 * @cfg {Boolean} checked initnal the element
15842 * Create a new CheckBox
15843 * @param {Object} config The config object
15846 Roo.bootstrap.CheckBox = function(config){
15847 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15852 * Fires when the element is checked or unchecked.
15853 * @param {Roo.bootstrap.CheckBox} this This input
15854 * @param {Boolean} checked The new checked value
15860 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15862 inputType: 'checkbox',
15869 getAutoCreate : function()
15871 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15877 cfg.cls = 'form-group checkbox' //input-group
15885 type : this.inputType,
15886 value : (!this.checked) ? this.valueOff : this.inputValue,
15887 cls : 'roo-checkbox', //'form-box',
15888 placeholder : this.placeholder || ''
15892 if (this.weight) { // Validity check?
15893 cfg.cls += " checkbox-" + this.weight;
15896 if (this.disabled) {
15897 input.disabled=true;
15901 input.checked = this.checked;
15905 input.name = this.name;
15909 input.cls += ' input-' + this.size;
15913 ['xs','sm','md','lg'].map(function(size){
15914 if (settings[size]) {
15915 cfg.cls += ' col-' + size + '-' + settings[size];
15921 var inputblock = input;
15926 if (this.before || this.after) {
15929 cls : 'input-group',
15933 inputblock.cn.push({
15935 cls : 'input-group-addon',
15939 inputblock.cn.push(input);
15941 inputblock.cn.push({
15943 cls : 'input-group-addon',
15950 if (align ==='left' && this.fieldLabel.length) {
15951 Roo.log("left and has label");
15957 cls : 'control-label col-md-' + this.labelWidth,
15958 html : this.fieldLabel
15962 cls : "col-md-" + (12 - this.labelWidth),
15969 } else if ( this.fieldLabel.length) {
15974 tag: this.boxLabel ? 'span' : 'label',
15976 cls: 'control-label box-input-label',
15977 //cls : 'input-group-addon',
15978 html : this.fieldLabel
15988 Roo.log(" no label && no align");
15989 cfg.cn = [ inputblock ] ;
15998 html: this.boxLabel
16010 * return the real input element.
16012 inputEl: function ()
16014 return this.el.select('input.roo-checkbox',true).first();
16019 return this.el.select('label.control-label',true).first();
16022 initEvents : function()
16024 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16026 this.inputEl().on('click', this.onClick, this);
16030 onClick : function()
16032 this.setChecked(!this.checked);
16035 setChecked : function(state,suppressEvent)
16037 this.checked = state;
16039 this.inputEl().dom.checked = state;
16041 if(suppressEvent !== true){
16042 this.fireEvent('check', this, state);
16045 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16049 setValue : function(v,suppressEvent)
16051 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16065 * @class Roo.bootstrap.Radio
16066 * @extends Roo.bootstrap.CheckBox
16067 * Bootstrap Radio class
16070 * Create a new Radio
16071 * @param {Object} config The config object
16074 Roo.bootstrap.Radio = function(config){
16075 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16079 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16081 inputType: 'radio',
16085 getAutoCreate : function()
16087 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16093 cfg.cls = 'form-group radio' //input-group
16098 type : this.inputType,
16099 value : (!this.checked) ? this.valueOff : this.inputValue,
16101 placeholder : this.placeholder || ''
16104 if (this.weight) { // Validity check?
16105 cfg.cls += " radio-" + this.weight;
16107 if (this.disabled) {
16108 input.disabled=true;
16112 input.checked = this.checked;
16116 input.name = this.name;
16120 input.cls += ' input-' + this.size;
16124 ['xs','sm','md','lg'].map(function(size){
16125 if (settings[size]) {
16126 cfg.cls += ' col-' + size + '-' + settings[size];
16130 var inputblock = input;
16132 if (this.before || this.after) {
16135 cls : 'input-group',
16139 inputblock.cn.push({
16141 cls : 'input-group-addon',
16145 inputblock.cn.push(input);
16147 inputblock.cn.push({
16149 cls : 'input-group-addon',
16156 if (align ==='left' && this.fieldLabel.length) {
16157 Roo.log("left and has label");
16163 cls : 'control-label col-md-' + this.labelWidth,
16164 html : this.fieldLabel
16168 cls : "col-md-" + (12 - this.labelWidth),
16175 } else if ( this.fieldLabel.length) {
16182 cls: 'control-label box-input-label',
16183 //cls : 'input-group-addon',
16184 html : this.fieldLabel
16194 Roo.log(" no label && no align");
16209 html: this.boxLabel
16216 inputEl: function ()
16218 return this.el.select('input.roo-radio',true).first();
16220 onClick : function()
16222 this.setChecked(true);
16225 setChecked : function(state,suppressEvent)
16228 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16229 v.dom.checked = false;
16233 this.checked = state;
16234 this.inputEl().dom.checked = state;
16236 if(suppressEvent !== true){
16237 this.fireEvent('check', this, state);
16240 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16244 getGroupValue : function()
16247 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16248 if(v.dom.checked == true){
16249 value = v.dom.value;
16257 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16258 * @return {Mixed} value The field value
16260 getValue : function(){
16261 return this.getGroupValue();
16267 //<script type="text/javascript">
16270 * Based Ext JS Library 1.1.1
16271 * Copyright(c) 2006-2007, Ext JS, LLC.
16277 * @class Roo.HtmlEditorCore
16278 * @extends Roo.Component
16279 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16281 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16284 Roo.HtmlEditorCore = function(config){
16287 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16290 * @event initialize
16291 * Fires when the editor is fully initialized (including the iframe)
16292 * @param {Roo.HtmlEditorCore} this
16297 * Fires when the editor is first receives the focus. Any insertion must wait
16298 * until after this event.
16299 * @param {Roo.HtmlEditorCore} this
16303 * @event beforesync
16304 * Fires before the textarea is updated with content from the editor iframe. Return false
16305 * to cancel the sync.
16306 * @param {Roo.HtmlEditorCore} this
16307 * @param {String} html
16311 * @event beforepush
16312 * Fires before the iframe editor is updated with content from the textarea. Return false
16313 * to cancel the push.
16314 * @param {Roo.HtmlEditorCore} this
16315 * @param {String} html
16320 * Fires when the textarea is updated with content from the editor iframe.
16321 * @param {Roo.HtmlEditorCore} this
16322 * @param {String} html
16327 * Fires when the iframe editor is updated with content from the textarea.
16328 * @param {Roo.HtmlEditorCore} this
16329 * @param {String} html
16334 * @event editorevent
16335 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16336 * @param {Roo.HtmlEditorCore} this
16344 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16348 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16354 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16359 * @cfg {Number} height (in pixels)
16363 * @cfg {Number} width (in pixels)
16368 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16371 stylesheets: false,
16376 // private properties
16377 validationEvent : false,
16379 initialized : false,
16381 sourceEditMode : false,
16382 onFocus : Roo.emptyFn,
16384 hideMode:'offsets',
16392 * Protected method that will not generally be called directly. It
16393 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16394 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16396 getDocMarkup : function(){
16399 Roo.log(this.stylesheets);
16401 // inherit styels from page...??
16402 if (this.stylesheets === false) {
16404 Roo.get(document.head).select('style').each(function(node) {
16405 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16408 Roo.get(document.head).select('link').each(function(node) {
16409 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16412 } else if (!this.stylesheets.length) {
16414 st = '<style type="text/css">' +
16415 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16418 Roo.each(this.stylesheets, function(s) {
16419 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16424 st += '<style type="text/css">' +
16425 'IMG { cursor: pointer } ' +
16429 return '<html><head>' + st +
16430 //<style type="text/css">' +
16431 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16433 ' </head><body class="roo-htmleditor-body"></body></html>';
16437 onRender : function(ct, position)
16440 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16441 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16444 this.el.dom.style.border = '0 none';
16445 this.el.dom.setAttribute('tabIndex', -1);
16446 this.el.addClass('x-hidden hide');
16450 if(Roo.isIE){ // fix IE 1px bogus margin
16451 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16455 this.frameId = Roo.id();
16459 var iframe = this.owner.wrap.createChild({
16461 cls: 'form-control', // bootstrap..
16463 name: this.frameId,
16464 frameBorder : 'no',
16465 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16470 this.iframe = iframe.dom;
16472 this.assignDocWin();
16474 this.doc.designMode = 'on';
16477 this.doc.write(this.getDocMarkup());
16481 var task = { // must defer to wait for browser to be ready
16483 //console.log("run task?" + this.doc.readyState);
16484 this.assignDocWin();
16485 if(this.doc.body || this.doc.readyState == 'complete'){
16487 this.doc.designMode="on";
16491 Roo.TaskMgr.stop(task);
16492 this.initEditor.defer(10, this);
16499 Roo.TaskMgr.start(task);
16506 onResize : function(w, h)
16508 Roo.log('resize: ' +w + ',' + h );
16509 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16513 if(typeof w == 'number'){
16515 this.iframe.style.width = w + 'px';
16517 if(typeof h == 'number'){
16519 this.iframe.style.height = h + 'px';
16521 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16528 * Toggles the editor between standard and source edit mode.
16529 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16531 toggleSourceEdit : function(sourceEditMode){
16533 this.sourceEditMode = sourceEditMode === true;
16535 if(this.sourceEditMode){
16537 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16540 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16541 //this.iframe.className = '';
16544 //this.setSize(this.owner.wrap.getSize());
16545 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16552 * Protected method that will not generally be called directly. If you need/want
16553 * custom HTML cleanup, this is the method you should override.
16554 * @param {String} html The HTML to be cleaned
16555 * return {String} The cleaned HTML
16557 cleanHtml : function(html){
16558 html = String(html);
16559 if(html.length > 5){
16560 if(Roo.isSafari){ // strip safari nonsense
16561 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16564 if(html == ' '){
16571 * HTML Editor -> Textarea
16572 * Protected method that will not generally be called directly. Syncs the contents
16573 * of the editor iframe with the textarea.
16575 syncValue : function(){
16576 if(this.initialized){
16577 var bd = (this.doc.body || this.doc.documentElement);
16578 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16579 var html = bd.innerHTML;
16581 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16582 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16584 html = '<div style="'+m[0]+'">' + html + '</div>';
16587 html = this.cleanHtml(html);
16588 // fix up the special chars.. normaly like back quotes in word...
16589 // however we do not want to do this with chinese..
16590 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16591 var cc = b.charCodeAt();
16593 (cc >= 0x4E00 && cc < 0xA000 ) ||
16594 (cc >= 0x3400 && cc < 0x4E00 ) ||
16595 (cc >= 0xf900 && cc < 0xfb00 )
16601 if(this.owner.fireEvent('beforesync', this, html) !== false){
16602 this.el.dom.value = html;
16603 this.owner.fireEvent('sync', this, html);
16609 * Protected method that will not generally be called directly. Pushes the value of the textarea
16610 * into the iframe editor.
16612 pushValue : function(){
16613 if(this.initialized){
16614 var v = this.el.dom.value.trim();
16616 // if(v.length < 1){
16620 if(this.owner.fireEvent('beforepush', this, v) !== false){
16621 var d = (this.doc.body || this.doc.documentElement);
16623 this.cleanUpPaste();
16624 this.el.dom.value = d.innerHTML;
16625 this.owner.fireEvent('push', this, v);
16631 deferFocus : function(){
16632 this.focus.defer(10, this);
16636 focus : function(){
16637 if(this.win && !this.sourceEditMode){
16644 assignDocWin: function()
16646 var iframe = this.iframe;
16649 this.doc = iframe.contentWindow.document;
16650 this.win = iframe.contentWindow;
16652 // if (!Roo.get(this.frameId)) {
16655 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16656 // this.win = Roo.get(this.frameId).dom.contentWindow;
16658 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16662 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16663 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16668 initEditor : function(){
16669 //console.log("INIT EDITOR");
16670 this.assignDocWin();
16674 this.doc.designMode="on";
16676 this.doc.write(this.getDocMarkup());
16679 var dbody = (this.doc.body || this.doc.documentElement);
16680 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16681 // this copies styles from the containing element into thsi one..
16682 // not sure why we need all of this..
16683 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16685 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16686 //ss['background-attachment'] = 'fixed'; // w3c
16687 dbody.bgProperties = 'fixed'; // ie
16688 //Roo.DomHelper.applyStyles(dbody, ss);
16689 Roo.EventManager.on(this.doc, {
16690 //'mousedown': this.onEditorEvent,
16691 'mouseup': this.onEditorEvent,
16692 'dblclick': this.onEditorEvent,
16693 'click': this.onEditorEvent,
16694 'keyup': this.onEditorEvent,
16699 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16701 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16702 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16704 this.initialized = true;
16706 this.owner.fireEvent('initialize', this);
16711 onDestroy : function(){
16717 //for (var i =0; i < this.toolbars.length;i++) {
16718 // // fixme - ask toolbars for heights?
16719 // this.toolbars[i].onDestroy();
16722 //this.wrap.dom.innerHTML = '';
16723 //this.wrap.remove();
16728 onFirstFocus : function(){
16730 this.assignDocWin();
16733 this.activated = true;
16736 if(Roo.isGecko){ // prevent silly gecko errors
16738 var s = this.win.getSelection();
16739 if(!s.focusNode || s.focusNode.nodeType != 3){
16740 var r = s.getRangeAt(0);
16741 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16746 this.execCmd('useCSS', true);
16747 this.execCmd('styleWithCSS', false);
16750 this.owner.fireEvent('activate', this);
16754 adjustFont: function(btn){
16755 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16756 //if(Roo.isSafari){ // safari
16759 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16760 if(Roo.isSafari){ // safari
16761 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16762 v = (v < 10) ? 10 : v;
16763 v = (v > 48) ? 48 : v;
16764 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16769 v = Math.max(1, v+adjust);
16771 this.execCmd('FontSize', v );
16774 onEditorEvent : function(e){
16775 this.owner.fireEvent('editorevent', this, e);
16776 // this.updateToolbar();
16777 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16780 insertTag : function(tg)
16782 // could be a bit smarter... -> wrap the current selected tRoo..
16783 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16785 range = this.createRange(this.getSelection());
16786 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16787 wrappingNode.appendChild(range.extractContents());
16788 range.insertNode(wrappingNode);
16795 this.execCmd("formatblock", tg);
16799 insertText : function(txt)
16803 var range = this.createRange();
16804 range.deleteContents();
16805 //alert(Sender.getAttribute('label'));
16807 range.insertNode(this.doc.createTextNode(txt));
16813 * Executes a Midas editor command on the editor document and performs necessary focus and
16814 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16815 * @param {String} cmd The Midas command
16816 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16818 relayCmd : function(cmd, value){
16820 this.execCmd(cmd, value);
16821 this.owner.fireEvent('editorevent', this);
16822 //this.updateToolbar();
16823 this.owner.deferFocus();
16827 * Executes a Midas editor command directly on the editor document.
16828 * For visual commands, you should use {@link #relayCmd} instead.
16829 * <b>This should only be called after the editor is initialized.</b>
16830 * @param {String} cmd The Midas command
16831 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16833 execCmd : function(cmd, value){
16834 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16841 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16843 * @param {String} text | dom node..
16845 insertAtCursor : function(text)
16850 if(!this.activated){
16856 var r = this.doc.selection.createRange();
16867 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16871 // from jquery ui (MIT licenced)
16873 var win = this.win;
16875 if (win.getSelection && win.getSelection().getRangeAt) {
16876 range = win.getSelection().getRangeAt(0);
16877 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16878 range.insertNode(node);
16879 } else if (win.document.selection && win.document.selection.createRange) {
16880 // no firefox support
16881 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16882 win.document.selection.createRange().pasteHTML(txt);
16884 // no firefox support
16885 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16886 this.execCmd('InsertHTML', txt);
16895 mozKeyPress : function(e){
16897 var c = e.getCharCode(), cmd;
16900 c = String.fromCharCode(c).toLowerCase();
16914 this.cleanUpPaste.defer(100, this);
16922 e.preventDefault();
16930 fixKeys : function(){ // load time branching for fastest keydown performance
16932 return function(e){
16933 var k = e.getKey(), r;
16936 r = this.doc.selection.createRange();
16939 r.pasteHTML('    ');
16946 r = this.doc.selection.createRange();
16948 var target = r.parentElement();
16949 if(!target || target.tagName.toLowerCase() != 'li'){
16951 r.pasteHTML('<br />');
16957 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16958 this.cleanUpPaste.defer(100, this);
16964 }else if(Roo.isOpera){
16965 return function(e){
16966 var k = e.getKey();
16970 this.execCmd('InsertHTML','    ');
16973 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16974 this.cleanUpPaste.defer(100, this);
16979 }else if(Roo.isSafari){
16980 return function(e){
16981 var k = e.getKey();
16985 this.execCmd('InsertText','\t');
16989 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16990 this.cleanUpPaste.defer(100, this);
16998 getAllAncestors: function()
17000 var p = this.getSelectedNode();
17003 a.push(p); // push blank onto stack..
17004 p = this.getParentElement();
17008 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17012 a.push(this.doc.body);
17016 lastSelNode : false,
17019 getSelection : function()
17021 this.assignDocWin();
17022 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17025 getSelectedNode: function()
17027 // this may only work on Gecko!!!
17029 // should we cache this!!!!
17034 var range = this.createRange(this.getSelection()).cloneRange();
17037 var parent = range.parentElement();
17039 var testRange = range.duplicate();
17040 testRange.moveToElementText(parent);
17041 if (testRange.inRange(range)) {
17044 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17047 parent = parent.parentElement;
17052 // is ancestor a text element.
17053 var ac = range.commonAncestorContainer;
17054 if (ac.nodeType == 3) {
17055 ac = ac.parentNode;
17058 var ar = ac.childNodes;
17061 var other_nodes = [];
17062 var has_other_nodes = false;
17063 for (var i=0;i<ar.length;i++) {
17064 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17067 // fullly contained node.
17069 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17074 // probably selected..
17075 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17076 other_nodes.push(ar[i]);
17080 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17085 has_other_nodes = true;
17087 if (!nodes.length && other_nodes.length) {
17088 nodes= other_nodes;
17090 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17096 createRange: function(sel)
17098 // this has strange effects when using with
17099 // top toolbar - not sure if it's a great idea.
17100 //this.editor.contentWindow.focus();
17101 if (typeof sel != "undefined") {
17103 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17105 return this.doc.createRange();
17108 return this.doc.createRange();
17111 getParentElement: function()
17114 this.assignDocWin();
17115 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17117 var range = this.createRange(sel);
17120 var p = range.commonAncestorContainer;
17121 while (p.nodeType == 3) { // text node
17132 * Range intersection.. the hard stuff...
17136 * [ -- selected range --- ]
17140 * if end is before start or hits it. fail.
17141 * if start is after end or hits it fail.
17143 * if either hits (but other is outside. - then it's not
17149 // @see http://www.thismuchiknow.co.uk/?p=64.
17150 rangeIntersectsNode : function(range, node)
17152 var nodeRange = node.ownerDocument.createRange();
17154 nodeRange.selectNode(node);
17156 nodeRange.selectNodeContents(node);
17159 var rangeStartRange = range.cloneRange();
17160 rangeStartRange.collapse(true);
17162 var rangeEndRange = range.cloneRange();
17163 rangeEndRange.collapse(false);
17165 var nodeStartRange = nodeRange.cloneRange();
17166 nodeStartRange.collapse(true);
17168 var nodeEndRange = nodeRange.cloneRange();
17169 nodeEndRange.collapse(false);
17171 return rangeStartRange.compareBoundaryPoints(
17172 Range.START_TO_START, nodeEndRange) == -1 &&
17173 rangeEndRange.compareBoundaryPoints(
17174 Range.START_TO_START, nodeStartRange) == 1;
17178 rangeCompareNode : function(range, node)
17180 var nodeRange = node.ownerDocument.createRange();
17182 nodeRange.selectNode(node);
17184 nodeRange.selectNodeContents(node);
17188 range.collapse(true);
17190 nodeRange.collapse(true);
17192 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17193 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17195 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17197 var nodeIsBefore = ss == 1;
17198 var nodeIsAfter = ee == -1;
17200 if (nodeIsBefore && nodeIsAfter)
17202 if (!nodeIsBefore && nodeIsAfter)
17203 return 1; //right trailed.
17205 if (nodeIsBefore && !nodeIsAfter)
17206 return 2; // left trailed.
17211 // private? - in a new class?
17212 cleanUpPaste : function()
17214 // cleans up the whole document..
17215 Roo.log('cleanuppaste');
17217 this.cleanUpChildren(this.doc.body);
17218 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17219 if (clean != this.doc.body.innerHTML) {
17220 this.doc.body.innerHTML = clean;
17225 cleanWordChars : function(input) {// change the chars to hex code
17226 var he = Roo.HtmlEditorCore;
17228 var output = input;
17229 Roo.each(he.swapCodes, function(sw) {
17230 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17232 output = output.replace(swapper, sw[1]);
17239 cleanUpChildren : function (n)
17241 if (!n.childNodes.length) {
17244 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17245 this.cleanUpChild(n.childNodes[i]);
17252 cleanUpChild : function (node)
17255 //console.log(node);
17256 if (node.nodeName == "#text") {
17257 // clean up silly Windows -- stuff?
17260 if (node.nodeName == "#comment") {
17261 node.parentNode.removeChild(node);
17262 // clean up silly Windows -- stuff?
17266 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17268 node.parentNode.removeChild(node);
17273 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17275 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17276 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17278 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17279 // remove_keep_children = true;
17282 if (remove_keep_children) {
17283 this.cleanUpChildren(node);
17284 // inserts everything just before this node...
17285 while (node.childNodes.length) {
17286 var cn = node.childNodes[0];
17287 node.removeChild(cn);
17288 node.parentNode.insertBefore(cn, node);
17290 node.parentNode.removeChild(node);
17294 if (!node.attributes || !node.attributes.length) {
17295 this.cleanUpChildren(node);
17299 function cleanAttr(n,v)
17302 if (v.match(/^\./) || v.match(/^\//)) {
17305 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17308 if (v.match(/^#/)) {
17311 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17312 node.removeAttribute(n);
17316 function cleanStyle(n,v)
17318 if (v.match(/expression/)) { //XSS?? should we even bother..
17319 node.removeAttribute(n);
17322 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17323 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17326 var parts = v.split(/;/);
17329 Roo.each(parts, function(p) {
17330 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17334 var l = p.split(':').shift().replace(/\s+/g,'');
17335 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17337 if ( cblack.indexOf(l) > -1) {
17338 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17339 //node.removeAttribute(n);
17343 // only allow 'c whitelisted system attributes'
17344 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17345 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17346 //node.removeAttribute(n);
17356 if (clean.length) {
17357 node.setAttribute(n, clean.join(';'));
17359 node.removeAttribute(n);
17365 for (var i = node.attributes.length-1; i > -1 ; i--) {
17366 var a = node.attributes[i];
17369 if (a.name.toLowerCase().substr(0,2)=='on') {
17370 node.removeAttribute(a.name);
17373 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17374 node.removeAttribute(a.name);
17377 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17378 cleanAttr(a.name,a.value); // fixme..
17381 if (a.name == 'style') {
17382 cleanStyle(a.name,a.value);
17385 /// clean up MS crap..
17386 // tecnically this should be a list of valid class'es..
17389 if (a.name == 'class') {
17390 if (a.value.match(/^Mso/)) {
17391 node.className = '';
17394 if (a.value.match(/body/)) {
17395 node.className = '';
17406 this.cleanUpChildren(node);
17411 * Clean up MS wordisms...
17413 cleanWord : function(node)
17416 var cleanWordChildren = function()
17418 if (!node.childNodes.length) {
17421 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17422 _t.cleanWord(node.childNodes[i]);
17428 this.cleanWord(this.doc.body);
17431 if (node.nodeName == "#text") {
17432 // clean up silly Windows -- stuff?
17435 if (node.nodeName == "#comment") {
17436 node.parentNode.removeChild(node);
17437 // clean up silly Windows -- stuff?
17441 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17442 node.parentNode.removeChild(node);
17446 // remove - but keep children..
17447 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17448 while (node.childNodes.length) {
17449 var cn = node.childNodes[0];
17450 node.removeChild(cn);
17451 node.parentNode.insertBefore(cn, node);
17453 node.parentNode.removeChild(node);
17454 cleanWordChildren();
17458 if (node.className.length) {
17460 var cn = node.className.split(/\W+/);
17462 Roo.each(cn, function(cls) {
17463 if (cls.match(/Mso[a-zA-Z]+/)) {
17468 node.className = cna.length ? cna.join(' ') : '';
17470 node.removeAttribute("class");
17474 if (node.hasAttribute("lang")) {
17475 node.removeAttribute("lang");
17478 if (node.hasAttribute("style")) {
17480 var styles = node.getAttribute("style").split(";");
17482 Roo.each(styles, function(s) {
17483 if (!s.match(/:/)) {
17486 var kv = s.split(":");
17487 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17490 // what ever is left... we allow.
17493 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17494 if (!nstyle.length) {
17495 node.removeAttribute('style');
17499 cleanWordChildren();
17503 domToHTML : function(currentElement, depth, nopadtext) {
17505 depth = depth || 0;
17506 nopadtext = nopadtext || false;
17508 if (!currentElement) {
17509 return this.domToHTML(this.doc.body);
17512 //Roo.log(currentElement);
17514 var allText = false;
17515 var nodeName = currentElement.nodeName;
17516 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17518 if (nodeName == '#text') {
17519 return currentElement.nodeValue;
17524 if (nodeName != 'BODY') {
17527 // Prints the node tagName, such as <A>, <IMG>, etc
17530 for(i = 0; i < currentElement.attributes.length;i++) {
17532 var aname = currentElement.attributes.item(i).name;
17533 if (!currentElement.attributes.item(i).value.length) {
17536 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17539 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17548 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17551 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17556 // Traverse the tree
17558 var currentElementChild = currentElement.childNodes.item(i);
17559 var allText = true;
17560 var innerHTML = '';
17562 while (currentElementChild) {
17563 // Formatting code (indent the tree so it looks nice on the screen)
17564 var nopad = nopadtext;
17565 if (lastnode == 'SPAN') {
17569 if (currentElementChild.nodeName == '#text') {
17570 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17571 if (!nopad && toadd.length > 80) {
17572 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17574 innerHTML += toadd;
17577 currentElementChild = currentElement.childNodes.item(i);
17583 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17585 // Recursively traverse the tree structure of the child node
17586 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17587 lastnode = currentElementChild.nodeName;
17589 currentElementChild=currentElement.childNodes.item(i);
17595 // The remaining code is mostly for formatting the tree
17596 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17601 ret+= "</"+tagName+">";
17607 // hide stuff that is not compatible
17621 * @event specialkey
17625 * @cfg {String} fieldClass @hide
17628 * @cfg {String} focusClass @hide
17631 * @cfg {String} autoCreate @hide
17634 * @cfg {String} inputType @hide
17637 * @cfg {String} invalidClass @hide
17640 * @cfg {String} invalidText @hide
17643 * @cfg {String} msgFx @hide
17646 * @cfg {String} validateOnBlur @hide
17650 Roo.HtmlEditorCore.white = [
17651 'area', 'br', 'img', 'input', 'hr', 'wbr',
17653 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17654 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17655 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17656 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17657 'table', 'ul', 'xmp',
17659 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17662 'dir', 'menu', 'ol', 'ul', 'dl',
17668 Roo.HtmlEditorCore.black = [
17669 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17671 'base', 'basefont', 'bgsound', 'blink', 'body',
17672 'frame', 'frameset', 'head', 'html', 'ilayer',
17673 'iframe', 'layer', 'link', 'meta', 'object',
17674 'script', 'style' ,'title', 'xml' // clean later..
17676 Roo.HtmlEditorCore.clean = [
17677 'script', 'style', 'title', 'xml'
17679 Roo.HtmlEditorCore.remove = [
17684 Roo.HtmlEditorCore.ablack = [
17688 Roo.HtmlEditorCore.aclean = [
17689 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17693 Roo.HtmlEditorCore.pwhite= [
17694 'http', 'https', 'mailto'
17697 // white listed style attributes.
17698 Roo.HtmlEditorCore.cwhite= [
17699 // 'text-align', /// default is to allow most things..
17705 // black listed style attributes.
17706 Roo.HtmlEditorCore.cblack= [
17707 // 'font-size' -- this can be set by the project
17711 Roo.HtmlEditorCore.swapCodes =[
17730 * @class Roo.bootstrap.HtmlEditor
17731 * @extends Roo.bootstrap.TextArea
17732 * Bootstrap HtmlEditor class
17735 * Create a new HtmlEditor
17736 * @param {Object} config The config object
17739 Roo.bootstrap.HtmlEditor = function(config){
17740 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17741 if (!this.toolbars) {
17742 this.toolbars = [];
17744 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17747 * @event initialize
17748 * Fires when the editor is fully initialized (including the iframe)
17749 * @param {HtmlEditor} this
17754 * Fires when the editor is first receives the focus. Any insertion must wait
17755 * until after this event.
17756 * @param {HtmlEditor} this
17760 * @event beforesync
17761 * Fires before the textarea is updated with content from the editor iframe. Return false
17762 * to cancel the sync.
17763 * @param {HtmlEditor} this
17764 * @param {String} html
17768 * @event beforepush
17769 * Fires before the iframe editor is updated with content from the textarea. Return false
17770 * to cancel the push.
17771 * @param {HtmlEditor} this
17772 * @param {String} html
17777 * Fires when the textarea is updated with content from the editor iframe.
17778 * @param {HtmlEditor} this
17779 * @param {String} html
17784 * Fires when the iframe editor is updated with content from the textarea.
17785 * @param {HtmlEditor} this
17786 * @param {String} html
17790 * @event editmodechange
17791 * Fires when the editor switches edit modes
17792 * @param {HtmlEditor} this
17793 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17795 editmodechange: true,
17797 * @event editorevent
17798 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17799 * @param {HtmlEditor} this
17803 * @event firstfocus
17804 * Fires when on first focus - needed by toolbars..
17805 * @param {HtmlEditor} this
17810 * Auto save the htmlEditor value as a file into Events
17811 * @param {HtmlEditor} this
17815 * @event savedpreview
17816 * preview the saved version of htmlEditor
17817 * @param {HtmlEditor} this
17824 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17828 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17833 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17838 * @cfg {Number} height (in pixels)
17842 * @cfg {Number} width (in pixels)
17847 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17850 stylesheets: false,
17855 // private properties
17856 validationEvent : false,
17858 initialized : false,
17861 onFocus : Roo.emptyFn,
17863 hideMode:'offsets',
17866 tbContainer : false,
17868 toolbarContainer :function() {
17869 return this.wrap.select('.x-html-editor-tb',true).first();
17873 * Protected method that will not generally be called directly. It
17874 * is called when the editor creates its toolbar. Override this method if you need to
17875 * add custom toolbar buttons.
17876 * @param {HtmlEditor} editor
17878 createToolbar : function(){
17880 Roo.log("create toolbars");
17882 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17883 this.toolbars[0].render(this.toolbarContainer());
17887 // if (!editor.toolbars || !editor.toolbars.length) {
17888 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17891 // for (var i =0 ; i < editor.toolbars.length;i++) {
17892 // editor.toolbars[i] = Roo.factory(
17893 // typeof(editor.toolbars[i]) == 'string' ?
17894 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17895 // Roo.bootstrap.HtmlEditor);
17896 // editor.toolbars[i].init(editor);
17902 onRender : function(ct, position)
17904 // Roo.log("Call onRender: " + this.xtype);
17906 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17908 this.wrap = this.inputEl().wrap({
17909 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17912 this.editorcore.onRender(ct, position);
17914 if (this.resizable) {
17915 this.resizeEl = new Roo.Resizable(this.wrap, {
17919 minHeight : this.height,
17920 height: this.height,
17921 handles : this.resizable,
17924 resize : function(r, w, h) {
17925 _t.onResize(w,h); // -something
17931 this.createToolbar(this);
17934 if(!this.width && this.resizable){
17935 this.setSize(this.wrap.getSize());
17937 if (this.resizeEl) {
17938 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17939 // should trigger onReize..
17945 onResize : function(w, h)
17947 Roo.log('resize: ' +w + ',' + h );
17948 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17952 if(this.inputEl() ){
17953 if(typeof w == 'number'){
17954 var aw = w - this.wrap.getFrameWidth('lr');
17955 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17958 if(typeof h == 'number'){
17959 var tbh = -11; // fixme it needs to tool bar size!
17960 for (var i =0; i < this.toolbars.length;i++) {
17961 // fixme - ask toolbars for heights?
17962 tbh += this.toolbars[i].el.getHeight();
17963 //if (this.toolbars[i].footer) {
17964 // tbh += this.toolbars[i].footer.el.getHeight();
17972 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17973 ah -= 5; // knock a few pixes off for look..
17974 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17978 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17979 this.editorcore.onResize(ew,eh);
17984 * Toggles the editor between standard and source edit mode.
17985 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17987 toggleSourceEdit : function(sourceEditMode)
17989 this.editorcore.toggleSourceEdit(sourceEditMode);
17991 if(this.editorcore.sourceEditMode){
17992 Roo.log('editor - showing textarea');
17995 // Roo.log(this.syncValue());
17997 this.inputEl().removeClass(['hide', 'x-hidden']);
17998 this.inputEl().dom.removeAttribute('tabIndex');
17999 this.inputEl().focus();
18001 Roo.log('editor - hiding textarea');
18003 // Roo.log(this.pushValue());
18006 this.inputEl().addClass(['hide', 'x-hidden']);
18007 this.inputEl().dom.setAttribute('tabIndex', -1);
18008 //this.deferFocus();
18011 if(this.resizable){
18012 this.setSize(this.wrap.getSize());
18015 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18018 // private (for BoxComponent)
18019 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18021 // private (for BoxComponent)
18022 getResizeEl : function(){
18026 // private (for BoxComponent)
18027 getPositionEl : function(){
18032 initEvents : function(){
18033 this.originalValue = this.getValue();
18037 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18040 // markInvalid : Roo.emptyFn,
18042 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18045 // clearInvalid : Roo.emptyFn,
18047 setValue : function(v){
18048 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18049 this.editorcore.pushValue();
18054 deferFocus : function(){
18055 this.focus.defer(10, this);
18059 focus : function(){
18060 this.editorcore.focus();
18066 onDestroy : function(){
18072 for (var i =0; i < this.toolbars.length;i++) {
18073 // fixme - ask toolbars for heights?
18074 this.toolbars[i].onDestroy();
18077 this.wrap.dom.innerHTML = '';
18078 this.wrap.remove();
18083 onFirstFocus : function(){
18084 //Roo.log("onFirstFocus");
18085 this.editorcore.onFirstFocus();
18086 for (var i =0; i < this.toolbars.length;i++) {
18087 this.toolbars[i].onFirstFocus();
18093 syncValue : function()
18095 this.editorcore.syncValue();
18098 pushValue : function()
18100 this.editorcore.pushValue();
18104 // hide stuff that is not compatible
18118 * @event specialkey
18122 * @cfg {String} fieldClass @hide
18125 * @cfg {String} focusClass @hide
18128 * @cfg {String} autoCreate @hide
18131 * @cfg {String} inputType @hide
18134 * @cfg {String} invalidClass @hide
18137 * @cfg {String} invalidText @hide
18140 * @cfg {String} msgFx @hide
18143 * @cfg {String} validateOnBlur @hide
18152 Roo.namespace('Roo.bootstrap.htmleditor');
18154 * @class Roo.bootstrap.HtmlEditorToolbar1
18159 new Roo.bootstrap.HtmlEditor({
18162 new Roo.bootstrap.HtmlEditorToolbar1({
18163 disable : { fonts: 1 , format: 1, ..., ... , ...],
18169 * @cfg {Object} disable List of elements to disable..
18170 * @cfg {Array} btns List of additional buttons.
18174 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18177 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18180 Roo.apply(this, config);
18182 // default disabled, based on 'good practice'..
18183 this.disable = this.disable || {};
18184 Roo.applyIf(this.disable, {
18187 specialElements : true
18189 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18191 this.editor = config.editor;
18192 this.editorcore = config.editor.editorcore;
18194 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18196 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18197 // dont call parent... till later.
18199 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18204 editorcore : false,
18209 "h1","h2","h3","h4","h5","h6",
18211 "abbr", "acronym", "address", "cite", "samp", "var",
18215 onRender : function(ct, position)
18217 // Roo.log("Call onRender: " + this.xtype);
18219 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18221 this.el.dom.style.marginBottom = '0';
18223 var editorcore = this.editorcore;
18224 var editor= this.editor;
18227 var btn = function(id,cmd , toggle, handler){
18229 var event = toggle ? 'toggle' : 'click';
18234 xns: Roo.bootstrap,
18237 enableToggle:toggle !== false,
18239 pressed : toggle ? false : null,
18242 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18243 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18252 xns: Roo.bootstrap,
18253 glyphicon : 'font',
18257 xns: Roo.bootstrap,
18261 Roo.each(this.formats, function(f) {
18262 style.menu.items.push({
18264 xns: Roo.bootstrap,
18265 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18270 editorcore.insertTag(this.tagname);
18277 children.push(style);
18280 btn('bold',false,true);
18281 btn('italic',false,true);
18282 btn('align-left', 'justifyleft',true);
18283 btn('align-center', 'justifycenter',true);
18284 btn('align-right' , 'justifyright',true);
18285 btn('link', false, false, function(btn) {
18286 //Roo.log("create link?");
18287 var url = prompt(this.createLinkText, this.defaultLinkValue);
18288 if(url && url != 'http:/'+'/'){
18289 this.editorcore.relayCmd('createlink', url);
18292 btn('list','insertunorderedlist',true);
18293 btn('pencil', false,true, function(btn){
18296 this.toggleSourceEdit(btn.pressed);
18302 xns: Roo.bootstrap,
18307 xns: Roo.bootstrap,
18312 cog.menu.items.push({
18314 xns: Roo.bootstrap,
18315 html : Clean styles,
18320 editorcore.insertTag(this.tagname);
18329 this.xtype = 'NavSimplebar';
18331 for(var i=0;i< children.length;i++) {
18333 this.buttons.add(this.addxtypeChild(children[i]));
18337 editor.on('editorevent', this.updateToolbar, this);
18339 onBtnClick : function(id)
18341 this.editorcore.relayCmd(id);
18342 this.editorcore.focus();
18346 * Protected method that will not generally be called directly. It triggers
18347 * a toolbar update by reading the markup state of the current selection in the editor.
18349 updateToolbar: function(){
18351 if(!this.editorcore.activated){
18352 this.editor.onFirstFocus(); // is this neeed?
18356 var btns = this.buttons;
18357 var doc = this.editorcore.doc;
18358 btns.get('bold').setActive(doc.queryCommandState('bold'));
18359 btns.get('italic').setActive(doc.queryCommandState('italic'));
18360 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18362 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18363 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18364 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18366 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18367 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18370 var ans = this.editorcore.getAllAncestors();
18371 if (this.formatCombo) {
18374 var store = this.formatCombo.store;
18375 this.formatCombo.setValue("");
18376 for (var i =0; i < ans.length;i++) {
18377 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18379 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18387 // hides menus... - so this cant be on a menu...
18388 Roo.bootstrap.MenuMgr.hideAll();
18390 Roo.bootstrap.MenuMgr.hideAll();
18391 //this.editorsyncValue();
18393 onFirstFocus: function() {
18394 this.buttons.each(function(item){
18398 toggleSourceEdit : function(sourceEditMode){
18401 if(sourceEditMode){
18402 Roo.log("disabling buttons");
18403 this.buttons.each( function(item){
18404 if(item.cmd != 'pencil'){
18410 Roo.log("enabling buttons");
18411 if(this.editorcore.initialized){
18412 this.buttons.each( function(item){
18418 Roo.log("calling toggole on editor");
18419 // tell the editor that it's been pressed..
18420 this.editor.toggleSourceEdit(sourceEditMode);
18430 * @class Roo.bootstrap.Table.AbstractSelectionModel
18431 * @extends Roo.util.Observable
18432 * Abstract base class for grid SelectionModels. It provides the interface that should be
18433 * implemented by descendant classes. This class should not be directly instantiated.
18436 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18437 this.locked = false;
18438 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18442 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18443 /** @ignore Called by the grid automatically. Do not call directly. */
18444 init : function(grid){
18450 * Locks the selections.
18453 this.locked = true;
18457 * Unlocks the selections.
18459 unlock : function(){
18460 this.locked = false;
18464 * Returns true if the selections are locked.
18465 * @return {Boolean}
18467 isLocked : function(){
18468 return this.locked;
18472 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18473 * @class Roo.bootstrap.Table.RowSelectionModel
18474 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18475 * It supports multiple selections and keyboard selection/navigation.
18477 * @param {Object} config
18480 Roo.bootstrap.Table.RowSelectionModel = function(config){
18481 Roo.apply(this, config);
18482 this.selections = new Roo.util.MixedCollection(false, function(o){
18487 this.lastActive = false;
18491 * @event selectionchange
18492 * Fires when the selection changes
18493 * @param {SelectionModel} this
18495 "selectionchange" : true,
18497 * @event afterselectionchange
18498 * Fires after the selection changes (eg. by key press or clicking)
18499 * @param {SelectionModel} this
18501 "afterselectionchange" : true,
18503 * @event beforerowselect
18504 * Fires when a row is selected being selected, return false to cancel.
18505 * @param {SelectionModel} this
18506 * @param {Number} rowIndex The selected index
18507 * @param {Boolean} keepExisting False if other selections will be cleared
18509 "beforerowselect" : true,
18512 * Fires when a row is selected.
18513 * @param {SelectionModel} this
18514 * @param {Number} rowIndex The selected index
18515 * @param {Roo.data.Record} r The record
18517 "rowselect" : true,
18519 * @event rowdeselect
18520 * Fires when a row is deselected.
18521 * @param {SelectionModel} this
18522 * @param {Number} rowIndex The selected index
18524 "rowdeselect" : true
18526 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18527 this.locked = false;
18530 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18532 * @cfg {Boolean} singleSelect
18533 * True to allow selection of only one row at a time (defaults to false)
18535 singleSelect : false,
18538 initEvents : function(){
18540 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18541 this.grid.on("mousedown", this.handleMouseDown, this);
18542 }else{ // allow click to work like normal
18543 this.grid.on("rowclick", this.handleDragableRowClick, this);
18546 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18547 "up" : function(e){
18549 this.selectPrevious(e.shiftKey);
18550 }else if(this.last !== false && this.lastActive !== false){
18551 var last = this.last;
18552 this.selectRange(this.last, this.lastActive-1);
18553 this.grid.getView().focusRow(this.lastActive);
18554 if(last !== false){
18558 this.selectFirstRow();
18560 this.fireEvent("afterselectionchange", this);
18562 "down" : function(e){
18564 this.selectNext(e.shiftKey);
18565 }else if(this.last !== false && this.lastActive !== false){
18566 var last = this.last;
18567 this.selectRange(this.last, this.lastActive+1);
18568 this.grid.getView().focusRow(this.lastActive);
18569 if(last !== false){
18573 this.selectFirstRow();
18575 this.fireEvent("afterselectionchange", this);
18580 var view = this.grid.view;
18581 view.on("refresh", this.onRefresh, this);
18582 view.on("rowupdated", this.onRowUpdated, this);
18583 view.on("rowremoved", this.onRemove, this);
18587 onRefresh : function(){
18588 var ds = this.grid.dataSource, i, v = this.grid.view;
18589 var s = this.selections;
18590 s.each(function(r){
18591 if((i = ds.indexOfId(r.id)) != -1){
18600 onRemove : function(v, index, r){
18601 this.selections.remove(r);
18605 onRowUpdated : function(v, index, r){
18606 if(this.isSelected(r)){
18607 v.onRowSelect(index);
18613 * @param {Array} records The records to select
18614 * @param {Boolean} keepExisting (optional) True to keep existing selections
18616 selectRecords : function(records, keepExisting){
18618 this.clearSelections();
18620 var ds = this.grid.dataSource;
18621 for(var i = 0, len = records.length; i < len; i++){
18622 this.selectRow(ds.indexOf(records[i]), true);
18627 * Gets the number of selected rows.
18630 getCount : function(){
18631 return this.selections.length;
18635 * Selects the first row in the grid.
18637 selectFirstRow : function(){
18642 * Select the last row.
18643 * @param {Boolean} keepExisting (optional) True to keep existing selections
18645 selectLastRow : function(keepExisting){
18646 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18650 * Selects the row immediately following the last selected row.
18651 * @param {Boolean} keepExisting (optional) True to keep existing selections
18653 selectNext : function(keepExisting){
18654 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18655 this.selectRow(this.last+1, keepExisting);
18656 this.grid.getView().focusRow(this.last);
18661 * Selects the row that precedes the last selected row.
18662 * @param {Boolean} keepExisting (optional) True to keep existing selections
18664 selectPrevious : function(keepExisting){
18666 this.selectRow(this.last-1, keepExisting);
18667 this.grid.getView().focusRow(this.last);
18672 * Returns the selected records
18673 * @return {Array} Array of selected records
18675 getSelections : function(){
18676 return [].concat(this.selections.items);
18680 * Returns the first selected record.
18683 getSelected : function(){
18684 return this.selections.itemAt(0);
18689 * Clears all selections.
18691 clearSelections : function(fast){
18692 if(this.locked) return;
18694 var ds = this.grid.dataSource;
18695 var s = this.selections;
18696 s.each(function(r){
18697 this.deselectRow(ds.indexOfId(r.id));
18701 this.selections.clear();
18708 * Selects all rows.
18710 selectAll : function(){
18711 if(this.locked) return;
18712 this.selections.clear();
18713 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18714 this.selectRow(i, true);
18719 * Returns True if there is a selection.
18720 * @return {Boolean}
18722 hasSelection : function(){
18723 return this.selections.length > 0;
18727 * Returns True if the specified row is selected.
18728 * @param {Number/Record} record The record or index of the record to check
18729 * @return {Boolean}
18731 isSelected : function(index){
18732 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18733 return (r && this.selections.key(r.id) ? true : false);
18737 * Returns True if the specified record id is selected.
18738 * @param {String} id The id of record to check
18739 * @return {Boolean}
18741 isIdSelected : function(id){
18742 return (this.selections.key(id) ? true : false);
18746 handleMouseDown : function(e, t){
18747 var view = this.grid.getView(), rowIndex;
18748 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18751 if(e.shiftKey && this.last !== false){
18752 var last = this.last;
18753 this.selectRange(last, rowIndex, e.ctrlKey);
18754 this.last = last; // reset the last
18755 view.focusRow(rowIndex);
18757 var isSelected = this.isSelected(rowIndex);
18758 if(e.button !== 0 && isSelected){
18759 view.focusRow(rowIndex);
18760 }else if(e.ctrlKey && isSelected){
18761 this.deselectRow(rowIndex);
18762 }else if(!isSelected){
18763 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18764 view.focusRow(rowIndex);
18767 this.fireEvent("afterselectionchange", this);
18770 handleDragableRowClick : function(grid, rowIndex, e)
18772 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18773 this.selectRow(rowIndex, false);
18774 grid.view.focusRow(rowIndex);
18775 this.fireEvent("afterselectionchange", this);
18780 * Selects multiple rows.
18781 * @param {Array} rows Array of the indexes of the row to select
18782 * @param {Boolean} keepExisting (optional) True to keep existing selections
18784 selectRows : function(rows, keepExisting){
18786 this.clearSelections();
18788 for(var i = 0, len = rows.length; i < len; i++){
18789 this.selectRow(rows[i], true);
18794 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18795 * @param {Number} startRow The index of the first row in the range
18796 * @param {Number} endRow The index of the last row in the range
18797 * @param {Boolean} keepExisting (optional) True to retain existing selections
18799 selectRange : function(startRow, endRow, keepExisting){
18800 if(this.locked) return;
18802 this.clearSelections();
18804 if(startRow <= endRow){
18805 for(var i = startRow; i <= endRow; i++){
18806 this.selectRow(i, true);
18809 for(var i = startRow; i >= endRow; i--){
18810 this.selectRow(i, true);
18816 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18817 * @param {Number} startRow The index of the first row in the range
18818 * @param {Number} endRow The index of the last row in the range
18820 deselectRange : function(startRow, endRow, preventViewNotify){
18821 if(this.locked) return;
18822 for(var i = startRow; i <= endRow; i++){
18823 this.deselectRow(i, preventViewNotify);
18829 * @param {Number} row The index of the row to select
18830 * @param {Boolean} keepExisting (optional) True to keep existing selections
18832 selectRow : function(index, keepExisting, preventViewNotify){
18833 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18834 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18835 if(!keepExisting || this.singleSelect){
18836 this.clearSelections();
18838 var r = this.grid.dataSource.getAt(index);
18839 this.selections.add(r);
18840 this.last = this.lastActive = index;
18841 if(!preventViewNotify){
18842 this.grid.getView().onRowSelect(index);
18844 this.fireEvent("rowselect", this, index, r);
18845 this.fireEvent("selectionchange", this);
18851 * @param {Number} row The index of the row to deselect
18853 deselectRow : function(index, preventViewNotify){
18854 if(this.locked) return;
18855 if(this.last == index){
18858 if(this.lastActive == index){
18859 this.lastActive = false;
18861 var r = this.grid.dataSource.getAt(index);
18862 this.selections.remove(r);
18863 if(!preventViewNotify){
18864 this.grid.getView().onRowDeselect(index);
18866 this.fireEvent("rowdeselect", this, index);
18867 this.fireEvent("selectionchange", this);
18871 restoreLast : function(){
18873 this.last = this._last;
18878 acceptsNav : function(row, col, cm){
18879 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18883 onEditorKey : function(field, e){
18884 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18889 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18891 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18893 }else if(k == e.ENTER && !e.ctrlKey){
18897 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18899 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18901 }else if(k == e.ESC){
18905 g.startEditing(newCell[0], newCell[1]);
18910 * Ext JS Library 1.1.1
18911 * Copyright(c) 2006-2007, Ext JS, LLC.
18913 * Originally Released Under LGPL - original licence link has changed is not relivant.
18916 * <script type="text/javascript">
18920 * @class Roo.bootstrap.PagingToolbar
18922 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18924 * Create a new PagingToolbar
18925 * @param {Object} config The config object
18927 Roo.bootstrap.PagingToolbar = function(config)
18929 // old args format still supported... - xtype is prefered..
18930 // created from xtype...
18931 var ds = config.dataSource;
18932 this.toolbarItems = [];
18933 if (config.items) {
18934 this.toolbarItems = config.items;
18935 // config.items = [];
18938 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18945 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18949 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18951 * @cfg {Roo.data.Store} dataSource
18952 * The underlying data store providing the paged data
18955 * @cfg {String/HTMLElement/Element} container
18956 * container The id or element that will contain the toolbar
18959 * @cfg {Boolean} displayInfo
18960 * True to display the displayMsg (defaults to false)
18963 * @cfg {Number} pageSize
18964 * The number of records to display per page (defaults to 20)
18968 * @cfg {String} displayMsg
18969 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18971 displayMsg : 'Displaying {0} - {1} of {2}',
18973 * @cfg {String} emptyMsg
18974 * The message to display when no records are found (defaults to "No data to display")
18976 emptyMsg : 'No data to display',
18978 * Customizable piece of the default paging text (defaults to "Page")
18981 beforePageText : "Page",
18983 * Customizable piece of the default paging text (defaults to "of %0")
18986 afterPageText : "of {0}",
18988 * Customizable piece of the default paging text (defaults to "First Page")
18991 firstText : "First Page",
18993 * Customizable piece of the default paging text (defaults to "Previous Page")
18996 prevText : "Previous Page",
18998 * Customizable piece of the default paging text (defaults to "Next Page")
19001 nextText : "Next Page",
19003 * Customizable piece of the default paging text (defaults to "Last Page")
19006 lastText : "Last Page",
19008 * Customizable piece of the default paging text (defaults to "Refresh")
19011 refreshText : "Refresh",
19015 onRender : function(ct, position)
19017 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19018 this.navgroup.parentId = this.id;
19019 this.navgroup.onRender(this.el, null);
19020 // add the buttons to the navgroup
19022 if(this.displayInfo){
19023 Roo.log(this.el.select('ul.navbar-nav',true).first());
19024 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19025 this.displayEl = this.el.select('.x-paging-info', true).first();
19026 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19027 // this.displayEl = navel.el.select('span',true).first();
19033 Roo.each(_this.buttons, function(e){
19034 Roo.factory(e).onRender(_this.el, null);
19038 Roo.each(_this.toolbarItems, function(e) {
19039 _this.navgroup.addItem(e);
19042 this.first = this.navgroup.addItem({
19043 tooltip: this.firstText,
19045 icon : 'fa fa-backward',
19047 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19050 this.prev = this.navgroup.addItem({
19051 tooltip: this.prevText,
19053 icon : 'fa fa-step-backward',
19055 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19057 //this.addSeparator();
19060 var field = this.navgroup.addItem( {
19062 cls : 'x-paging-position',
19064 html : this.beforePageText +
19065 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19066 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19069 this.field = field.el.select('input', true).first();
19070 this.field.on("keydown", this.onPagingKeydown, this);
19071 this.field.on("focus", function(){this.dom.select();});
19074 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19075 //this.field.setHeight(18);
19076 //this.addSeparator();
19077 this.next = this.navgroup.addItem({
19078 tooltip: this.nextText,
19080 html : ' <i class="fa fa-step-forward">',
19082 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19084 this.last = this.navgroup.addItem({
19085 tooltip: this.lastText,
19086 icon : 'fa fa-forward',
19089 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19091 //this.addSeparator();
19092 this.loading = this.navgroup.addItem({
19093 tooltip: this.refreshText,
19094 icon: 'fa fa-refresh',
19096 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19102 updateInfo : function(){
19103 if(this.displayEl){
19104 var count = this.ds.getCount();
19105 var msg = count == 0 ?
19109 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19111 this.displayEl.update(msg);
19116 onLoad : function(ds, r, o){
19117 this.cursor = o.params ? o.params.start : 0;
19118 var d = this.getPageData(),
19122 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19123 this.field.dom.value = ap;
19124 this.first.setDisabled(ap == 1);
19125 this.prev.setDisabled(ap == 1);
19126 this.next.setDisabled(ap == ps);
19127 this.last.setDisabled(ap == ps);
19128 this.loading.enable();
19133 getPageData : function(){
19134 var total = this.ds.getTotalCount();
19137 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19138 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19143 onLoadError : function(){
19144 this.loading.enable();
19148 onPagingKeydown : function(e){
19149 var k = e.getKey();
19150 var d = this.getPageData();
19152 var v = this.field.dom.value, pageNum;
19153 if(!v || isNaN(pageNum = parseInt(v, 10))){
19154 this.field.dom.value = d.activePage;
19157 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19158 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19161 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))
19163 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19164 this.field.dom.value = pageNum;
19165 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19168 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19170 var v = this.field.dom.value, pageNum;
19171 var increment = (e.shiftKey) ? 10 : 1;
19172 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19174 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19175 this.field.dom.value = d.activePage;
19178 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19180 this.field.dom.value = parseInt(v, 10) + increment;
19181 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19182 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19189 beforeLoad : function(){
19191 this.loading.disable();
19196 onClick : function(which){
19203 ds.load({params:{start: 0, limit: this.pageSize}});
19206 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19209 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19212 var total = ds.getTotalCount();
19213 var extra = total % this.pageSize;
19214 var lastStart = extra ? (total - extra) : total-this.pageSize;
19215 ds.load({params:{start: lastStart, limit: this.pageSize}});
19218 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19224 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19225 * @param {Roo.data.Store} store The data store to unbind
19227 unbind : function(ds){
19228 ds.un("beforeload", this.beforeLoad, this);
19229 ds.un("load", this.onLoad, this);
19230 ds.un("loadexception", this.onLoadError, this);
19231 ds.un("remove", this.updateInfo, this);
19232 ds.un("add", this.updateInfo, this);
19233 this.ds = undefined;
19237 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19238 * @param {Roo.data.Store} store The data store to bind
19240 bind : function(ds){
19241 ds.on("beforeload", this.beforeLoad, this);
19242 ds.on("load", this.onLoad, this);
19243 ds.on("loadexception", this.onLoadError, this);
19244 ds.on("remove", this.updateInfo, this);
19245 ds.on("add", this.updateInfo, this);
19256 * @class Roo.bootstrap.MessageBar
19257 * @extends Roo.bootstrap.Component
19258 * Bootstrap MessageBar class
19259 * @cfg {String} html contents of the MessageBar
19260 * @cfg {String} weight (info | success | warning | danger) default info
19261 * @cfg {String} beforeClass insert the bar before the given class
19262 * @cfg {Boolean} closable (true | false) default false
19263 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19266 * Create a new Element
19267 * @param {Object} config The config object
19270 Roo.bootstrap.MessageBar = function(config){
19271 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19274 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19280 beforeClass: 'bootstrap-sticky-wrap',
19282 getAutoCreate : function(){
19286 cls: 'alert alert-dismissable alert-' + this.weight,
19291 html: this.html || ''
19297 cfg.cls += ' alert-messages-fixed';
19311 onRender : function(ct, position)
19313 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19316 var cfg = Roo.apply({}, this.getAutoCreate());
19320 cfg.cls += ' ' + this.cls;
19323 cfg.style = this.style;
19325 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19327 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19330 this.el.select('>button.close').on('click', this.hide, this);
19336 if (!this.rendered) {
19342 this.fireEvent('show', this);
19348 if (!this.rendered) {
19354 this.fireEvent('hide', this);
19357 update : function()
19359 // var e = this.el.dom.firstChild;
19361 // if(this.closable){
19362 // e = e.nextSibling;
19365 // e.data = this.html || '';
19367 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19383 * @class Roo.bootstrap.Graph
19384 * @extends Roo.bootstrap.Component
19385 * Bootstrap Graph class
19389 @cfg {String} graphtype bar | vbar | pie
19390 @cfg {number} g_x coodinator | centre x (pie)
19391 @cfg {number} g_y coodinator | centre y (pie)
19392 @cfg {number} g_r radius (pie)
19393 @cfg {number} g_height height of the chart (respected by all elements in the set)
19394 @cfg {number} g_width width of the chart (respected by all elements in the set)
19395 @cfg {Object} title The title of the chart
19398 -opts (object) options for the chart
19400 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19401 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19403 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.
19404 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19406 o stretch (boolean)
19408 -opts (object) options for the pie
19411 o startAngle (number)
19412 o endAngle (number)
19416 * Create a new Input
19417 * @param {Object} config The config object
19420 Roo.bootstrap.Graph = function(config){
19421 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19427 * The img click event for the img.
19428 * @param {Roo.EventObject} e
19434 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19445 //g_colors: this.colors,
19452 getAutoCreate : function(){
19463 onRender : function(ct,position){
19464 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19465 this.raphael = Raphael(this.el.dom);
19467 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19468 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19469 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19470 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19472 r.text(160, 10, "Single Series Chart").attr(txtattr);
19473 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19474 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19475 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19477 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19478 r.barchart(330, 10, 300, 220, data1);
19479 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19480 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19483 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19484 // r.barchart(30, 30, 560, 250, xdata, {
19485 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19486 // axis : "0 0 1 1",
19487 // axisxlabels : xdata
19488 // //yvalues : cols,
19491 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19493 // this.load(null,xdata,{
19494 // axis : "0 0 1 1",
19495 // axisxlabels : xdata
19500 load : function(graphtype,xdata,opts){
19501 this.raphael.clear();
19503 graphtype = this.graphtype;
19508 var r = this.raphael,
19509 fin = function () {
19510 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19512 fout = function () {
19513 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19515 pfin = function() {
19516 this.sector.stop();
19517 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19520 this.label[0].stop();
19521 this.label[0].attr({ r: 7.5 });
19522 this.label[1].attr({ "font-weight": 800 });
19525 pfout = function() {
19526 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19529 this.label[0].animate({ r: 5 }, 500, "bounce");
19530 this.label[1].attr({ "font-weight": 400 });
19536 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19539 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19542 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19543 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19545 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19552 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19557 setTitle: function(o)
19562 initEvents: function() {
19565 this.el.on('click', this.onClick, this);
19569 onClick : function(e)
19571 Roo.log('img onclick');
19572 this.fireEvent('click', this, e);
19584 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19587 * @class Roo.bootstrap.dash.NumberBox
19588 * @extends Roo.bootstrap.Component
19589 * Bootstrap NumberBox class
19590 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19591 * @cfg {String} headline Box headline
19592 * @cfg {String} content Box content
19593 * @cfg {String} icon Box icon
19594 * @cfg {String} footer Footer text
19595 * @cfg {String} fhref Footer href
19598 * Create a new NumberBox
19599 * @param {Object} config The config object
19603 Roo.bootstrap.dash.NumberBox = function(config){
19604 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19608 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19618 getAutoCreate : function(){
19622 cls : 'small-box bg-' + this.bgcolor,
19630 cls : 'roo-headline',
19631 html : this.headline
19635 cls : 'roo-content',
19636 html : this.content
19650 cls : 'ion ' + this.icon
19659 cls : 'small-box-footer',
19660 href : this.fhref || '#',
19664 cfg.cn.push(footer);
19671 onRender : function(ct,position){
19672 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19679 setHeadline: function (value)
19681 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19684 setFooter: function (value, href)
19686 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19689 this.el.select('a.small-box-footer',true).first().attr('href', href);
19694 setContent: function (value)
19696 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19699 initEvents: function()
19713 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19716 * @class Roo.bootstrap.dash.TabBox
19717 * @extends Roo.bootstrap.Component
19718 * Bootstrap TabBox class
19719 * @cfg {String} title Title of the TabBox
19720 * @cfg {String} icon Icon of the TabBox
19721 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19724 * Create a new TabBox
19725 * @param {Object} config The config object
19729 Roo.bootstrap.dash.TabBox = function(config){
19730 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19735 * When a pane is added
19736 * @param {Roo.bootstrap.dash.TabPane} pane
19743 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19749 getChildContainer : function()
19751 return this.el.select('.tab-content', true).first();
19754 getAutoCreate : function(){
19758 cls: 'pull-left header',
19766 cls: 'fa ' + this.icon
19773 cls: 'nav-tabs-custom',
19777 cls: 'nav nav-tabs pull-right',
19784 cls: 'tab-content no-padding',
19792 initEvents : function()
19794 //Roo.log('add add pane handler');
19795 this.on('addpane', this.onAddPane, this);
19798 * Updates the box title
19799 * @param {String} html to set the title to.
19801 setTitle : function(value)
19803 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19805 onAddPane : function(pane)
19807 //Roo.log('addpane');
19809 // tabs are rendere left to right..
19810 if(!this.showtabs){
19814 var ctr = this.el.select('.nav-tabs', true).first();
19817 var existing = ctr.select('.nav-tab',true);
19818 var qty = existing.getCount();;
19821 var tab = ctr.createChild({
19823 cls : 'nav-tab' + (qty ? '' : ' active'),
19831 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19834 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19836 pane.el.addClass('active');
19841 onTabClick : function(ev,un,ob,pane)
19843 //Roo.log('tab - prev default');
19844 ev.preventDefault();
19847 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19848 pane.tab.addClass('active');
19849 //Roo.log(pane.title);
19850 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19851 // technically we should have a deactivate event.. but maybe add later.
19852 // and it should not de-activate the selected tab...
19854 pane.el.addClass('active');
19855 pane.fireEvent('activate');
19870 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19872 * @class Roo.bootstrap.TabPane
19873 * @extends Roo.bootstrap.Component
19874 * Bootstrap TabPane class
19875 * @cfg {Boolean} active (false | true) Default false
19876 * @cfg {String} title title of panel
19880 * Create a new TabPane
19881 * @param {Object} config The config object
19884 Roo.bootstrap.dash.TabPane = function(config){
19885 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19891 * When a pane is activated
19892 * @param {Roo.bootstrap.dash.TabPane} pane
19899 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19904 // the tabBox that this is attached to.
19907 getAutoCreate : function()
19915 cfg.cls += ' active';
19920 initEvents : function()
19922 //Roo.log('trigger add pane handler');
19923 this.parent().fireEvent('addpane', this)
19927 * Updates the tab title
19928 * @param {String} html to set the title to.
19930 setTitle: function(str)
19936 this.tab.select('a', true).first().dom.innerHTML = str;
19953 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19956 * @class Roo.bootstrap.menu.Menu
19957 * @extends Roo.bootstrap.Component
19958 * Bootstrap Menu class - container for Menu
19959 * @cfg {String} html Text of the menu
19960 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19961 * @cfg {String} icon Font awesome icon
19962 * @cfg {String} pos Menu align to (top | bottom) default bottom
19966 * Create a new Menu
19967 * @param {Object} config The config object
19971 Roo.bootstrap.menu.Menu = function(config){
19972 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19976 * @event beforeshow
19977 * Fires before this menu is displayed
19978 * @param {Roo.bootstrap.menu.Menu} this
19982 * @event beforehide
19983 * Fires before this menu is hidden
19984 * @param {Roo.bootstrap.menu.Menu} this
19989 * Fires after this menu is displayed
19990 * @param {Roo.bootstrap.menu.Menu} this
19995 * Fires after this menu is hidden
19996 * @param {Roo.bootstrap.menu.Menu} this
20001 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20002 * @param {Roo.bootstrap.menu.Menu} this
20003 * @param {Roo.EventObject} e
20010 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20014 weight : 'default',
20019 getChildContainer : function() {
20020 if(this.isSubMenu){
20024 return this.el.select('ul.dropdown-menu', true).first();
20027 getAutoCreate : function()
20032 cls : 'roo-menu-text',
20040 cls : 'fa ' + this.icon
20051 cls : 'dropdown-button btn btn-' + this.weight,
20056 cls : 'dropdown-toggle btn btn-' + this.weight,
20066 cls : 'dropdown-menu'
20072 if(this.pos == 'top'){
20073 cfg.cls += ' dropup';
20076 if(this.isSubMenu){
20079 cls : 'dropdown-menu'
20086 onRender : function(ct, position)
20088 this.isSubMenu = ct.hasClass('dropdown-submenu');
20090 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20093 initEvents : function()
20095 if(this.isSubMenu){
20099 this.hidden = true;
20101 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20102 this.triggerEl.on('click', this.onTriggerPress, this);
20104 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20105 this.buttonEl.on('click', this.onClick, this);
20111 if(this.isSubMenu){
20115 return this.el.select('ul.dropdown-menu', true).first();
20118 onClick : function(e)
20120 this.fireEvent("click", this, e);
20123 onTriggerPress : function(e)
20125 if (this.isVisible()) {
20132 isVisible : function(){
20133 return !this.hidden;
20138 this.fireEvent("beforeshow", this);
20140 this.hidden = false;
20141 this.el.addClass('open');
20143 Roo.get(document).on("mouseup", this.onMouseUp, this);
20145 this.fireEvent("show", this);
20152 this.fireEvent("beforehide", this);
20154 this.hidden = true;
20155 this.el.removeClass('open');
20157 Roo.get(document).un("mouseup", this.onMouseUp);
20159 this.fireEvent("hide", this);
20162 onMouseUp : function()
20176 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20179 * @class Roo.bootstrap.menu.Item
20180 * @extends Roo.bootstrap.Component
20181 * Bootstrap MenuItem class
20182 * @cfg {Boolean} submenu (true | false) default false
20183 * @cfg {String} html text of the item
20184 * @cfg {String} href the link
20185 * @cfg {Boolean} disable (true | false) default false
20186 * @cfg {Boolean} preventDefault (true | false) default true
20187 * @cfg {String} icon Font awesome icon
20188 * @cfg {String} pos Submenu align to (left | right) default right
20192 * Create a new Item
20193 * @param {Object} config The config object
20197 Roo.bootstrap.menu.Item = function(config){
20198 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20202 * Fires when the mouse is hovering over this menu
20203 * @param {Roo.bootstrap.menu.Item} this
20204 * @param {Roo.EventObject} e
20209 * Fires when the mouse exits this menu
20210 * @param {Roo.bootstrap.menu.Item} this
20211 * @param {Roo.EventObject} e
20217 * The raw click event for the entire grid.
20218 * @param {Roo.EventObject} e
20224 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20229 preventDefault: true,
20234 getAutoCreate : function()
20239 cls : 'roo-menu-item-text',
20247 cls : 'fa ' + this.icon
20256 href : this.href || '#',
20263 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20267 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20269 if(this.pos == 'left'){
20270 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20277 initEvents : function()
20279 this.el.on('mouseover', this.onMouseOver, this);
20280 this.el.on('mouseout', this.onMouseOut, this);
20282 this.el.select('a', true).first().on('click', this.onClick, this);
20286 onClick : function(e)
20288 if(this.preventDefault){
20289 e.preventDefault();
20292 this.fireEvent("click", this, e);
20295 onMouseOver : function(e)
20297 if(this.submenu && this.pos == 'left'){
20298 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20301 this.fireEvent("mouseover", this, e);
20304 onMouseOut : function(e)
20306 this.fireEvent("mouseout", this, e);
20318 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20321 * @class Roo.bootstrap.menu.Separator
20322 * @extends Roo.bootstrap.Component
20323 * Bootstrap Separator class
20326 * Create a new Separator
20327 * @param {Object} config The config object
20331 Roo.bootstrap.menu.Separator = function(config){
20332 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20335 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20337 getAutoCreate : function(){