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){
3704 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3705 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3706 this.parent().setActiveItem(this);
3711 isActive: function () {
3714 setActive : function(state, fire, is_was_active)
3716 if (this.active && !state & this.navId) {
3717 this.was_active = true;
3718 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3720 nv.clearWasActive(this);
3724 this.active = state;
3727 this.el.removeClass('active');
3728 } else if (!this.el.hasClass('active')) {
3729 this.el.addClass('active');
3732 this.fireEvent('changed', this, state);
3735 // show a panel if it's registered and related..
3737 if (!this.navId || !this.tabId || !state || is_was_active) {
3741 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3745 var pan = tg.getPanelByName(this.tabId);
3749 // if we can not flip to new panel - go back to old nav highlight..
3750 if (false == tg.showPanel(pan)) {
3751 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3753 var onav = nv.getWasActive();
3755 onav.setActive(true, false, true);
3764 // this should not be here...
3765 setDisabled : function(state)
3767 this.disabled = state;
3769 this.el.removeClass('disabled');
3770 } else if (!this.el.hasClass('disabled')) {
3771 this.el.addClass('disabled');
3784 * <span> icon </span>
3785 * <span> text </span>
3786 * <span>badge </span>
3790 * @class Roo.bootstrap.NavSidebarItem
3791 * @extends Roo.bootstrap.NavItem
3792 * Bootstrap Navbar.NavSidebarItem class
3794 * Create a new Navbar Button
3795 * @param {Object} config The config object
3797 Roo.bootstrap.NavSidebarItem = function(config){
3798 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3803 * The raw click event for the entire grid.
3804 * @param {Roo.EventObject} e
3809 * Fires when the active item active state changes
3810 * @param {Roo.bootstrap.NavSidebarItem} this
3811 * @param {boolean} state the new state
3819 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3822 getAutoCreate : function(){
3827 href : this.href || '#',
3839 html : this.html || ''
3844 cfg.cls += ' active';
3848 if (this.glyphicon || this.icon) {
3849 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3850 a.cn.push({ tag : 'i', cls : c }) ;
3855 if (this.badge !== '') {
3856 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3860 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3861 a.cls += 'dropdown-toggle treeview' ;
3885 * @class Roo.bootstrap.Row
3886 * @extends Roo.bootstrap.Component
3887 * Bootstrap Row class (contains columns...)
3891 * @param {Object} config The config object
3894 Roo.bootstrap.Row = function(config){
3895 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3898 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3900 getAutoCreate : function(){
3919 * @class Roo.bootstrap.Element
3920 * @extends Roo.bootstrap.Component
3921 * Bootstrap Element class
3922 * @cfg {String} html contents of the element
3923 * @cfg {String} tag tag of the element
3924 * @cfg {String} cls class of the element
3927 * Create a new Element
3928 * @param {Object} config The config object
3931 Roo.bootstrap.Element = function(config){
3932 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3935 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3942 getAutoCreate : function(){
3967 * @class Roo.bootstrap.Pagination
3968 * @extends Roo.bootstrap.Component
3969 * Bootstrap Pagination class
3970 * @cfg {String} size xs | sm | md | lg
3971 * @cfg {Boolean} inverse false | true
3974 * Create a new Pagination
3975 * @param {Object} config The config object
3978 Roo.bootstrap.Pagination = function(config){
3979 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3982 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3988 getAutoCreate : function(){
3994 cfg.cls += ' inverse';
4000 cfg.cls += " " + this.cls;
4018 * @class Roo.bootstrap.PaginationItem
4019 * @extends Roo.bootstrap.Component
4020 * Bootstrap PaginationItem class
4021 * @cfg {String} html text
4022 * @cfg {String} href the link
4023 * @cfg {Boolean} preventDefault (true | false) default true
4024 * @cfg {Boolean} active (true | false) default false
4028 * Create a new PaginationItem
4029 * @param {Object} config The config object
4033 Roo.bootstrap.PaginationItem = function(config){
4034 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4039 * The raw click event for the entire grid.
4040 * @param {Roo.EventObject} e
4046 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4050 preventDefault: true,
4054 getAutoCreate : function(){
4060 href : this.href ? this.href : '#',
4061 html : this.html ? this.html : ''
4071 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4077 initEvents: function() {
4079 this.el.on('click', this.onClick, this);
4082 onClick : function(e)
4084 Roo.log('PaginationItem on click ');
4085 if(this.preventDefault){
4089 this.fireEvent('click', this, e);
4105 * @class Roo.bootstrap.Slider
4106 * @extends Roo.bootstrap.Component
4107 * Bootstrap Slider class
4110 * Create a new Slider
4111 * @param {Object} config The config object
4114 Roo.bootstrap.Slider = function(config){
4115 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4118 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4120 getAutoCreate : function(){
4124 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4128 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4140 * Ext JS Library 1.1.1
4141 * Copyright(c) 2006-2007, Ext JS, LLC.
4143 * Originally Released Under LGPL - original licence link has changed is not relivant.
4146 * <script type="text/javascript">
4151 * @class Roo.grid.ColumnModel
4152 * @extends Roo.util.Observable
4153 * This is the default implementation of a ColumnModel used by the Grid. It defines
4154 * the columns in the grid.
4157 var colModel = new Roo.grid.ColumnModel([
4158 {header: "Ticker", width: 60, sortable: true, locked: true},
4159 {header: "Company Name", width: 150, sortable: true},
4160 {header: "Market Cap.", width: 100, sortable: true},
4161 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4162 {header: "Employees", width: 100, sortable: true, resizable: false}
4167 * The config options listed for this class are options which may appear in each
4168 * individual column definition.
4169 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4171 * @param {Object} config An Array of column config objects. See this class's
4172 * config objects for details.
4174 Roo.grid.ColumnModel = function(config){
4176 * The config passed into the constructor
4178 this.config = config;
4181 // if no id, create one
4182 // if the column does not have a dataIndex mapping,
4183 // map it to the order it is in the config
4184 for(var i = 0, len = config.length; i < len; i++){
4186 if(typeof c.dataIndex == "undefined"){
4189 if(typeof c.renderer == "string"){
4190 c.renderer = Roo.util.Format[c.renderer];
4192 if(typeof c.id == "undefined"){
4195 if(c.editor && c.editor.xtype){
4196 c.editor = Roo.factory(c.editor, Roo.grid);
4198 if(c.editor && c.editor.isFormField){
4199 c.editor = new Roo.grid.GridEditor(c.editor);
4201 this.lookup[c.id] = c;
4205 * The width of columns which have no width specified (defaults to 100)
4208 this.defaultWidth = 100;
4211 * Default sortable of columns which have no sortable specified (defaults to false)
4214 this.defaultSortable = false;
4218 * @event widthchange
4219 * Fires when the width of a column changes.
4220 * @param {ColumnModel} this
4221 * @param {Number} columnIndex The column index
4222 * @param {Number} newWidth The new width
4224 "widthchange": true,
4226 * @event headerchange
4227 * Fires when the text of a header changes.
4228 * @param {ColumnModel} this
4229 * @param {Number} columnIndex The column index
4230 * @param {Number} newText The new header text
4232 "headerchange": true,
4234 * @event hiddenchange
4235 * Fires when a column is hidden or "unhidden".
4236 * @param {ColumnModel} this
4237 * @param {Number} columnIndex The column index
4238 * @param {Boolean} hidden true if hidden, false otherwise
4240 "hiddenchange": true,
4242 * @event columnmoved
4243 * Fires when a column is moved.
4244 * @param {ColumnModel} this
4245 * @param {Number} oldIndex
4246 * @param {Number} newIndex
4248 "columnmoved" : true,
4250 * @event columlockchange
4251 * Fires when a column's locked state is changed
4252 * @param {ColumnModel} this
4253 * @param {Number} colIndex
4254 * @param {Boolean} locked true if locked
4256 "columnlockchange" : true
4258 Roo.grid.ColumnModel.superclass.constructor.call(this);
4260 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4262 * @cfg {String} header The header text to display in the Grid view.
4265 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4266 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4267 * specified, the column's index is used as an index into the Record's data Array.
4270 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4271 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4274 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4275 * Defaults to the value of the {@link #defaultSortable} property.
4276 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4279 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4282 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4285 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4288 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4291 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4292 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4293 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4294 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4297 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4300 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4304 * Returns the id of the column at the specified index.
4305 * @param {Number} index The column index
4306 * @return {String} the id
4308 getColumnId : function(index){
4309 return this.config[index].id;
4313 * Returns the column for a specified id.
4314 * @param {String} id The column id
4315 * @return {Object} the column
4317 getColumnById : function(id){
4318 return this.lookup[id];
4323 * Returns the column for a specified dataIndex.
4324 * @param {String} dataIndex The column dataIndex
4325 * @return {Object|Boolean} the column or false if not found
4327 getColumnByDataIndex: function(dataIndex){
4328 var index = this.findColumnIndex(dataIndex);
4329 return index > -1 ? this.config[index] : false;
4333 * Returns the index for a specified column id.
4334 * @param {String} id The column id
4335 * @return {Number} the index, or -1 if not found
4337 getIndexById : function(id){
4338 for(var i = 0, len = this.config.length; i < len; i++){
4339 if(this.config[i].id == id){
4347 * Returns the index for a specified column dataIndex.
4348 * @param {String} dataIndex The column dataIndex
4349 * @return {Number} the index, or -1 if not found
4352 findColumnIndex : function(dataIndex){
4353 for(var i = 0, len = this.config.length; i < len; i++){
4354 if(this.config[i].dataIndex == dataIndex){
4362 moveColumn : function(oldIndex, newIndex){
4363 var c = this.config[oldIndex];
4364 this.config.splice(oldIndex, 1);
4365 this.config.splice(newIndex, 0, c);
4366 this.dataMap = null;
4367 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4370 isLocked : function(colIndex){
4371 return this.config[colIndex].locked === true;
4374 setLocked : function(colIndex, value, suppressEvent){
4375 if(this.isLocked(colIndex) == value){
4378 this.config[colIndex].locked = value;
4380 this.fireEvent("columnlockchange", this, colIndex, value);
4384 getTotalLockedWidth : function(){
4386 for(var i = 0; i < this.config.length; i++){
4387 if(this.isLocked(i) && !this.isHidden(i)){
4388 this.totalWidth += this.getColumnWidth(i);
4394 getLockedCount : function(){
4395 for(var i = 0, len = this.config.length; i < len; i++){
4396 if(!this.isLocked(i)){
4403 * Returns the number of columns.
4406 getColumnCount : function(visibleOnly){
4407 if(visibleOnly === true){
4409 for(var i = 0, len = this.config.length; i < len; i++){
4410 if(!this.isHidden(i)){
4416 return this.config.length;
4420 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4421 * @param {Function} fn
4422 * @param {Object} scope (optional)
4423 * @return {Array} result
4425 getColumnsBy : function(fn, scope){
4427 for(var i = 0, len = this.config.length; i < len; i++){
4428 var c = this.config[i];
4429 if(fn.call(scope||this, c, i) === true){
4437 * Returns true if the specified column is sortable.
4438 * @param {Number} col The column index
4441 isSortable : function(col){
4442 if(typeof this.config[col].sortable == "undefined"){
4443 return this.defaultSortable;
4445 return this.config[col].sortable;
4449 * Returns the rendering (formatting) function defined for the column.
4450 * @param {Number} col The column index.
4451 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4453 getRenderer : function(col){
4454 if(!this.config[col].renderer){
4455 return Roo.grid.ColumnModel.defaultRenderer;
4457 return this.config[col].renderer;
4461 * Sets the rendering (formatting) function for a column.
4462 * @param {Number} col The column index
4463 * @param {Function} fn The function to use to process the cell's raw data
4464 * to return HTML markup for the grid view. The render function is called with
4465 * the following parameters:<ul>
4466 * <li>Data value.</li>
4467 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4468 * <li>css A CSS style string to apply to the table cell.</li>
4469 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4470 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4471 * <li>Row index</li>
4472 * <li>Column index</li>
4473 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4475 setRenderer : function(col, fn){
4476 this.config[col].renderer = fn;
4480 * Returns the width for the specified column.
4481 * @param {Number} col The column index
4484 getColumnWidth : function(col){
4485 return this.config[col].width * 1 || this.defaultWidth;
4489 * Sets the width for a column.
4490 * @param {Number} col The column index
4491 * @param {Number} width The new width
4493 setColumnWidth : function(col, width, suppressEvent){
4494 this.config[col].width = width;
4495 this.totalWidth = null;
4497 this.fireEvent("widthchange", this, col, width);
4502 * Returns the total width of all columns.
4503 * @param {Boolean} includeHidden True to include hidden column widths
4506 getTotalWidth : function(includeHidden){
4507 if(!this.totalWidth){
4508 this.totalWidth = 0;
4509 for(var i = 0, len = this.config.length; i < len; i++){
4510 if(includeHidden || !this.isHidden(i)){
4511 this.totalWidth += this.getColumnWidth(i);
4515 return this.totalWidth;
4519 * Returns the header for the specified column.
4520 * @param {Number} col The column index
4523 getColumnHeader : function(col){
4524 return this.config[col].header;
4528 * Sets the header for a column.
4529 * @param {Number} col The column index
4530 * @param {String} header The new header
4532 setColumnHeader : function(col, header){
4533 this.config[col].header = header;
4534 this.fireEvent("headerchange", this, col, header);
4538 * Returns the tooltip for the specified column.
4539 * @param {Number} col The column index
4542 getColumnTooltip : function(col){
4543 return this.config[col].tooltip;
4546 * Sets the tooltip for a column.
4547 * @param {Number} col The column index
4548 * @param {String} tooltip The new tooltip
4550 setColumnTooltip : function(col, tooltip){
4551 this.config[col].tooltip = tooltip;
4555 * Returns the dataIndex for the specified column.
4556 * @param {Number} col The column index
4559 getDataIndex : function(col){
4560 return this.config[col].dataIndex;
4564 * Sets the dataIndex for a column.
4565 * @param {Number} col The column index
4566 * @param {Number} dataIndex The new dataIndex
4568 setDataIndex : function(col, dataIndex){
4569 this.config[col].dataIndex = dataIndex;
4575 * Returns true if the cell is editable.
4576 * @param {Number} colIndex The column index
4577 * @param {Number} rowIndex The row index
4580 isCellEditable : function(colIndex, rowIndex){
4581 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4585 * Returns the editor defined for the cell/column.
4586 * return false or null to disable editing.
4587 * @param {Number} colIndex The column index
4588 * @param {Number} rowIndex The row index
4591 getCellEditor : function(colIndex, rowIndex){
4592 return this.config[colIndex].editor;
4596 * Sets if a column is editable.
4597 * @param {Number} col The column index
4598 * @param {Boolean} editable True if the column is editable
4600 setEditable : function(col, editable){
4601 this.config[col].editable = editable;
4606 * Returns true if the column is hidden.
4607 * @param {Number} colIndex The column index
4610 isHidden : function(colIndex){
4611 return this.config[colIndex].hidden;
4616 * Returns true if the column width cannot be changed
4618 isFixed : function(colIndex){
4619 return this.config[colIndex].fixed;
4623 * Returns true if the column can be resized
4626 isResizable : function(colIndex){
4627 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4630 * Sets if a column is hidden.
4631 * @param {Number} colIndex The column index
4632 * @param {Boolean} hidden True if the column is hidden
4634 setHidden : function(colIndex, hidden){
4635 this.config[colIndex].hidden = hidden;
4636 this.totalWidth = null;
4637 this.fireEvent("hiddenchange", this, colIndex, hidden);
4641 * Sets the editor for a column.
4642 * @param {Number} col The column index
4643 * @param {Object} editor The editor object
4645 setEditor : function(col, editor){
4646 this.config[col].editor = editor;
4650 Roo.grid.ColumnModel.defaultRenderer = function(value){
4651 if(typeof value == "string" && value.length < 1){
4657 // Alias for backwards compatibility
4658 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4661 * Ext JS Library 1.1.1
4662 * Copyright(c) 2006-2007, Ext JS, LLC.
4664 * Originally Released Under LGPL - original licence link has changed is not relivant.
4667 * <script type="text/javascript">
4671 * @class Roo.LoadMask
4672 * A simple utility class for generically masking elements while loading data. If the element being masked has
4673 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4674 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4675 * element's UpdateManager load indicator and will be destroyed after the initial load.
4677 * Create a new LoadMask
4678 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4679 * @param {Object} config The config object
4681 Roo.LoadMask = function(el, config){
4682 this.el = Roo.get(el);
4683 Roo.apply(this, config);
4685 this.store.on('beforeload', this.onBeforeLoad, this);
4686 this.store.on('load', this.onLoad, this);
4687 this.store.on('loadexception', this.onLoadException, this);
4688 this.removeMask = false;
4690 var um = this.el.getUpdateManager();
4691 um.showLoadIndicator = false; // disable the default indicator
4692 um.on('beforeupdate', this.onBeforeLoad, this);
4693 um.on('update', this.onLoad, this);
4694 um.on('failure', this.onLoad, this);
4695 this.removeMask = true;
4699 Roo.LoadMask.prototype = {
4701 * @cfg {Boolean} removeMask
4702 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4703 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4707 * The text to display in a centered loading message box (defaults to 'Loading...')
4711 * @cfg {String} msgCls
4712 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4714 msgCls : 'x-mask-loading',
4717 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4723 * Disables the mask to prevent it from being displayed
4725 disable : function(){
4726 this.disabled = true;
4730 * Enables the mask so that it can be displayed
4732 enable : function(){
4733 this.disabled = false;
4736 onLoadException : function()
4740 if (typeof(arguments[3]) != 'undefined') {
4741 Roo.MessageBox.alert("Error loading",arguments[3]);
4745 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4746 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4755 this.el.unmask(this.removeMask);
4760 this.el.unmask(this.removeMask);
4764 onBeforeLoad : function(){
4766 this.el.mask(this.msg, this.msgCls);
4771 destroy : function(){
4773 this.store.un('beforeload', this.onBeforeLoad, this);
4774 this.store.un('load', this.onLoad, this);
4775 this.store.un('loadexception', this.onLoadException, this);
4777 var um = this.el.getUpdateManager();
4778 um.un('beforeupdate', this.onBeforeLoad, this);
4779 um.un('update', this.onLoad, this);
4780 um.un('failure', this.onLoad, this);
4791 * @class Roo.bootstrap.Table
4792 * @extends Roo.bootstrap.Component
4793 * Bootstrap Table class
4794 * @cfg {String} cls table class
4795 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4796 * @cfg {String} bgcolor Specifies the background color for a table
4797 * @cfg {Number} border Specifies whether the table cells should have borders or not
4798 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4799 * @cfg {Number} cellspacing Specifies the space between cells
4800 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4801 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4802 * @cfg {String} sortable Specifies that the table should be sortable
4803 * @cfg {String} summary Specifies a summary of the content of a table
4804 * @cfg {Number} width Specifies the width of a table
4805 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4807 * @cfg {boolean} striped Should the rows be alternative striped
4808 * @cfg {boolean} bordered Add borders to the table
4809 * @cfg {boolean} hover Add hover highlighting
4810 * @cfg {boolean} condensed Format condensed
4811 * @cfg {boolean} responsive Format condensed
4812 * @cfg {Boolean} loadMask (true|false) default false
4813 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4814 * @cfg {Boolean} thead (true|false) generate thead, default true
4815 * @cfg {Boolean} RowSelection (true|false) default false
4816 * @cfg {Boolean} CellSelection (true|false) default false
4818 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4822 * Create a new Table
4823 * @param {Object} config The config object
4826 Roo.bootstrap.Table = function(config){
4827 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4830 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4831 this.sm = this.selModel;
4832 this.sm.xmodule = this.xmodule || false;
4834 if (this.cm && typeof(this.cm.config) == 'undefined') {
4835 this.colModel = new Roo.grid.ColumnModel(this.cm);
4836 this.cm = this.colModel;
4837 this.cm.xmodule = this.xmodule || false;
4840 this.store= Roo.factory(this.store, Roo.data);
4841 this.ds = this.store;
4842 this.ds.xmodule = this.xmodule || false;
4845 if (this.footer && this.store) {
4846 this.footer.dataSource = this.ds;
4847 this.footer = Roo.factory(this.footer);
4854 * Fires when a cell is clicked
4855 * @param {Roo.bootstrap.Table} this
4856 * @param {Roo.Element} el
4857 * @param {Number} rowIndex
4858 * @param {Number} columnIndex
4859 * @param {Roo.EventObject} e
4863 * @event celldblclick
4864 * Fires when a cell is double clicked
4865 * @param {Roo.bootstrap.Table} this
4866 * @param {Roo.Element} el
4867 * @param {Number} rowIndex
4868 * @param {Number} columnIndex
4869 * @param {Roo.EventObject} e
4871 "celldblclick" : true,
4874 * Fires when a row is clicked
4875 * @param {Roo.bootstrap.Table} this
4876 * @param {Roo.Element} el
4877 * @param {Number} rowIndex
4878 * @param {Roo.EventObject} e
4882 * @event rowdblclick
4883 * Fires when a row is double clicked
4884 * @param {Roo.bootstrap.Table} this
4885 * @param {Roo.Element} el
4886 * @param {Number} rowIndex
4887 * @param {Roo.EventObject} e
4889 "rowdblclick" : true,
4892 * Fires when a mouseover occur
4893 * @param {Roo.bootstrap.Table} this
4894 * @param {Roo.Element} el
4895 * @param {Number} rowIndex
4896 * @param {Number} columnIndex
4897 * @param {Roo.EventObject} e
4902 * Fires when a mouseout occur
4903 * @param {Roo.bootstrap.Table} this
4904 * @param {Roo.Element} el
4905 * @param {Number} rowIndex
4906 * @param {Number} columnIndex
4907 * @param {Roo.EventObject} e
4912 * Fires when a row is rendered, so you can change add a style to it.
4913 * @param {Roo.bootstrap.Table} this
4914 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4921 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4945 RowSelection : false,
4946 CellSelection : false,
4949 // Roo.Element - the tbody
4952 getAutoCreate : function(){
4953 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4962 cfg.cls += ' table-striped';
4966 cfg.cls += ' table-hover';
4968 if (this.bordered) {
4969 cfg.cls += ' table-bordered';
4971 if (this.condensed) {
4972 cfg.cls += ' table-condensed';
4974 if (this.responsive) {
4975 cfg.cls += ' table-responsive';
4979 cfg.cls+= ' ' +this.cls;
4982 // this lot should be simplifed...
4985 cfg.align=this.align;
4988 cfg.bgcolor=this.bgcolor;
4991 cfg.border=this.border;
4993 if (this.cellpadding) {
4994 cfg.cellpadding=this.cellpadding;
4996 if (this.cellspacing) {
4997 cfg.cellspacing=this.cellspacing;
5000 cfg.frame=this.frame;
5003 cfg.rules=this.rules;
5005 if (this.sortable) {
5006 cfg.sortable=this.sortable;
5009 cfg.summary=this.summary;
5012 cfg.width=this.width;
5015 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5018 if(this.store || this.cm){
5020 cfg.cn.push(this.renderHeader());
5023 cfg.cn.push(this.renderBody());
5026 cfg.cn.push(this.renderFooter());
5029 cfg.cls+= ' TableGrid';
5032 return { cn : [ cfg ] };
5035 initEvents : function()
5037 if(!this.store || !this.cm){
5041 //Roo.log('initEvents with ds!!!!');
5043 this.mainBody = this.el.select('tbody', true).first();
5048 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5049 e.on('click', _this.sort, _this);
5052 this.el.on("click", this.onClick, this);
5053 this.el.on("dblclick", this.onDblClick, this);
5055 this.parent().el.setStyle('position', 'relative');
5057 this.footer.parentId = this.id;
5058 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5061 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5063 this.store.on('load', this.onLoad, this);
5064 this.store.on('beforeload', this.onBeforeLoad, this);
5065 this.store.on('update', this.onUpdate, this);
5069 onMouseover : function(e, el)
5071 var cell = Roo.get(el);
5077 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5078 cell = cell.findParent('td', false, true);
5081 var row = cell.findParent('tr', false, true);
5082 var cellIndex = cell.dom.cellIndex;
5083 var rowIndex = row.dom.rowIndex - 1; // start from 0
5085 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5089 onMouseout : function(e, el)
5091 var cell = Roo.get(el);
5097 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5098 cell = cell.findParent('td', false, true);
5101 var row = cell.findParent('tr', false, true);
5102 var cellIndex = cell.dom.cellIndex;
5103 var rowIndex = row.dom.rowIndex - 1; // start from 0
5105 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5109 onClick : function(e, el)
5111 var cell = Roo.get(el);
5113 if(!cell || (!this.CellSelection && !this.RowSelection)){
5118 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5119 cell = cell.findParent('td', false, true);
5122 var row = cell.findParent('tr', false, true);
5123 var cellIndex = cell.dom.cellIndex;
5124 var rowIndex = row.dom.rowIndex - 1;
5126 if(this.CellSelection){
5127 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5130 if(this.RowSelection){
5131 this.fireEvent('rowclick', this, row, rowIndex, e);
5137 onDblClick : function(e,el)
5139 var cell = Roo.get(el);
5141 if(!cell || (!this.CellSelection && !this.RowSelection)){
5145 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5146 cell = cell.findParent('td', false, true);
5149 var row = cell.findParent('tr', false, true);
5150 var cellIndex = cell.dom.cellIndex;
5151 var rowIndex = row.dom.rowIndex - 1;
5153 if(this.CellSelection){
5154 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5157 if(this.RowSelection){
5158 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5162 sort : function(e,el)
5164 var col = Roo.get(el)
5166 if(!col.hasClass('sortable')){
5170 var sort = col.attr('sort');
5173 if(col.hasClass('glyphicon-arrow-up')){
5177 this.store.sortInfo = {field : sort, direction : dir};
5180 Roo.log("calling footer first");
5181 this.footer.onClick('first');
5184 this.store.load({ params : { start : 0 } });
5188 renderHeader : function()
5197 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5199 var config = cm.config[i];
5204 html: cm.getColumnHeader(i)
5207 if(typeof(config.hidden) != 'undefined' && config.hidden){
5208 c.style += ' display:none;';
5211 if(typeof(config.dataIndex) != 'undefined'){
5212 c.sort = config.dataIndex;
5215 if(typeof(config.sortable) != 'undefined' && config.sortable){
5219 if(typeof(config.align) != 'undefined' && config.align.length){
5220 c.style += ' text-align:' + config.align + ';';
5223 if(typeof(config.width) != 'undefined'){
5224 c.style += ' width:' + config.width + 'px;';
5233 renderBody : function()
5243 colspan : this.cm.getColumnCount()
5253 renderFooter : function()
5263 colspan : this.cm.getColumnCount()
5277 Roo.log('ds onload');
5282 var ds = this.store;
5284 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5285 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5287 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5288 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5291 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5292 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5296 var tbody = this.mainBody;
5298 if(ds.getCount() > 0){
5299 ds.data.each(function(d,rowIndex){
5300 var row = this.renderRow(cm, ds, rowIndex);
5302 tbody.createChild(row);
5306 if(row.cellObjects.length){
5307 Roo.each(row.cellObjects, function(r){
5308 _this.renderCellObject(r);
5315 Roo.each(this.el.select('tbody td', true).elements, function(e){
5316 e.on('mouseover', _this.onMouseover, _this);
5319 Roo.each(this.el.select('tbody td', true).elements, function(e){
5320 e.on('mouseout', _this.onMouseout, _this);
5323 //if(this.loadMask){
5324 // this.maskEl.hide();
5329 onUpdate : function(ds,record)
5331 this.refreshRow(record);
5333 onRemove : function(ds, record, index, isUpdate){
5334 if(isUpdate !== true){
5335 this.fireEvent("beforerowremoved", this, index, record);
5337 var bt = this.mainBody.dom;
5339 bt.removeChild(bt.rows[index]);
5342 if(isUpdate !== true){
5343 //this.stripeRows(index);
5344 //this.syncRowHeights(index, index);
5346 this.fireEvent("rowremoved", this, index, record);
5351 refreshRow : function(record){
5352 var ds = this.store, index;
5353 if(typeof record == 'number'){
5355 record = ds.getAt(index);
5357 index = ds.indexOf(record);
5359 this.insertRow(ds, index, true);
5360 this.onRemove(ds, record, index+1, true);
5361 //this.syncRowHeights(index, index);
5363 this.fireEvent("rowupdated", this, index, record);
5366 insertRow : function(dm, rowIndex, isUpdate){
5369 this.fireEvent("beforerowsinserted", this, rowIndex);
5371 //var s = this.getScrollState();
5372 var row = this.renderRow(this.cm, this.store, rowIndex);
5373 // insert before rowIndex..
5374 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5378 if(row.cellObjects.length){
5379 Roo.each(row.cellObjects, function(r){
5380 _this.renderCellObject(r);
5385 this.fireEvent("rowsinserted", this, rowIndex);
5386 //this.syncRowHeights(firstRow, lastRow);
5387 //this.stripeRows(firstRow);
5394 getRowDom : function(rowIndex)
5396 // not sure if I need to check this.. but let's do it anyway..
5397 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5398 this.mainBody.dom.rows[rowIndex] : false
5400 // returns the object tree for a tr..
5403 renderRow : function(cm, ds, rowIndex) {
5405 var d = ds.getAt(rowIndex);
5412 var cellObjects = [];
5414 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5415 var config = cm.config[i];
5417 var renderer = cm.getRenderer(i);
5421 if(typeof(renderer) !== 'undefined'){
5422 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5424 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5425 // and are rendered into the cells after the row is rendered - using the id for the element.
5427 if(typeof(value) === 'object'){
5437 rowIndex : rowIndex,
5442 this.fireEvent('rowclass', this, rowcfg);
5446 cls : rowcfg.rowClass,
5448 html: (typeof(value) === 'object') ? '' : value
5455 if(typeof(config.hidden) != 'undefined' && config.hidden){
5456 td.style += ' display:none;';
5459 if(typeof(config.align) != 'undefined' && config.align.length){
5460 td.style += ' text-align:' + config.align + ';';
5463 if(typeof(config.width) != 'undefined'){
5464 td.style += ' width:' + config.width + 'px;';
5471 row.cellObjects = cellObjects;
5479 onBeforeLoad : function()
5481 //Roo.log('ds onBeforeLoad');
5485 //if(this.loadMask){
5486 // this.maskEl.show();
5492 this.el.select('tbody', true).first().dom.innerHTML = '';
5495 getSelectionModel : function(){
5497 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5499 return this.selModel;
5502 * Render the Roo.bootstrap object from renderder
5504 renderCellObject : function(r)
5508 var t = r.cfg.render(r.container);
5511 Roo.each(r.cfg.cn, function(c){
5513 container: t.getChildContainer(),
5516 _this.renderCellObject(child);
5533 * @class Roo.bootstrap.TableCell
5534 * @extends Roo.bootstrap.Component
5535 * Bootstrap TableCell class
5536 * @cfg {String} html cell contain text
5537 * @cfg {String} cls cell class
5538 * @cfg {String} tag cell tag (td|th) default td
5539 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5540 * @cfg {String} align Aligns the content in a cell
5541 * @cfg {String} axis Categorizes cells
5542 * @cfg {String} bgcolor Specifies the background color of a cell
5543 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5544 * @cfg {Number} colspan Specifies the number of columns a cell should span
5545 * @cfg {String} headers Specifies one or more header cells a cell is related to
5546 * @cfg {Number} height Sets the height of a cell
5547 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5548 * @cfg {Number} rowspan Sets the number of rows a cell should span
5549 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5550 * @cfg {String} valign Vertical aligns the content in a cell
5551 * @cfg {Number} width Specifies the width of a cell
5554 * Create a new TableCell
5555 * @param {Object} config The config object
5558 Roo.bootstrap.TableCell = function(config){
5559 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5562 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5582 getAutoCreate : function(){
5583 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5603 cfg.align=this.align
5609 cfg.bgcolor=this.bgcolor
5612 cfg.charoff=this.charoff
5615 cfg.colspan=this.colspan
5618 cfg.headers=this.headers
5621 cfg.height=this.height
5624 cfg.nowrap=this.nowrap
5627 cfg.rowspan=this.rowspan
5630 cfg.scope=this.scope
5633 cfg.valign=this.valign
5636 cfg.width=this.width
5655 * @class Roo.bootstrap.TableRow
5656 * @extends Roo.bootstrap.Component
5657 * Bootstrap TableRow class
5658 * @cfg {String} cls row class
5659 * @cfg {String} align Aligns the content in a table row
5660 * @cfg {String} bgcolor Specifies a background color for a table row
5661 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5662 * @cfg {String} valign Vertical aligns the content in a table row
5665 * Create a new TableRow
5666 * @param {Object} config The config object
5669 Roo.bootstrap.TableRow = function(config){
5670 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5673 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5681 getAutoCreate : function(){
5682 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5692 cfg.align = this.align;
5695 cfg.bgcolor = this.bgcolor;
5698 cfg.charoff = this.charoff;
5701 cfg.valign = this.valign;
5719 * @class Roo.bootstrap.TableBody
5720 * @extends Roo.bootstrap.Component
5721 * Bootstrap TableBody class
5722 * @cfg {String} cls element class
5723 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5724 * @cfg {String} align Aligns the content inside the element
5725 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5726 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5729 * Create a new TableBody
5730 * @param {Object} config The config object
5733 Roo.bootstrap.TableBody = function(config){
5734 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5737 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5745 getAutoCreate : function(){
5746 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5760 cfg.align = this.align;
5763 cfg.charoff = this.charoff;
5766 cfg.valign = this.valign;
5773 // initEvents : function()
5780 // this.store = Roo.factory(this.store, Roo.data);
5781 // this.store.on('load', this.onLoad, this);
5783 // this.store.load();
5787 // onLoad: function ()
5789 // this.fireEvent('load', this);
5799 * Ext JS Library 1.1.1
5800 * Copyright(c) 2006-2007, Ext JS, LLC.
5802 * Originally Released Under LGPL - original licence link has changed is not relivant.
5805 * <script type="text/javascript">
5808 // as we use this in bootstrap.
5809 Roo.namespace('Roo.form');
5811 * @class Roo.form.Action
5812 * Internal Class used to handle form actions
5814 * @param {Roo.form.BasicForm} el The form element or its id
5815 * @param {Object} config Configuration options
5820 // define the action interface
5821 Roo.form.Action = function(form, options){
5823 this.options = options || {};
5826 * Client Validation Failed
5829 Roo.form.Action.CLIENT_INVALID = 'client';
5831 * Server Validation Failed
5834 Roo.form.Action.SERVER_INVALID = 'server';
5836 * Connect to Server Failed
5839 Roo.form.Action.CONNECT_FAILURE = 'connect';
5841 * Reading Data from Server Failed
5844 Roo.form.Action.LOAD_FAILURE = 'load';
5846 Roo.form.Action.prototype = {
5848 failureType : undefined,
5849 response : undefined,
5853 run : function(options){
5858 success : function(response){
5863 handleResponse : function(response){
5867 // default connection failure
5868 failure : function(response){
5870 this.response = response;
5871 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5872 this.form.afterAction(this, false);
5875 processResponse : function(response){
5876 this.response = response;
5877 if(!response.responseText){
5880 this.result = this.handleResponse(response);
5884 // utility functions used internally
5885 getUrl : function(appendParams){
5886 var url = this.options.url || this.form.url || this.form.el.dom.action;
5888 var p = this.getParams();
5890 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5896 getMethod : function(){
5897 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5900 getParams : function(){
5901 var bp = this.form.baseParams;
5902 var p = this.options.params;
5904 if(typeof p == "object"){
5905 p = Roo.urlEncode(Roo.applyIf(p, bp));
5906 }else if(typeof p == 'string' && bp){
5907 p += '&' + Roo.urlEncode(bp);
5910 p = Roo.urlEncode(bp);
5915 createCallback : function(){
5917 success: this.success,
5918 failure: this.failure,
5920 timeout: (this.form.timeout*1000),
5921 upload: this.form.fileUpload ? this.success : undefined
5926 Roo.form.Action.Submit = function(form, options){
5927 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5930 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5933 haveProgress : false,
5934 uploadComplete : false,
5936 // uploadProgress indicator.
5937 uploadProgress : function()
5939 if (!this.form.progressUrl) {
5943 if (!this.haveProgress) {
5944 Roo.MessageBox.progress("Uploading", "Uploading");
5946 if (this.uploadComplete) {
5947 Roo.MessageBox.hide();
5951 this.haveProgress = true;
5953 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5955 var c = new Roo.data.Connection();
5957 url : this.form.progressUrl,
5962 success : function(req){
5963 //console.log(data);
5967 rdata = Roo.decode(req.responseText)
5969 Roo.log("Invalid data from server..");
5973 if (!rdata || !rdata.success) {
5975 Roo.MessageBox.alert(Roo.encode(rdata));
5978 var data = rdata.data;
5980 if (this.uploadComplete) {
5981 Roo.MessageBox.hide();
5986 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5987 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5990 this.uploadProgress.defer(2000,this);
5993 failure: function(data) {
5994 Roo.log('progress url failed ');
6005 // run get Values on the form, so it syncs any secondary forms.
6006 this.form.getValues();
6008 var o = this.options;
6009 var method = this.getMethod();
6010 var isPost = method == 'POST';
6011 if(o.clientValidation === false || this.form.isValid()){
6013 if (this.form.progressUrl) {
6014 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6015 (new Date() * 1) + '' + Math.random());
6020 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6021 form:this.form.el.dom,
6022 url:this.getUrl(!isPost),
6024 params:isPost ? this.getParams() : null,
6025 isUpload: this.form.fileUpload
6028 this.uploadProgress();
6030 }else if (o.clientValidation !== false){ // client validation failed
6031 this.failureType = Roo.form.Action.CLIENT_INVALID;
6032 this.form.afterAction(this, false);
6036 success : function(response)
6038 this.uploadComplete= true;
6039 if (this.haveProgress) {
6040 Roo.MessageBox.hide();
6044 var result = this.processResponse(response);
6045 if(result === true || result.success){
6046 this.form.afterAction(this, true);
6050 this.form.markInvalid(result.errors);
6051 this.failureType = Roo.form.Action.SERVER_INVALID;
6053 this.form.afterAction(this, false);
6055 failure : function(response)
6057 this.uploadComplete= true;
6058 if (this.haveProgress) {
6059 Roo.MessageBox.hide();
6062 this.response = response;
6063 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6064 this.form.afterAction(this, false);
6067 handleResponse : function(response){
6068 if(this.form.errorReader){
6069 var rs = this.form.errorReader.read(response);
6072 for(var i = 0, len = rs.records.length; i < len; i++) {
6073 var r = rs.records[i];
6077 if(errors.length < 1){
6081 success : rs.success,
6087 ret = Roo.decode(response.responseText);
6091 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6101 Roo.form.Action.Load = function(form, options){
6102 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6103 this.reader = this.form.reader;
6106 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6111 Roo.Ajax.request(Roo.apply(
6112 this.createCallback(), {
6113 method:this.getMethod(),
6114 url:this.getUrl(false),
6115 params:this.getParams()
6119 success : function(response){
6121 var result = this.processResponse(response);
6122 if(result === true || !result.success || !result.data){
6123 this.failureType = Roo.form.Action.LOAD_FAILURE;
6124 this.form.afterAction(this, false);
6127 this.form.clearInvalid();
6128 this.form.setValues(result.data);
6129 this.form.afterAction(this, true);
6132 handleResponse : function(response){
6133 if(this.form.reader){
6134 var rs = this.form.reader.read(response);
6135 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6137 success : rs.success,
6141 return Roo.decode(response.responseText);
6145 Roo.form.Action.ACTION_TYPES = {
6146 'load' : Roo.form.Action.Load,
6147 'submit' : Roo.form.Action.Submit
6156 * @class Roo.bootstrap.Form
6157 * @extends Roo.bootstrap.Component
6158 * Bootstrap Form class
6159 * @cfg {String} method GET | POST (default POST)
6160 * @cfg {String} labelAlign top | left (default top)
6161 * @cfg {String} align left | right - for navbars
6162 * @cfg {Boolean} loadMask load mask when submit (default true)
6167 * @param {Object} config The config object
6171 Roo.bootstrap.Form = function(config){
6172 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6175 * @event clientvalidation
6176 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6177 * @param {Form} this
6178 * @param {Boolean} valid true if the form has passed client-side validation
6180 clientvalidation: true,
6182 * @event beforeaction
6183 * Fires before any action is performed. Return false to cancel the action.
6184 * @param {Form} this
6185 * @param {Action} action The action to be performed
6189 * @event actionfailed
6190 * Fires when an action fails.
6191 * @param {Form} this
6192 * @param {Action} action The action that failed
6194 actionfailed : true,
6196 * @event actioncomplete
6197 * Fires when an action is completed.
6198 * @param {Form} this
6199 * @param {Action} action The action that completed
6201 actioncomplete : true
6206 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6209 * @cfg {String} method
6210 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6215 * The URL to use for form actions if one isn't supplied in the action options.
6218 * @cfg {Boolean} fileUpload
6219 * Set to true if this form is a file upload.
6223 * @cfg {Object} baseParams
6224 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6228 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6232 * @cfg {Sting} align (left|right) for navbar forms
6237 activeAction : null,
6240 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6241 * element by passing it or its id or mask the form itself by passing in true.
6244 waitMsgTarget : false,
6248 getAutoCreate : function(){
6252 method : this.method || 'POST',
6253 id : this.id || Roo.id(),
6256 if (this.parent().xtype.match(/^Nav/)) {
6257 cfg.cls = 'navbar-form navbar-' + this.align;
6261 if (this.labelAlign == 'left' ) {
6262 cfg.cls += ' form-horizontal';
6268 initEvents : function()
6270 this.el.on('submit', this.onSubmit, this);
6271 // this was added as random key presses on the form where triggering form submit.
6272 this.el.on('keypress', function(e) {
6273 if (e.getCharCode() != 13) {
6276 // we might need to allow it for textareas.. and some other items.
6277 // check e.getTarget().
6279 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6283 Roo.log("keypress blocked");
6291 onSubmit : function(e){
6296 * Returns true if client-side validation on the form is successful.
6299 isValid : function(){
6300 var items = this.getItems();
6302 items.each(function(f){
6311 * Returns true if any fields in this form have changed since their original load.
6314 isDirty : function(){
6316 var items = this.getItems();
6317 items.each(function(f){
6327 * Performs a predefined action (submit or load) or custom actions you define on this form.
6328 * @param {String} actionName The name of the action type
6329 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6330 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6331 * accept other config options):
6333 Property Type Description
6334 ---------------- --------------- ----------------------------------------------------------------------------------
6335 url String The url for the action (defaults to the form's url)
6336 method String The form method to use (defaults to the form's method, or POST if not defined)
6337 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6338 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6339 validate the form on the client (defaults to false)
6341 * @return {BasicForm} this
6343 doAction : function(action, options){
6344 if(typeof action == 'string'){
6345 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6347 if(this.fireEvent('beforeaction', this, action) !== false){
6348 this.beforeAction(action);
6349 action.run.defer(100, action);
6355 beforeAction : function(action){
6356 var o = action.options;
6359 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6361 // not really supported yet.. ??
6363 //if(this.waitMsgTarget === true){
6364 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6365 //}else if(this.waitMsgTarget){
6366 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6367 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6369 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6375 afterAction : function(action, success){
6376 this.activeAction = null;
6377 var o = action.options;
6379 //if(this.waitMsgTarget === true){
6381 //}else if(this.waitMsgTarget){
6382 // this.waitMsgTarget.unmask();
6384 // Roo.MessageBox.updateProgress(1);
6385 // Roo.MessageBox.hide();
6392 Roo.callback(o.success, o.scope, [this, action]);
6393 this.fireEvent('actioncomplete', this, action);
6397 // failure condition..
6398 // we have a scenario where updates need confirming.
6399 // eg. if a locking scenario exists..
6400 // we look for { errors : { needs_confirm : true }} in the response.
6402 (typeof(action.result) != 'undefined') &&
6403 (typeof(action.result.errors) != 'undefined') &&
6404 (typeof(action.result.errors.needs_confirm) != 'undefined')
6407 Roo.log("not supported yet");
6410 Roo.MessageBox.confirm(
6411 "Change requires confirmation",
6412 action.result.errorMsg,
6417 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6427 Roo.callback(o.failure, o.scope, [this, action]);
6428 // show an error message if no failed handler is set..
6429 if (!this.hasListener('actionfailed')) {
6430 Roo.log("need to add dialog support");
6432 Roo.MessageBox.alert("Error",
6433 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6434 action.result.errorMsg :
6435 "Saving Failed, please check your entries or try again"
6440 this.fireEvent('actionfailed', this, action);
6445 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6446 * @param {String} id The value to search for
6449 findField : function(id){
6450 var items = this.getItems();
6451 var field = items.get(id);
6453 items.each(function(f){
6454 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6461 return field || null;
6464 * Mark fields in this form invalid in bulk.
6465 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6466 * @return {BasicForm} this
6468 markInvalid : function(errors){
6469 if(errors instanceof Array){
6470 for(var i = 0, len = errors.length; i < len; i++){
6471 var fieldError = errors[i];
6472 var f = this.findField(fieldError.id);
6474 f.markInvalid(fieldError.msg);
6480 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6481 field.markInvalid(errors[id]);
6485 //Roo.each(this.childForms || [], function (f) {
6486 // f.markInvalid(errors);
6493 * Set values for fields in this form in bulk.
6494 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6495 * @return {BasicForm} this
6497 setValues : function(values){
6498 if(values instanceof Array){ // array of objects
6499 for(var i = 0, len = values.length; i < len; i++){
6501 var f = this.findField(v.id);
6503 f.setValue(v.value);
6504 if(this.trackResetOnLoad){
6505 f.originalValue = f.getValue();
6509 }else{ // object hash
6512 if(typeof values[id] != 'function' && (field = this.findField(id))){
6514 if (field.setFromData &&
6516 field.displayField &&
6517 // combos' with local stores can
6518 // be queried via setValue()
6519 // to set their value..
6520 (field.store && !field.store.isLocal)
6524 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6525 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6526 field.setFromData(sd);
6529 field.setValue(values[id]);
6533 if(this.trackResetOnLoad){
6534 field.originalValue = field.getValue();
6540 //Roo.each(this.childForms || [], function (f) {
6541 // f.setValues(values);
6548 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6549 * they are returned as an array.
6550 * @param {Boolean} asString
6553 getValues : function(asString){
6554 //if (this.childForms) {
6555 // copy values from the child forms
6556 // Roo.each(this.childForms, function (f) {
6557 // this.setValues(f.getValues());
6563 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6564 if(asString === true){
6567 return Roo.urlDecode(fs);
6571 * Returns the fields in this form as an object with key/value pairs.
6572 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6575 getFieldValues : function(with_hidden)
6577 var items = this.getItems();
6579 items.each(function(f){
6583 var v = f.getValue();
6584 if (f.inputType =='radio') {
6585 if (typeof(ret[f.getName()]) == 'undefined') {
6586 ret[f.getName()] = ''; // empty..
6589 if (!f.el.dom.checked) {
6597 // not sure if this supported any more..
6598 if ((typeof(v) == 'object') && f.getRawValue) {
6599 v = f.getRawValue() ; // dates..
6601 // combo boxes where name != hiddenName...
6602 if (f.name != f.getName()) {
6603 ret[f.name] = f.getRawValue();
6605 ret[f.getName()] = v;
6612 * Clears all invalid messages in this form.
6613 * @return {BasicForm} this
6615 clearInvalid : function(){
6616 var items = this.getItems();
6618 items.each(function(f){
6629 * @return {BasicForm} this
6632 var items = this.getItems();
6633 items.each(function(f){
6637 Roo.each(this.childForms || [], function (f) {
6644 getItems : function()
6646 var r=new Roo.util.MixedCollection(false, function(o){
6647 return o.id || (o.id = Roo.id());
6649 var iter = function(el) {
6656 Roo.each(el.items,function(e) {
6675 * Ext JS Library 1.1.1
6676 * Copyright(c) 2006-2007, Ext JS, LLC.
6678 * Originally Released Under LGPL - original licence link has changed is not relivant.
6681 * <script type="text/javascript">
6684 * @class Roo.form.VTypes
6685 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6688 Roo.form.VTypes = function(){
6689 // closure these in so they are only created once.
6690 var alpha = /^[a-zA-Z_]+$/;
6691 var alphanum = /^[a-zA-Z0-9_]+$/;
6692 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6693 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6695 // All these messages and functions are configurable
6698 * The function used to validate email addresses
6699 * @param {String} value The email address
6701 'email' : function(v){
6702 return email.test(v);
6705 * The error text to display when the email validation function returns false
6708 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6710 * The keystroke filter mask to be applied on email input
6713 'emailMask' : /[a-z0-9_\.\-@]/i,
6716 * The function used to validate URLs
6717 * @param {String} value The URL
6719 'url' : function(v){
6723 * The error text to display when the url validation function returns false
6726 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6729 * The function used to validate alpha values
6730 * @param {String} value The value
6732 'alpha' : function(v){
6733 return alpha.test(v);
6736 * The error text to display when the alpha validation function returns false
6739 'alphaText' : 'This field should only contain letters and _',
6741 * The keystroke filter mask to be applied on alpha input
6744 'alphaMask' : /[a-z_]/i,
6747 * The function used to validate alphanumeric values
6748 * @param {String} value The value
6750 'alphanum' : function(v){
6751 return alphanum.test(v);
6754 * The error text to display when the alphanumeric validation function returns false
6757 'alphanumText' : 'This field should only contain letters, numbers and _',
6759 * The keystroke filter mask to be applied on alphanumeric input
6762 'alphanumMask' : /[a-z0-9_]/i
6772 * @class Roo.bootstrap.Input
6773 * @extends Roo.bootstrap.Component
6774 * Bootstrap Input class
6775 * @cfg {Boolean} disabled is it disabled
6776 * @cfg {String} fieldLabel - the label associated
6777 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6778 * @cfg {String} name name of the input
6779 * @cfg {string} fieldLabel - the label associated
6780 * @cfg {string} inputType - input / file submit ...
6781 * @cfg {string} placeholder - placeholder to put in text.
6782 * @cfg {string} before - input group add on before
6783 * @cfg {string} after - input group add on after
6784 * @cfg {string} size - (lg|sm) or leave empty..
6785 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6786 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6787 * @cfg {Number} md colspan out of 12 for computer-sized screens
6788 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6789 * @cfg {string} value default value of the input
6790 * @cfg {Number} labelWidth set the width of label (0-12)
6791 * @cfg {String} labelAlign (top|left)
6792 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6793 * @cfg {String} align (left|center|right) Default left
6797 * Create a new Input
6798 * @param {Object} config The config object
6801 Roo.bootstrap.Input = function(config){
6802 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6807 * Fires when this field receives input focus.
6808 * @param {Roo.form.Field} this
6813 * Fires when this field loses input focus.
6814 * @param {Roo.form.Field} this
6819 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6820 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6821 * @param {Roo.form.Field} this
6822 * @param {Roo.EventObject} e The event object
6827 * Fires just before the field blurs if the field value has changed.
6828 * @param {Roo.form.Field} this
6829 * @param {Mixed} newValue The new value
6830 * @param {Mixed} oldValue The original value
6835 * Fires after the field has been marked as invalid.
6836 * @param {Roo.form.Field} this
6837 * @param {String} msg The validation message
6842 * Fires after the field has been validated with no errors.
6843 * @param {Roo.form.Field} this
6848 * Fires after the key up
6849 * @param {Roo.form.Field} this
6850 * @param {Roo.EventObject} e The event Object
6856 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6858 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6859 automatic validation (defaults to "keyup").
6861 validationEvent : "keyup",
6863 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6865 validateOnBlur : true,
6867 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6869 validationDelay : 250,
6871 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6873 focusClass : "x-form-focus", // not needed???
6877 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6879 invalidClass : "has-error",
6882 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6884 selectOnFocus : false,
6887 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6891 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6896 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6898 disableKeyFilter : false,
6901 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6905 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6909 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6911 blankText : "This field is required",
6914 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6918 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6920 maxLength : Number.MAX_VALUE,
6922 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6924 minLengthText : "The minimum length for this field is {0}",
6926 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6928 maxLengthText : "The maximum length for this field is {0}",
6932 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6933 * If available, this function will be called only after the basic validators all return true, and will be passed the
6934 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6938 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6939 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6940 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6944 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6967 formatedValue : false,
6969 parentLabelAlign : function()
6972 while (parent.parent()) {
6973 parent = parent.parent();
6974 if (typeof(parent.labelAlign) !='undefined') {
6975 return parent.labelAlign;
6982 getAutoCreate : function(){
6984 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6990 if(this.inputType != 'hidden'){
6991 cfg.cls = 'form-group' //input-group
6997 type : this.inputType,
6999 cls : 'form-control',
7000 placeholder : this.placeholder || ''
7005 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7008 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7009 input.maxLength = this.maxLength;
7012 if (this.disabled) {
7013 input.disabled=true;
7016 if (this.readOnly) {
7017 input.readonly=true;
7021 input.name = this.name;
7024 input.cls += ' input-' + this.size;
7027 ['xs','sm','md','lg'].map(function(size){
7028 if (settings[size]) {
7029 cfg.cls += ' col-' + size + '-' + settings[size];
7033 var inputblock = input;
7035 if (this.before || this.after) {
7038 cls : 'input-group',
7041 if (this.before && typeof(this.before) == 'string') {
7043 inputblock.cn.push({
7045 cls : 'roo-input-before input-group-addon',
7049 if (this.before && typeof(this.before) == 'object') {
7050 this.before = Roo.factory(this.before);
7051 Roo.log(this.before);
7052 inputblock.cn.push({
7054 cls : 'roo-input-before input-group-' +
7055 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7059 inputblock.cn.push(input);
7061 if (this.after && typeof(this.after) == 'string') {
7062 inputblock.cn.push({
7064 cls : 'roo-input-after input-group-addon',
7068 if (this.after && typeof(this.after) == 'object') {
7069 this.after = Roo.factory(this.after);
7070 Roo.log(this.after);
7071 inputblock.cn.push({
7073 cls : 'roo-input-after input-group-' +
7074 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7079 if (align ==='left' && this.fieldLabel.length) {
7080 Roo.log("left and has label");
7086 cls : 'control-label col-sm-' + this.labelWidth,
7087 html : this.fieldLabel
7091 cls : "col-sm-" + (12 - this.labelWidth),
7098 } else if ( this.fieldLabel.length) {
7104 //cls : 'input-group-addon',
7105 html : this.fieldLabel
7115 Roo.log(" no label && no align");
7124 Roo.log('input-parentType: ' + this.parentType);
7126 if (this.parentType === 'Navbar' && this.parent().bar) {
7127 cfg.cls += ' navbar-form';
7135 * return the real input element.
7137 inputEl: function ()
7139 return this.el.select('input.form-control',true).first();
7141 setDisabled : function(v)
7143 var i = this.inputEl().dom;
7145 i.removeAttribute('disabled');
7149 i.setAttribute('disabled','true');
7151 initEvents : function()
7154 this.inputEl().on("keydown" , this.fireKey, this);
7155 this.inputEl().on("focus", this.onFocus, this);
7156 this.inputEl().on("blur", this.onBlur, this);
7158 this.inputEl().relayEvent('keyup', this);
7160 // reference to original value for reset
7161 this.originalValue = this.getValue();
7162 //Roo.form.TextField.superclass.initEvents.call(this);
7163 if(this.validationEvent == 'keyup'){
7164 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7165 this.inputEl().on('keyup', this.filterValidation, this);
7167 else if(this.validationEvent !== false){
7168 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7171 if(this.selectOnFocus){
7172 this.on("focus", this.preFocus, this);
7175 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7176 this.inputEl().on("keypress", this.filterKeys, this);
7179 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7180 this.el.on("click", this.autoSize, this);
7183 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7184 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7187 if (typeof(this.before) == 'object') {
7188 this.before.render(this.el.select('.roo-input-before',true).first());
7190 if (typeof(this.after) == 'object') {
7191 this.after.render(this.el.select('.roo-input-after',true).first());
7196 filterValidation : function(e){
7197 if(!e.isNavKeyPress()){
7198 this.validationTask.delay(this.validationDelay);
7202 * Validates the field value
7203 * @return {Boolean} True if the value is valid, else false
7205 validate : function(){
7206 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7207 if(this.disabled || this.validateValue(this.getRawValue())){
7208 this.clearInvalid();
7216 * Validates a value according to the field's validation rules and marks the field as invalid
7217 * if the validation fails
7218 * @param {Mixed} value The value to validate
7219 * @return {Boolean} True if the value is valid, else false
7221 validateValue : function(value){
7222 if(value.length < 1) { // if it's blank
7223 if(this.allowBlank){
7224 this.clearInvalid();
7227 this.markInvalid(this.blankText);
7231 if(value.length < this.minLength){
7232 this.markInvalid(String.format(this.minLengthText, this.minLength));
7235 if(value.length > this.maxLength){
7236 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7240 var vt = Roo.form.VTypes;
7241 if(!vt[this.vtype](value, this)){
7242 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7246 if(typeof this.validator == "function"){
7247 var msg = this.validator(value);
7249 this.markInvalid(msg);
7253 if(this.regex && !this.regex.test(value)){
7254 this.markInvalid(this.regexText);
7263 fireKey : function(e){
7264 //Roo.log('field ' + e.getKey());
7265 if(e.isNavKeyPress()){
7266 this.fireEvent("specialkey", this, e);
7269 focus : function (selectText){
7271 this.inputEl().focus();
7272 if(selectText === true){
7273 this.inputEl().dom.select();
7279 onFocus : function(){
7280 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7281 // this.el.addClass(this.focusClass);
7284 this.hasFocus = true;
7285 this.startValue = this.getValue();
7286 this.fireEvent("focus", this);
7290 beforeBlur : Roo.emptyFn,
7294 onBlur : function(){
7296 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7297 //this.el.removeClass(this.focusClass);
7299 this.hasFocus = false;
7300 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7303 var v = this.getValue();
7304 if(String(v) !== String(this.startValue)){
7305 this.fireEvent('change', this, v, this.startValue);
7307 this.fireEvent("blur", this);
7311 * Resets the current field value to the originally loaded value and clears any validation messages
7314 this.setValue(this.originalValue);
7315 this.clearInvalid();
7318 * Returns the name of the field
7319 * @return {Mixed} name The name field
7321 getName: function(){
7325 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7326 * @return {Mixed} value The field value
7328 getValue : function(){
7330 var v = this.inputEl().getValue();
7335 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7336 * @return {Mixed} value The field value
7338 getRawValue : function(){
7339 var v = this.inputEl().getValue();
7345 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7346 * @param {Mixed} value The value to set
7348 setRawValue : function(v){
7349 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7352 selectText : function(start, end){
7353 var v = this.getRawValue();
7355 start = start === undefined ? 0 : start;
7356 end = end === undefined ? v.length : end;
7357 var d = this.inputEl().dom;
7358 if(d.setSelectionRange){
7359 d.setSelectionRange(start, end);
7360 }else if(d.createTextRange){
7361 var range = d.createTextRange();
7362 range.moveStart("character", start);
7363 range.moveEnd("character", v.length-end);
7370 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7371 * @param {Mixed} value The value to set
7373 setValue : function(v){
7376 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7382 processValue : function(value){
7383 if(this.stripCharsRe){
7384 var newValue = value.replace(this.stripCharsRe, '');
7385 if(newValue !== value){
7386 this.setRawValue(newValue);
7393 preFocus : function(){
7395 if(this.selectOnFocus){
7396 this.inputEl().dom.select();
7399 filterKeys : function(e){
7401 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7404 var c = e.getCharCode(), cc = String.fromCharCode(c);
7405 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7408 if(!this.maskRe.test(cc)){
7413 * Clear any invalid styles/messages for this field
7415 clearInvalid : function(){
7417 if(!this.el || this.preventMark){ // not rendered
7420 this.el.removeClass(this.invalidClass);
7422 switch(this.msgTarget){
7424 this.el.dom.qtip = '';
7427 this.el.dom.title = '';
7431 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7436 this.errorIcon.dom.qtip = '';
7437 this.errorIcon.hide();
7438 this.un('resize', this.alignErrorIcon, this);
7442 var t = Roo.getDom(this.msgTarget);
7444 t.style.display = 'none';
7448 this.fireEvent('valid', this);
7451 * Mark this field as invalid
7452 * @param {String} msg The validation message
7454 markInvalid : function(msg){
7455 if(!this.el || this.preventMark){ // not rendered
7458 this.el.addClass(this.invalidClass);
7460 msg = msg || this.invalidText;
7461 switch(this.msgTarget){
7463 this.el.dom.qtip = msg;
7464 this.el.dom.qclass = 'x-form-invalid-tip';
7465 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7466 Roo.QuickTips.enable();
7470 this.el.dom.title = msg;
7474 var elp = this.el.findParent('.x-form-element', 5, true);
7475 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7476 this.errorEl.setWidth(elp.getWidth(true)-20);
7478 this.errorEl.update(msg);
7479 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7482 if(!this.errorIcon){
7483 var elp = this.el.findParent('.x-form-element', 5, true);
7484 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7486 this.alignErrorIcon();
7487 this.errorIcon.dom.qtip = msg;
7488 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7489 this.errorIcon.show();
7490 this.on('resize', this.alignErrorIcon, this);
7493 var t = Roo.getDom(this.msgTarget);
7495 t.style.display = this.msgDisplay;
7499 this.fireEvent('invalid', this, msg);
7502 SafariOnKeyDown : function(event)
7504 // this is a workaround for a password hang bug on chrome/ webkit.
7506 var isSelectAll = false;
7508 if(this.inputEl().dom.selectionEnd > 0){
7509 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7511 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7512 event.preventDefault();
7517 if(isSelectAll){ // backspace and delete key
7519 event.preventDefault();
7520 // this is very hacky as keydown always get's upper case.
7522 var cc = String.fromCharCode(event.getCharCode());
7523 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7527 adjustWidth : function(tag, w){
7528 tag = tag.toLowerCase();
7529 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7530 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7534 if(tag == 'textarea'){
7537 }else if(Roo.isOpera){
7541 if(tag == 'textarea'){
7560 * @class Roo.bootstrap.TextArea
7561 * @extends Roo.bootstrap.Input
7562 * Bootstrap TextArea class
7563 * @cfg {Number} cols Specifies the visible width of a text area
7564 * @cfg {Number} rows Specifies the visible number of lines in a text area
7565 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7566 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7567 * @cfg {string} html text
7570 * Create a new TextArea
7571 * @param {Object} config The config object
7574 Roo.bootstrap.TextArea = function(config){
7575 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7579 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7589 getAutoCreate : function(){
7591 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7602 value : this.value || '',
7603 html: this.html || '',
7604 cls : 'form-control',
7605 placeholder : this.placeholder || ''
7609 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7610 input.maxLength = this.maxLength;
7614 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7618 input.cols = this.cols;
7621 if (this.readOnly) {
7622 input.readonly = true;
7626 input.name = this.name;
7630 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7634 ['xs','sm','md','lg'].map(function(size){
7635 if (settings[size]) {
7636 cfg.cls += ' col-' + size + '-' + settings[size];
7640 var inputblock = input;
7642 if (this.before || this.after) {
7645 cls : 'input-group',
7649 inputblock.cn.push({
7651 cls : 'input-group-addon',
7655 inputblock.cn.push(input);
7657 inputblock.cn.push({
7659 cls : 'input-group-addon',
7666 if (align ==='left' && this.fieldLabel.length) {
7667 Roo.log("left and has label");
7673 cls : 'control-label col-sm-' + this.labelWidth,
7674 html : this.fieldLabel
7678 cls : "col-sm-" + (12 - this.labelWidth),
7685 } else if ( this.fieldLabel.length) {
7691 //cls : 'input-group-addon',
7692 html : this.fieldLabel
7702 Roo.log(" no label && no align");
7712 if (this.disabled) {
7713 input.disabled=true;
7720 * return the real textarea element.
7722 inputEl: function ()
7724 return this.el.select('textarea.form-control',true).first();
7732 * trigger field - base class for combo..
7737 * @class Roo.bootstrap.TriggerField
7738 * @extends Roo.bootstrap.Input
7739 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7740 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7741 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7742 * for which you can provide a custom implementation. For example:
7744 var trigger = new Roo.bootstrap.TriggerField();
7745 trigger.onTriggerClick = myTriggerFn;
7746 trigger.applyTo('my-field');
7749 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7750 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7751 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7752 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7754 * Create a new TriggerField.
7755 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7756 * to the base TextField)
7758 Roo.bootstrap.TriggerField = function(config){
7759 this.mimicing = false;
7760 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7763 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7765 * @cfg {String} triggerClass A CSS class to apply to the trigger
7768 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7772 /** @cfg {Boolean} grow @hide */
7773 /** @cfg {Number} growMin @hide */
7774 /** @cfg {Number} growMax @hide */
7780 autoSize: Roo.emptyFn,
7787 actionMode : 'wrap',
7791 getAutoCreate : function(){
7793 var align = this.labelAlign || this.parentLabelAlign();
7798 cls: 'form-group' //input-group
7805 type : this.inputType,
7806 cls : 'form-control',
7807 autocomplete: 'off',
7808 placeholder : this.placeholder || ''
7812 input.name = this.name;
7815 input.cls += ' input-' + this.size;
7818 if (this.disabled) {
7819 input.disabled=true;
7822 var inputblock = input;
7824 if (this.before || this.after) {
7827 cls : 'input-group',
7831 inputblock.cn.push({
7833 cls : 'input-group-addon',
7837 inputblock.cn.push(input);
7839 inputblock.cn.push({
7841 cls : 'input-group-addon',
7854 cls: 'form-hidden-field'
7862 Roo.log('multiple');
7870 cls: 'form-hidden-field'
7874 cls: 'select2-choices',
7878 cls: 'select2-search-field',
7891 cls: 'select2-container input-group',
7896 // cls: 'typeahead typeahead-long dropdown-menu',
7897 // style: 'display:none'
7902 if(!this.multiple && this.showToggleBtn){
7905 cls : 'input-group-addon btn dropdown-toggle',
7913 cls: 'combobox-clear',
7927 combobox.cls += ' select2-container-multi';
7930 if (align ==='left' && this.fieldLabel.length) {
7932 Roo.log("left and has label");
7938 cls : 'control-label col-sm-' + this.labelWidth,
7939 html : this.fieldLabel
7943 cls : "col-sm-" + (12 - this.labelWidth),
7950 } else if ( this.fieldLabel.length) {
7956 //cls : 'input-group-addon',
7957 html : this.fieldLabel
7967 Roo.log(" no label && no align");
7974 ['xs','sm','md','lg'].map(function(size){
7975 if (settings[size]) {
7976 cfg.cls += ' col-' + size + '-' + settings[size];
7987 onResize : function(w, h){
7988 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7989 // if(typeof w == 'number'){
7990 // var x = w - this.trigger.getWidth();
7991 // this.inputEl().setWidth(this.adjustWidth('input', x));
7992 // this.trigger.setStyle('left', x+'px');
7997 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8000 getResizeEl : function(){
8001 return this.inputEl();
8005 getPositionEl : function(){
8006 return this.inputEl();
8010 alignErrorIcon : function(){
8011 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8015 initEvents : function(){
8019 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8020 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8021 if(!this.multiple && this.showToggleBtn){
8022 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8023 if(this.hideTrigger){
8024 this.trigger.setDisplayed(false);
8026 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8030 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8033 //this.trigger.addClassOnOver('x-form-trigger-over');
8034 //this.trigger.addClassOnClick('x-form-trigger-click');
8037 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8041 createList : function()
8043 this.list = Roo.get(document.body).createChild({
8045 cls: 'typeahead typeahead-long dropdown-menu',
8046 style: 'display:none'
8049 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8054 initTrigger : function(){
8059 onDestroy : function(){
8061 this.trigger.removeAllListeners();
8062 // this.trigger.remove();
8065 // this.wrap.remove();
8067 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8071 onFocus : function(){
8072 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8075 this.wrap.addClass('x-trigger-wrap-focus');
8076 this.mimicing = true;
8077 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8078 if(this.monitorTab){
8079 this.el.on("keydown", this.checkTab, this);
8086 checkTab : function(e){
8087 if(e.getKey() == e.TAB){
8093 onBlur : function(){
8098 mimicBlur : function(e, t){
8100 if(!this.wrap.contains(t) && this.validateBlur()){
8107 triggerBlur : function(){
8108 this.mimicing = false;
8109 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8110 if(this.monitorTab){
8111 this.el.un("keydown", this.checkTab, this);
8113 //this.wrap.removeClass('x-trigger-wrap-focus');
8114 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8118 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8119 validateBlur : function(e, t){
8124 onDisable : function(){
8125 this.inputEl().dom.disabled = true;
8126 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8128 // this.wrap.addClass('x-item-disabled');
8133 onEnable : function(){
8134 this.inputEl().dom.disabled = false;
8135 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8137 // this.el.removeClass('x-item-disabled');
8142 onShow : function(){
8143 var ae = this.getActionEl();
8146 ae.dom.style.display = '';
8147 ae.dom.style.visibility = 'visible';
8153 onHide : function(){
8154 var ae = this.getActionEl();
8155 ae.dom.style.display = 'none';
8159 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8160 * by an implementing function.
8162 * @param {EventObject} e
8164 onTriggerClick : Roo.emptyFn
8168 * Ext JS Library 1.1.1
8169 * Copyright(c) 2006-2007, Ext JS, LLC.
8171 * Originally Released Under LGPL - original licence link has changed is not relivant.
8174 * <script type="text/javascript">
8179 * @class Roo.data.SortTypes
8181 * Defines the default sorting (casting?) comparison functions used when sorting data.
8183 Roo.data.SortTypes = {
8185 * Default sort that does nothing
8186 * @param {Mixed} s The value being converted
8187 * @return {Mixed} The comparison value
8194 * The regular expression used to strip tags
8198 stripTagsRE : /<\/?[^>]+>/gi,
8201 * Strips all HTML tags to sort on text only
8202 * @param {Mixed} s The value being converted
8203 * @return {String} The comparison value
8205 asText : function(s){
8206 return String(s).replace(this.stripTagsRE, "");
8210 * Strips all HTML tags to sort on text only - Case insensitive
8211 * @param {Mixed} s The value being converted
8212 * @return {String} The comparison value
8214 asUCText : function(s){
8215 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8219 * Case insensitive string
8220 * @param {Mixed} s The value being converted
8221 * @return {String} The comparison value
8223 asUCString : function(s) {
8224 return String(s).toUpperCase();
8229 * @param {Mixed} s The value being converted
8230 * @return {Number} The comparison value
8232 asDate : function(s) {
8236 if(s instanceof Date){
8239 return Date.parse(String(s));
8244 * @param {Mixed} s The value being converted
8245 * @return {Float} The comparison value
8247 asFloat : function(s) {
8248 var val = parseFloat(String(s).replace(/,/g, ""));
8249 if(isNaN(val)) val = 0;
8255 * @param {Mixed} s The value being converted
8256 * @return {Number} The comparison value
8258 asInt : function(s) {
8259 var val = parseInt(String(s).replace(/,/g, ""));
8260 if(isNaN(val)) val = 0;
8265 * Ext JS Library 1.1.1
8266 * Copyright(c) 2006-2007, Ext JS, LLC.
8268 * Originally Released Under LGPL - original licence link has changed is not relivant.
8271 * <script type="text/javascript">
8275 * @class Roo.data.Record
8276 * Instances of this class encapsulate both record <em>definition</em> information, and record
8277 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8278 * to access Records cached in an {@link Roo.data.Store} object.<br>
8280 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8281 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8284 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8286 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8287 * {@link #create}. The parameters are the same.
8288 * @param {Array} data An associative Array of data values keyed by the field name.
8289 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8290 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8291 * not specified an integer id is generated.
8293 Roo.data.Record = function(data, id){
8294 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8299 * Generate a constructor for a specific record layout.
8300 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8301 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8302 * Each field definition object may contain the following properties: <ul>
8303 * <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,
8304 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8305 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8306 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8307 * is being used, then this is a string containing the javascript expression to reference the data relative to
8308 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8309 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8310 * this may be omitted.</p></li>
8311 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8312 * <ul><li>auto (Default, implies no conversion)</li>
8317 * <li>date</li></ul></p></li>
8318 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8319 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8320 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8321 * by the Reader into an object that will be stored in the Record. It is passed the
8322 * following parameters:<ul>
8323 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8325 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8327 * <br>usage:<br><pre><code>
8328 var TopicRecord = Roo.data.Record.create(
8329 {name: 'title', mapping: 'topic_title'},
8330 {name: 'author', mapping: 'username'},
8331 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8332 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8333 {name: 'lastPoster', mapping: 'user2'},
8334 {name: 'excerpt', mapping: 'post_text'}
8337 var myNewRecord = new TopicRecord({
8338 title: 'Do my job please',
8341 lastPost: new Date(),
8342 lastPoster: 'Animal',
8343 excerpt: 'No way dude!'
8345 myStore.add(myNewRecord);
8350 Roo.data.Record.create = function(o){
8352 f.superclass.constructor.apply(this, arguments);
8354 Roo.extend(f, Roo.data.Record);
8355 var p = f.prototype;
8356 p.fields = new Roo.util.MixedCollection(false, function(field){
8359 for(var i = 0, len = o.length; i < len; i++){
8360 p.fields.add(new Roo.data.Field(o[i]));
8362 f.getField = function(name){
8363 return p.fields.get(name);
8368 Roo.data.Record.AUTO_ID = 1000;
8369 Roo.data.Record.EDIT = 'edit';
8370 Roo.data.Record.REJECT = 'reject';
8371 Roo.data.Record.COMMIT = 'commit';
8373 Roo.data.Record.prototype = {
8375 * Readonly flag - true if this record has been modified.
8384 join : function(store){
8389 * Set the named field to the specified value.
8390 * @param {String} name The name of the field to set.
8391 * @param {Object} value The value to set the field to.
8393 set : function(name, value){
8394 if(this.data[name] == value){
8401 if(typeof this.modified[name] == 'undefined'){
8402 this.modified[name] = this.data[name];
8404 this.data[name] = value;
8405 if(!this.editing && this.store){
8406 this.store.afterEdit(this);
8411 * Get the value of the named field.
8412 * @param {String} name The name of the field to get the value of.
8413 * @return {Object} The value of the field.
8415 get : function(name){
8416 return this.data[name];
8420 beginEdit : function(){
8421 this.editing = true;
8426 cancelEdit : function(){
8427 this.editing = false;
8428 delete this.modified;
8432 endEdit : function(){
8433 this.editing = false;
8434 if(this.dirty && this.store){
8435 this.store.afterEdit(this);
8440 * Usually called by the {@link Roo.data.Store} which owns the Record.
8441 * Rejects all changes made to the Record since either creation, or the last commit operation.
8442 * Modified fields are reverted to their original values.
8444 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8445 * of reject operations.
8447 reject : function(){
8448 var m = this.modified;
8450 if(typeof m[n] != "function"){
8451 this.data[n] = m[n];
8455 delete this.modified;
8456 this.editing = false;
8458 this.store.afterReject(this);
8463 * Usually called by the {@link Roo.data.Store} which owns the Record.
8464 * Commits all changes made to the Record since either creation, or the last commit operation.
8466 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8467 * of commit operations.
8469 commit : function(){
8471 delete this.modified;
8472 this.editing = false;
8474 this.store.afterCommit(this);
8479 hasError : function(){
8480 return this.error != null;
8484 clearError : function(){
8489 * Creates a copy of this record.
8490 * @param {String} id (optional) A new record id if you don't want to use this record's id
8493 copy : function(newId) {
8494 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8498 * Ext JS Library 1.1.1
8499 * Copyright(c) 2006-2007, Ext JS, LLC.
8501 * Originally Released Under LGPL - original licence link has changed is not relivant.
8504 * <script type="text/javascript">
8510 * @class Roo.data.Store
8511 * @extends Roo.util.Observable
8512 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8513 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8515 * 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
8516 * has no knowledge of the format of the data returned by the Proxy.<br>
8518 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8519 * instances from the data object. These records are cached and made available through accessor functions.
8521 * Creates a new Store.
8522 * @param {Object} config A config object containing the objects needed for the Store to access data,
8523 * and read the data into Records.
8525 Roo.data.Store = function(config){
8526 this.data = new Roo.util.MixedCollection(false);
8527 this.data.getKey = function(o){
8530 this.baseParams = {};
8537 "multisort" : "_multisort"
8540 if(config && config.data){
8541 this.inlineData = config.data;
8545 Roo.apply(this, config);
8547 if(this.reader){ // reader passed
8548 this.reader = Roo.factory(this.reader, Roo.data);
8549 this.reader.xmodule = this.xmodule || false;
8550 if(!this.recordType){
8551 this.recordType = this.reader.recordType;
8553 if(this.reader.onMetaChange){
8554 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8558 if(this.recordType){
8559 this.fields = this.recordType.prototype.fields;
8565 * @event datachanged
8566 * Fires when the data cache has changed, and a widget which is using this Store
8567 * as a Record cache should refresh its view.
8568 * @param {Store} this
8573 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8574 * @param {Store} this
8575 * @param {Object} meta The JSON metadata
8580 * Fires when Records have been added to the Store
8581 * @param {Store} this
8582 * @param {Roo.data.Record[]} records The array of Records added
8583 * @param {Number} index The index at which the record(s) were added
8588 * Fires when a Record has been removed from the Store
8589 * @param {Store} this
8590 * @param {Roo.data.Record} record The Record that was removed
8591 * @param {Number} index The index at which the record was removed
8596 * Fires when a Record has been updated
8597 * @param {Store} this
8598 * @param {Roo.data.Record} record The Record that was updated
8599 * @param {String} operation The update operation being performed. Value may be one of:
8601 Roo.data.Record.EDIT
8602 Roo.data.Record.REJECT
8603 Roo.data.Record.COMMIT
8609 * Fires when the data cache has been cleared.
8610 * @param {Store} this
8615 * Fires before a request is made for a new data object. If the beforeload handler returns false
8616 * the load action will be canceled.
8617 * @param {Store} this
8618 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8622 * @event beforeloadadd
8623 * Fires after a new set of Records has been loaded.
8624 * @param {Store} this
8625 * @param {Roo.data.Record[]} records The Records that were loaded
8626 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8628 beforeloadadd : true,
8631 * Fires after a new set of Records has been loaded, before they are added to the store.
8632 * @param {Store} this
8633 * @param {Roo.data.Record[]} records The Records that were loaded
8634 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8635 * @params {Object} return from reader
8639 * @event loadexception
8640 * Fires if an exception occurs in the Proxy during loading.
8641 * Called with the signature of the Proxy's "loadexception" event.
8642 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8645 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8646 * @param {Object} load options
8647 * @param {Object} jsonData from your request (normally this contains the Exception)
8649 loadexception : true
8653 this.proxy = Roo.factory(this.proxy, Roo.data);
8654 this.proxy.xmodule = this.xmodule || false;
8655 this.relayEvents(this.proxy, ["loadexception"]);
8657 this.sortToggle = {};
8658 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8660 Roo.data.Store.superclass.constructor.call(this);
8662 if(this.inlineData){
8663 this.loadData(this.inlineData);
8664 delete this.inlineData;
8668 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8670 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8671 * without a remote query - used by combo/forms at present.
8675 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8678 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8681 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8682 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8685 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8686 * on any HTTP request
8689 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8692 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8696 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8697 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8702 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8703 * loaded or when a record is removed. (defaults to false).
8705 pruneModifiedRecords : false,
8711 * Add Records to the Store and fires the add event.
8712 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8714 add : function(records){
8715 records = [].concat(records);
8716 for(var i = 0, len = records.length; i < len; i++){
8717 records[i].join(this);
8719 var index = this.data.length;
8720 this.data.addAll(records);
8721 this.fireEvent("add", this, records, index);
8725 * Remove a Record from the Store and fires the remove event.
8726 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8728 remove : function(record){
8729 var index = this.data.indexOf(record);
8730 this.data.removeAt(index);
8731 if(this.pruneModifiedRecords){
8732 this.modified.remove(record);
8734 this.fireEvent("remove", this, record, index);
8738 * Remove all Records from the Store and fires the clear event.
8740 removeAll : function(){
8742 if(this.pruneModifiedRecords){
8745 this.fireEvent("clear", this);
8749 * Inserts Records to the Store at the given index and fires the add event.
8750 * @param {Number} index The start index at which to insert the passed Records.
8751 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8753 insert : function(index, records){
8754 records = [].concat(records);
8755 for(var i = 0, len = records.length; i < len; i++){
8756 this.data.insert(index, records[i]);
8757 records[i].join(this);
8759 this.fireEvent("add", this, records, index);
8763 * Get the index within the cache of the passed Record.
8764 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8765 * @return {Number} The index of the passed Record. Returns -1 if not found.
8767 indexOf : function(record){
8768 return this.data.indexOf(record);
8772 * Get the index within the cache of the Record with the passed id.
8773 * @param {String} id The id of the Record to find.
8774 * @return {Number} The index of the Record. Returns -1 if not found.
8776 indexOfId : function(id){
8777 return this.data.indexOfKey(id);
8781 * Get the Record with the specified id.
8782 * @param {String} id The id of the Record to find.
8783 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8785 getById : function(id){
8786 return this.data.key(id);
8790 * Get the Record at the specified index.
8791 * @param {Number} index The index of the Record to find.
8792 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8794 getAt : function(index){
8795 return this.data.itemAt(index);
8799 * Returns a range of Records between specified indices.
8800 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8801 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8802 * @return {Roo.data.Record[]} An array of Records
8804 getRange : function(start, end){
8805 return this.data.getRange(start, end);
8809 storeOptions : function(o){
8810 o = Roo.apply({}, o);
8813 this.lastOptions = o;
8817 * Loads the Record cache from the configured Proxy using the configured Reader.
8819 * If using remote paging, then the first load call must specify the <em>start</em>
8820 * and <em>limit</em> properties in the options.params property to establish the initial
8821 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8823 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8824 * and this call will return before the new data has been loaded. Perform any post-processing
8825 * in a callback function, or in a "load" event handler.</strong>
8827 * @param {Object} options An object containing properties which control loading options:<ul>
8828 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8829 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8830 * passed the following arguments:<ul>
8831 * <li>r : Roo.data.Record[]</li>
8832 * <li>options: Options object from the load call</li>
8833 * <li>success: Boolean success indicator</li></ul></li>
8834 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8835 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8838 load : function(options){
8839 options = options || {};
8840 if(this.fireEvent("beforeload", this, options) !== false){
8841 this.storeOptions(options);
8842 var p = Roo.apply(options.params || {}, this.baseParams);
8843 // if meta was not loaded from remote source.. try requesting it.
8844 if (!this.reader.metaFromRemote) {
8847 if(this.sortInfo && this.remoteSort){
8848 var pn = this.paramNames;
8849 p[pn["sort"]] = this.sortInfo.field;
8850 p[pn["dir"]] = this.sortInfo.direction;
8852 if (this.multiSort) {
8853 var pn = this.paramNames;
8854 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8857 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8862 * Reloads the Record cache from the configured Proxy using the configured Reader and
8863 * the options from the last load operation performed.
8864 * @param {Object} options (optional) An object containing properties which may override the options
8865 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8866 * the most recently used options are reused).
8868 reload : function(options){
8869 this.load(Roo.applyIf(options||{}, this.lastOptions));
8873 // Called as a callback by the Reader during a load operation.
8874 loadRecords : function(o, options, success){
8875 if(!o || success === false){
8876 if(success !== false){
8877 this.fireEvent("load", this, [], options, o);
8879 if(options.callback){
8880 options.callback.call(options.scope || this, [], options, false);
8884 // if data returned failure - throw an exception.
8885 if (o.success === false) {
8886 // show a message if no listener is registered.
8887 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8888 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8890 // loadmask wil be hooked into this..
8891 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8894 var r = o.records, t = o.totalRecords || r.length;
8896 this.fireEvent("beforeloadadd", this, r, options, o);
8898 if(!options || options.add !== true){
8899 if(this.pruneModifiedRecords){
8902 for(var i = 0, len = r.length; i < len; i++){
8906 this.data = this.snapshot;
8907 delete this.snapshot;
8910 this.data.addAll(r);
8911 this.totalLength = t;
8913 this.fireEvent("datachanged", this);
8915 this.totalLength = Math.max(t, this.data.length+r.length);
8918 this.fireEvent("load", this, r, options, o);
8919 if(options.callback){
8920 options.callback.call(options.scope || this, r, options, true);
8926 * Loads data from a passed data block. A Reader which understands the format of the data
8927 * must have been configured in the constructor.
8928 * @param {Object} data The data block from which to read the Records. The format of the data expected
8929 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8930 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8932 loadData : function(o, append){
8933 var r = this.reader.readRecords(o);
8934 this.loadRecords(r, {add: append}, true);
8938 * Gets the number of cached records.
8940 * <em>If using paging, this may not be the total size of the dataset. If the data object
8941 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8942 * the data set size</em>
8944 getCount : function(){
8945 return this.data.length || 0;
8949 * Gets the total number of records in the dataset as returned by the server.
8951 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8952 * the dataset size</em>
8954 getTotalCount : function(){
8955 return this.totalLength || 0;
8959 * Returns the sort state of the Store as an object with two properties:
8961 field {String} The name of the field by which the Records are sorted
8962 direction {String} The sort order, "ASC" or "DESC"
8965 getSortState : function(){
8966 return this.sortInfo;
8970 applySort : function(){
8971 if(this.sortInfo && !this.remoteSort){
8972 var s = this.sortInfo, f = s.field;
8973 var st = this.fields.get(f).sortType;
8974 var fn = function(r1, r2){
8975 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8976 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8978 this.data.sort(s.direction, fn);
8979 if(this.snapshot && this.snapshot != this.data){
8980 this.snapshot.sort(s.direction, fn);
8986 * Sets the default sort column and order to be used by the next load operation.
8987 * @param {String} fieldName The name of the field to sort by.
8988 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8990 setDefaultSort : function(field, dir){
8991 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8996 * If remote sorting is used, the sort is performed on the server, and the cache is
8997 * reloaded. If local sorting is used, the cache is sorted internally.
8998 * @param {String} fieldName The name of the field to sort by.
8999 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9001 sort : function(fieldName, dir){
9002 var f = this.fields.get(fieldName);
9004 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9006 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9007 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9012 this.sortToggle[f.name] = dir;
9013 this.sortInfo = {field: f.name, direction: dir};
9014 if(!this.remoteSort){
9016 this.fireEvent("datachanged", this);
9018 this.load(this.lastOptions);
9023 * Calls the specified function for each of the Records in the cache.
9024 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9025 * Returning <em>false</em> aborts and exits the iteration.
9026 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9028 each : function(fn, scope){
9029 this.data.each(fn, scope);
9033 * Gets all records modified since the last commit. Modified records are persisted across load operations
9034 * (e.g., during paging).
9035 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9037 getModifiedRecords : function(){
9038 return this.modified;
9042 createFilterFn : function(property, value, anyMatch){
9043 if(!value.exec){ // not a regex
9044 value = String(value);
9045 if(value.length == 0){
9048 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9051 return value.test(r.data[property]);
9056 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9057 * @param {String} property A field on your records
9058 * @param {Number} start The record index to start at (defaults to 0)
9059 * @param {Number} end The last record index to include (defaults to length - 1)
9060 * @return {Number} The sum
9062 sum : function(property, start, end){
9063 var rs = this.data.items, v = 0;
9065 end = (end || end === 0) ? end : rs.length-1;
9067 for(var i = start; i <= end; i++){
9068 v += (rs[i].data[property] || 0);
9074 * Filter the records by a specified property.
9075 * @param {String} field A field on your records
9076 * @param {String/RegExp} value Either a string that the field
9077 * should start with or a RegExp to test against the field
9078 * @param {Boolean} anyMatch True to match any part not just the beginning
9080 filter : function(property, value, anyMatch){
9081 var fn = this.createFilterFn(property, value, anyMatch);
9082 return fn ? this.filterBy(fn) : this.clearFilter();
9086 * Filter by a function. The specified function will be called with each
9087 * record in this data source. If the function returns true the record is included,
9088 * otherwise it is filtered.
9089 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9090 * @param {Object} scope (optional) The scope of the function (defaults to this)
9092 filterBy : function(fn, scope){
9093 this.snapshot = this.snapshot || this.data;
9094 this.data = this.queryBy(fn, scope||this);
9095 this.fireEvent("datachanged", this);
9099 * Query the records by a specified property.
9100 * @param {String} field A field on your records
9101 * @param {String/RegExp} value Either a string that the field
9102 * should start with or a RegExp to test against the field
9103 * @param {Boolean} anyMatch True to match any part not just the beginning
9104 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9106 query : function(property, value, anyMatch){
9107 var fn = this.createFilterFn(property, value, anyMatch);
9108 return fn ? this.queryBy(fn) : this.data.clone();
9112 * Query by a function. The specified function will be called with each
9113 * record in this data source. If the function returns true the record is included
9115 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9116 * @param {Object} scope (optional) The scope of the function (defaults to this)
9117 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9119 queryBy : function(fn, scope){
9120 var data = this.snapshot || this.data;
9121 return data.filterBy(fn, scope||this);
9125 * Collects unique values for a particular dataIndex from this store.
9126 * @param {String} dataIndex The property to collect
9127 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9128 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9129 * @return {Array} An array of the unique values
9131 collect : function(dataIndex, allowNull, bypassFilter){
9132 var d = (bypassFilter === true && this.snapshot) ?
9133 this.snapshot.items : this.data.items;
9134 var v, sv, r = [], l = {};
9135 for(var i = 0, len = d.length; i < len; i++){
9136 v = d[i].data[dataIndex];
9138 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9147 * Revert to a view of the Record cache with no filtering applied.
9148 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9150 clearFilter : function(suppressEvent){
9151 if(this.snapshot && this.snapshot != this.data){
9152 this.data = this.snapshot;
9153 delete this.snapshot;
9154 if(suppressEvent !== true){
9155 this.fireEvent("datachanged", this);
9161 afterEdit : function(record){
9162 if(this.modified.indexOf(record) == -1){
9163 this.modified.push(record);
9165 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9169 afterReject : function(record){
9170 this.modified.remove(record);
9171 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9175 afterCommit : function(record){
9176 this.modified.remove(record);
9177 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9181 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9182 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9184 commitChanges : function(){
9185 var m = this.modified.slice(0);
9187 for(var i = 0, len = m.length; i < len; i++){
9193 * Cancel outstanding changes on all changed records.
9195 rejectChanges : function(){
9196 var m = this.modified.slice(0);
9198 for(var i = 0, len = m.length; i < len; i++){
9203 onMetaChange : function(meta, rtype, o){
9204 this.recordType = rtype;
9205 this.fields = rtype.prototype.fields;
9206 delete this.snapshot;
9207 this.sortInfo = meta.sortInfo || this.sortInfo;
9209 this.fireEvent('metachange', this, this.reader.meta);
9212 moveIndex : function(data, type)
9214 var index = this.indexOf(data);
9216 var newIndex = index + type;
9220 this.insert(newIndex, data);
9225 * Ext JS Library 1.1.1
9226 * Copyright(c) 2006-2007, Ext JS, LLC.
9228 * Originally Released Under LGPL - original licence link has changed is not relivant.
9231 * <script type="text/javascript">
9235 * @class Roo.data.SimpleStore
9236 * @extends Roo.data.Store
9237 * Small helper class to make creating Stores from Array data easier.
9238 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9239 * @cfg {Array} fields An array of field definition objects, or field name strings.
9240 * @cfg {Array} data The multi-dimensional array of data
9242 * @param {Object} config
9244 Roo.data.SimpleStore = function(config){
9245 Roo.data.SimpleStore.superclass.constructor.call(this, {
9247 reader: new Roo.data.ArrayReader({
9250 Roo.data.Record.create(config.fields)
9252 proxy : new Roo.data.MemoryProxy(config.data)
9256 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9258 * Ext JS Library 1.1.1
9259 * Copyright(c) 2006-2007, Ext JS, LLC.
9261 * Originally Released Under LGPL - original licence link has changed is not relivant.
9264 * <script type="text/javascript">
9269 * @extends Roo.data.Store
9270 * @class Roo.data.JsonStore
9271 * Small helper class to make creating Stores for JSON data easier. <br/>
9273 var store = new Roo.data.JsonStore({
9274 url: 'get-images.php',
9276 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9279 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9280 * JsonReader and HttpProxy (unless inline data is provided).</b>
9281 * @cfg {Array} fields An array of field definition objects, or field name strings.
9283 * @param {Object} config
9285 Roo.data.JsonStore = function(c){
9286 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9287 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9288 reader: new Roo.data.JsonReader(c, c.fields)
9291 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9293 * Ext JS Library 1.1.1
9294 * Copyright(c) 2006-2007, Ext JS, LLC.
9296 * Originally Released Under LGPL - original licence link has changed is not relivant.
9299 * <script type="text/javascript">
9303 Roo.data.Field = function(config){
9304 if(typeof config == "string"){
9305 config = {name: config};
9307 Roo.apply(this, config);
9313 var st = Roo.data.SortTypes;
9314 // named sortTypes are supported, here we look them up
9315 if(typeof this.sortType == "string"){
9316 this.sortType = st[this.sortType];
9319 // set default sortType for strings and dates
9323 this.sortType = st.asUCString;
9326 this.sortType = st.asDate;
9329 this.sortType = st.none;
9334 var stripRe = /[\$,%]/g;
9336 // prebuilt conversion function for this field, instead of
9337 // switching every time we're reading a value
9339 var cv, dateFormat = this.dateFormat;
9344 cv = function(v){ return v; };
9347 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9351 return v !== undefined && v !== null && v !== '' ?
9352 parseInt(String(v).replace(stripRe, ""), 10) : '';
9357 return v !== undefined && v !== null && v !== '' ?
9358 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9363 cv = function(v){ return v === true || v === "true" || v == 1; };
9370 if(v instanceof Date){
9374 if(dateFormat == "timestamp"){
9375 return new Date(v*1000);
9377 return Date.parseDate(v, dateFormat);
9379 var parsed = Date.parse(v);
9380 return parsed ? new Date(parsed) : null;
9389 Roo.data.Field.prototype = {
9397 * Ext JS Library 1.1.1
9398 * Copyright(c) 2006-2007, Ext JS, LLC.
9400 * Originally Released Under LGPL - original licence link has changed is not relivant.
9403 * <script type="text/javascript">
9406 // Base class for reading structured data from a data source. This class is intended to be
9407 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9410 * @class Roo.data.DataReader
9411 * Base class for reading structured data from a data source. This class is intended to be
9412 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9415 Roo.data.DataReader = function(meta, recordType){
9419 this.recordType = recordType instanceof Array ?
9420 Roo.data.Record.create(recordType) : recordType;
9423 Roo.data.DataReader.prototype = {
9425 * Create an empty record
9426 * @param {Object} data (optional) - overlay some values
9427 * @return {Roo.data.Record} record created.
9429 newRow : function(d) {
9431 this.recordType.prototype.fields.each(function(c) {
9433 case 'int' : da[c.name] = 0; break;
9434 case 'date' : da[c.name] = new Date(); break;
9435 case 'float' : da[c.name] = 0.0; break;
9436 case 'boolean' : da[c.name] = false; break;
9437 default : da[c.name] = ""; break;
9441 return new this.recordType(Roo.apply(da, d));
9446 * Ext JS Library 1.1.1
9447 * Copyright(c) 2006-2007, Ext JS, LLC.
9449 * Originally Released Under LGPL - original licence link has changed is not relivant.
9452 * <script type="text/javascript">
9456 * @class Roo.data.DataProxy
9457 * @extends Roo.data.Observable
9458 * This class is an abstract base class for implementations which provide retrieval of
9459 * unformatted data objects.<br>
9461 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9462 * (of the appropriate type which knows how to parse the data object) to provide a block of
9463 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9465 * Custom implementations must implement the load method as described in
9466 * {@link Roo.data.HttpProxy#load}.
9468 Roo.data.DataProxy = function(){
9472 * Fires before a network request is made to retrieve a data object.
9473 * @param {Object} This DataProxy object.
9474 * @param {Object} params The params parameter to the load function.
9479 * Fires before the load method's callback is called.
9480 * @param {Object} This DataProxy object.
9481 * @param {Object} o The data object.
9482 * @param {Object} arg The callback argument object passed to the load function.
9486 * @event loadexception
9487 * Fires if an Exception occurs during data retrieval.
9488 * @param {Object} This DataProxy object.
9489 * @param {Object} o The data object.
9490 * @param {Object} arg The callback argument object passed to the load function.
9491 * @param {Object} e The Exception.
9493 loadexception : true
9495 Roo.data.DataProxy.superclass.constructor.call(this);
9498 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9501 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9505 * Ext JS Library 1.1.1
9506 * Copyright(c) 2006-2007, Ext JS, LLC.
9508 * Originally Released Under LGPL - original licence link has changed is not relivant.
9511 * <script type="text/javascript">
9514 * @class Roo.data.MemoryProxy
9515 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9516 * to the Reader when its load method is called.
9518 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9520 Roo.data.MemoryProxy = function(data){
9524 Roo.data.MemoryProxy.superclass.constructor.call(this);
9528 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9530 * Load data from the requested source (in this case an in-memory
9531 * data object passed to the constructor), read the data object into
9532 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9533 * process that block using the passed callback.
9534 * @param {Object} params This parameter is not used by the MemoryProxy class.
9535 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9536 * object into a block of Roo.data.Records.
9537 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9538 * The function must be passed <ul>
9539 * <li>The Record block object</li>
9540 * <li>The "arg" argument from the load function</li>
9541 * <li>A boolean success indicator</li>
9543 * @param {Object} scope The scope in which to call the callback
9544 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9546 load : function(params, reader, callback, scope, arg){
9547 params = params || {};
9550 result = reader.readRecords(this.data);
9552 this.fireEvent("loadexception", this, arg, null, e);
9553 callback.call(scope, null, arg, false);
9556 callback.call(scope, result, arg, true);
9560 update : function(params, records){
9565 * Ext JS Library 1.1.1
9566 * Copyright(c) 2006-2007, Ext JS, LLC.
9568 * Originally Released Under LGPL - original licence link has changed is not relivant.
9571 * <script type="text/javascript">
9574 * @class Roo.data.HttpProxy
9575 * @extends Roo.data.DataProxy
9576 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9577 * configured to reference a certain URL.<br><br>
9579 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9580 * from which the running page was served.<br><br>
9582 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9584 * Be aware that to enable the browser to parse an XML document, the server must set
9585 * the Content-Type header in the HTTP response to "text/xml".
9587 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9588 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9589 * will be used to make the request.
9591 Roo.data.HttpProxy = function(conn){
9592 Roo.data.HttpProxy.superclass.constructor.call(this);
9593 // is conn a conn config or a real conn?
9595 this.useAjax = !conn || !conn.events;
9599 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9600 // thse are take from connection...
9603 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9606 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9607 * extra parameters to each request made by this object. (defaults to undefined)
9610 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9611 * to each request made by this object. (defaults to undefined)
9614 * @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)
9617 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9620 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9626 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9630 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9631 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9632 * a finer-grained basis than the DataProxy events.
9634 getConnection : function(){
9635 return this.useAjax ? Roo.Ajax : this.conn;
9639 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9640 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9641 * process that block using the passed callback.
9642 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9643 * for the request to the remote server.
9644 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9645 * object into a block of Roo.data.Records.
9646 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9647 * The function must be passed <ul>
9648 * <li>The Record block object</li>
9649 * <li>The "arg" argument from the load function</li>
9650 * <li>A boolean success indicator</li>
9652 * @param {Object} scope The scope in which to call the callback
9653 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9655 load : function(params, reader, callback, scope, arg){
9656 if(this.fireEvent("beforeload", this, params) !== false){
9658 params : params || {},
9660 callback : callback,
9665 callback : this.loadResponse,
9669 Roo.applyIf(o, this.conn);
9670 if(this.activeRequest){
9671 Roo.Ajax.abort(this.activeRequest);
9673 this.activeRequest = Roo.Ajax.request(o);
9675 this.conn.request(o);
9678 callback.call(scope||this, null, arg, false);
9683 loadResponse : function(o, success, response){
9684 delete this.activeRequest;
9686 this.fireEvent("loadexception", this, o, response);
9687 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9692 result = o.reader.read(response);
9694 this.fireEvent("loadexception", this, o, response, e);
9695 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9699 this.fireEvent("load", this, o, o.request.arg);
9700 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9704 update : function(dataSet){
9709 updateResponse : function(dataSet){
9714 * Ext JS Library 1.1.1
9715 * Copyright(c) 2006-2007, Ext JS, LLC.
9717 * Originally Released Under LGPL - original licence link has changed is not relivant.
9720 * <script type="text/javascript">
9724 * @class Roo.data.ScriptTagProxy
9725 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9726 * other than the originating domain of the running page.<br><br>
9728 * <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
9729 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9731 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9732 * source code that is used as the source inside a <script> tag.<br><br>
9734 * In order for the browser to process the returned data, the server must wrap the data object
9735 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9736 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9737 * depending on whether the callback name was passed:
9740 boolean scriptTag = false;
9741 String cb = request.getParameter("callback");
9744 response.setContentType("text/javascript");
9746 response.setContentType("application/x-json");
9748 Writer out = response.getWriter();
9750 out.write(cb + "(");
9752 out.print(dataBlock.toJsonString());
9759 * @param {Object} config A configuration object.
9761 Roo.data.ScriptTagProxy = function(config){
9762 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9763 Roo.apply(this, config);
9764 this.head = document.getElementsByTagName("head")[0];
9767 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9769 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9771 * @cfg {String} url The URL from which to request the data object.
9774 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9778 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9779 * the server the name of the callback function set up by the load call to process the returned data object.
9780 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9781 * javascript output which calls this named function passing the data object as its only parameter.
9783 callbackParam : "callback",
9785 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9786 * name to the request.
9791 * Load data from the configured URL, read the data object into
9792 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9793 * process that block using the passed callback.
9794 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9795 * for the request to the remote server.
9796 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9797 * object into a block of Roo.data.Records.
9798 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9799 * The function must be passed <ul>
9800 * <li>The Record block object</li>
9801 * <li>The "arg" argument from the load function</li>
9802 * <li>A boolean success indicator</li>
9804 * @param {Object} scope The scope in which to call the callback
9805 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9807 load : function(params, reader, callback, scope, arg){
9808 if(this.fireEvent("beforeload", this, params) !== false){
9810 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9813 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9815 url += "&_dc=" + (new Date().getTime());
9817 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9820 cb : "stcCallback"+transId,
9821 scriptId : "stcScript"+transId,
9825 callback : callback,
9831 window[trans.cb] = function(o){
9832 conn.handleResponse(o, trans);
9835 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9837 if(this.autoAbort !== false){
9841 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9843 var script = document.createElement("script");
9844 script.setAttribute("src", url);
9845 script.setAttribute("type", "text/javascript");
9846 script.setAttribute("id", trans.scriptId);
9847 this.head.appendChild(script);
9851 callback.call(scope||this, null, arg, false);
9856 isLoading : function(){
9857 return this.trans ? true : false;
9861 * Abort the current server request.
9864 if(this.isLoading()){
9865 this.destroyTrans(this.trans);
9870 destroyTrans : function(trans, isLoaded){
9871 this.head.removeChild(document.getElementById(trans.scriptId));
9872 clearTimeout(trans.timeoutId);
9874 window[trans.cb] = undefined;
9876 delete window[trans.cb];
9879 // if hasn't been loaded, wait for load to remove it to prevent script error
9880 window[trans.cb] = function(){
9881 window[trans.cb] = undefined;
9883 delete window[trans.cb];
9890 handleResponse : function(o, trans){
9892 this.destroyTrans(trans, true);
9895 result = trans.reader.readRecords(o);
9897 this.fireEvent("loadexception", this, o, trans.arg, e);
9898 trans.callback.call(trans.scope||window, null, trans.arg, false);
9901 this.fireEvent("load", this, o, trans.arg);
9902 trans.callback.call(trans.scope||window, result, trans.arg, true);
9906 handleFailure : function(trans){
9908 this.destroyTrans(trans, false);
9909 this.fireEvent("loadexception", this, null, trans.arg);
9910 trans.callback.call(trans.scope||window, null, trans.arg, false);
9914 * Ext JS Library 1.1.1
9915 * Copyright(c) 2006-2007, Ext JS, LLC.
9917 * Originally Released Under LGPL - original licence link has changed is not relivant.
9920 * <script type="text/javascript">
9924 * @class Roo.data.JsonReader
9925 * @extends Roo.data.DataReader
9926 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9927 * based on mappings in a provided Roo.data.Record constructor.
9929 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9930 * in the reply previously.
9935 var RecordDef = Roo.data.Record.create([
9936 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9937 {name: 'occupation'} // This field will use "occupation" as the mapping.
9939 var myReader = new Roo.data.JsonReader({
9940 totalProperty: "results", // The property which contains the total dataset size (optional)
9941 root: "rows", // The property which contains an Array of row objects
9942 id: "id" // The property within each row object that provides an ID for the record (optional)
9946 * This would consume a JSON file like this:
9948 { 'results': 2, 'rows': [
9949 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9950 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9953 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9954 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9955 * paged from the remote server.
9956 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9957 * @cfg {String} root name of the property which contains the Array of row objects.
9958 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9960 * Create a new JsonReader
9961 * @param {Object} meta Metadata configuration options
9962 * @param {Object} recordType Either an Array of field definition objects,
9963 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9965 Roo.data.JsonReader = function(meta, recordType){
9968 // set some defaults:
9970 totalProperty: 'total',
9971 successProperty : 'success',
9976 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9978 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9981 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9982 * Used by Store query builder to append _requestMeta to params.
9985 metaFromRemote : false,
9987 * This method is only used by a DataProxy which has retrieved data from a remote server.
9988 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9989 * @return {Object} data A data block which is used by an Roo.data.Store object as
9990 * a cache of Roo.data.Records.
9992 read : function(response){
9993 var json = response.responseText;
9995 var o = /* eval:var:o */ eval("("+json+")");
9997 throw {message: "JsonReader.read: Json object not found"};
10003 this.metaFromRemote = true;
10004 this.meta = o.metaData;
10005 this.recordType = Roo.data.Record.create(o.metaData.fields);
10006 this.onMetaChange(this.meta, this.recordType, o);
10008 return this.readRecords(o);
10011 // private function a store will implement
10012 onMetaChange : function(meta, recordType, o){
10019 simpleAccess: function(obj, subsc) {
10026 getJsonAccessor: function(){
10028 return function(expr) {
10030 return(re.test(expr))
10031 ? new Function("obj", "return obj." + expr)
10036 return Roo.emptyFn;
10041 * Create a data block containing Roo.data.Records from an XML document.
10042 * @param {Object} o An object which contains an Array of row objects in the property specified
10043 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10044 * which contains the total size of the dataset.
10045 * @return {Object} data A data block which is used by an Roo.data.Store object as
10046 * a cache of Roo.data.Records.
10048 readRecords : function(o){
10050 * After any data loads, the raw JSON data is available for further custom processing.
10054 var s = this.meta, Record = this.recordType,
10055 f = Record.prototype.fields, fi = f.items, fl = f.length;
10057 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10059 if(s.totalProperty) {
10060 this.getTotal = this.getJsonAccessor(s.totalProperty);
10062 if(s.successProperty) {
10063 this.getSuccess = this.getJsonAccessor(s.successProperty);
10065 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10067 var g = this.getJsonAccessor(s.id);
10068 this.getId = function(rec) {
10070 return (r === undefined || r === "") ? null : r;
10073 this.getId = function(){return null;};
10076 for(var jj = 0; jj < fl; jj++){
10078 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10079 this.ef[jj] = this.getJsonAccessor(map);
10083 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10084 if(s.totalProperty){
10085 var vt = parseInt(this.getTotal(o), 10);
10090 if(s.successProperty){
10091 var vs = this.getSuccess(o);
10092 if(vs === false || vs === 'false'){
10097 for(var i = 0; i < c; i++){
10100 var id = this.getId(n);
10101 for(var j = 0; j < fl; j++){
10103 var v = this.ef[j](n);
10105 Roo.log('missing convert for ' + f.name);
10109 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10111 var record = new Record(values, id);
10113 records[i] = record;
10119 totalRecords : totalRecords
10124 * Ext JS Library 1.1.1
10125 * Copyright(c) 2006-2007, Ext JS, LLC.
10127 * Originally Released Under LGPL - original licence link has changed is not relivant.
10130 * <script type="text/javascript">
10134 * @class Roo.data.ArrayReader
10135 * @extends Roo.data.DataReader
10136 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10137 * Each element of that Array represents a row of data fields. The
10138 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10139 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10143 var RecordDef = Roo.data.Record.create([
10144 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10145 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10147 var myReader = new Roo.data.ArrayReader({
10148 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10152 * This would consume an Array like this:
10154 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10156 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10158 * Create a new JsonReader
10159 * @param {Object} meta Metadata configuration options.
10160 * @param {Object} recordType Either an Array of field definition objects
10161 * as specified to {@link Roo.data.Record#create},
10162 * or an {@link Roo.data.Record} object
10163 * created using {@link Roo.data.Record#create}.
10165 Roo.data.ArrayReader = function(meta, recordType){
10166 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10169 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10171 * Create a data block containing Roo.data.Records from an XML document.
10172 * @param {Object} o An Array of row objects which represents the dataset.
10173 * @return {Object} data A data block which is used by an Roo.data.Store object as
10174 * a cache of Roo.data.Records.
10176 readRecords : function(o){
10177 var sid = this.meta ? this.meta.id : null;
10178 var recordType = this.recordType, fields = recordType.prototype.fields;
10181 for(var i = 0; i < root.length; i++){
10184 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10185 for(var j = 0, jlen = fields.length; j < jlen; j++){
10186 var f = fields.items[j];
10187 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10188 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10190 values[f.name] = v;
10192 var record = new recordType(values, id);
10194 records[records.length] = record;
10198 totalRecords : records.length
10207 * @class Roo.bootstrap.ComboBox
10208 * @extends Roo.bootstrap.TriggerField
10209 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10210 * @cfg {Boolean} append (true|false) default false
10211 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10212 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10213 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10214 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10215 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10217 * Create a new ComboBox.
10218 * @param {Object} config Configuration options
10220 Roo.bootstrap.ComboBox = function(config){
10221 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10225 * Fires when the dropdown list is expanded
10226 * @param {Roo.bootstrap.ComboBox} combo This combo box
10231 * Fires when the dropdown list is collapsed
10232 * @param {Roo.bootstrap.ComboBox} combo This combo box
10236 * @event beforeselect
10237 * Fires before a list item is selected. Return false to cancel the selection.
10238 * @param {Roo.bootstrap.ComboBox} combo This combo box
10239 * @param {Roo.data.Record} record The data record returned from the underlying store
10240 * @param {Number} index The index of the selected item in the dropdown list
10242 'beforeselect' : true,
10245 * Fires when a list item is selected
10246 * @param {Roo.bootstrap.ComboBox} combo This combo box
10247 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10248 * @param {Number} index The index of the selected item in the dropdown list
10252 * @event beforequery
10253 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10254 * The event object passed has these properties:
10255 * @param {Roo.bootstrap.ComboBox} combo This combo box
10256 * @param {String} query The query
10257 * @param {Boolean} forceAll true to force "all" query
10258 * @param {Boolean} cancel true to cancel the query
10259 * @param {Object} e The query event object
10261 'beforequery': true,
10264 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10265 * @param {Roo.bootstrap.ComboBox} combo This combo box
10270 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10271 * @param {Roo.bootstrap.ComboBox} combo This combo box
10272 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10277 * Fires when the remove value from the combobox array
10278 * @param {Roo.bootstrap.ComboBox} combo This combo box
10285 this.tickItems = [];
10287 this.selectedIndex = -1;
10288 if(this.mode == 'local'){
10289 if(config.queryDelay === undefined){
10290 this.queryDelay = 10;
10292 if(config.minChars === undefined){
10298 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10301 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10302 * rendering into an Roo.Editor, defaults to false)
10305 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10306 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10309 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10312 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10313 * the dropdown list (defaults to undefined, with no header element)
10317 * @cfg {String/Roo.Template} tpl The template to use to render the output
10321 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10323 listWidth: undefined,
10325 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10326 * mode = 'remote' or 'text' if mode = 'local')
10328 displayField: undefined,
10330 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10331 * mode = 'remote' or 'value' if mode = 'local').
10332 * Note: use of a valueField requires the user make a selection
10333 * in order for a value to be mapped.
10335 valueField: undefined,
10339 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10340 * field's data value (defaults to the underlying DOM element's name)
10342 hiddenName: undefined,
10344 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10348 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10350 selectedClass: 'active',
10353 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10357 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10358 * anchor positions (defaults to 'tl-bl')
10360 listAlign: 'tl-bl?',
10362 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10366 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10367 * query specified by the allQuery config option (defaults to 'query')
10369 triggerAction: 'query',
10371 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10372 * (defaults to 4, does not apply if editable = false)
10376 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10377 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10381 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10382 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10386 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10387 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10391 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10392 * when editable = true (defaults to false)
10394 selectOnFocus:false,
10396 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10398 queryParam: 'query',
10400 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10401 * when mode = 'remote' (defaults to 'Loading...')
10403 loadingText: 'Loading...',
10405 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10409 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10413 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10414 * traditional select (defaults to true)
10418 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10422 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10426 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10427 * listWidth has a higher value)
10431 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10432 * allow the user to set arbitrary text into the field (defaults to false)
10434 forceSelection:false,
10436 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10437 * if typeAhead = true (defaults to 250)
10439 typeAheadDelay : 250,
10441 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10442 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10444 valueNotFoundText : undefined,
10446 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10448 blockFocus : false,
10451 * @cfg {Boolean} disableClear Disable showing of clear button.
10453 disableClear : false,
10455 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10457 alwaysQuery : false,
10460 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10474 btnPosition : 'right',
10475 triggerList : true,
10476 showToggleBtn : true,
10477 // element that contains real text value.. (when hidden is used..)
10479 getAutoCreate : function()
10486 if(!this.tickable){
10487 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10492 * ComboBox with tickable selections
10495 var align = this.labelAlign || this.parentLabelAlign();
10498 cls : 'form-group roo-combobox-tickable' //input-group
10504 cls : 'tickable-buttons',
10509 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10516 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10523 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10530 Roo.each(buttons.cn, function(c){
10532 c.cls += ' btn-' + _this.size;
10535 if (_this.disabled) {
10546 cls: 'form-hidden-field'
10550 cls: 'select2-choices',
10554 cls: 'select2-search-field',
10566 cls: 'select2-container input-group select2-container-multi',
10571 // cls: 'typeahead typeahead-long dropdown-menu',
10572 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10577 if (align ==='left' && this.fieldLabel.length) {
10579 Roo.log("left and has label");
10585 cls : 'control-label col-sm-' + this.labelWidth,
10586 html : this.fieldLabel
10590 cls : "col-sm-" + (12 - this.labelWidth),
10597 } else if ( this.fieldLabel.length) {
10603 //cls : 'input-group-addon',
10604 html : this.fieldLabel
10614 Roo.log(" no label && no align");
10621 ['xs','sm','md','lg'].map(function(size){
10622 if (settings[size]) {
10623 cfg.cls += ' col-' + size + '-' + settings[size];
10632 initEvents: function()
10636 throw "can not find store for combo";
10638 this.store = Roo.factory(this.store, Roo.data);
10641 this.initTickableEvents();
10645 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10647 if(this.hiddenName){
10649 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10651 this.hiddenField.dom.value =
10652 this.hiddenValue !== undefined ? this.hiddenValue :
10653 this.value !== undefined ? this.value : '';
10655 // prevent input submission
10656 this.el.dom.removeAttribute('name');
10657 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10662 // this.el.dom.setAttribute('autocomplete', 'off');
10665 var cls = 'x-combo-list';
10667 //this.list = new Roo.Layer({
10668 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10674 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10675 _this.list.setWidth(lw);
10678 this.list.on('mouseover', this.onViewOver, this);
10679 this.list.on('mousemove', this.onViewMove, this);
10681 this.list.on('scroll', this.onViewScroll, this);
10684 this.list.swallowEvent('mousewheel');
10685 this.assetHeight = 0;
10688 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10689 this.assetHeight += this.header.getHeight();
10692 this.innerList = this.list.createChild({cls:cls+'-inner'});
10693 this.innerList.on('mouseover', this.onViewOver, this);
10694 this.innerList.on('mousemove', this.onViewMove, this);
10695 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10697 if(this.allowBlank && !this.pageSize && !this.disableClear){
10698 this.footer = this.list.createChild({cls:cls+'-ft'});
10699 this.pageTb = new Roo.Toolbar(this.footer);
10703 this.footer = this.list.createChild({cls:cls+'-ft'});
10704 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10705 {pageSize: this.pageSize});
10709 if (this.pageTb && this.allowBlank && !this.disableClear) {
10711 this.pageTb.add(new Roo.Toolbar.Fill(), {
10712 cls: 'x-btn-icon x-btn-clear',
10714 handler: function()
10717 _this.clearValue();
10718 _this.onSelect(false, -1);
10723 this.assetHeight += this.footer.getHeight();
10728 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10731 this.view = new Roo.View(this.list, this.tpl, {
10732 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10734 //this.view.wrapEl.setDisplayed(false);
10735 this.view.on('click', this.onViewClick, this);
10739 this.store.on('beforeload', this.onBeforeLoad, this);
10740 this.store.on('load', this.onLoad, this);
10741 this.store.on('loadexception', this.onLoadException, this);
10743 if(this.resizable){
10744 this.resizer = new Roo.Resizable(this.list, {
10745 pinned:true, handles:'se'
10747 this.resizer.on('resize', function(r, w, h){
10748 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10749 this.listWidth = w;
10750 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10751 this.restrictHeight();
10753 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10756 if(!this.editable){
10757 this.editable = true;
10758 this.setEditable(false);
10763 if (typeof(this.events.add.listeners) != 'undefined') {
10765 this.addicon = this.wrap.createChild(
10766 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10768 this.addicon.on('click', function(e) {
10769 this.fireEvent('add', this);
10772 if (typeof(this.events.edit.listeners) != 'undefined') {
10774 this.editicon = this.wrap.createChild(
10775 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10776 if (this.addicon) {
10777 this.editicon.setStyle('margin-left', '40px');
10779 this.editicon.on('click', function(e) {
10781 // we fire even if inothing is selected..
10782 this.fireEvent('edit', this, this.lastData );
10788 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10789 "up" : function(e){
10790 this.inKeyMode = true;
10794 "down" : function(e){
10795 if(!this.isExpanded()){
10796 this.onTriggerClick();
10798 this.inKeyMode = true;
10803 "enter" : function(e){
10804 // this.onViewClick();
10808 if(this.fireEvent("specialkey", this, e)){
10809 this.onViewClick(false);
10815 "esc" : function(e){
10819 "tab" : function(e){
10822 if(this.fireEvent("specialkey", this, e)){
10823 this.onViewClick(false);
10831 doRelay : function(foo, bar, hname){
10832 if(hname == 'down' || this.scope.isExpanded()){
10833 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10842 this.queryDelay = Math.max(this.queryDelay || 10,
10843 this.mode == 'local' ? 10 : 250);
10846 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10848 if(this.typeAhead){
10849 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10851 if(this.editable !== false){
10852 this.inputEl().on("keyup", this.onKeyUp, this);
10854 if(this.forceSelection){
10855 this.inputEl().on('blur', this.doForce, this);
10859 this.choices = this.el.select('ul.select2-choices', true).first();
10860 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10864 initTickableEvents: function()
10868 if(this.hiddenName){
10870 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10872 this.hiddenField.dom.value =
10873 this.hiddenValue !== undefined ? this.hiddenValue :
10874 this.value !== undefined ? this.value : '';
10876 // prevent input submission
10877 this.el.dom.removeAttribute('name');
10878 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10883 // this.list = this.el.select('ul.dropdown-menu',true).first();
10885 this.choices = this.el.select('ul.select2-choices', true).first();
10886 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10887 if(this.triggerList){
10888 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10891 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10892 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10894 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10895 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10897 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10898 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10900 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10901 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10902 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10905 this.cancelBtn.hide();
10910 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10911 _this.list.setWidth(lw);
10914 this.list.on('mouseover', this.onViewOver, this);
10915 this.list.on('mousemove', this.onViewMove, this);
10917 this.list.on('scroll', this.onViewScroll, this);
10920 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>';
10923 this.view = new Roo.View(this.list, this.tpl, {
10924 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10927 //this.view.wrapEl.setDisplayed(false);
10928 this.view.on('click', this.onViewClick, this);
10932 this.store.on('beforeload', this.onBeforeLoad, this);
10933 this.store.on('load', this.onLoad, this);
10934 this.store.on('loadexception', this.onLoadException, this);
10936 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10937 // "up" : function(e){
10938 // this.inKeyMode = true;
10939 // this.selectPrev();
10942 // "down" : function(e){
10943 // if(!this.isExpanded()){
10944 // this.onTriggerClick();
10946 // this.inKeyMode = true;
10947 // this.selectNext();
10951 // "enter" : function(e){
10952 //// this.onViewClick();
10954 // this.collapse();
10956 // if(this.fireEvent("specialkey", this, e)){
10957 // this.onViewClick(false);
10963 // "esc" : function(e){
10964 // this.collapse();
10967 // "tab" : function(e){
10968 // this.collapse();
10970 // if(this.fireEvent("specialkey", this, e)){
10971 // this.onViewClick(false);
10979 // doRelay : function(foo, bar, hname){
10980 // if(hname == 'down' || this.scope.isExpanded()){
10981 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10986 // forceKeyDown: true
10990 this.queryDelay = Math.max(this.queryDelay || 10,
10991 this.mode == 'local' ? 10 : 250);
10994 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10996 if(this.typeAhead){
10997 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11001 onDestroy : function(){
11003 this.view.setStore(null);
11004 this.view.el.removeAllListeners();
11005 this.view.el.remove();
11006 this.view.purgeListeners();
11009 this.list.dom.innerHTML = '';
11013 this.store.un('beforeload', this.onBeforeLoad, this);
11014 this.store.un('load', this.onLoad, this);
11015 this.store.un('loadexception', this.onLoadException, this);
11017 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11021 fireKey : function(e){
11022 if(e.isNavKeyPress() && !this.list.isVisible()){
11023 this.fireEvent("specialkey", this, e);
11028 onResize: function(w, h){
11029 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11031 // if(typeof w != 'number'){
11032 // // we do not handle it!?!?
11035 // var tw = this.trigger.getWidth();
11036 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11037 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11039 // this.inputEl().setWidth( this.adjustWidth('input', x));
11041 // //this.trigger.setStyle('left', x+'px');
11043 // if(this.list && this.listWidth === undefined){
11044 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11045 // this.list.setWidth(lw);
11046 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11054 * Allow or prevent the user from directly editing the field text. If false is passed,
11055 * the user will only be able to select from the items defined in the dropdown list. This method
11056 * is the runtime equivalent of setting the 'editable' config option at config time.
11057 * @param {Boolean} value True to allow the user to directly edit the field text
11059 setEditable : function(value){
11060 if(value == this.editable){
11063 this.editable = value;
11065 this.inputEl().dom.setAttribute('readOnly', true);
11066 this.inputEl().on('mousedown', this.onTriggerClick, this);
11067 this.inputEl().addClass('x-combo-noedit');
11069 this.inputEl().dom.setAttribute('readOnly', false);
11070 this.inputEl().un('mousedown', this.onTriggerClick, this);
11071 this.inputEl().removeClass('x-combo-noedit');
11077 onBeforeLoad : function(combo,opts){
11078 if(!this.hasFocus){
11082 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11084 // this.restrictHeight();
11085 this.selectedIndex = -1;
11089 onLoad : function(){
11091 this.hasQuery = false;
11093 if(!this.hasFocus){
11097 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11098 this.loading.hide();
11101 if(this.store.getCount() > 0){
11103 // this.restrictHeight();
11104 if(this.lastQuery == this.allQuery){
11105 if(this.editable && !this.tickable){
11106 this.inputEl().dom.select();
11110 !this.selectByValue(this.value, true) &&
11111 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11112 this.store.lastOptions.add != true)
11114 this.select(0, true);
11117 if(this.autoFocus){
11120 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11121 this.taTask.delay(this.typeAheadDelay);
11125 this.onEmptyResults();
11131 onLoadException : function()
11133 this.hasQuery = false;
11135 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11136 this.loading.hide();
11140 Roo.log(this.store.reader.jsonData);
11141 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11143 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11149 onTypeAhead : function(){
11150 if(this.store.getCount() > 0){
11151 var r = this.store.getAt(0);
11152 var newValue = r.data[this.displayField];
11153 var len = newValue.length;
11154 var selStart = this.getRawValue().length;
11156 if(selStart != len){
11157 this.setRawValue(newValue);
11158 this.selectText(selStart, newValue.length);
11164 onSelect : function(record, index){
11166 if(this.fireEvent('beforeselect', this, record, index) !== false){
11168 this.setFromData(index > -1 ? record.data : false);
11171 this.fireEvent('select', this, record, index);
11176 * Returns the currently selected field value or empty string if no value is set.
11177 * @return {String} value The selected value
11179 getValue : function(){
11182 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11185 if(this.valueField){
11186 return typeof this.value != 'undefined' ? this.value : '';
11188 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11193 * Clears any text/value currently set in the field
11195 clearValue : function(){
11196 if(this.hiddenField){
11197 this.hiddenField.dom.value = '';
11200 this.setRawValue('');
11201 this.lastSelectionText = '';
11206 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11207 * will be displayed in the field. If the value does not match the data value of an existing item,
11208 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11209 * Otherwise the field will be blank (although the value will still be set).
11210 * @param {String} value The value to match
11212 setValue : function(v){
11219 if(this.valueField){
11220 var r = this.findRecord(this.valueField, v);
11222 text = r.data[this.displayField];
11223 }else if(this.valueNotFoundText !== undefined){
11224 text = this.valueNotFoundText;
11227 this.lastSelectionText = text;
11228 if(this.hiddenField){
11229 this.hiddenField.dom.value = v;
11231 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11235 * @property {Object} the last set data for the element
11240 * Sets the value of the field based on a object which is related to the record format for the store.
11241 * @param {Object} value the value to set as. or false on reset?
11243 setFromData : function(o){
11246 if(typeof o.display_name !== 'string'){
11247 for(var i=0;i<o.display_name.length;i++){
11248 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11256 var dv = ''; // display value
11257 var vv = ''; // value value..
11259 if (this.displayField) {
11260 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11262 // this is an error condition!!!
11263 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11266 if(this.valueField){
11267 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11270 if(this.hiddenField){
11271 this.hiddenField.dom.value = vv;
11273 this.lastSelectionText = dv;
11274 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11278 // no hidden field.. - we store the value in 'value', but still display
11279 // display field!!!!
11280 this.lastSelectionText = dv;
11281 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11287 reset : function(){
11288 // overridden so that last data is reset..
11289 this.setValue(this.originalValue);
11290 this.clearInvalid();
11291 this.lastData = false;
11293 this.view.clearSelections();
11297 findRecord : function(prop, value){
11299 if(this.store.getCount() > 0){
11300 this.store.each(function(r){
11301 if(r.data[prop] == value){
11311 getName: function()
11313 // returns hidden if it's set..
11314 if (!this.rendered) {return ''};
11315 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11319 onViewMove : function(e, t){
11320 this.inKeyMode = false;
11324 onViewOver : function(e, t){
11325 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11328 var item = this.view.findItemFromChild(t);
11331 var index = this.view.indexOf(item);
11332 this.select(index, false);
11337 onViewClick : function(view, doFocus, el, e)
11339 var index = this.view.getSelectedIndexes()[0];
11341 var r = this.store.getAt(index);
11345 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11352 Roo.each(this.tickItems, function(v,k){
11354 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11355 _this.tickItems.splice(k, 1);
11365 this.tickItems.push(r.data);
11370 this.onSelect(r, index);
11372 if(doFocus !== false && !this.blockFocus){
11373 this.inputEl().focus();
11378 restrictHeight : function(){
11379 //this.innerList.dom.style.height = '';
11380 //var inner = this.innerList.dom;
11381 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11382 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11383 //this.list.beginUpdate();
11384 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11385 this.list.alignTo(this.inputEl(), this.listAlign);
11386 this.list.alignTo(this.inputEl(), this.listAlign);
11387 //this.list.endUpdate();
11391 onEmptyResults : function(){
11396 * Returns true if the dropdown list is expanded, else false.
11398 isExpanded : function(){
11399 return this.list.isVisible();
11403 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11404 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11405 * @param {String} value The data value of the item to select
11406 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11407 * selected item if it is not currently in view (defaults to true)
11408 * @return {Boolean} True if the value matched an item in the list, else false
11410 selectByValue : function(v, scrollIntoView){
11411 if(v !== undefined && v !== null){
11412 var r = this.findRecord(this.valueField || this.displayField, v);
11414 this.select(this.store.indexOf(r), scrollIntoView);
11422 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11423 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11424 * @param {Number} index The zero-based index of the list item to select
11425 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11426 * selected item if it is not currently in view (defaults to true)
11428 select : function(index, scrollIntoView){
11429 this.selectedIndex = index;
11430 this.view.select(index);
11431 if(scrollIntoView !== false){
11432 var el = this.view.getNode(index);
11433 if(el && !this.multiple && !this.tickable){
11434 this.list.scrollChildIntoView(el, false);
11440 selectNext : function(){
11441 var ct = this.store.getCount();
11443 if(this.selectedIndex == -1){
11445 }else if(this.selectedIndex < ct-1){
11446 this.select(this.selectedIndex+1);
11452 selectPrev : function(){
11453 var ct = this.store.getCount();
11455 if(this.selectedIndex == -1){
11457 }else if(this.selectedIndex != 0){
11458 this.select(this.selectedIndex-1);
11464 onKeyUp : function(e){
11465 if(this.editable !== false && !e.isSpecialKey()){
11466 this.lastKey = e.getKey();
11467 this.dqTask.delay(this.queryDelay);
11472 validateBlur : function(){
11473 return !this.list || !this.list.isVisible();
11477 initQuery : function(){
11478 this.doQuery(this.getRawValue());
11482 doForce : function(){
11483 if(this.inputEl().dom.value.length > 0){
11484 this.inputEl().dom.value =
11485 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11491 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11492 * query allowing the query action to be canceled if needed.
11493 * @param {String} query The SQL query to execute
11494 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11495 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11496 * saved in the current store (defaults to false)
11498 doQuery : function(q, forceAll){
11500 if(q === undefined || q === null){
11505 forceAll: forceAll,
11509 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11514 forceAll = qe.forceAll;
11515 if(forceAll === true || (q.length >= this.minChars)){
11517 this.hasQuery = true;
11519 if(this.lastQuery != q || this.alwaysQuery){
11520 this.lastQuery = q;
11521 if(this.mode == 'local'){
11522 this.selectedIndex = -1;
11524 this.store.clearFilter();
11526 this.store.filter(this.displayField, q);
11530 this.store.baseParams[this.queryParam] = q;
11532 var options = {params : this.getParams(q)};
11535 options.add = true;
11536 options.params.start = this.page * this.pageSize;
11539 this.store.load(options);
11541 * this code will make the page width larger, at the beginning, the list not align correctly,
11542 * we should expand the list on onLoad
11543 * so command out it
11548 this.selectedIndex = -1;
11553 this.loadNext = false;
11557 getParams : function(q){
11559 //p[this.queryParam] = q;
11563 p.limit = this.pageSize;
11569 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11571 collapse : function(){
11572 if(!this.isExpanded()){
11580 this.cancelBtn.hide();
11581 this.trigger.show();
11584 Roo.get(document).un('mousedown', this.collapseIf, this);
11585 Roo.get(document).un('mousewheel', this.collapseIf, this);
11586 if (!this.editable) {
11587 Roo.get(document).un('keydown', this.listKeyPress, this);
11589 this.fireEvent('collapse', this);
11593 collapseIf : function(e){
11594 var in_combo = e.within(this.el);
11595 var in_list = e.within(this.list);
11596 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11598 if (in_combo || in_list || is_list) {
11599 //e.stopPropagation();
11604 this.onTickableFooterButtonClick(e, false, false);
11612 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11614 expand : function(){
11616 if(this.isExpanded() || !this.hasFocus){
11620 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11621 this.list.setWidth(lw);
11626 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11627 this.list.setWidth(lw);
11631 this.restrictHeight();
11635 this.tickItems = Roo.apply([], this.item);
11638 this.cancelBtn.show();
11639 this.trigger.hide();
11643 Roo.get(document).on('mousedown', this.collapseIf, this);
11644 Roo.get(document).on('mousewheel', this.collapseIf, this);
11645 if (!this.editable) {
11646 Roo.get(document).on('keydown', this.listKeyPress, this);
11649 this.fireEvent('expand', this);
11653 // Implements the default empty TriggerField.onTriggerClick function
11654 onTriggerClick : function(e)
11656 Roo.log('trigger click');
11658 if(this.disabled || !this.triggerList){
11663 this.loadNext = false;
11665 if(this.isExpanded()){
11667 if (!this.blockFocus) {
11668 this.inputEl().focus();
11672 this.hasFocus = true;
11673 if(this.triggerAction == 'all') {
11674 this.doQuery(this.allQuery, true);
11676 this.doQuery(this.getRawValue());
11678 if (!this.blockFocus) {
11679 this.inputEl().focus();
11684 onTickableTriggerClick : function(e)
11691 this.loadNext = false;
11692 this.hasFocus = true;
11694 if(this.triggerAction == 'all') {
11695 this.doQuery(this.allQuery, true);
11697 this.doQuery(this.getRawValue());
11701 onSearchFieldClick : function(e)
11703 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11708 this.loadNext = false;
11709 this.hasFocus = true;
11711 if(this.triggerAction == 'all') {
11712 this.doQuery(this.allQuery, true);
11714 this.doQuery(this.getRawValue());
11718 listKeyPress : function(e)
11720 //Roo.log('listkeypress');
11721 // scroll to first matching element based on key pres..
11722 if (e.isSpecialKey()) {
11725 var k = String.fromCharCode(e.getKey()).toUpperCase();
11728 var csel = this.view.getSelectedNodes();
11729 var cselitem = false;
11731 var ix = this.view.indexOf(csel[0]);
11732 cselitem = this.store.getAt(ix);
11733 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11739 this.store.each(function(v) {
11741 // start at existing selection.
11742 if (cselitem.id == v.id) {
11748 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11749 match = this.store.indexOf(v);
11755 if (match === false) {
11756 return true; // no more action?
11759 this.view.select(match);
11760 var sn = Roo.get(this.view.getSelectedNodes()[0])
11761 //sn.scrollIntoView(sn.dom.parentNode, false);
11764 onViewScroll : function(e, t){
11766 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){
11770 this.hasQuery = true;
11772 this.loading = this.list.select('.loading', true).first();
11774 if(this.loading === null){
11775 this.list.createChild({
11777 cls: 'loading select2-more-results select2-active',
11778 html: 'Loading more results...'
11781 this.loading = this.list.select('.loading', true).first();
11783 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11785 this.loading.hide();
11788 this.loading.show();
11793 this.loadNext = true;
11795 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11800 addItem : function(o)
11802 var dv = ''; // display value
11804 if (this.displayField) {
11805 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11807 // this is an error condition!!!
11808 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11815 var choice = this.choices.createChild({
11817 cls: 'select2-search-choice',
11826 cls: 'select2-search-choice-close',
11831 }, this.searchField);
11833 var close = choice.select('a.select2-search-choice-close', true).first()
11835 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11843 this.inputEl().dom.value = '';
11847 onRemoveItem : function(e, _self, o)
11849 e.preventDefault();
11850 var index = this.item.indexOf(o.data) * 1;
11853 Roo.log('not this item?!');
11857 this.item.splice(index, 1);
11862 this.fireEvent('remove', this, e);
11866 syncValue : function()
11868 if(!this.item.length){
11875 Roo.each(this.item, function(i){
11876 if(_this.valueField){
11877 value.push(i[_this.valueField]);
11884 this.value = value.join(',');
11886 if(this.hiddenField){
11887 this.hiddenField.dom.value = this.value;
11891 clearItem : function()
11893 if(!this.multiple){
11899 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11906 inputEl: function ()
11909 return this.searchField;
11911 return this.el.select('input.form-control',true).first();
11915 onTickableFooterButtonClick : function(e, btn, el)
11917 e.preventDefault();
11919 if(btn && btn.name == 'cancel'){
11920 this.tickItems = Roo.apply([], this.item);
11929 Roo.each(this.tickItems, function(o){
11940 * @cfg {Boolean} grow
11944 * @cfg {Number} growMin
11948 * @cfg {Number} growMax
11958 * Ext JS Library 1.1.1
11959 * Copyright(c) 2006-2007, Ext JS, LLC.
11961 * Originally Released Under LGPL - original licence link has changed is not relivant.
11964 * <script type="text/javascript">
11969 * @extends Roo.util.Observable
11970 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11971 * This class also supports single and multi selection modes. <br>
11972 * Create a data model bound view:
11974 var store = new Roo.data.Store(...);
11976 var view = new Roo.View({
11978 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11980 singleSelect: true,
11981 selectedClass: "ydataview-selected",
11985 // listen for node click?
11986 view.on("click", function(vw, index, node, e){
11987 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11991 dataModel.load("foobar.xml");
11993 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11995 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11996 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11998 * Note: old style constructor is still suported (container, template, config)
12001 * Create a new View
12002 * @param {Object} config The config object
12005 Roo.View = function(config, depreciated_tpl, depreciated_config){
12007 this.parent = false;
12009 if (typeof(depreciated_tpl) == 'undefined') {
12010 // new way.. - universal constructor.
12011 Roo.apply(this, config);
12012 this.el = Roo.get(this.el);
12015 this.el = Roo.get(config);
12016 this.tpl = depreciated_tpl;
12017 Roo.apply(this, depreciated_config);
12019 this.wrapEl = this.el.wrap().wrap();
12020 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12023 if(typeof(this.tpl) == "string"){
12024 this.tpl = new Roo.Template(this.tpl);
12026 // support xtype ctors..
12027 this.tpl = new Roo.factory(this.tpl, Roo);
12031 this.tpl.compile();
12036 * @event beforeclick
12037 * Fires before a click is processed. Returns false to cancel the default action.
12038 * @param {Roo.View} this
12039 * @param {Number} index The index of the target node
12040 * @param {HTMLElement} node The target node
12041 * @param {Roo.EventObject} e The raw event object
12043 "beforeclick" : true,
12046 * Fires when a template node is clicked.
12047 * @param {Roo.View} this
12048 * @param {Number} index The index of the target node
12049 * @param {HTMLElement} node The target node
12050 * @param {Roo.EventObject} e The raw event object
12055 * Fires when a template node is double clicked.
12056 * @param {Roo.View} this
12057 * @param {Number} index The index of the target node
12058 * @param {HTMLElement} node The target node
12059 * @param {Roo.EventObject} e The raw event object
12063 * @event contextmenu
12064 * Fires when a template node is right clicked.
12065 * @param {Roo.View} this
12066 * @param {Number} index The index of the target node
12067 * @param {HTMLElement} node The target node
12068 * @param {Roo.EventObject} e The raw event object
12070 "contextmenu" : true,
12072 * @event selectionchange
12073 * Fires when the selected nodes change.
12074 * @param {Roo.View} this
12075 * @param {Array} selections Array of the selected nodes
12077 "selectionchange" : true,
12080 * @event beforeselect
12081 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12082 * @param {Roo.View} this
12083 * @param {HTMLElement} node The node to be selected
12084 * @param {Array} selections Array of currently selected nodes
12086 "beforeselect" : true,
12088 * @event preparedata
12089 * Fires on every row to render, to allow you to change the data.
12090 * @param {Roo.View} this
12091 * @param {Object} data to be rendered (change this)
12093 "preparedata" : true
12101 "click": this.onClick,
12102 "dblclick": this.onDblClick,
12103 "contextmenu": this.onContextMenu,
12107 this.selections = [];
12109 this.cmp = new Roo.CompositeElementLite([]);
12111 this.store = Roo.factory(this.store, Roo.data);
12112 this.setStore(this.store, true);
12115 if ( this.footer && this.footer.xtype) {
12117 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12119 this.footer.dataSource = this.store
12120 this.footer.container = fctr;
12121 this.footer = Roo.factory(this.footer, Roo);
12122 fctr.insertFirst(this.el);
12124 // this is a bit insane - as the paging toolbar seems to detach the el..
12125 // dom.parentNode.parentNode.parentNode
12126 // they get detached?
12130 Roo.View.superclass.constructor.call(this);
12135 Roo.extend(Roo.View, Roo.util.Observable, {
12138 * @cfg {Roo.data.Store} store Data store to load data from.
12143 * @cfg {String|Roo.Element} el The container element.
12148 * @cfg {String|Roo.Template} tpl The template used by this View
12152 * @cfg {String} dataName the named area of the template to use as the data area
12153 * Works with domtemplates roo-name="name"
12157 * @cfg {String} selectedClass The css class to add to selected nodes
12159 selectedClass : "x-view-selected",
12161 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12166 * @cfg {String} text to display on mask (default Loading)
12170 * @cfg {Boolean} multiSelect Allow multiple selection
12172 multiSelect : false,
12174 * @cfg {Boolean} singleSelect Allow single selection
12176 singleSelect: false,
12179 * @cfg {Boolean} toggleSelect - selecting
12181 toggleSelect : false,
12184 * @cfg {Boolean} tickable - selecting
12189 * Returns the element this view is bound to.
12190 * @return {Roo.Element}
12192 getEl : function(){
12193 return this.wrapEl;
12199 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12201 refresh : function(){
12202 Roo.log('refresh');
12205 // if we are using something like 'domtemplate', then
12206 // the what gets used is:
12207 // t.applySubtemplate(NAME, data, wrapping data..)
12208 // the outer template then get' applied with
12209 // the store 'extra data'
12210 // and the body get's added to the
12211 // roo-name="data" node?
12212 // <span class='roo-tpl-{name}'></span> ?????
12216 this.clearSelections();
12217 this.el.update("");
12219 var records = this.store.getRange();
12220 if(records.length < 1) {
12222 // is this valid?? = should it render a template??
12224 this.el.update(this.emptyText);
12228 if (this.dataName) {
12229 this.el.update(t.apply(this.store.meta)); //????
12230 el = this.el.child('.roo-tpl-' + this.dataName);
12233 for(var i = 0, len = records.length; i < len; i++){
12234 var data = this.prepareData(records[i].data, i, records[i]);
12235 this.fireEvent("preparedata", this, data, i, records[i]);
12237 var d = Roo.apply({}, data);
12240 Roo.apply(d, {'roo-id' : Roo.id()});
12244 Roo.each(this.parent.item, function(item){
12245 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12248 Roo.apply(d, {'roo-data-checked' : 'checked'});
12252 html[html.length] = Roo.util.Format.trim(
12254 t.applySubtemplate(this.dataName, d, this.store.meta) :
12261 el.update(html.join(""));
12262 this.nodes = el.dom.childNodes;
12263 this.updateIndexes(0);
12268 * Function to override to reformat the data that is sent to
12269 * the template for each node.
12270 * DEPRICATED - use the preparedata event handler.
12271 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12272 * a JSON object for an UpdateManager bound view).
12274 prepareData : function(data, index, record)
12276 this.fireEvent("preparedata", this, data, index, record);
12280 onUpdate : function(ds, record){
12281 Roo.log('on update');
12282 this.clearSelections();
12283 var index = this.store.indexOf(record);
12284 var n = this.nodes[index];
12285 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12286 n.parentNode.removeChild(n);
12287 this.updateIndexes(index, index);
12293 onAdd : function(ds, records, index)
12295 Roo.log(['on Add', ds, records, index] );
12296 this.clearSelections();
12297 if(this.nodes.length == 0){
12301 var n = this.nodes[index];
12302 for(var i = 0, len = records.length; i < len; i++){
12303 var d = this.prepareData(records[i].data, i, records[i]);
12305 this.tpl.insertBefore(n, d);
12308 this.tpl.append(this.el, d);
12311 this.updateIndexes(index);
12314 onRemove : function(ds, record, index){
12315 Roo.log('onRemove');
12316 this.clearSelections();
12317 var el = this.dataName ?
12318 this.el.child('.roo-tpl-' + this.dataName) :
12321 el.dom.removeChild(this.nodes[index]);
12322 this.updateIndexes(index);
12326 * Refresh an individual node.
12327 * @param {Number} index
12329 refreshNode : function(index){
12330 this.onUpdate(this.store, this.store.getAt(index));
12333 updateIndexes : function(startIndex, endIndex){
12334 var ns = this.nodes;
12335 startIndex = startIndex || 0;
12336 endIndex = endIndex || ns.length - 1;
12337 for(var i = startIndex; i <= endIndex; i++){
12338 ns[i].nodeIndex = i;
12343 * Changes the data store this view uses and refresh the view.
12344 * @param {Store} store
12346 setStore : function(store, initial){
12347 if(!initial && this.store){
12348 this.store.un("datachanged", this.refresh);
12349 this.store.un("add", this.onAdd);
12350 this.store.un("remove", this.onRemove);
12351 this.store.un("update", this.onUpdate);
12352 this.store.un("clear", this.refresh);
12353 this.store.un("beforeload", this.onBeforeLoad);
12354 this.store.un("load", this.onLoad);
12355 this.store.un("loadexception", this.onLoad);
12359 store.on("datachanged", this.refresh, this);
12360 store.on("add", this.onAdd, this);
12361 store.on("remove", this.onRemove, this);
12362 store.on("update", this.onUpdate, this);
12363 store.on("clear", this.refresh, this);
12364 store.on("beforeload", this.onBeforeLoad, this);
12365 store.on("load", this.onLoad, this);
12366 store.on("loadexception", this.onLoad, this);
12374 * onbeforeLoad - masks the loading area.
12377 onBeforeLoad : function(store,opts)
12379 Roo.log('onBeforeLoad');
12381 this.el.update("");
12383 this.el.mask(this.mask ? this.mask : "Loading" );
12385 onLoad : function ()
12392 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12393 * @param {HTMLElement} node
12394 * @return {HTMLElement} The template node
12396 findItemFromChild : function(node){
12397 var el = this.dataName ?
12398 this.el.child('.roo-tpl-' + this.dataName,true) :
12401 if(!node || node.parentNode == el){
12404 var p = node.parentNode;
12405 while(p && p != el){
12406 if(p.parentNode == el){
12415 onClick : function(e){
12416 var item = this.findItemFromChild(e.getTarget());
12418 var index = this.indexOf(item);
12419 if(this.onItemClick(item, index, e) !== false){
12420 this.fireEvent("click", this, index, item, e);
12423 this.clearSelections();
12428 onContextMenu : function(e){
12429 var item = this.findItemFromChild(e.getTarget());
12431 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12436 onDblClick : function(e){
12437 var item = this.findItemFromChild(e.getTarget());
12439 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12443 onItemClick : function(item, index, e)
12445 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12448 if (this.toggleSelect) {
12449 var m = this.isSelected(item) ? 'unselect' : 'select';
12452 _t[m](item, true, false);
12455 if(this.multiSelect || this.singleSelect){
12456 if(this.multiSelect && e.shiftKey && this.lastSelection){
12457 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12459 this.select(item, this.multiSelect && e.ctrlKey);
12460 this.lastSelection = item;
12463 if(!this.tickable){
12464 e.preventDefault();
12472 * Get the number of selected nodes.
12475 getSelectionCount : function(){
12476 return this.selections.length;
12480 * Get the currently selected nodes.
12481 * @return {Array} An array of HTMLElements
12483 getSelectedNodes : function(){
12484 return this.selections;
12488 * Get the indexes of the selected nodes.
12491 getSelectedIndexes : function(){
12492 var indexes = [], s = this.selections;
12493 for(var i = 0, len = s.length; i < len; i++){
12494 indexes.push(s[i].nodeIndex);
12500 * Clear all selections
12501 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12503 clearSelections : function(suppressEvent){
12504 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12505 this.cmp.elements = this.selections;
12506 this.cmp.removeClass(this.selectedClass);
12507 this.selections = [];
12508 if(!suppressEvent){
12509 this.fireEvent("selectionchange", this, this.selections);
12515 * Returns true if the passed node is selected
12516 * @param {HTMLElement/Number} node The node or node index
12517 * @return {Boolean}
12519 isSelected : function(node){
12520 var s = this.selections;
12524 node = this.getNode(node);
12525 return s.indexOf(node) !== -1;
12530 * @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
12531 * @param {Boolean} keepExisting (optional) true to keep existing selections
12532 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12534 select : function(nodeInfo, keepExisting, suppressEvent){
12535 if(nodeInfo instanceof Array){
12537 this.clearSelections(true);
12539 for(var i = 0, len = nodeInfo.length; i < len; i++){
12540 this.select(nodeInfo[i], true, true);
12544 var node = this.getNode(nodeInfo);
12545 if(!node || this.isSelected(node)){
12546 return; // already selected.
12549 this.clearSelections(true);
12551 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12552 Roo.fly(node).addClass(this.selectedClass);
12553 this.selections.push(node);
12554 if(!suppressEvent){
12555 this.fireEvent("selectionchange", this, this.selections);
12563 * @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
12564 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12565 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12567 unselect : function(nodeInfo, keepExisting, suppressEvent)
12569 if(nodeInfo instanceof Array){
12570 Roo.each(this.selections, function(s) {
12571 this.unselect(s, nodeInfo);
12575 var node = this.getNode(nodeInfo);
12576 if(!node || !this.isSelected(node)){
12577 Roo.log("not selected");
12578 return; // not selected.
12582 Roo.each(this.selections, function(s) {
12584 Roo.fly(node).removeClass(this.selectedClass);
12591 this.selections= ns;
12592 this.fireEvent("selectionchange", this, this.selections);
12596 * Gets a template node.
12597 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12598 * @return {HTMLElement} The node or null if it wasn't found
12600 getNode : function(nodeInfo){
12601 if(typeof nodeInfo == "string"){
12602 return document.getElementById(nodeInfo);
12603 }else if(typeof nodeInfo == "number"){
12604 return this.nodes[nodeInfo];
12610 * Gets a range template nodes.
12611 * @param {Number} startIndex
12612 * @param {Number} endIndex
12613 * @return {Array} An array of nodes
12615 getNodes : function(start, end){
12616 var ns = this.nodes;
12617 start = start || 0;
12618 end = typeof end == "undefined" ? ns.length - 1 : end;
12621 for(var i = start; i <= end; i++){
12625 for(var i = start; i >= end; i--){
12633 * Finds the index of the passed node
12634 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12635 * @return {Number} The index of the node or -1
12637 indexOf : function(node){
12638 node = this.getNode(node);
12639 if(typeof node.nodeIndex == "number"){
12640 return node.nodeIndex;
12642 var ns = this.nodes;
12643 for(var i = 0, len = ns.length; i < len; i++){
12654 * based on jquery fullcalendar
12658 Roo.bootstrap = Roo.bootstrap || {};
12660 * @class Roo.bootstrap.Calendar
12661 * @extends Roo.bootstrap.Component
12662 * Bootstrap Calendar class
12663 * @cfg {Boolean} loadMask (true|false) default false
12664 * @cfg {Object} header generate the user specific header of the calendar, default false
12667 * Create a new Container
12668 * @param {Object} config The config object
12673 Roo.bootstrap.Calendar = function(config){
12674 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12678 * Fires when a date is selected
12679 * @param {DatePicker} this
12680 * @param {Date} date The selected date
12684 * @event monthchange
12685 * Fires when the displayed month changes
12686 * @param {DatePicker} this
12687 * @param {Date} date The selected month
12689 'monthchange': true,
12691 * @event evententer
12692 * Fires when mouse over an event
12693 * @param {Calendar} this
12694 * @param {event} Event
12696 'evententer': true,
12698 * @event eventleave
12699 * Fires when the mouse leaves an
12700 * @param {Calendar} this
12703 'eventleave': true,
12705 * @event eventclick
12706 * Fires when the mouse click an
12707 * @param {Calendar} this
12716 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12719 * @cfg {Number} startDay
12720 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12728 getAutoCreate : function(){
12731 var fc_button = function(name, corner, style, content ) {
12732 return Roo.apply({},{
12734 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12736 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12739 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12750 style : 'width:100%',
12757 cls : 'fc-header-left',
12759 fc_button('prev', 'left', 'arrow', '‹' ),
12760 fc_button('next', 'right', 'arrow', '›' ),
12761 { tag: 'span', cls: 'fc-header-space' },
12762 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12770 cls : 'fc-header-center',
12774 cls: 'fc-header-title',
12777 html : 'month / year'
12785 cls : 'fc-header-right',
12787 /* fc_button('month', 'left', '', 'month' ),
12788 fc_button('week', '', '', 'week' ),
12789 fc_button('day', 'right', '', 'day' )
12801 header = this.header;
12804 var cal_heads = function() {
12806 // fixme - handle this.
12808 for (var i =0; i < Date.dayNames.length; i++) {
12809 var d = Date.dayNames[i];
12812 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12813 html : d.substring(0,3)
12817 ret[0].cls += ' fc-first';
12818 ret[6].cls += ' fc-last';
12821 var cal_cell = function(n) {
12824 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12829 cls: 'fc-day-number',
12833 cls: 'fc-day-content',
12837 style: 'position: relative;' // height: 17px;
12849 var cal_rows = function() {
12852 for (var r = 0; r < 6; r++) {
12859 for (var i =0; i < Date.dayNames.length; i++) {
12860 var d = Date.dayNames[i];
12861 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12864 row.cn[0].cls+=' fc-first';
12865 row.cn[0].cn[0].style = 'min-height:90px';
12866 row.cn[6].cls+=' fc-last';
12870 ret[0].cls += ' fc-first';
12871 ret[4].cls += ' fc-prev-last';
12872 ret[5].cls += ' fc-last';
12879 cls: 'fc-border-separate',
12880 style : 'width:100%',
12888 cls : 'fc-first fc-last',
12906 cls : 'fc-content',
12907 style : "position: relative;",
12910 cls : 'fc-view fc-view-month fc-grid',
12911 style : 'position: relative',
12912 unselectable : 'on',
12915 cls : 'fc-event-container',
12916 style : 'position:absolute;z-index:8;top:0;left:0;'
12934 initEvents : function()
12937 throw "can not find store for calendar";
12943 style: "text-align:center",
12947 style: "background-color:white;width:50%;margin:250 auto",
12951 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12962 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12964 var size = this.el.select('.fc-content', true).first().getSize();
12965 this.maskEl.setSize(size.width, size.height);
12966 this.maskEl.enableDisplayMode("block");
12967 if(!this.loadMask){
12968 this.maskEl.hide();
12971 this.store = Roo.factory(this.store, Roo.data);
12972 this.store.on('load', this.onLoad, this);
12973 this.store.on('beforeload', this.onBeforeLoad, this);
12977 this.cells = this.el.select('.fc-day',true);
12978 //Roo.log(this.cells);
12979 this.textNodes = this.el.query('.fc-day-number');
12980 this.cells.addClassOnOver('fc-state-hover');
12982 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12983 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12984 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12985 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12987 this.on('monthchange', this.onMonthChange, this);
12989 this.update(new Date().clearTime());
12992 resize : function() {
12993 var sz = this.el.getSize();
12995 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12996 this.el.select('.fc-day-content div',true).setHeight(34);
13001 showPrevMonth : function(e){
13002 this.update(this.activeDate.add("mo", -1));
13004 showToday : function(e){
13005 this.update(new Date().clearTime());
13008 showNextMonth : function(e){
13009 this.update(this.activeDate.add("mo", 1));
13013 showPrevYear : function(){
13014 this.update(this.activeDate.add("y", -1));
13018 showNextYear : function(){
13019 this.update(this.activeDate.add("y", 1));
13024 update : function(date)
13026 var vd = this.activeDate;
13027 this.activeDate = date;
13028 // if(vd && this.el){
13029 // var t = date.getTime();
13030 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13031 // Roo.log('using add remove');
13033 // this.fireEvent('monthchange', this, date);
13035 // this.cells.removeClass("fc-state-highlight");
13036 // this.cells.each(function(c){
13037 // if(c.dateValue == t){
13038 // c.addClass("fc-state-highlight");
13039 // setTimeout(function(){
13040 // try{c.dom.firstChild.focus();}catch(e){}
13050 var days = date.getDaysInMonth();
13052 var firstOfMonth = date.getFirstDateOfMonth();
13053 var startingPos = firstOfMonth.getDay()-this.startDay;
13055 if(startingPos < this.startDay){
13059 var pm = date.add(Date.MONTH, -1);
13060 var prevStart = pm.getDaysInMonth()-startingPos;
13062 this.cells = this.el.select('.fc-day',true);
13063 this.textNodes = this.el.query('.fc-day-number');
13064 this.cells.addClassOnOver('fc-state-hover');
13066 var cells = this.cells.elements;
13067 var textEls = this.textNodes;
13069 Roo.each(cells, function(cell){
13070 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13073 days += startingPos;
13075 // convert everything to numbers so it's fast
13076 var day = 86400000;
13077 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13080 //Roo.log(prevStart);
13082 var today = new Date().clearTime().getTime();
13083 var sel = date.clearTime().getTime();
13084 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13085 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13086 var ddMatch = this.disabledDatesRE;
13087 var ddText = this.disabledDatesText;
13088 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13089 var ddaysText = this.disabledDaysText;
13090 var format = this.format;
13092 var setCellClass = function(cal, cell){
13096 //Roo.log('set Cell Class');
13098 var t = d.getTime();
13102 cell.dateValue = t;
13104 cell.className += " fc-today";
13105 cell.className += " fc-state-highlight";
13106 cell.title = cal.todayText;
13109 // disable highlight in other month..
13110 //cell.className += " fc-state-highlight";
13115 cell.className = " fc-state-disabled";
13116 cell.title = cal.minText;
13120 cell.className = " fc-state-disabled";
13121 cell.title = cal.maxText;
13125 if(ddays.indexOf(d.getDay()) != -1){
13126 cell.title = ddaysText;
13127 cell.className = " fc-state-disabled";
13130 if(ddMatch && format){
13131 var fvalue = d.dateFormat(format);
13132 if(ddMatch.test(fvalue)){
13133 cell.title = ddText.replace("%0", fvalue);
13134 cell.className = " fc-state-disabled";
13138 if (!cell.initialClassName) {
13139 cell.initialClassName = cell.dom.className;
13142 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13147 for(; i < startingPos; i++) {
13148 textEls[i].innerHTML = (++prevStart);
13149 d.setDate(d.getDate()+1);
13151 cells[i].className = "fc-past fc-other-month";
13152 setCellClass(this, cells[i]);
13157 for(; i < days; i++){
13158 intDay = i - startingPos + 1;
13159 textEls[i].innerHTML = (intDay);
13160 d.setDate(d.getDate()+1);
13162 cells[i].className = ''; // "x-date-active";
13163 setCellClass(this, cells[i]);
13167 for(; i < 42; i++) {
13168 textEls[i].innerHTML = (++extraDays);
13169 d.setDate(d.getDate()+1);
13171 cells[i].className = "fc-future fc-other-month";
13172 setCellClass(this, cells[i]);
13175 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13177 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13179 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13180 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13182 if(totalRows != 6){
13183 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13184 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13187 this.fireEvent('monthchange', this, date);
13191 if(!this.internalRender){
13192 var main = this.el.dom.firstChild;
13193 var w = main.offsetWidth;
13194 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13195 Roo.fly(main).setWidth(w);
13196 this.internalRender = true;
13197 // opera does not respect the auto grow header center column
13198 // then, after it gets a width opera refuses to recalculate
13199 // without a second pass
13200 if(Roo.isOpera && !this.secondPass){
13201 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13202 this.secondPass = true;
13203 this.update.defer(10, this, [date]);
13210 findCell : function(dt) {
13211 dt = dt.clearTime().getTime();
13213 this.cells.each(function(c){
13214 //Roo.log("check " +c.dateValue + '?=' + dt);
13215 if(c.dateValue == dt){
13225 findCells : function(ev) {
13226 var s = ev.start.clone().clearTime().getTime();
13228 var e= ev.end.clone().clearTime().getTime();
13231 this.cells.each(function(c){
13232 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13234 if(c.dateValue > e){
13237 if(c.dateValue < s){
13246 // findBestRow: function(cells)
13250 // for (var i =0 ; i < cells.length;i++) {
13251 // ret = Math.max(cells[i].rows || 0,ret);
13258 addItem : function(ev)
13260 // look for vertical location slot in
13261 var cells = this.findCells(ev);
13263 // ev.row = this.findBestRow(cells);
13265 // work out the location.
13269 for(var i =0; i < cells.length; i++) {
13271 cells[i].row = cells[0].row;
13274 cells[i].row = cells[i].row + 1;
13284 if (crow.start.getY() == cells[i].getY()) {
13286 crow.end = cells[i];
13303 cells[0].events.push(ev);
13305 this.calevents.push(ev);
13308 clearEvents: function() {
13310 if(!this.calevents){
13314 Roo.each(this.cells.elements, function(c){
13320 Roo.each(this.calevents, function(e) {
13321 Roo.each(e.els, function(el) {
13322 el.un('mouseenter' ,this.onEventEnter, this);
13323 el.un('mouseleave' ,this.onEventLeave, this);
13328 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13334 renderEvents: function()
13338 this.cells.each(function(c) {
13347 if(c.row != c.events.length){
13348 r = 4 - (4 - (c.row - c.events.length));
13351 c.events = ev.slice(0, r);
13352 c.more = ev.slice(r);
13354 if(c.more.length && c.more.length == 1){
13355 c.events.push(c.more.pop());
13358 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13362 this.cells.each(function(c) {
13364 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13367 for (var e = 0; e < c.events.length; e++){
13368 var ev = c.events[e];
13369 var rows = ev.rows;
13371 for(var i = 0; i < rows.length; i++) {
13373 // how many rows should it span..
13376 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13377 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13379 unselectable : "on",
13382 cls: 'fc-event-inner',
13386 // cls: 'fc-event-time',
13387 // html : cells.length > 1 ? '' : ev.time
13391 cls: 'fc-event-title',
13392 html : String.format('{0}', ev.title)
13399 cls: 'ui-resizable-handle ui-resizable-e',
13400 html : '  '
13407 cfg.cls += ' fc-event-start';
13409 if ((i+1) == rows.length) {
13410 cfg.cls += ' fc-event-end';
13413 var ctr = _this.el.select('.fc-event-container',true).first();
13414 var cg = ctr.createChild(cfg);
13416 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13417 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13419 var r = (c.more.length) ? 1 : 0;
13420 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13421 cg.setWidth(ebox.right - sbox.x -2);
13423 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13424 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13425 cg.on('click', _this.onEventClick, _this, ev);
13436 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13437 style : 'position: absolute',
13438 unselectable : "on",
13441 cls: 'fc-event-inner',
13445 cls: 'fc-event-title',
13453 cls: 'ui-resizable-handle ui-resizable-e',
13454 html : '  '
13460 var ctr = _this.el.select('.fc-event-container',true).first();
13461 var cg = ctr.createChild(cfg);
13463 var sbox = c.select('.fc-day-content',true).first().getBox();
13464 var ebox = c.select('.fc-day-content',true).first().getBox();
13466 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13467 cg.setWidth(ebox.right - sbox.x -2);
13469 cg.on('click', _this.onMoreEventClick, _this, c.more);
13479 onEventEnter: function (e, el,event,d) {
13480 this.fireEvent('evententer', this, el, event);
13483 onEventLeave: function (e, el,event,d) {
13484 this.fireEvent('eventleave', this, el, event);
13487 onEventClick: function (e, el,event,d) {
13488 this.fireEvent('eventclick', this, el, event);
13491 onMonthChange: function () {
13495 onMoreEventClick: function(e, el, more)
13499 this.calpopover.placement = 'right';
13500 this.calpopover.setTitle('More');
13502 this.calpopover.setContent('');
13504 var ctr = this.calpopover.el.select('.popover-content', true).first();
13506 Roo.each(more, function(m){
13508 cls : 'fc-event-hori fc-event-draggable',
13511 var cg = ctr.createChild(cfg);
13513 cg.on('click', _this.onEventClick, _this, m);
13516 this.calpopover.show(el);
13521 onLoad: function ()
13523 this.calevents = [];
13526 if(this.store.getCount() > 0){
13527 this.store.data.each(function(d){
13530 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13531 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13532 time : d.data.start_time,
13533 title : d.data.title,
13534 description : d.data.description,
13535 venue : d.data.venue
13540 this.renderEvents();
13542 if(this.calevents.length && this.loadMask){
13543 this.maskEl.hide();
13547 onBeforeLoad: function()
13549 this.clearEvents();
13551 this.maskEl.show();
13565 * @class Roo.bootstrap.Popover
13566 * @extends Roo.bootstrap.Component
13567 * Bootstrap Popover class
13568 * @cfg {String} html contents of the popover (or false to use children..)
13569 * @cfg {String} title of popover (or false to hide)
13570 * @cfg {String} placement how it is placed
13571 * @cfg {String} trigger click || hover (or false to trigger manually)
13572 * @cfg {String} over what (parent or false to trigger manually.)
13575 * Create a new Popover
13576 * @param {Object} config The config object
13579 Roo.bootstrap.Popover = function(config){
13580 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13583 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13585 title: 'Fill in a title',
13588 placement : 'right',
13589 trigger : 'hover', // hover
13593 can_build_overlaid : false,
13595 getChildContainer : function()
13597 return this.el.select('.popover-content',true).first();
13600 getAutoCreate : function(){
13601 Roo.log('make popover?');
13603 cls : 'popover roo-dynamic',
13604 style: 'display:block',
13610 cls : 'popover-inner',
13614 cls: 'popover-title',
13618 cls : 'popover-content',
13629 setTitle: function(str)
13631 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13633 setContent: function(str)
13635 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13637 // as it get's added to the bottom of the page.
13638 onRender : function(ct, position)
13640 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13642 var cfg = Roo.apply({}, this.getAutoCreate());
13646 cfg.cls += ' ' + this.cls;
13649 cfg.style = this.style;
13651 Roo.log("adding to ")
13652 this.el = Roo.get(document.body).createChild(cfg, position);
13658 initEvents : function()
13660 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13661 this.el.enableDisplayMode('block');
13663 if (this.over === false) {
13666 if (this.triggers === false) {
13669 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13670 var triggers = this.trigger ? this.trigger.split(' ') : [];
13671 Roo.each(triggers, function(trigger) {
13673 if (trigger == 'click') {
13674 on_el.on('click', this.toggle, this);
13675 } else if (trigger != 'manual') {
13676 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13677 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13679 on_el.on(eventIn ,this.enter, this);
13680 on_el.on(eventOut, this.leave, this);
13691 toggle : function () {
13692 this.hoverState == 'in' ? this.leave() : this.enter();
13695 enter : function () {
13698 clearTimeout(this.timeout);
13700 this.hoverState = 'in'
13702 if (!this.delay || !this.delay.show) {
13707 this.timeout = setTimeout(function () {
13708 if (_t.hoverState == 'in') {
13711 }, this.delay.show)
13713 leave : function() {
13714 clearTimeout(this.timeout);
13716 this.hoverState = 'out'
13718 if (!this.delay || !this.delay.hide) {
13723 this.timeout = setTimeout(function () {
13724 if (_t.hoverState == 'out') {
13727 }, this.delay.hide)
13730 show : function (on_el)
13733 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13736 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13737 if (this.html !== false) {
13738 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13740 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13741 if (!this.title.length) {
13742 this.el.select('.popover-title',true).hide();
13745 var placement = typeof this.placement == 'function' ?
13746 this.placement.call(this, this.el, on_el) :
13749 var autoToken = /\s?auto?\s?/i;
13750 var autoPlace = autoToken.test(placement);
13752 placement = placement.replace(autoToken, '') || 'top';
13756 //this.el.setXY([0,0]);
13758 this.el.dom.style.display='block';
13759 this.el.addClass(placement);
13761 //this.el.appendTo(on_el);
13763 var p = this.getPosition();
13764 var box = this.el.getBox();
13769 var align = Roo.bootstrap.Popover.alignment[placement]
13770 this.el.alignTo(on_el, align[0],align[1]);
13771 //var arrow = this.el.select('.arrow',true).first();
13772 //arrow.set(align[2],
13774 this.el.addClass('in');
13775 this.hoverState = null;
13777 if (this.el.hasClass('fade')) {
13784 this.el.setXY([0,0]);
13785 this.el.removeClass('in');
13792 Roo.bootstrap.Popover.alignment = {
13793 'left' : ['r-l', [-10,0], 'right'],
13794 'right' : ['l-r', [10,0], 'left'],
13795 'bottom' : ['t-b', [0,10], 'top'],
13796 'top' : [ 'b-t', [0,-10], 'bottom']
13807 * @class Roo.bootstrap.Progress
13808 * @extends Roo.bootstrap.Component
13809 * Bootstrap Progress class
13810 * @cfg {Boolean} striped striped of the progress bar
13811 * @cfg {Boolean} active animated of the progress bar
13815 * Create a new Progress
13816 * @param {Object} config The config object
13819 Roo.bootstrap.Progress = function(config){
13820 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13823 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13828 getAutoCreate : function(){
13836 cfg.cls += ' progress-striped';
13840 cfg.cls += ' active';
13859 * @class Roo.bootstrap.ProgressBar
13860 * @extends Roo.bootstrap.Component
13861 * Bootstrap ProgressBar class
13862 * @cfg {Number} aria_valuenow aria-value now
13863 * @cfg {Number} aria_valuemin aria-value min
13864 * @cfg {Number} aria_valuemax aria-value max
13865 * @cfg {String} label label for the progress bar
13866 * @cfg {String} panel (success | info | warning | danger )
13867 * @cfg {String} role role of the progress bar
13868 * @cfg {String} sr_only text
13872 * Create a new ProgressBar
13873 * @param {Object} config The config object
13876 Roo.bootstrap.ProgressBar = function(config){
13877 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13880 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13884 aria_valuemax : 100,
13890 getAutoCreate : function()
13895 cls: 'progress-bar',
13896 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13908 cfg.role = this.role;
13911 if(this.aria_valuenow){
13912 cfg['aria-valuenow'] = this.aria_valuenow;
13915 if(this.aria_valuemin){
13916 cfg['aria-valuemin'] = this.aria_valuemin;
13919 if(this.aria_valuemax){
13920 cfg['aria-valuemax'] = this.aria_valuemax;
13923 if(this.label && !this.sr_only){
13924 cfg.html = this.label;
13928 cfg.cls += ' progress-bar-' + this.panel;
13934 update : function(aria_valuenow)
13936 this.aria_valuenow = aria_valuenow;
13938 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13953 * @class Roo.bootstrap.TabGroup
13954 * @extends Roo.bootstrap.Column
13955 * Bootstrap Column class
13956 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13957 * @cfg {Boolean} carousel true to make the group behave like a carousel
13960 * Create a new TabGroup
13961 * @param {Object} config The config object
13964 Roo.bootstrap.TabGroup = function(config){
13965 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13967 this.navId = Roo.id();
13970 Roo.bootstrap.TabGroup.register(this);
13974 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13977 transition : false,
13979 getAutoCreate : function()
13981 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13983 cfg.cls += ' tab-content';
13985 if (this.carousel) {
13986 cfg.cls += ' carousel slide';
13988 cls : 'carousel-inner'
13995 getChildContainer : function()
13997 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14001 * register a Navigation item
14002 * @param {Roo.bootstrap.NavItem} the navitem to add
14004 register : function(item)
14006 this.tabs.push( item);
14007 item.navId = this.navId; // not really needed..
14011 getActivePanel : function()
14014 Roo.each(this.tabs, function(t) {
14024 getPanelByName : function(n)
14027 Roo.each(this.tabs, function(t) {
14028 if (t.tabId == n) {
14036 indexOfPanel : function(p)
14039 Roo.each(this.tabs, function(t,i) {
14040 if (t.tabId == p.tabId) {
14049 * show a specific panel
14050 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14051 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14053 showPanel : function (pan)
14056 if (typeof(pan) == 'number') {
14057 pan = this.tabs[pan];
14059 if (typeof(pan) == 'string') {
14060 pan = this.getPanelByName(pan);
14062 if (pan.tabId == this.getActivePanel().tabId) {
14065 var cur = this.getActivePanel();
14067 if (false === cur.fireEvent('beforedeactivate')) {
14071 if (this.carousel) {
14072 this.transition = true;
14073 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14074 var lr = dir == 'next' ? 'left' : 'right';
14075 pan.el.addClass(dir); // or prev
14076 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14077 cur.el.addClass(lr); // or right
14078 pan.el.addClass(lr);
14081 cur.el.on('transitionend', function() {
14082 Roo.log("trans end?");
14084 pan.el.removeClass([lr,dir]);
14085 pan.setActive(true);
14087 cur.el.removeClass([lr]);
14088 cur.setActive(false);
14090 _this.transition = false;
14092 }, this, { single: true } );
14096 cur.setActive(false);
14097 pan.setActive(true);
14101 showPanelNext : function()
14103 var i = this.indexOfPanel(this.getActivePanel());
14104 if (i > this.tabs.length) {
14107 this.showPanel(this.tabs[i+1]);
14109 showPanelPrev : function()
14111 var i = this.indexOfPanel(this.getActivePanel());
14115 this.showPanel(this.tabs[i-1]);
14126 Roo.apply(Roo.bootstrap.TabGroup, {
14130 * register a Navigation Group
14131 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14133 register : function(navgrp)
14135 this.groups[navgrp.navId] = navgrp;
14139 * fetch a Navigation Group based on the navigation ID
14140 * if one does not exist , it will get created.
14141 * @param {string} the navgroup to add
14142 * @returns {Roo.bootstrap.NavGroup} the navgroup
14144 get: function(navId) {
14145 if (typeof(this.groups[navId]) == 'undefined') {
14146 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14148 return this.groups[navId] ;
14163 * @class Roo.bootstrap.TabPanel
14164 * @extends Roo.bootstrap.Component
14165 * Bootstrap TabPanel class
14166 * @cfg {Boolean} active panel active
14167 * @cfg {String} html panel content
14168 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14169 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14173 * Create a new TabPanel
14174 * @param {Object} config The config object
14177 Roo.bootstrap.TabPanel = function(config){
14178 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14182 * Fires when the active status changes
14183 * @param {Roo.bootstrap.TabPanel} this
14184 * @param {Boolean} state the new state
14189 * @event beforedeactivate
14190 * Fires before a tab is de-activated - can be used to do validation on a form.
14191 * @param {Roo.bootstrap.TabPanel} this
14192 * @return {Boolean} false if there is an error
14195 'beforedeactivate': true
14198 this.tabId = this.tabId || Roo.id();
14202 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14209 getAutoCreate : function(){
14212 // item is needed for carousel - not sure if it has any effect otherwise
14213 cls: 'tab-pane item',
14214 html: this.html || ''
14218 cfg.cls += ' active';
14222 cfg.tabId = this.tabId;
14229 initEvents: function()
14231 Roo.log('-------- init events on tab panel ---------');
14233 var p = this.parent();
14234 this.navId = this.navId || p.navId;
14236 if (typeof(this.navId) != 'undefined') {
14237 // not really needed.. but just in case.. parent should be a NavGroup.
14238 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14239 Roo.log(['register', tg, this]);
14245 onRender : function(ct, position)
14247 // Roo.log("Call onRender: " + this.xtype);
14249 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14257 setActive: function(state)
14259 Roo.log("panel - set active " + this.tabId + "=" + state);
14261 this.active = state;
14263 this.el.removeClass('active');
14265 } else if (!this.el.hasClass('active')) {
14266 this.el.addClass('active');
14268 this.fireEvent('changed', this, state);
14285 * @class Roo.bootstrap.DateField
14286 * @extends Roo.bootstrap.Input
14287 * Bootstrap DateField class
14288 * @cfg {Number} weekStart default 0
14289 * @cfg {Number} weekStart default 0
14290 * @cfg {Number} viewMode default empty, (months|years)
14291 * @cfg {Number} minViewMode default empty, (months|years)
14292 * @cfg {Number} startDate default -Infinity
14293 * @cfg {Number} endDate default Infinity
14294 * @cfg {Boolean} todayHighlight default false
14295 * @cfg {Boolean} todayBtn default false
14296 * @cfg {Boolean} calendarWeeks default false
14297 * @cfg {Object} daysOfWeekDisabled default empty
14299 * @cfg {Boolean} keyboardNavigation default true
14300 * @cfg {String} language default en
14303 * Create a new DateField
14304 * @param {Object} config The config object
14307 Roo.bootstrap.DateField = function(config){
14308 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14312 * Fires when this field show.
14313 * @param {Roo.bootstrap.DateField} this
14314 * @param {Mixed} date The date value
14319 * Fires when this field hide.
14320 * @param {Roo.bootstrap.DateField} this
14321 * @param {Mixed} date The date value
14326 * Fires when select a date.
14327 * @param {Roo.bootstrap.DateField} this
14328 * @param {Mixed} date The date value
14334 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14337 * @cfg {String} format
14338 * The default date format string which can be overriden for localization support. The format must be
14339 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14343 * @cfg {String} altFormats
14344 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14345 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14347 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14355 todayHighlight : false,
14361 keyboardNavigation: true,
14363 calendarWeeks: false,
14365 startDate: -Infinity,
14369 daysOfWeekDisabled: [],
14373 UTCDate: function()
14375 return new Date(Date.UTC.apply(Date, arguments));
14378 UTCToday: function()
14380 var today = new Date();
14381 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14384 getDate: function() {
14385 var d = this.getUTCDate();
14386 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14389 getUTCDate: function() {
14393 setDate: function(d) {
14394 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14397 setUTCDate: function(d) {
14399 this.setValue(this.formatDate(this.date));
14402 onRender: function(ct, position)
14405 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14407 this.language = this.language || 'en';
14408 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14409 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14411 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14412 this.format = this.format || 'm/d/y';
14413 this.isInline = false;
14414 this.isInput = true;
14415 this.component = this.el.select('.add-on', true).first() || false;
14416 this.component = (this.component && this.component.length === 0) ? false : this.component;
14417 this.hasInput = this.component && this.inputEL().length;
14419 if (typeof(this.minViewMode === 'string')) {
14420 switch (this.minViewMode) {
14422 this.minViewMode = 1;
14425 this.minViewMode = 2;
14428 this.minViewMode = 0;
14433 if (typeof(this.viewMode === 'string')) {
14434 switch (this.viewMode) {
14447 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14449 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14451 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14453 this.picker().on('mousedown', this.onMousedown, this);
14454 this.picker().on('click', this.onClick, this);
14456 this.picker().addClass('datepicker-dropdown');
14458 this.startViewMode = this.viewMode;
14461 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14462 if(!this.calendarWeeks){
14467 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14468 v.attr('colspan', function(i, val){
14469 return parseInt(val) + 1;
14474 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14476 this.setStartDate(this.startDate);
14477 this.setEndDate(this.endDate);
14479 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14486 if(this.isInline) {
14491 picker : function()
14493 return this.pickerEl;
14494 // return this.el.select('.datepicker', true).first();
14497 fillDow: function()
14499 var dowCnt = this.weekStart;
14508 if(this.calendarWeeks){
14516 while (dowCnt < this.weekStart + 7) {
14520 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14524 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14527 fillMonths: function()
14530 var months = this.picker().select('>.datepicker-months td', true).first();
14532 months.dom.innerHTML = '';
14538 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14541 months.createChild(month);
14548 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;
14550 if (this.date < this.startDate) {
14551 this.viewDate = new Date(this.startDate);
14552 } else if (this.date > this.endDate) {
14553 this.viewDate = new Date(this.endDate);
14555 this.viewDate = new Date(this.date);
14563 var d = new Date(this.viewDate),
14564 year = d.getUTCFullYear(),
14565 month = d.getUTCMonth(),
14566 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14567 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14568 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14569 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14570 currentDate = this.date && this.date.valueOf(),
14571 today = this.UTCToday();
14573 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14575 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14577 // this.picker.select('>tfoot th.today').
14578 // .text(dates[this.language].today)
14579 // .toggle(this.todayBtn !== false);
14581 this.updateNavArrows();
14584 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14586 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14588 prevMonth.setUTCDate(day);
14590 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14592 var nextMonth = new Date(prevMonth);
14594 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14596 nextMonth = nextMonth.valueOf();
14598 var fillMonths = false;
14600 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14602 while(prevMonth.valueOf() < nextMonth) {
14605 if (prevMonth.getUTCDay() === this.weekStart) {
14607 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14615 if(this.calendarWeeks){
14616 // ISO 8601: First week contains first thursday.
14617 // ISO also states week starts on Monday, but we can be more abstract here.
14619 // Start of current week: based on weekstart/current date
14620 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14621 // Thursday of this week
14622 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14623 // First Thursday of year, year from thursday
14624 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14625 // Calendar week: ms between thursdays, div ms per day, div 7 days
14626 calWeek = (th - yth) / 864e5 / 7 + 1;
14628 fillMonths.cn.push({
14636 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14638 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14641 if (this.todayHighlight &&
14642 prevMonth.getUTCFullYear() == today.getFullYear() &&
14643 prevMonth.getUTCMonth() == today.getMonth() &&
14644 prevMonth.getUTCDate() == today.getDate()) {
14645 clsName += ' today';
14648 if (currentDate && prevMonth.valueOf() === currentDate) {
14649 clsName += ' active';
14652 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14653 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14654 clsName += ' disabled';
14657 fillMonths.cn.push({
14659 cls: 'day ' + clsName,
14660 html: prevMonth.getDate()
14663 prevMonth.setDate(prevMonth.getDate()+1);
14666 var currentYear = this.date && this.date.getUTCFullYear();
14667 var currentMonth = this.date && this.date.getUTCMonth();
14669 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14671 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14672 v.removeClass('active');
14674 if(currentYear === year && k === currentMonth){
14675 v.addClass('active');
14678 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14679 v.addClass('disabled');
14685 year = parseInt(year/10, 10) * 10;
14687 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14689 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14692 for (var i = -1; i < 11; i++) {
14693 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14695 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14703 showMode: function(dir)
14706 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14708 Roo.each(this.picker().select('>div',true).elements, function(v){
14709 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14712 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14717 if(this.isInline) return;
14719 this.picker().removeClass(['bottom', 'top']);
14721 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14723 * place to the top of element!
14727 this.picker().addClass('top');
14728 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14733 this.picker().addClass('bottom');
14735 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14738 parseDate : function(value)
14740 if(!value || value instanceof Date){
14743 var v = Date.parseDate(value, this.format);
14744 if (!v && this.useIso) {
14745 v = Date.parseDate(value, 'Y-m-d');
14747 if(!v && this.altFormats){
14748 if(!this.altFormatsArray){
14749 this.altFormatsArray = this.altFormats.split("|");
14751 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14752 v = Date.parseDate(value, this.altFormatsArray[i]);
14758 formatDate : function(date, fmt)
14760 return (!date || !(date instanceof Date)) ?
14761 date : date.dateFormat(fmt || this.format);
14764 onFocus : function()
14766 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14770 onBlur : function()
14772 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14774 var d = this.inputEl().getValue();
14783 this.picker().show();
14787 this.fireEvent('show', this, this.date);
14792 if(this.isInline) return;
14793 this.picker().hide();
14794 this.viewMode = this.startViewMode;
14797 this.fireEvent('hide', this, this.date);
14801 onMousedown: function(e)
14803 e.stopPropagation();
14804 e.preventDefault();
14809 Roo.bootstrap.DateField.superclass.keyup.call(this);
14813 setValue: function(v)
14815 var d = new Date(v).clearTime();
14817 if(isNaN(d.getTime())){
14818 this.date = this.viewDate = '';
14819 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14823 v = this.formatDate(d);
14825 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14827 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14831 this.fireEvent('select', this, this.date);
14835 getValue: function()
14837 return this.formatDate(this.date);
14840 fireKey: function(e)
14842 if (!this.picker().isVisible()){
14843 if (e.keyCode == 27) // allow escape to hide and re-show picker
14848 var dateChanged = false,
14850 newDate, newViewDate;
14855 e.preventDefault();
14859 if (!this.keyboardNavigation) break;
14860 dir = e.keyCode == 37 ? -1 : 1;
14863 newDate = this.moveYear(this.date, dir);
14864 newViewDate = this.moveYear(this.viewDate, dir);
14865 } else if (e.shiftKey){
14866 newDate = this.moveMonth(this.date, dir);
14867 newViewDate = this.moveMonth(this.viewDate, dir);
14869 newDate = new Date(this.date);
14870 newDate.setUTCDate(this.date.getUTCDate() + dir);
14871 newViewDate = new Date(this.viewDate);
14872 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14874 if (this.dateWithinRange(newDate)){
14875 this.date = newDate;
14876 this.viewDate = newViewDate;
14877 this.setValue(this.formatDate(this.date));
14879 e.preventDefault();
14880 dateChanged = true;
14885 if (!this.keyboardNavigation) break;
14886 dir = e.keyCode == 38 ? -1 : 1;
14888 newDate = this.moveYear(this.date, dir);
14889 newViewDate = this.moveYear(this.viewDate, dir);
14890 } else if (e.shiftKey){
14891 newDate = this.moveMonth(this.date, dir);
14892 newViewDate = this.moveMonth(this.viewDate, dir);
14894 newDate = new Date(this.date);
14895 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14896 newViewDate = new Date(this.viewDate);
14897 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14899 if (this.dateWithinRange(newDate)){
14900 this.date = newDate;
14901 this.viewDate = newViewDate;
14902 this.setValue(this.formatDate(this.date));
14904 e.preventDefault();
14905 dateChanged = true;
14909 this.setValue(this.formatDate(this.date));
14911 e.preventDefault();
14914 this.setValue(this.formatDate(this.date));
14928 onClick: function(e)
14930 e.stopPropagation();
14931 e.preventDefault();
14933 var target = e.getTarget();
14935 if(target.nodeName.toLowerCase() === 'i'){
14936 target = Roo.get(target).dom.parentNode;
14939 var nodeName = target.nodeName;
14940 var className = target.className;
14941 var html = target.innerHTML;
14943 switch(nodeName.toLowerCase()) {
14945 switch(className) {
14951 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14952 switch(this.viewMode){
14954 this.viewDate = this.moveMonth(this.viewDate, dir);
14958 this.viewDate = this.moveYear(this.viewDate, dir);
14964 var date = new Date();
14965 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14967 this.setValue(this.formatDate(this.date));
14974 if (className.indexOf('disabled') === -1) {
14975 this.viewDate.setUTCDate(1);
14976 if (className.indexOf('month') !== -1) {
14977 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14979 var year = parseInt(html, 10) || 0;
14980 this.viewDate.setUTCFullYear(year);
14989 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14990 var day = parseInt(html, 10) || 1;
14991 var year = this.viewDate.getUTCFullYear(),
14992 month = this.viewDate.getUTCMonth();
14994 if (className.indexOf('old') !== -1) {
15001 } else if (className.indexOf('new') !== -1) {
15009 this.date = this.UTCDate(year, month, day,0,0,0,0);
15010 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15012 this.setValue(this.formatDate(this.date));
15019 setStartDate: function(startDate)
15021 this.startDate = startDate || -Infinity;
15022 if (this.startDate !== -Infinity) {
15023 this.startDate = this.parseDate(this.startDate);
15026 this.updateNavArrows();
15029 setEndDate: function(endDate)
15031 this.endDate = endDate || Infinity;
15032 if (this.endDate !== Infinity) {
15033 this.endDate = this.parseDate(this.endDate);
15036 this.updateNavArrows();
15039 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15041 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15042 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15043 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15045 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15046 return parseInt(d, 10);
15049 this.updateNavArrows();
15052 updateNavArrows: function()
15054 var d = new Date(this.viewDate),
15055 year = d.getUTCFullYear(),
15056 month = d.getUTCMonth();
15058 Roo.each(this.picker().select('.prev', true).elements, function(v){
15060 switch (this.viewMode) {
15063 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15069 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15076 Roo.each(this.picker().select('.next', true).elements, function(v){
15078 switch (this.viewMode) {
15081 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15087 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15095 moveMonth: function(date, dir)
15097 if (!dir) return date;
15098 var new_date = new Date(date.valueOf()),
15099 day = new_date.getUTCDate(),
15100 month = new_date.getUTCMonth(),
15101 mag = Math.abs(dir),
15103 dir = dir > 0 ? 1 : -1;
15106 // If going back one month, make sure month is not current month
15107 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15109 return new_date.getUTCMonth() == month;
15111 // If going forward one month, make sure month is as expected
15112 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15114 return new_date.getUTCMonth() != new_month;
15116 new_month = month + dir;
15117 new_date.setUTCMonth(new_month);
15118 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15119 if (new_month < 0 || new_month > 11)
15120 new_month = (new_month + 12) % 12;
15122 // For magnitudes >1, move one month at a time...
15123 for (var i=0; i<mag; i++)
15124 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15125 new_date = this.moveMonth(new_date, dir);
15126 // ...then reset the day, keeping it in the new month
15127 new_month = new_date.getUTCMonth();
15128 new_date.setUTCDate(day);
15130 return new_month != new_date.getUTCMonth();
15133 // Common date-resetting loop -- if date is beyond end of month, make it
15136 new_date.setUTCDate(--day);
15137 new_date.setUTCMonth(new_month);
15142 moveYear: function(date, dir)
15144 return this.moveMonth(date, dir*12);
15147 dateWithinRange: function(date)
15149 return date >= this.startDate && date <= this.endDate;
15155 this.picker().remove();
15160 Roo.apply(Roo.bootstrap.DateField, {
15171 html: '<i class="fa fa-arrow-left"/>'
15181 html: '<i class="fa fa-arrow-right"/>'
15223 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15224 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15225 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15226 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15227 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15240 navFnc: 'FullYear',
15245 navFnc: 'FullYear',
15250 Roo.apply(Roo.bootstrap.DateField, {
15254 cls: 'datepicker dropdown-menu',
15258 cls: 'datepicker-days',
15262 cls: 'table-condensed',
15264 Roo.bootstrap.DateField.head,
15268 Roo.bootstrap.DateField.footer
15275 cls: 'datepicker-months',
15279 cls: 'table-condensed',
15281 Roo.bootstrap.DateField.head,
15282 Roo.bootstrap.DateField.content,
15283 Roo.bootstrap.DateField.footer
15290 cls: 'datepicker-years',
15294 cls: 'table-condensed',
15296 Roo.bootstrap.DateField.head,
15297 Roo.bootstrap.DateField.content,
15298 Roo.bootstrap.DateField.footer
15317 * @class Roo.bootstrap.TimeField
15318 * @extends Roo.bootstrap.Input
15319 * Bootstrap DateField class
15323 * Create a new TimeField
15324 * @param {Object} config The config object
15327 Roo.bootstrap.TimeField = function(config){
15328 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15332 * Fires when this field show.
15333 * @param {Roo.bootstrap.DateField} this
15334 * @param {Mixed} date The date value
15339 * Fires when this field hide.
15340 * @param {Roo.bootstrap.DateField} this
15341 * @param {Mixed} date The date value
15346 * Fires when select a date.
15347 * @param {Roo.bootstrap.DateField} this
15348 * @param {Mixed} date The date value
15354 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15357 * @cfg {String} format
15358 * The default time format string which can be overriden for localization support. The format must be
15359 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15363 onRender: function(ct, position)
15366 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15368 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15370 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15372 this.pop = this.picker().select('>.datepicker-time',true).first();
15373 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15375 this.picker().on('mousedown', this.onMousedown, this);
15376 this.picker().on('click', this.onClick, this);
15378 this.picker().addClass('datepicker-dropdown');
15383 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15384 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15385 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15386 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15387 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15388 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15392 fireKey: function(e){
15393 if (!this.picker().isVisible()){
15394 if (e.keyCode == 27) // allow escape to hide and re-show picker
15399 e.preventDefault();
15407 this.onTogglePeriod();
15410 this.onIncrementMinutes();
15413 this.onDecrementMinutes();
15422 onClick: function(e) {
15423 e.stopPropagation();
15424 e.preventDefault();
15427 picker : function()
15429 return this.el.select('.datepicker', true).first();
15432 fillTime: function()
15434 var time = this.pop.select('tbody', true).first();
15436 time.dom.innerHTML = '';
15451 cls: 'hours-up glyphicon glyphicon-chevron-up'
15471 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15492 cls: 'timepicker-hour',
15507 cls: 'timepicker-minute',
15522 cls: 'btn btn-primary period',
15544 cls: 'hours-down glyphicon glyphicon-chevron-down'
15564 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15582 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15589 var hours = this.time.getHours();
15590 var minutes = this.time.getMinutes();
15603 hours = hours - 12;
15607 hours = '0' + hours;
15611 minutes = '0' + minutes;
15614 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15615 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15616 this.pop.select('button', true).first().dom.innerHTML = period;
15622 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15624 var cls = ['bottom'];
15626 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15633 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15638 this.picker().addClass(cls.join('-'));
15642 Roo.each(cls, function(c){
15644 _this.picker().setTop(_this.inputEl().getHeight());
15648 _this.picker().setTop(0 - _this.picker().getHeight());
15653 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15657 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15664 onFocus : function()
15666 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15670 onBlur : function()
15672 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15678 this.picker().show();
15683 this.fireEvent('show', this, this.date);
15688 this.picker().hide();
15691 this.fireEvent('hide', this, this.date);
15694 setTime : function()
15697 this.setValue(this.time.format(this.format));
15699 this.fireEvent('select', this, this.date);
15704 onMousedown: function(e){
15705 e.stopPropagation();
15706 e.preventDefault();
15709 onIncrementHours: function()
15711 Roo.log('onIncrementHours');
15712 this.time = this.time.add(Date.HOUR, 1);
15717 onDecrementHours: function()
15719 Roo.log('onDecrementHours');
15720 this.time = this.time.add(Date.HOUR, -1);
15724 onIncrementMinutes: function()
15726 Roo.log('onIncrementMinutes');
15727 this.time = this.time.add(Date.MINUTE, 1);
15731 onDecrementMinutes: function()
15733 Roo.log('onDecrementMinutes');
15734 this.time = this.time.add(Date.MINUTE, -1);
15738 onTogglePeriod: function()
15740 Roo.log('onTogglePeriod');
15741 this.time = this.time.add(Date.HOUR, 12);
15748 Roo.apply(Roo.bootstrap.TimeField, {
15778 cls: 'btn btn-info ok',
15790 Roo.apply(Roo.bootstrap.TimeField, {
15794 cls: 'datepicker dropdown-menu',
15798 cls: 'datepicker-time',
15802 cls: 'table-condensed',
15804 Roo.bootstrap.TimeField.content,
15805 Roo.bootstrap.TimeField.footer
15824 * @class Roo.bootstrap.CheckBox
15825 * @extends Roo.bootstrap.Input
15826 * Bootstrap CheckBox class
15828 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15829 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15830 * @cfg {String} boxLabel The text that appears beside the checkbox
15831 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15832 * @cfg {Boolean} checked initnal the element
15836 * Create a new CheckBox
15837 * @param {Object} config The config object
15840 Roo.bootstrap.CheckBox = function(config){
15841 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15846 * Fires when the element is checked or unchecked.
15847 * @param {Roo.bootstrap.CheckBox} this This input
15848 * @param {Boolean} checked The new checked value
15854 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15856 inputType: 'checkbox',
15863 getAutoCreate : function()
15865 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15871 cfg.cls = 'form-group checkbox' //input-group
15879 type : this.inputType,
15880 value : (!this.checked) ? this.valueOff : this.inputValue,
15881 cls : 'roo-checkbox', //'form-box',
15882 placeholder : this.placeholder || ''
15886 if (this.weight) { // Validity check?
15887 cfg.cls += " checkbox-" + this.weight;
15890 if (this.disabled) {
15891 input.disabled=true;
15895 input.checked = this.checked;
15899 input.name = this.name;
15903 input.cls += ' input-' + this.size;
15907 ['xs','sm','md','lg'].map(function(size){
15908 if (settings[size]) {
15909 cfg.cls += ' col-' + size + '-' + settings[size];
15915 var inputblock = input;
15920 if (this.before || this.after) {
15923 cls : 'input-group',
15927 inputblock.cn.push({
15929 cls : 'input-group-addon',
15933 inputblock.cn.push(input);
15935 inputblock.cn.push({
15937 cls : 'input-group-addon',
15944 if (align ==='left' && this.fieldLabel.length) {
15945 Roo.log("left and has label");
15951 cls : 'control-label col-md-' + this.labelWidth,
15952 html : this.fieldLabel
15956 cls : "col-md-" + (12 - this.labelWidth),
15963 } else if ( this.fieldLabel.length) {
15968 tag: this.boxLabel ? 'span' : 'label',
15970 cls: 'control-label box-input-label',
15971 //cls : 'input-group-addon',
15972 html : this.fieldLabel
15982 Roo.log(" no label && no align");
15983 cfg.cn = [ inputblock ] ;
15992 html: this.boxLabel
16004 * return the real input element.
16006 inputEl: function ()
16008 return this.el.select('input.roo-checkbox',true).first();
16013 return this.el.select('label.control-label',true).first();
16016 initEvents : function()
16018 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16020 this.inputEl().on('click', this.onClick, this);
16024 onClick : function()
16026 this.setChecked(!this.checked);
16029 setChecked : function(state,suppressEvent)
16031 this.checked = state;
16033 this.inputEl().dom.checked = state;
16035 if(suppressEvent !== true){
16036 this.fireEvent('check', this, state);
16039 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16043 setValue : function(v,suppressEvent)
16045 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16059 * @class Roo.bootstrap.Radio
16060 * @extends Roo.bootstrap.CheckBox
16061 * Bootstrap Radio class
16064 * Create a new Radio
16065 * @param {Object} config The config object
16068 Roo.bootstrap.Radio = function(config){
16069 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16073 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16075 inputType: 'radio',
16079 getAutoCreate : function()
16081 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16087 cfg.cls = 'form-group radio' //input-group
16092 type : this.inputType,
16093 value : (!this.checked) ? this.valueOff : this.inputValue,
16095 placeholder : this.placeholder || ''
16098 if (this.weight) { // Validity check?
16099 cfg.cls += " radio-" + this.weight;
16101 if (this.disabled) {
16102 input.disabled=true;
16106 input.checked = this.checked;
16110 input.name = this.name;
16114 input.cls += ' input-' + this.size;
16118 ['xs','sm','md','lg'].map(function(size){
16119 if (settings[size]) {
16120 cfg.cls += ' col-' + size + '-' + settings[size];
16124 var inputblock = input;
16126 if (this.before || this.after) {
16129 cls : 'input-group',
16133 inputblock.cn.push({
16135 cls : 'input-group-addon',
16139 inputblock.cn.push(input);
16141 inputblock.cn.push({
16143 cls : 'input-group-addon',
16150 if (align ==='left' && this.fieldLabel.length) {
16151 Roo.log("left and has label");
16157 cls : 'control-label col-md-' + this.labelWidth,
16158 html : this.fieldLabel
16162 cls : "col-md-" + (12 - this.labelWidth),
16169 } else if ( this.fieldLabel.length) {
16176 cls: 'control-label box-input-label',
16177 //cls : 'input-group-addon',
16178 html : this.fieldLabel
16188 Roo.log(" no label && no align");
16203 html: this.boxLabel
16210 inputEl: function ()
16212 return this.el.select('input.roo-radio',true).first();
16214 onClick : function()
16216 this.setChecked(true);
16219 setChecked : function(state,suppressEvent)
16222 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16223 v.dom.checked = false;
16227 this.checked = state;
16228 this.inputEl().dom.checked = state;
16230 if(suppressEvent !== true){
16231 this.fireEvent('check', this, state);
16234 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16238 getGroupValue : function()
16241 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16242 if(v.dom.checked == true){
16243 value = v.dom.value;
16251 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16252 * @return {Mixed} value The field value
16254 getValue : function(){
16255 return this.getGroupValue();
16261 //<script type="text/javascript">
16264 * Based Ext JS Library 1.1.1
16265 * Copyright(c) 2006-2007, Ext JS, LLC.
16271 * @class Roo.HtmlEditorCore
16272 * @extends Roo.Component
16273 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16275 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16278 Roo.HtmlEditorCore = function(config){
16281 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16284 * @event initialize
16285 * Fires when the editor is fully initialized (including the iframe)
16286 * @param {Roo.HtmlEditorCore} this
16291 * Fires when the editor is first receives the focus. Any insertion must wait
16292 * until after this event.
16293 * @param {Roo.HtmlEditorCore} this
16297 * @event beforesync
16298 * Fires before the textarea is updated with content from the editor iframe. Return false
16299 * to cancel the sync.
16300 * @param {Roo.HtmlEditorCore} this
16301 * @param {String} html
16305 * @event beforepush
16306 * Fires before the iframe editor is updated with content from the textarea. Return false
16307 * to cancel the push.
16308 * @param {Roo.HtmlEditorCore} this
16309 * @param {String} html
16314 * Fires when the textarea is updated with content from the editor iframe.
16315 * @param {Roo.HtmlEditorCore} this
16316 * @param {String} html
16321 * Fires when the iframe editor is updated with content from the textarea.
16322 * @param {Roo.HtmlEditorCore} this
16323 * @param {String} html
16328 * @event editorevent
16329 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16330 * @param {Roo.HtmlEditorCore} this
16338 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16342 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16348 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16353 * @cfg {Number} height (in pixels)
16357 * @cfg {Number} width (in pixels)
16362 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16365 stylesheets: false,
16370 // private properties
16371 validationEvent : false,
16373 initialized : false,
16375 sourceEditMode : false,
16376 onFocus : Roo.emptyFn,
16378 hideMode:'offsets',
16386 * Protected method that will not generally be called directly. It
16387 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16388 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16390 getDocMarkup : function(){
16393 Roo.log(this.stylesheets);
16395 // inherit styels from page...??
16396 if (this.stylesheets === false) {
16398 Roo.get(document.head).select('style').each(function(node) {
16399 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16402 Roo.get(document.head).select('link').each(function(node) {
16403 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16406 } else if (!this.stylesheets.length) {
16408 st = '<style type="text/css">' +
16409 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16412 Roo.each(this.stylesheets, function(s) {
16413 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16418 st += '<style type="text/css">' +
16419 'IMG { cursor: pointer } ' +
16423 return '<html><head>' + st +
16424 //<style type="text/css">' +
16425 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16427 ' </head><body class="roo-htmleditor-body"></body></html>';
16431 onRender : function(ct, position)
16434 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16435 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16438 this.el.dom.style.border = '0 none';
16439 this.el.dom.setAttribute('tabIndex', -1);
16440 this.el.addClass('x-hidden hide');
16444 if(Roo.isIE){ // fix IE 1px bogus margin
16445 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16449 this.frameId = Roo.id();
16453 var iframe = this.owner.wrap.createChild({
16455 cls: 'form-control', // bootstrap..
16457 name: this.frameId,
16458 frameBorder : 'no',
16459 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16464 this.iframe = iframe.dom;
16466 this.assignDocWin();
16468 this.doc.designMode = 'on';
16471 this.doc.write(this.getDocMarkup());
16475 var task = { // must defer to wait for browser to be ready
16477 //console.log("run task?" + this.doc.readyState);
16478 this.assignDocWin();
16479 if(this.doc.body || this.doc.readyState == 'complete'){
16481 this.doc.designMode="on";
16485 Roo.TaskMgr.stop(task);
16486 this.initEditor.defer(10, this);
16493 Roo.TaskMgr.start(task);
16500 onResize : function(w, h)
16502 Roo.log('resize: ' +w + ',' + h );
16503 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16507 if(typeof w == 'number'){
16509 this.iframe.style.width = w + 'px';
16511 if(typeof h == 'number'){
16513 this.iframe.style.height = h + 'px';
16515 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16522 * Toggles the editor between standard and source edit mode.
16523 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16525 toggleSourceEdit : function(sourceEditMode){
16527 this.sourceEditMode = sourceEditMode === true;
16529 if(this.sourceEditMode){
16531 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16534 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16535 //this.iframe.className = '';
16538 //this.setSize(this.owner.wrap.getSize());
16539 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16546 * Protected method that will not generally be called directly. If you need/want
16547 * custom HTML cleanup, this is the method you should override.
16548 * @param {String} html The HTML to be cleaned
16549 * return {String} The cleaned HTML
16551 cleanHtml : function(html){
16552 html = String(html);
16553 if(html.length > 5){
16554 if(Roo.isSafari){ // strip safari nonsense
16555 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16558 if(html == ' '){
16565 * HTML Editor -> Textarea
16566 * Protected method that will not generally be called directly. Syncs the contents
16567 * of the editor iframe with the textarea.
16569 syncValue : function(){
16570 if(this.initialized){
16571 var bd = (this.doc.body || this.doc.documentElement);
16572 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16573 var html = bd.innerHTML;
16575 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16576 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16578 html = '<div style="'+m[0]+'">' + html + '</div>';
16581 html = this.cleanHtml(html);
16582 // fix up the special chars.. normaly like back quotes in word...
16583 // however we do not want to do this with chinese..
16584 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16585 var cc = b.charCodeAt();
16587 (cc >= 0x4E00 && cc < 0xA000 ) ||
16588 (cc >= 0x3400 && cc < 0x4E00 ) ||
16589 (cc >= 0xf900 && cc < 0xfb00 )
16595 if(this.owner.fireEvent('beforesync', this, html) !== false){
16596 this.el.dom.value = html;
16597 this.owner.fireEvent('sync', this, html);
16603 * Protected method that will not generally be called directly. Pushes the value of the textarea
16604 * into the iframe editor.
16606 pushValue : function(){
16607 if(this.initialized){
16608 var v = this.el.dom.value.trim();
16610 // if(v.length < 1){
16614 if(this.owner.fireEvent('beforepush', this, v) !== false){
16615 var d = (this.doc.body || this.doc.documentElement);
16617 this.cleanUpPaste();
16618 this.el.dom.value = d.innerHTML;
16619 this.owner.fireEvent('push', this, v);
16625 deferFocus : function(){
16626 this.focus.defer(10, this);
16630 focus : function(){
16631 if(this.win && !this.sourceEditMode){
16638 assignDocWin: function()
16640 var iframe = this.iframe;
16643 this.doc = iframe.contentWindow.document;
16644 this.win = iframe.contentWindow;
16646 // if (!Roo.get(this.frameId)) {
16649 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16650 // this.win = Roo.get(this.frameId).dom.contentWindow;
16652 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16656 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16657 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16662 initEditor : function(){
16663 //console.log("INIT EDITOR");
16664 this.assignDocWin();
16668 this.doc.designMode="on";
16670 this.doc.write(this.getDocMarkup());
16673 var dbody = (this.doc.body || this.doc.documentElement);
16674 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16675 // this copies styles from the containing element into thsi one..
16676 // not sure why we need all of this..
16677 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16679 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16680 //ss['background-attachment'] = 'fixed'; // w3c
16681 dbody.bgProperties = 'fixed'; // ie
16682 //Roo.DomHelper.applyStyles(dbody, ss);
16683 Roo.EventManager.on(this.doc, {
16684 //'mousedown': this.onEditorEvent,
16685 'mouseup': this.onEditorEvent,
16686 'dblclick': this.onEditorEvent,
16687 'click': this.onEditorEvent,
16688 'keyup': this.onEditorEvent,
16693 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16695 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16696 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16698 this.initialized = true;
16700 this.owner.fireEvent('initialize', this);
16705 onDestroy : function(){
16711 //for (var i =0; i < this.toolbars.length;i++) {
16712 // // fixme - ask toolbars for heights?
16713 // this.toolbars[i].onDestroy();
16716 //this.wrap.dom.innerHTML = '';
16717 //this.wrap.remove();
16722 onFirstFocus : function(){
16724 this.assignDocWin();
16727 this.activated = true;
16730 if(Roo.isGecko){ // prevent silly gecko errors
16732 var s = this.win.getSelection();
16733 if(!s.focusNode || s.focusNode.nodeType != 3){
16734 var r = s.getRangeAt(0);
16735 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16740 this.execCmd('useCSS', true);
16741 this.execCmd('styleWithCSS', false);
16744 this.owner.fireEvent('activate', this);
16748 adjustFont: function(btn){
16749 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16750 //if(Roo.isSafari){ // safari
16753 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16754 if(Roo.isSafari){ // safari
16755 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16756 v = (v < 10) ? 10 : v;
16757 v = (v > 48) ? 48 : v;
16758 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16763 v = Math.max(1, v+adjust);
16765 this.execCmd('FontSize', v );
16768 onEditorEvent : function(e){
16769 this.owner.fireEvent('editorevent', this, e);
16770 // this.updateToolbar();
16771 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16774 insertTag : function(tg)
16776 // could be a bit smarter... -> wrap the current selected tRoo..
16777 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16779 range = this.createRange(this.getSelection());
16780 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16781 wrappingNode.appendChild(range.extractContents());
16782 range.insertNode(wrappingNode);
16789 this.execCmd("formatblock", tg);
16793 insertText : function(txt)
16797 var range = this.createRange();
16798 range.deleteContents();
16799 //alert(Sender.getAttribute('label'));
16801 range.insertNode(this.doc.createTextNode(txt));
16807 * Executes a Midas editor command on the editor document and performs necessary focus and
16808 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16809 * @param {String} cmd The Midas command
16810 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16812 relayCmd : function(cmd, value){
16814 this.execCmd(cmd, value);
16815 this.owner.fireEvent('editorevent', this);
16816 //this.updateToolbar();
16817 this.owner.deferFocus();
16821 * Executes a Midas editor command directly on the editor document.
16822 * For visual commands, you should use {@link #relayCmd} instead.
16823 * <b>This should only be called after the editor is initialized.</b>
16824 * @param {String} cmd The Midas command
16825 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16827 execCmd : function(cmd, value){
16828 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16835 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16837 * @param {String} text | dom node..
16839 insertAtCursor : function(text)
16844 if(!this.activated){
16850 var r = this.doc.selection.createRange();
16861 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16865 // from jquery ui (MIT licenced)
16867 var win = this.win;
16869 if (win.getSelection && win.getSelection().getRangeAt) {
16870 range = win.getSelection().getRangeAt(0);
16871 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16872 range.insertNode(node);
16873 } else if (win.document.selection && win.document.selection.createRange) {
16874 // no firefox support
16875 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16876 win.document.selection.createRange().pasteHTML(txt);
16878 // no firefox support
16879 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16880 this.execCmd('InsertHTML', txt);
16889 mozKeyPress : function(e){
16891 var c = e.getCharCode(), cmd;
16894 c = String.fromCharCode(c).toLowerCase();
16908 this.cleanUpPaste.defer(100, this);
16916 e.preventDefault();
16924 fixKeys : function(){ // load time branching for fastest keydown performance
16926 return function(e){
16927 var k = e.getKey(), r;
16930 r = this.doc.selection.createRange();
16933 r.pasteHTML('    ');
16940 r = this.doc.selection.createRange();
16942 var target = r.parentElement();
16943 if(!target || target.tagName.toLowerCase() != 'li'){
16945 r.pasteHTML('<br />');
16951 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16952 this.cleanUpPaste.defer(100, this);
16958 }else if(Roo.isOpera){
16959 return function(e){
16960 var k = e.getKey();
16964 this.execCmd('InsertHTML','    ');
16967 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16968 this.cleanUpPaste.defer(100, this);
16973 }else if(Roo.isSafari){
16974 return function(e){
16975 var k = e.getKey();
16979 this.execCmd('InsertText','\t');
16983 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16984 this.cleanUpPaste.defer(100, this);
16992 getAllAncestors: function()
16994 var p = this.getSelectedNode();
16997 a.push(p); // push blank onto stack..
16998 p = this.getParentElement();
17002 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17006 a.push(this.doc.body);
17010 lastSelNode : false,
17013 getSelection : function()
17015 this.assignDocWin();
17016 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17019 getSelectedNode: function()
17021 // this may only work on Gecko!!!
17023 // should we cache this!!!!
17028 var range = this.createRange(this.getSelection()).cloneRange();
17031 var parent = range.parentElement();
17033 var testRange = range.duplicate();
17034 testRange.moveToElementText(parent);
17035 if (testRange.inRange(range)) {
17038 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17041 parent = parent.parentElement;
17046 // is ancestor a text element.
17047 var ac = range.commonAncestorContainer;
17048 if (ac.nodeType == 3) {
17049 ac = ac.parentNode;
17052 var ar = ac.childNodes;
17055 var other_nodes = [];
17056 var has_other_nodes = false;
17057 for (var i=0;i<ar.length;i++) {
17058 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17061 // fullly contained node.
17063 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17068 // probably selected..
17069 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17070 other_nodes.push(ar[i]);
17074 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17079 has_other_nodes = true;
17081 if (!nodes.length && other_nodes.length) {
17082 nodes= other_nodes;
17084 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17090 createRange: function(sel)
17092 // this has strange effects when using with
17093 // top toolbar - not sure if it's a great idea.
17094 //this.editor.contentWindow.focus();
17095 if (typeof sel != "undefined") {
17097 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17099 return this.doc.createRange();
17102 return this.doc.createRange();
17105 getParentElement: function()
17108 this.assignDocWin();
17109 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17111 var range = this.createRange(sel);
17114 var p = range.commonAncestorContainer;
17115 while (p.nodeType == 3) { // text node
17126 * Range intersection.. the hard stuff...
17130 * [ -- selected range --- ]
17134 * if end is before start or hits it. fail.
17135 * if start is after end or hits it fail.
17137 * if either hits (but other is outside. - then it's not
17143 // @see http://www.thismuchiknow.co.uk/?p=64.
17144 rangeIntersectsNode : function(range, node)
17146 var nodeRange = node.ownerDocument.createRange();
17148 nodeRange.selectNode(node);
17150 nodeRange.selectNodeContents(node);
17153 var rangeStartRange = range.cloneRange();
17154 rangeStartRange.collapse(true);
17156 var rangeEndRange = range.cloneRange();
17157 rangeEndRange.collapse(false);
17159 var nodeStartRange = nodeRange.cloneRange();
17160 nodeStartRange.collapse(true);
17162 var nodeEndRange = nodeRange.cloneRange();
17163 nodeEndRange.collapse(false);
17165 return rangeStartRange.compareBoundaryPoints(
17166 Range.START_TO_START, nodeEndRange) == -1 &&
17167 rangeEndRange.compareBoundaryPoints(
17168 Range.START_TO_START, nodeStartRange) == 1;
17172 rangeCompareNode : function(range, node)
17174 var nodeRange = node.ownerDocument.createRange();
17176 nodeRange.selectNode(node);
17178 nodeRange.selectNodeContents(node);
17182 range.collapse(true);
17184 nodeRange.collapse(true);
17186 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17187 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17189 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17191 var nodeIsBefore = ss == 1;
17192 var nodeIsAfter = ee == -1;
17194 if (nodeIsBefore && nodeIsAfter)
17196 if (!nodeIsBefore && nodeIsAfter)
17197 return 1; //right trailed.
17199 if (nodeIsBefore && !nodeIsAfter)
17200 return 2; // left trailed.
17205 // private? - in a new class?
17206 cleanUpPaste : function()
17208 // cleans up the whole document..
17209 Roo.log('cleanuppaste');
17211 this.cleanUpChildren(this.doc.body);
17212 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17213 if (clean != this.doc.body.innerHTML) {
17214 this.doc.body.innerHTML = clean;
17219 cleanWordChars : function(input) {// change the chars to hex code
17220 var he = Roo.HtmlEditorCore;
17222 var output = input;
17223 Roo.each(he.swapCodes, function(sw) {
17224 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17226 output = output.replace(swapper, sw[1]);
17233 cleanUpChildren : function (n)
17235 if (!n.childNodes.length) {
17238 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17239 this.cleanUpChild(n.childNodes[i]);
17246 cleanUpChild : function (node)
17249 //console.log(node);
17250 if (node.nodeName == "#text") {
17251 // clean up silly Windows -- stuff?
17254 if (node.nodeName == "#comment") {
17255 node.parentNode.removeChild(node);
17256 // clean up silly Windows -- stuff?
17260 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17262 node.parentNode.removeChild(node);
17267 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17269 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17270 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17272 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17273 // remove_keep_children = true;
17276 if (remove_keep_children) {
17277 this.cleanUpChildren(node);
17278 // inserts everything just before this node...
17279 while (node.childNodes.length) {
17280 var cn = node.childNodes[0];
17281 node.removeChild(cn);
17282 node.parentNode.insertBefore(cn, node);
17284 node.parentNode.removeChild(node);
17288 if (!node.attributes || !node.attributes.length) {
17289 this.cleanUpChildren(node);
17293 function cleanAttr(n,v)
17296 if (v.match(/^\./) || v.match(/^\//)) {
17299 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17302 if (v.match(/^#/)) {
17305 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17306 node.removeAttribute(n);
17310 function cleanStyle(n,v)
17312 if (v.match(/expression/)) { //XSS?? should we even bother..
17313 node.removeAttribute(n);
17316 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17317 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17320 var parts = v.split(/;/);
17323 Roo.each(parts, function(p) {
17324 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17328 var l = p.split(':').shift().replace(/\s+/g,'');
17329 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17331 if ( cblack.indexOf(l) > -1) {
17332 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17333 //node.removeAttribute(n);
17337 // only allow 'c whitelisted system attributes'
17338 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17339 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17340 //node.removeAttribute(n);
17350 if (clean.length) {
17351 node.setAttribute(n, clean.join(';'));
17353 node.removeAttribute(n);
17359 for (var i = node.attributes.length-1; i > -1 ; i--) {
17360 var a = node.attributes[i];
17363 if (a.name.toLowerCase().substr(0,2)=='on') {
17364 node.removeAttribute(a.name);
17367 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17368 node.removeAttribute(a.name);
17371 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17372 cleanAttr(a.name,a.value); // fixme..
17375 if (a.name == 'style') {
17376 cleanStyle(a.name,a.value);
17379 /// clean up MS crap..
17380 // tecnically this should be a list of valid class'es..
17383 if (a.name == 'class') {
17384 if (a.value.match(/^Mso/)) {
17385 node.className = '';
17388 if (a.value.match(/body/)) {
17389 node.className = '';
17400 this.cleanUpChildren(node);
17405 * Clean up MS wordisms...
17407 cleanWord : function(node)
17410 var cleanWordChildren = function()
17412 if (!node.childNodes.length) {
17415 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17416 _t.cleanWord(node.childNodes[i]);
17422 this.cleanWord(this.doc.body);
17425 if (node.nodeName == "#text") {
17426 // clean up silly Windows -- stuff?
17429 if (node.nodeName == "#comment") {
17430 node.parentNode.removeChild(node);
17431 // clean up silly Windows -- stuff?
17435 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17436 node.parentNode.removeChild(node);
17440 // remove - but keep children..
17441 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17442 while (node.childNodes.length) {
17443 var cn = node.childNodes[0];
17444 node.removeChild(cn);
17445 node.parentNode.insertBefore(cn, node);
17447 node.parentNode.removeChild(node);
17448 cleanWordChildren();
17452 if (node.className.length) {
17454 var cn = node.className.split(/\W+/);
17456 Roo.each(cn, function(cls) {
17457 if (cls.match(/Mso[a-zA-Z]+/)) {
17462 node.className = cna.length ? cna.join(' ') : '';
17464 node.removeAttribute("class");
17468 if (node.hasAttribute("lang")) {
17469 node.removeAttribute("lang");
17472 if (node.hasAttribute("style")) {
17474 var styles = node.getAttribute("style").split(";");
17476 Roo.each(styles, function(s) {
17477 if (!s.match(/:/)) {
17480 var kv = s.split(":");
17481 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17484 // what ever is left... we allow.
17487 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17488 if (!nstyle.length) {
17489 node.removeAttribute('style');
17493 cleanWordChildren();
17497 domToHTML : function(currentElement, depth, nopadtext) {
17499 depth = depth || 0;
17500 nopadtext = nopadtext || false;
17502 if (!currentElement) {
17503 return this.domToHTML(this.doc.body);
17506 //Roo.log(currentElement);
17508 var allText = false;
17509 var nodeName = currentElement.nodeName;
17510 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17512 if (nodeName == '#text') {
17513 return currentElement.nodeValue;
17518 if (nodeName != 'BODY') {
17521 // Prints the node tagName, such as <A>, <IMG>, etc
17524 for(i = 0; i < currentElement.attributes.length;i++) {
17526 var aname = currentElement.attributes.item(i).name;
17527 if (!currentElement.attributes.item(i).value.length) {
17530 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17533 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17542 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17545 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17550 // Traverse the tree
17552 var currentElementChild = currentElement.childNodes.item(i);
17553 var allText = true;
17554 var innerHTML = '';
17556 while (currentElementChild) {
17557 // Formatting code (indent the tree so it looks nice on the screen)
17558 var nopad = nopadtext;
17559 if (lastnode == 'SPAN') {
17563 if (currentElementChild.nodeName == '#text') {
17564 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17565 if (!nopad && toadd.length > 80) {
17566 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17568 innerHTML += toadd;
17571 currentElementChild = currentElement.childNodes.item(i);
17577 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17579 // Recursively traverse the tree structure of the child node
17580 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17581 lastnode = currentElementChild.nodeName;
17583 currentElementChild=currentElement.childNodes.item(i);
17589 // The remaining code is mostly for formatting the tree
17590 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17595 ret+= "</"+tagName+">";
17601 // hide stuff that is not compatible
17615 * @event specialkey
17619 * @cfg {String} fieldClass @hide
17622 * @cfg {String} focusClass @hide
17625 * @cfg {String} autoCreate @hide
17628 * @cfg {String} inputType @hide
17631 * @cfg {String} invalidClass @hide
17634 * @cfg {String} invalidText @hide
17637 * @cfg {String} msgFx @hide
17640 * @cfg {String} validateOnBlur @hide
17644 Roo.HtmlEditorCore.white = [
17645 'area', 'br', 'img', 'input', 'hr', 'wbr',
17647 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17648 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17649 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17650 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17651 'table', 'ul', 'xmp',
17653 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17656 'dir', 'menu', 'ol', 'ul', 'dl',
17662 Roo.HtmlEditorCore.black = [
17663 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17665 'base', 'basefont', 'bgsound', 'blink', 'body',
17666 'frame', 'frameset', 'head', 'html', 'ilayer',
17667 'iframe', 'layer', 'link', 'meta', 'object',
17668 'script', 'style' ,'title', 'xml' // clean later..
17670 Roo.HtmlEditorCore.clean = [
17671 'script', 'style', 'title', 'xml'
17673 Roo.HtmlEditorCore.remove = [
17678 Roo.HtmlEditorCore.ablack = [
17682 Roo.HtmlEditorCore.aclean = [
17683 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17687 Roo.HtmlEditorCore.pwhite= [
17688 'http', 'https', 'mailto'
17691 // white listed style attributes.
17692 Roo.HtmlEditorCore.cwhite= [
17693 // 'text-align', /// default is to allow most things..
17699 // black listed style attributes.
17700 Roo.HtmlEditorCore.cblack= [
17701 // 'font-size' -- this can be set by the project
17705 Roo.HtmlEditorCore.swapCodes =[
17724 * @class Roo.bootstrap.HtmlEditor
17725 * @extends Roo.bootstrap.TextArea
17726 * Bootstrap HtmlEditor class
17729 * Create a new HtmlEditor
17730 * @param {Object} config The config object
17733 Roo.bootstrap.HtmlEditor = function(config){
17734 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17735 if (!this.toolbars) {
17736 this.toolbars = [];
17738 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17741 * @event initialize
17742 * Fires when the editor is fully initialized (including the iframe)
17743 * @param {HtmlEditor} this
17748 * Fires when the editor is first receives the focus. Any insertion must wait
17749 * until after this event.
17750 * @param {HtmlEditor} this
17754 * @event beforesync
17755 * Fires before the textarea is updated with content from the editor iframe. Return false
17756 * to cancel the sync.
17757 * @param {HtmlEditor} this
17758 * @param {String} html
17762 * @event beforepush
17763 * Fires before the iframe editor is updated with content from the textarea. Return false
17764 * to cancel the push.
17765 * @param {HtmlEditor} this
17766 * @param {String} html
17771 * Fires when the textarea is updated with content from the editor iframe.
17772 * @param {HtmlEditor} this
17773 * @param {String} html
17778 * Fires when the iframe editor is updated with content from the textarea.
17779 * @param {HtmlEditor} this
17780 * @param {String} html
17784 * @event editmodechange
17785 * Fires when the editor switches edit modes
17786 * @param {HtmlEditor} this
17787 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17789 editmodechange: true,
17791 * @event editorevent
17792 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17793 * @param {HtmlEditor} this
17797 * @event firstfocus
17798 * Fires when on first focus - needed by toolbars..
17799 * @param {HtmlEditor} this
17804 * Auto save the htmlEditor value as a file into Events
17805 * @param {HtmlEditor} this
17809 * @event savedpreview
17810 * preview the saved version of htmlEditor
17811 * @param {HtmlEditor} this
17818 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17822 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17827 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17832 * @cfg {Number} height (in pixels)
17836 * @cfg {Number} width (in pixels)
17841 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17844 stylesheets: false,
17849 // private properties
17850 validationEvent : false,
17852 initialized : false,
17855 onFocus : Roo.emptyFn,
17857 hideMode:'offsets',
17860 tbContainer : false,
17862 toolbarContainer :function() {
17863 return this.wrap.select('.x-html-editor-tb',true).first();
17867 * Protected method that will not generally be called directly. It
17868 * is called when the editor creates its toolbar. Override this method if you need to
17869 * add custom toolbar buttons.
17870 * @param {HtmlEditor} editor
17872 createToolbar : function(){
17874 Roo.log("create toolbars");
17876 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17877 this.toolbars[0].render(this.toolbarContainer());
17881 // if (!editor.toolbars || !editor.toolbars.length) {
17882 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17885 // for (var i =0 ; i < editor.toolbars.length;i++) {
17886 // editor.toolbars[i] = Roo.factory(
17887 // typeof(editor.toolbars[i]) == 'string' ?
17888 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17889 // Roo.bootstrap.HtmlEditor);
17890 // editor.toolbars[i].init(editor);
17896 onRender : function(ct, position)
17898 // Roo.log("Call onRender: " + this.xtype);
17900 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17902 this.wrap = this.inputEl().wrap({
17903 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17906 this.editorcore.onRender(ct, position);
17908 if (this.resizable) {
17909 this.resizeEl = new Roo.Resizable(this.wrap, {
17913 minHeight : this.height,
17914 height: this.height,
17915 handles : this.resizable,
17918 resize : function(r, w, h) {
17919 _t.onResize(w,h); // -something
17925 this.createToolbar(this);
17928 if(!this.width && this.resizable){
17929 this.setSize(this.wrap.getSize());
17931 if (this.resizeEl) {
17932 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17933 // should trigger onReize..
17939 onResize : function(w, h)
17941 Roo.log('resize: ' +w + ',' + h );
17942 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17946 if(this.inputEl() ){
17947 if(typeof w == 'number'){
17948 var aw = w - this.wrap.getFrameWidth('lr');
17949 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17952 if(typeof h == 'number'){
17953 var tbh = -11; // fixme it needs to tool bar size!
17954 for (var i =0; i < this.toolbars.length;i++) {
17955 // fixme - ask toolbars for heights?
17956 tbh += this.toolbars[i].el.getHeight();
17957 //if (this.toolbars[i].footer) {
17958 // tbh += this.toolbars[i].footer.el.getHeight();
17966 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17967 ah -= 5; // knock a few pixes off for look..
17968 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17972 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17973 this.editorcore.onResize(ew,eh);
17978 * Toggles the editor between standard and source edit mode.
17979 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17981 toggleSourceEdit : function(sourceEditMode)
17983 this.editorcore.toggleSourceEdit(sourceEditMode);
17985 if(this.editorcore.sourceEditMode){
17986 Roo.log('editor - showing textarea');
17989 // Roo.log(this.syncValue());
17991 this.inputEl().removeClass(['hide', 'x-hidden']);
17992 this.inputEl().dom.removeAttribute('tabIndex');
17993 this.inputEl().focus();
17995 Roo.log('editor - hiding textarea');
17997 // Roo.log(this.pushValue());
18000 this.inputEl().addClass(['hide', 'x-hidden']);
18001 this.inputEl().dom.setAttribute('tabIndex', -1);
18002 //this.deferFocus();
18005 if(this.resizable){
18006 this.setSize(this.wrap.getSize());
18009 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18012 // private (for BoxComponent)
18013 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18015 // private (for BoxComponent)
18016 getResizeEl : function(){
18020 // private (for BoxComponent)
18021 getPositionEl : function(){
18026 initEvents : function(){
18027 this.originalValue = this.getValue();
18031 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18034 // markInvalid : Roo.emptyFn,
18036 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18039 // clearInvalid : Roo.emptyFn,
18041 setValue : function(v){
18042 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18043 this.editorcore.pushValue();
18048 deferFocus : function(){
18049 this.focus.defer(10, this);
18053 focus : function(){
18054 this.editorcore.focus();
18060 onDestroy : function(){
18066 for (var i =0; i < this.toolbars.length;i++) {
18067 // fixme - ask toolbars for heights?
18068 this.toolbars[i].onDestroy();
18071 this.wrap.dom.innerHTML = '';
18072 this.wrap.remove();
18077 onFirstFocus : function(){
18078 //Roo.log("onFirstFocus");
18079 this.editorcore.onFirstFocus();
18080 for (var i =0; i < this.toolbars.length;i++) {
18081 this.toolbars[i].onFirstFocus();
18087 syncValue : function()
18089 this.editorcore.syncValue();
18092 pushValue : function()
18094 this.editorcore.pushValue();
18098 // hide stuff that is not compatible
18112 * @event specialkey
18116 * @cfg {String} fieldClass @hide
18119 * @cfg {String} focusClass @hide
18122 * @cfg {String} autoCreate @hide
18125 * @cfg {String} inputType @hide
18128 * @cfg {String} invalidClass @hide
18131 * @cfg {String} invalidText @hide
18134 * @cfg {String} msgFx @hide
18137 * @cfg {String} validateOnBlur @hide
18146 Roo.namespace('Roo.bootstrap.htmleditor');
18148 * @class Roo.bootstrap.HtmlEditorToolbar1
18153 new Roo.bootstrap.HtmlEditor({
18156 new Roo.bootstrap.HtmlEditorToolbar1({
18157 disable : { fonts: 1 , format: 1, ..., ... , ...],
18163 * @cfg {Object} disable List of elements to disable..
18164 * @cfg {Array} btns List of additional buttons.
18168 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18171 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18174 Roo.apply(this, config);
18176 // default disabled, based on 'good practice'..
18177 this.disable = this.disable || {};
18178 Roo.applyIf(this.disable, {
18181 specialElements : true
18183 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18185 this.editor = config.editor;
18186 this.editorcore = config.editor.editorcore;
18188 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18190 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18191 // dont call parent... till later.
18193 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18198 editorcore : false,
18203 "h1","h2","h3","h4","h5","h6",
18205 "abbr", "acronym", "address", "cite", "samp", "var",
18209 onRender : function(ct, position)
18211 // Roo.log("Call onRender: " + this.xtype);
18213 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18215 this.el.dom.style.marginBottom = '0';
18217 var editorcore = this.editorcore;
18218 var editor= this.editor;
18221 var btn = function(id,cmd , toggle, handler){
18223 var event = toggle ? 'toggle' : 'click';
18228 xns: Roo.bootstrap,
18231 enableToggle:toggle !== false,
18233 pressed : toggle ? false : null,
18236 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18237 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18246 xns: Roo.bootstrap,
18247 glyphicon : 'font',
18251 xns: Roo.bootstrap,
18255 Roo.each(this.formats, function(f) {
18256 style.menu.items.push({
18258 xns: Roo.bootstrap,
18259 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18264 editorcore.insertTag(this.tagname);
18271 children.push(style);
18274 btn('bold',false,true);
18275 btn('italic',false,true);
18276 btn('align-left', 'justifyleft',true);
18277 btn('align-center', 'justifycenter',true);
18278 btn('align-right' , 'justifyright',true);
18279 btn('link', false, false, function(btn) {
18280 //Roo.log("create link?");
18281 var url = prompt(this.createLinkText, this.defaultLinkValue);
18282 if(url && url != 'http:/'+'/'){
18283 this.editorcore.relayCmd('createlink', url);
18286 btn('list','insertunorderedlist',true);
18287 btn('pencil', false,true, function(btn){
18290 this.toggleSourceEdit(btn.pressed);
18296 xns: Roo.bootstrap,
18301 xns: Roo.bootstrap,
18306 cog.menu.items.push({
18308 xns: Roo.bootstrap,
18309 html : Clean styles,
18314 editorcore.insertTag(this.tagname);
18323 this.xtype = 'NavSimplebar';
18325 for(var i=0;i< children.length;i++) {
18327 this.buttons.add(this.addxtypeChild(children[i]));
18331 editor.on('editorevent', this.updateToolbar, this);
18333 onBtnClick : function(id)
18335 this.editorcore.relayCmd(id);
18336 this.editorcore.focus();
18340 * Protected method that will not generally be called directly. It triggers
18341 * a toolbar update by reading the markup state of the current selection in the editor.
18343 updateToolbar: function(){
18345 if(!this.editorcore.activated){
18346 this.editor.onFirstFocus(); // is this neeed?
18350 var btns = this.buttons;
18351 var doc = this.editorcore.doc;
18352 btns.get('bold').setActive(doc.queryCommandState('bold'));
18353 btns.get('italic').setActive(doc.queryCommandState('italic'));
18354 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18356 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18357 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18358 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18360 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18361 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18364 var ans = this.editorcore.getAllAncestors();
18365 if (this.formatCombo) {
18368 var store = this.formatCombo.store;
18369 this.formatCombo.setValue("");
18370 for (var i =0; i < ans.length;i++) {
18371 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18373 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18381 // hides menus... - so this cant be on a menu...
18382 Roo.bootstrap.MenuMgr.hideAll();
18384 Roo.bootstrap.MenuMgr.hideAll();
18385 //this.editorsyncValue();
18387 onFirstFocus: function() {
18388 this.buttons.each(function(item){
18392 toggleSourceEdit : function(sourceEditMode){
18395 if(sourceEditMode){
18396 Roo.log("disabling buttons");
18397 this.buttons.each( function(item){
18398 if(item.cmd != 'pencil'){
18404 Roo.log("enabling buttons");
18405 if(this.editorcore.initialized){
18406 this.buttons.each( function(item){
18412 Roo.log("calling toggole on editor");
18413 // tell the editor that it's been pressed..
18414 this.editor.toggleSourceEdit(sourceEditMode);
18424 * @class Roo.bootstrap.Table.AbstractSelectionModel
18425 * @extends Roo.util.Observable
18426 * Abstract base class for grid SelectionModels. It provides the interface that should be
18427 * implemented by descendant classes. This class should not be directly instantiated.
18430 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18431 this.locked = false;
18432 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18436 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18437 /** @ignore Called by the grid automatically. Do not call directly. */
18438 init : function(grid){
18444 * Locks the selections.
18447 this.locked = true;
18451 * Unlocks the selections.
18453 unlock : function(){
18454 this.locked = false;
18458 * Returns true if the selections are locked.
18459 * @return {Boolean}
18461 isLocked : function(){
18462 return this.locked;
18466 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18467 * @class Roo.bootstrap.Table.RowSelectionModel
18468 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18469 * It supports multiple selections and keyboard selection/navigation.
18471 * @param {Object} config
18474 Roo.bootstrap.Table.RowSelectionModel = function(config){
18475 Roo.apply(this, config);
18476 this.selections = new Roo.util.MixedCollection(false, function(o){
18481 this.lastActive = false;
18485 * @event selectionchange
18486 * Fires when the selection changes
18487 * @param {SelectionModel} this
18489 "selectionchange" : true,
18491 * @event afterselectionchange
18492 * Fires after the selection changes (eg. by key press or clicking)
18493 * @param {SelectionModel} this
18495 "afterselectionchange" : true,
18497 * @event beforerowselect
18498 * Fires when a row is selected being selected, return false to cancel.
18499 * @param {SelectionModel} this
18500 * @param {Number} rowIndex The selected index
18501 * @param {Boolean} keepExisting False if other selections will be cleared
18503 "beforerowselect" : true,
18506 * Fires when a row is selected.
18507 * @param {SelectionModel} this
18508 * @param {Number} rowIndex The selected index
18509 * @param {Roo.data.Record} r The record
18511 "rowselect" : true,
18513 * @event rowdeselect
18514 * Fires when a row is deselected.
18515 * @param {SelectionModel} this
18516 * @param {Number} rowIndex The selected index
18518 "rowdeselect" : true
18520 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18521 this.locked = false;
18524 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18526 * @cfg {Boolean} singleSelect
18527 * True to allow selection of only one row at a time (defaults to false)
18529 singleSelect : false,
18532 initEvents : function(){
18534 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18535 this.grid.on("mousedown", this.handleMouseDown, this);
18536 }else{ // allow click to work like normal
18537 this.grid.on("rowclick", this.handleDragableRowClick, this);
18540 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18541 "up" : function(e){
18543 this.selectPrevious(e.shiftKey);
18544 }else if(this.last !== false && this.lastActive !== false){
18545 var last = this.last;
18546 this.selectRange(this.last, this.lastActive-1);
18547 this.grid.getView().focusRow(this.lastActive);
18548 if(last !== false){
18552 this.selectFirstRow();
18554 this.fireEvent("afterselectionchange", this);
18556 "down" : function(e){
18558 this.selectNext(e.shiftKey);
18559 }else if(this.last !== false && this.lastActive !== false){
18560 var last = this.last;
18561 this.selectRange(this.last, this.lastActive+1);
18562 this.grid.getView().focusRow(this.lastActive);
18563 if(last !== false){
18567 this.selectFirstRow();
18569 this.fireEvent("afterselectionchange", this);
18574 var view = this.grid.view;
18575 view.on("refresh", this.onRefresh, this);
18576 view.on("rowupdated", this.onRowUpdated, this);
18577 view.on("rowremoved", this.onRemove, this);
18581 onRefresh : function(){
18582 var ds = this.grid.dataSource, i, v = this.grid.view;
18583 var s = this.selections;
18584 s.each(function(r){
18585 if((i = ds.indexOfId(r.id)) != -1){
18594 onRemove : function(v, index, r){
18595 this.selections.remove(r);
18599 onRowUpdated : function(v, index, r){
18600 if(this.isSelected(r)){
18601 v.onRowSelect(index);
18607 * @param {Array} records The records to select
18608 * @param {Boolean} keepExisting (optional) True to keep existing selections
18610 selectRecords : function(records, keepExisting){
18612 this.clearSelections();
18614 var ds = this.grid.dataSource;
18615 for(var i = 0, len = records.length; i < len; i++){
18616 this.selectRow(ds.indexOf(records[i]), true);
18621 * Gets the number of selected rows.
18624 getCount : function(){
18625 return this.selections.length;
18629 * Selects the first row in the grid.
18631 selectFirstRow : function(){
18636 * Select the last row.
18637 * @param {Boolean} keepExisting (optional) True to keep existing selections
18639 selectLastRow : function(keepExisting){
18640 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18644 * Selects the row immediately following the last selected row.
18645 * @param {Boolean} keepExisting (optional) True to keep existing selections
18647 selectNext : function(keepExisting){
18648 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18649 this.selectRow(this.last+1, keepExisting);
18650 this.grid.getView().focusRow(this.last);
18655 * Selects the row that precedes the last selected row.
18656 * @param {Boolean} keepExisting (optional) True to keep existing selections
18658 selectPrevious : function(keepExisting){
18660 this.selectRow(this.last-1, keepExisting);
18661 this.grid.getView().focusRow(this.last);
18666 * Returns the selected records
18667 * @return {Array} Array of selected records
18669 getSelections : function(){
18670 return [].concat(this.selections.items);
18674 * Returns the first selected record.
18677 getSelected : function(){
18678 return this.selections.itemAt(0);
18683 * Clears all selections.
18685 clearSelections : function(fast){
18686 if(this.locked) return;
18688 var ds = this.grid.dataSource;
18689 var s = this.selections;
18690 s.each(function(r){
18691 this.deselectRow(ds.indexOfId(r.id));
18695 this.selections.clear();
18702 * Selects all rows.
18704 selectAll : function(){
18705 if(this.locked) return;
18706 this.selections.clear();
18707 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18708 this.selectRow(i, true);
18713 * Returns True if there is a selection.
18714 * @return {Boolean}
18716 hasSelection : function(){
18717 return this.selections.length > 0;
18721 * Returns True if the specified row is selected.
18722 * @param {Number/Record} record The record or index of the record to check
18723 * @return {Boolean}
18725 isSelected : function(index){
18726 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18727 return (r && this.selections.key(r.id) ? true : false);
18731 * Returns True if the specified record id is selected.
18732 * @param {String} id The id of record to check
18733 * @return {Boolean}
18735 isIdSelected : function(id){
18736 return (this.selections.key(id) ? true : false);
18740 handleMouseDown : function(e, t){
18741 var view = this.grid.getView(), rowIndex;
18742 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18745 if(e.shiftKey && this.last !== false){
18746 var last = this.last;
18747 this.selectRange(last, rowIndex, e.ctrlKey);
18748 this.last = last; // reset the last
18749 view.focusRow(rowIndex);
18751 var isSelected = this.isSelected(rowIndex);
18752 if(e.button !== 0 && isSelected){
18753 view.focusRow(rowIndex);
18754 }else if(e.ctrlKey && isSelected){
18755 this.deselectRow(rowIndex);
18756 }else if(!isSelected){
18757 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18758 view.focusRow(rowIndex);
18761 this.fireEvent("afterselectionchange", this);
18764 handleDragableRowClick : function(grid, rowIndex, e)
18766 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18767 this.selectRow(rowIndex, false);
18768 grid.view.focusRow(rowIndex);
18769 this.fireEvent("afterselectionchange", this);
18774 * Selects multiple rows.
18775 * @param {Array} rows Array of the indexes of the row to select
18776 * @param {Boolean} keepExisting (optional) True to keep existing selections
18778 selectRows : function(rows, keepExisting){
18780 this.clearSelections();
18782 for(var i = 0, len = rows.length; i < len; i++){
18783 this.selectRow(rows[i], true);
18788 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18789 * @param {Number} startRow The index of the first row in the range
18790 * @param {Number} endRow The index of the last row in the range
18791 * @param {Boolean} keepExisting (optional) True to retain existing selections
18793 selectRange : function(startRow, endRow, keepExisting){
18794 if(this.locked) return;
18796 this.clearSelections();
18798 if(startRow <= endRow){
18799 for(var i = startRow; i <= endRow; i++){
18800 this.selectRow(i, true);
18803 for(var i = startRow; i >= endRow; i--){
18804 this.selectRow(i, true);
18810 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18811 * @param {Number} startRow The index of the first row in the range
18812 * @param {Number} endRow The index of the last row in the range
18814 deselectRange : function(startRow, endRow, preventViewNotify){
18815 if(this.locked) return;
18816 for(var i = startRow; i <= endRow; i++){
18817 this.deselectRow(i, preventViewNotify);
18823 * @param {Number} row The index of the row to select
18824 * @param {Boolean} keepExisting (optional) True to keep existing selections
18826 selectRow : function(index, keepExisting, preventViewNotify){
18827 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18828 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18829 if(!keepExisting || this.singleSelect){
18830 this.clearSelections();
18832 var r = this.grid.dataSource.getAt(index);
18833 this.selections.add(r);
18834 this.last = this.lastActive = index;
18835 if(!preventViewNotify){
18836 this.grid.getView().onRowSelect(index);
18838 this.fireEvent("rowselect", this, index, r);
18839 this.fireEvent("selectionchange", this);
18845 * @param {Number} row The index of the row to deselect
18847 deselectRow : function(index, preventViewNotify){
18848 if(this.locked) return;
18849 if(this.last == index){
18852 if(this.lastActive == index){
18853 this.lastActive = false;
18855 var r = this.grid.dataSource.getAt(index);
18856 this.selections.remove(r);
18857 if(!preventViewNotify){
18858 this.grid.getView().onRowDeselect(index);
18860 this.fireEvent("rowdeselect", this, index);
18861 this.fireEvent("selectionchange", this);
18865 restoreLast : function(){
18867 this.last = this._last;
18872 acceptsNav : function(row, col, cm){
18873 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18877 onEditorKey : function(field, e){
18878 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18883 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18885 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18887 }else if(k == e.ENTER && !e.ctrlKey){
18891 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18893 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18895 }else if(k == e.ESC){
18899 g.startEditing(newCell[0], newCell[1]);
18904 * Ext JS Library 1.1.1
18905 * Copyright(c) 2006-2007, Ext JS, LLC.
18907 * Originally Released Under LGPL - original licence link has changed is not relivant.
18910 * <script type="text/javascript">
18914 * @class Roo.bootstrap.PagingToolbar
18916 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18918 * Create a new PagingToolbar
18919 * @param {Object} config The config object
18921 Roo.bootstrap.PagingToolbar = function(config)
18923 // old args format still supported... - xtype is prefered..
18924 // created from xtype...
18925 var ds = config.dataSource;
18926 this.toolbarItems = [];
18927 if (config.items) {
18928 this.toolbarItems = config.items;
18929 // config.items = [];
18932 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18939 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18943 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18945 * @cfg {Roo.data.Store} dataSource
18946 * The underlying data store providing the paged data
18949 * @cfg {String/HTMLElement/Element} container
18950 * container The id or element that will contain the toolbar
18953 * @cfg {Boolean} displayInfo
18954 * True to display the displayMsg (defaults to false)
18957 * @cfg {Number} pageSize
18958 * The number of records to display per page (defaults to 20)
18962 * @cfg {String} displayMsg
18963 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18965 displayMsg : 'Displaying {0} - {1} of {2}',
18967 * @cfg {String} emptyMsg
18968 * The message to display when no records are found (defaults to "No data to display")
18970 emptyMsg : 'No data to display',
18972 * Customizable piece of the default paging text (defaults to "Page")
18975 beforePageText : "Page",
18977 * Customizable piece of the default paging text (defaults to "of %0")
18980 afterPageText : "of {0}",
18982 * Customizable piece of the default paging text (defaults to "First Page")
18985 firstText : "First Page",
18987 * Customizable piece of the default paging text (defaults to "Previous Page")
18990 prevText : "Previous Page",
18992 * Customizable piece of the default paging text (defaults to "Next Page")
18995 nextText : "Next Page",
18997 * Customizable piece of the default paging text (defaults to "Last Page")
19000 lastText : "Last Page",
19002 * Customizable piece of the default paging text (defaults to "Refresh")
19005 refreshText : "Refresh",
19009 onRender : function(ct, position)
19011 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19012 this.navgroup.parentId = this.id;
19013 this.navgroup.onRender(this.el, null);
19014 // add the buttons to the navgroup
19016 if(this.displayInfo){
19017 Roo.log(this.el.select('ul.navbar-nav',true).first());
19018 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19019 this.displayEl = this.el.select('.x-paging-info', true).first();
19020 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19021 // this.displayEl = navel.el.select('span',true).first();
19027 Roo.each(_this.buttons, function(e){
19028 Roo.factory(e).onRender(_this.el, null);
19032 Roo.each(_this.toolbarItems, function(e) {
19033 _this.navgroup.addItem(e);
19036 this.first = this.navgroup.addItem({
19037 tooltip: this.firstText,
19039 icon : 'fa fa-backward',
19041 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19044 this.prev = this.navgroup.addItem({
19045 tooltip: this.prevText,
19047 icon : 'fa fa-step-backward',
19049 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19051 //this.addSeparator();
19054 var field = this.navgroup.addItem( {
19056 cls : 'x-paging-position',
19058 html : this.beforePageText +
19059 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19060 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19063 this.field = field.el.select('input', true).first();
19064 this.field.on("keydown", this.onPagingKeydown, this);
19065 this.field.on("focus", function(){this.dom.select();});
19068 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19069 //this.field.setHeight(18);
19070 //this.addSeparator();
19071 this.next = this.navgroup.addItem({
19072 tooltip: this.nextText,
19074 html : ' <i class="fa fa-step-forward">',
19076 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19078 this.last = this.navgroup.addItem({
19079 tooltip: this.lastText,
19080 icon : 'fa fa-forward',
19083 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19085 //this.addSeparator();
19086 this.loading = this.navgroup.addItem({
19087 tooltip: this.refreshText,
19088 icon: 'fa fa-refresh',
19090 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19096 updateInfo : function(){
19097 if(this.displayEl){
19098 var count = this.ds.getCount();
19099 var msg = count == 0 ?
19103 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19105 this.displayEl.update(msg);
19110 onLoad : function(ds, r, o){
19111 this.cursor = o.params ? o.params.start : 0;
19112 var d = this.getPageData(),
19116 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19117 this.field.dom.value = ap;
19118 this.first.setDisabled(ap == 1);
19119 this.prev.setDisabled(ap == 1);
19120 this.next.setDisabled(ap == ps);
19121 this.last.setDisabled(ap == ps);
19122 this.loading.enable();
19127 getPageData : function(){
19128 var total = this.ds.getTotalCount();
19131 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19132 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19137 onLoadError : function(){
19138 this.loading.enable();
19142 onPagingKeydown : function(e){
19143 var k = e.getKey();
19144 var d = this.getPageData();
19146 var v = this.field.dom.value, pageNum;
19147 if(!v || isNaN(pageNum = parseInt(v, 10))){
19148 this.field.dom.value = d.activePage;
19151 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19152 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19155 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))
19157 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19158 this.field.dom.value = pageNum;
19159 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19162 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19164 var v = this.field.dom.value, pageNum;
19165 var increment = (e.shiftKey) ? 10 : 1;
19166 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19168 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19169 this.field.dom.value = d.activePage;
19172 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19174 this.field.dom.value = parseInt(v, 10) + increment;
19175 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19176 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19183 beforeLoad : function(){
19185 this.loading.disable();
19190 onClick : function(which){
19197 ds.load({params:{start: 0, limit: this.pageSize}});
19200 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19203 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19206 var total = ds.getTotalCount();
19207 var extra = total % this.pageSize;
19208 var lastStart = extra ? (total - extra) : total-this.pageSize;
19209 ds.load({params:{start: lastStart, limit: this.pageSize}});
19212 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19218 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19219 * @param {Roo.data.Store} store The data store to unbind
19221 unbind : function(ds){
19222 ds.un("beforeload", this.beforeLoad, this);
19223 ds.un("load", this.onLoad, this);
19224 ds.un("loadexception", this.onLoadError, this);
19225 ds.un("remove", this.updateInfo, this);
19226 ds.un("add", this.updateInfo, this);
19227 this.ds = undefined;
19231 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19232 * @param {Roo.data.Store} store The data store to bind
19234 bind : function(ds){
19235 ds.on("beforeload", this.beforeLoad, this);
19236 ds.on("load", this.onLoad, this);
19237 ds.on("loadexception", this.onLoadError, this);
19238 ds.on("remove", this.updateInfo, this);
19239 ds.on("add", this.updateInfo, this);
19250 * @class Roo.bootstrap.MessageBar
19251 * @extends Roo.bootstrap.Component
19252 * Bootstrap MessageBar class
19253 * @cfg {String} html contents of the MessageBar
19254 * @cfg {String} weight (info | success | warning | danger) default info
19255 * @cfg {String} beforeClass insert the bar before the given class
19256 * @cfg {Boolean} closable (true | false) default false
19257 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19260 * Create a new Element
19261 * @param {Object} config The config object
19264 Roo.bootstrap.MessageBar = function(config){
19265 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19268 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19274 beforeClass: 'bootstrap-sticky-wrap',
19276 getAutoCreate : function(){
19280 cls: 'alert alert-dismissable alert-' + this.weight,
19285 html: this.html || ''
19291 cfg.cls += ' alert-messages-fixed';
19305 onRender : function(ct, position)
19307 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19310 var cfg = Roo.apply({}, this.getAutoCreate());
19314 cfg.cls += ' ' + this.cls;
19317 cfg.style = this.style;
19319 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19321 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19324 this.el.select('>button.close').on('click', this.hide, this);
19330 if (!this.rendered) {
19336 this.fireEvent('show', this);
19342 if (!this.rendered) {
19348 this.fireEvent('hide', this);
19351 update : function()
19353 // var e = this.el.dom.firstChild;
19355 // if(this.closable){
19356 // e = e.nextSibling;
19359 // e.data = this.html || '';
19361 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19377 * @class Roo.bootstrap.Graph
19378 * @extends Roo.bootstrap.Component
19379 * Bootstrap Graph class
19383 @cfg {String} graphtype bar | vbar | pie
19384 @cfg {number} g_x coodinator | centre x (pie)
19385 @cfg {number} g_y coodinator | centre y (pie)
19386 @cfg {number} g_r radius (pie)
19387 @cfg {number} g_height height of the chart (respected by all elements in the set)
19388 @cfg {number} g_width width of the chart (respected by all elements in the set)
19389 @cfg {Object} title The title of the chart
19392 -opts (object) options for the chart
19394 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19395 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19397 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.
19398 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19400 o stretch (boolean)
19402 -opts (object) options for the pie
19405 o startAngle (number)
19406 o endAngle (number)
19410 * Create a new Input
19411 * @param {Object} config The config object
19414 Roo.bootstrap.Graph = function(config){
19415 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19421 * The img click event for the img.
19422 * @param {Roo.EventObject} e
19428 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19439 //g_colors: this.colors,
19446 getAutoCreate : function(){
19457 onRender : function(ct,position){
19458 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19459 this.raphael = Raphael(this.el.dom);
19461 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19462 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19463 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19464 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19466 r.text(160, 10, "Single Series Chart").attr(txtattr);
19467 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19468 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19469 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19471 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19472 r.barchart(330, 10, 300, 220, data1);
19473 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19474 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19477 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19478 // r.barchart(30, 30, 560, 250, xdata, {
19479 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19480 // axis : "0 0 1 1",
19481 // axisxlabels : xdata
19482 // //yvalues : cols,
19485 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19487 // this.load(null,xdata,{
19488 // axis : "0 0 1 1",
19489 // axisxlabels : xdata
19494 load : function(graphtype,xdata,opts){
19495 this.raphael.clear();
19497 graphtype = this.graphtype;
19502 var r = this.raphael,
19503 fin = function () {
19504 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19506 fout = function () {
19507 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19509 pfin = function() {
19510 this.sector.stop();
19511 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19514 this.label[0].stop();
19515 this.label[0].attr({ r: 7.5 });
19516 this.label[1].attr({ "font-weight": 800 });
19519 pfout = function() {
19520 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19523 this.label[0].animate({ r: 5 }, 500, "bounce");
19524 this.label[1].attr({ "font-weight": 400 });
19530 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19533 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19536 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19537 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19539 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19546 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19551 setTitle: function(o)
19556 initEvents: function() {
19559 this.el.on('click', this.onClick, this);
19563 onClick : function(e)
19565 Roo.log('img onclick');
19566 this.fireEvent('click', this, e);
19578 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19581 * @class Roo.bootstrap.dash.NumberBox
19582 * @extends Roo.bootstrap.Component
19583 * Bootstrap NumberBox class
19584 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19585 * @cfg {String} headline Box headline
19586 * @cfg {String} content Box content
19587 * @cfg {String} icon Box icon
19588 * @cfg {String} footer Footer text
19589 * @cfg {String} fhref Footer href
19592 * Create a new NumberBox
19593 * @param {Object} config The config object
19597 Roo.bootstrap.dash.NumberBox = function(config){
19598 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19602 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19612 getAutoCreate : function(){
19616 cls : 'small-box bg-' + this.bgcolor,
19624 cls : 'roo-headline',
19625 html : this.headline
19629 cls : 'roo-content',
19630 html : this.content
19644 cls : 'ion ' + this.icon
19653 cls : 'small-box-footer',
19654 href : this.fhref || '#',
19658 cfg.cn.push(footer);
19665 onRender : function(ct,position){
19666 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19673 setHeadline: function (value)
19675 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19678 setFooter: function (value, href)
19680 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19683 this.el.select('a.small-box-footer',true).first().attr('href', href);
19688 setContent: function (value)
19690 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19693 initEvents: function()
19707 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19710 * @class Roo.bootstrap.dash.TabBox
19711 * @extends Roo.bootstrap.Component
19712 * Bootstrap TabBox class
19713 * @cfg {String} title Title of the TabBox
19714 * @cfg {String} icon Icon of the TabBox
19715 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19718 * Create a new TabBox
19719 * @param {Object} config The config object
19723 Roo.bootstrap.dash.TabBox = function(config){
19724 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19729 * When a pane is added
19730 * @param {Roo.bootstrap.dash.TabPane} pane
19737 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19743 getChildContainer : function()
19745 return this.el.select('.tab-content', true).first();
19748 getAutoCreate : function(){
19752 cls: 'pull-left header',
19760 cls: 'fa ' + this.icon
19767 cls: 'nav-tabs-custom',
19771 cls: 'nav nav-tabs pull-right',
19778 cls: 'tab-content no-padding',
19786 initEvents : function()
19788 //Roo.log('add add pane handler');
19789 this.on('addpane', this.onAddPane, this);
19792 * Updates the box title
19793 * @param {String} html to set the title to.
19795 setTitle : function(value)
19797 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19799 onAddPane : function(pane)
19801 //Roo.log('addpane');
19803 // tabs are rendere left to right..
19804 if(!this.showtabs){
19808 var ctr = this.el.select('.nav-tabs', true).first();
19811 var existing = ctr.select('.nav-tab',true);
19812 var qty = existing.getCount();;
19815 var tab = ctr.createChild({
19817 cls : 'nav-tab' + (qty ? '' : ' active'),
19825 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19828 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19830 pane.el.addClass('active');
19835 onTabClick : function(ev,un,ob,pane)
19837 //Roo.log('tab - prev default');
19838 ev.preventDefault();
19841 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19842 pane.tab.addClass('active');
19843 //Roo.log(pane.title);
19844 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19845 // technically we should have a deactivate event.. but maybe add later.
19846 // and it should not de-activate the selected tab...
19848 pane.el.addClass('active');
19849 pane.fireEvent('activate');
19864 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19866 * @class Roo.bootstrap.TabPane
19867 * @extends Roo.bootstrap.Component
19868 * Bootstrap TabPane class
19869 * @cfg {Boolean} active (false | true) Default false
19870 * @cfg {String} title title of panel
19874 * Create a new TabPane
19875 * @param {Object} config The config object
19878 Roo.bootstrap.dash.TabPane = function(config){
19879 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19885 * When a pane is activated
19886 * @param {Roo.bootstrap.dash.TabPane} pane
19893 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19898 // the tabBox that this is attached to.
19901 getAutoCreate : function()
19909 cfg.cls += ' active';
19914 initEvents : function()
19916 //Roo.log('trigger add pane handler');
19917 this.parent().fireEvent('addpane', this)
19921 * Updates the tab title
19922 * @param {String} html to set the title to.
19924 setTitle: function(str)
19930 this.tab.select('a', true).first().dom.innerHTML = str;
19947 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19950 * @class Roo.bootstrap.menu.Menu
19951 * @extends Roo.bootstrap.Component
19952 * Bootstrap Menu class - container for Menu
19953 * @cfg {String} html Text of the menu
19954 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19955 * @cfg {String} icon Font awesome icon
19956 * @cfg {String} pos Menu align to (top | bottom) default bottom
19960 * Create a new Menu
19961 * @param {Object} config The config object
19965 Roo.bootstrap.menu.Menu = function(config){
19966 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19970 * @event beforeshow
19971 * Fires before this menu is displayed
19972 * @param {Roo.bootstrap.menu.Menu} this
19976 * @event beforehide
19977 * Fires before this menu is hidden
19978 * @param {Roo.bootstrap.menu.Menu} this
19983 * Fires after this menu is displayed
19984 * @param {Roo.bootstrap.menu.Menu} this
19989 * Fires after this menu is hidden
19990 * @param {Roo.bootstrap.menu.Menu} this
19995 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19996 * @param {Roo.bootstrap.menu.Menu} this
19997 * @param {Roo.EventObject} e
20004 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20008 weight : 'default',
20013 getChildContainer : function() {
20014 if(this.isSubMenu){
20018 return this.el.select('ul.dropdown-menu', true).first();
20021 getAutoCreate : function()
20026 cls : 'roo-menu-text',
20034 cls : 'fa ' + this.icon
20045 cls : 'dropdown-button btn btn-' + this.weight,
20050 cls : 'dropdown-toggle btn btn-' + this.weight,
20060 cls : 'dropdown-menu'
20066 if(this.pos == 'top'){
20067 cfg.cls += ' dropup';
20070 if(this.isSubMenu){
20073 cls : 'dropdown-menu'
20080 onRender : function(ct, position)
20082 this.isSubMenu = ct.hasClass('dropdown-submenu');
20084 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20087 initEvents : function()
20089 if(this.isSubMenu){
20093 this.hidden = true;
20095 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20096 this.triggerEl.on('click', this.onTriggerPress, this);
20098 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20099 this.buttonEl.on('click', this.onClick, this);
20105 if(this.isSubMenu){
20109 return this.el.select('ul.dropdown-menu', true).first();
20112 onClick : function(e)
20114 this.fireEvent("click", this, e);
20117 onTriggerPress : function(e)
20119 if (this.isVisible()) {
20126 isVisible : function(){
20127 return !this.hidden;
20132 this.fireEvent("beforeshow", this);
20134 this.hidden = false;
20135 this.el.addClass('open');
20137 Roo.get(document).on("mouseup", this.onMouseUp, this);
20139 this.fireEvent("show", this);
20146 this.fireEvent("beforehide", this);
20148 this.hidden = true;
20149 this.el.removeClass('open');
20151 Roo.get(document).un("mouseup", this.onMouseUp);
20153 this.fireEvent("hide", this);
20156 onMouseUp : function()
20170 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20173 * @class Roo.bootstrap.menu.Item
20174 * @extends Roo.bootstrap.Component
20175 * Bootstrap MenuItem class
20176 * @cfg {Boolean} submenu (true | false) default false
20177 * @cfg {String} html text of the item
20178 * @cfg {String} href the link
20179 * @cfg {Boolean} disable (true | false) default false
20180 * @cfg {Boolean} preventDefault (true | false) default true
20181 * @cfg {String} icon Font awesome icon
20182 * @cfg {String} pos Submenu align to (left | right) default right
20186 * Create a new Item
20187 * @param {Object} config The config object
20191 Roo.bootstrap.menu.Item = function(config){
20192 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20196 * Fires when the mouse is hovering over this menu
20197 * @param {Roo.bootstrap.menu.Item} this
20198 * @param {Roo.EventObject} e
20203 * Fires when the mouse exits this menu
20204 * @param {Roo.bootstrap.menu.Item} this
20205 * @param {Roo.EventObject} e
20211 * The raw click event for the entire grid.
20212 * @param {Roo.EventObject} e
20218 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20223 preventDefault: true,
20228 getAutoCreate : function()
20233 cls : 'roo-menu-item-text',
20241 cls : 'fa ' + this.icon
20250 href : this.href || '#',
20257 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20261 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20263 if(this.pos == 'left'){
20264 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20271 initEvents : function()
20273 this.el.on('mouseover', this.onMouseOver, this);
20274 this.el.on('mouseout', this.onMouseOut, this);
20276 this.el.select('a', true).first().on('click', this.onClick, this);
20280 onClick : function(e)
20282 if(this.preventDefault){
20283 e.preventDefault();
20286 this.fireEvent("click", this, e);
20289 onMouseOver : function(e)
20291 if(this.submenu && this.pos == 'left'){
20292 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20295 this.fireEvent("mouseover", this, e);
20298 onMouseOut : function(e)
20300 this.fireEvent("mouseout", this, e);
20312 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20315 * @class Roo.bootstrap.menu.Separator
20316 * @extends Roo.bootstrap.Component
20317 * Bootstrap Separator class
20320 * Create a new Separator
20321 * @param {Object} config The config object
20325 Roo.bootstrap.menu.Separator = function(config){
20326 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20329 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20331 getAutoCreate : function(){