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...
44 * Initialize Events for the element
46 initEvents : function()
48 Roo.log("------------ component init events ----------");
49 Roo.log(this.tooltip);
51 this.getTooltipEl().attr('tooltip', this.tooltip);
59 can_build_overlaid : true,
66 // returns the parent component..
67 return Roo.ComponentMgr.get(this.parentId)
73 onRender : function(ct, position)
75 // Roo.log("Call onRender: " + this.xtype);
77 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
80 if (this.el.attr('xtype')) {
81 this.el.attr('xtypex', this.el.attr('xtype'));
82 this.el.dom.removeAttribute('xtype');
92 var cfg = Roo.apply({}, this.getAutoCreate());
95 // fill in the extra attributes
96 if (this.xattr && typeof(this.xattr) =='object') {
97 for (var i in this.xattr) {
98 cfg[i] = this.xattr[i];
103 cfg.dataId = this.dataId;
107 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
110 if (this.style) { // fixme needs to support more complex style data.
111 cfg.style = this.style;
115 cfg.name = this.name;
119 this.el = ct.createChild(cfg, position);
121 if(this.tabIndex !== undefined){
122 this.el.dom.setAttribute('tabIndex', this.tabIndex);
129 * Fetch the element to add children to
130 * @return {Roo.Element} defaults to this.el
132 getChildContainer : function()
137 * Fetch the element to display the tooltip on.
138 * @return {Roo.Element} defaults to this.el
140 getTooltipEl : function()
145 addxtype : function(tree,cntr)
149 cn = Roo.factory(tree);
151 cn.parentType = this.xtype; //??
152 cn.parentId = this.id;
154 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
156 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
158 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
160 var build_from_html = Roo.XComponent.build_from_html;
162 var is_body = (tree.xtype == 'Body') ;
164 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
166 var self_cntr_el = Roo.get(this[cntr](false));
168 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
169 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
170 return this.addxtypeChild(tree,cntr);
173 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
176 return this.addxtypeChild(Roo.apply({}, tree),cntr);
179 Roo.log('skipping render');
187 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
193 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
197 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
202 addxtypeChild : function (tree, cntr)
204 Roo.log('addxtypeChild:' + cntr);
206 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
209 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
210 (typeof(tree['flexy:foreach']) != 'undefined');
214 skip_children = false;
215 // render the element if it's not BODY.
216 if (tree.xtype != 'Body') {
218 cn = Roo.factory(tree);
220 cn.parentType = this.xtype; //??
221 cn.parentId = this.id;
223 var build_from_html = Roo.XComponent.build_from_html;
226 // does the container contain child eleemnts with 'xtype' attributes.
227 // that match this xtype..
228 // note - when we render we create these as well..
229 // so we should check to see if body has xtype set.
230 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
232 var self_cntr_el = Roo.get(this[cntr](false));
233 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
236 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
237 // and are not displayed -this causes this to use up the wrong element when matching.
238 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
241 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
242 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
248 //echild.dom.removeAttribute('xtype');
250 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
251 Roo.log(self_cntr_el);
259 // if object has flexy:if - then it may or may not be rendered.
260 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
261 // skip a flexy if element.
262 Roo.log('skipping render');
265 Roo.log('skipping all children');
266 skip_children = true;
271 // actually if flexy:foreach is found, we really want to create
272 // multiple copies here...
274 //Roo.log(this[cntr]());
275 cn.render(this[cntr](true));
277 // then add the element..
285 if (typeof (tree.menu) != 'undefined') {
286 tree.menu.parentType = cn.xtype;
287 tree.menu.triggerEl = cn.el;
288 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
292 if (!tree.items || !tree.items.length) {
296 var items = tree.items;
299 //Roo.log(items.length);
301 if (!skip_children) {
302 for(var i =0;i < items.length;i++) {
303 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
325 * @class Roo.bootstrap.Body
326 * @extends Roo.bootstrap.Component
327 * Bootstrap Body class
331 * @param {Object} config The config object
334 Roo.bootstrap.Body = function(config){
335 Roo.bootstrap.Body.superclass.constructor.call(this, config);
336 this.el = Roo.get(document.body);
337 if (this.cls && this.cls.length) {
338 Roo.get(document.body).addClass(this.cls);
342 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
347 onRender : function(ct, position)
349 /* Roo.log("Roo.bootstrap.Body - onRender");
350 if (this.cls && this.cls.length) {
351 Roo.get(document.body).addClass(this.cls);
371 * @class Roo.bootstrap.ButtonGroup
372 * @extends Roo.bootstrap.Component
373 * Bootstrap ButtonGroup class
374 * @cfg {String} size lg | sm | xs (default empty normal)
375 * @cfg {String} align vertical | justified (default none)
376 * @cfg {String} direction up | down (default down)
377 * @cfg {Boolean} toolbar false | true
378 * @cfg {Boolean} btn true | false
383 * @param {Object} config The config object
386 Roo.bootstrap.ButtonGroup = function(config){
387 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
390 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
398 getAutoCreate : function(){
404 cfg.html = this.html || cfg.html;
415 if (['vertical','justified'].indexOf(this.align)!==-1) {
416 cfg.cls = 'btn-group-' + this.align;
418 if (this.align == 'justified') {
419 console.log(this.items);
423 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
424 cfg.cls += ' btn-group-' + this.size;
427 if (this.direction == 'up') {
428 cfg.cls += ' dropup' ;
444 * @class Roo.bootstrap.Button
445 * @extends Roo.bootstrap.Component
446 * Bootstrap Button class
447 * @cfg {String} html The button content
448 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
449 * @cfg {String} size empty | lg | sm | xs
450 * @cfg {String} tag empty | a | input | submit
451 * @cfg {String} href empty or href
452 * @cfg {Boolean} disabled false | true
453 * @cfg {Boolean} isClose false | true
454 * @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
455 * @cfg {String} badge text for badge
456 * @cfg {String} theme default (or empty) | glow
457 * @cfg {Boolean} inverse false | true
458 * @cfg {Boolean} toggle false | true
459 * @cfg {String} ontext text for on toggle state
460 * @cfg {String} offtext text for off toggle state
461 * @cfg {Boolean} defaulton true | false
462 * @cfg {Boolean} preventDefault (true | false) default true
463 * @cfg {Boolean} removeClass true | false remove the standard class..
464 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
467 * Create a new button
468 * @param {Object} config The config object
472 Roo.bootstrap.Button = function(config){
473 Roo.bootstrap.Button.superclass.constructor.call(this, config);
478 * When a butotn is pressed
479 * @param {Roo.EventObject} e
484 * After the button has been toggles
485 * @param {Roo.EventObject} e
486 * @param {boolean} pressed (also available as button.pressed)
492 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
510 preventDefault: true,
519 getAutoCreate : function(){
527 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
528 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
533 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
535 if (this.toggle == true) {
538 cls: 'slider-frame roo-button',
543 'data-off-text':'OFF',
544 cls: 'slider-button',
550 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
551 cfg.cls += ' '+this.weight;
560 cfg["aria-hidden"] = true;
562 cfg.html = "×";
568 if (this.theme==='default') {
569 cfg.cls = 'btn roo-button';
571 //if (this.parentType != 'Navbar') {
572 this.weight = this.weight.length ? this.weight : 'default';
574 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
576 cfg.cls += ' btn-' + this.weight;
578 } else if (this.theme==='glow') {
581 cfg.cls = 'btn-glow roo-button';
583 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
585 cfg.cls += ' ' + this.weight;
591 this.cls += ' inverse';
596 cfg.cls += ' active';
600 cfg.disabled = 'disabled';
604 Roo.log('changing to ul' );
606 this.glyphicon = 'caret';
609 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
611 //gsRoo.log(this.parentType);
612 if (this.parentType === 'Navbar' && !this.parent().bar) {
613 Roo.log('changing to li?');
622 href : this.href || '#'
625 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
626 cfg.cls += ' dropdown';
633 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
635 if (this.glyphicon) {
636 cfg.html = ' ' + cfg.html;
641 cls: 'glyphicon glyphicon-' + this.glyphicon
651 // cfg.cls='btn roo-button';
655 var value = cfg.html;
660 cls: 'glyphicon glyphicon-' + this.glyphicon,
679 cfg.cls += ' dropdown';
680 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
683 if (cfg.tag !== 'a' && this.href !== '') {
684 throw "Tag must be a to set href.";
685 } else if (this.href.length > 0) {
686 cfg.href = this.href;
689 if(this.removeClass){
694 cfg.target = this.target;
699 initEvents: function() {
700 // Roo.log('init events?');
701 // Roo.log(this.el.dom);
704 if (typeof (this.menu) != 'undefined') {
705 this.menu.parentType = this.xtype;
706 this.menu.triggerEl = this.el;
707 this.addxtype(Roo.apply({}, this.menu));
711 if (this.el.hasClass('roo-button')) {
712 this.el.on('click', this.onClick, this);
714 this.el.select('.roo-button').on('click', this.onClick, this);
717 if(this.removeClass){
718 this.el.on('click', this.onClick, this);
721 this.el.enableDisplayMode();
724 onClick : function(e)
730 Roo.log('button on click ');
731 if(this.preventDefault){
734 if (this.pressed === true || this.pressed === false) {
735 this.pressed = !this.pressed;
736 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
737 this.fireEvent('toggle', this, e, this.pressed);
741 this.fireEvent('click', this, e);
745 * Enables this button
749 this.disabled = false;
750 this.el.removeClass('disabled');
754 * Disable this button
758 this.disabled = true;
759 this.el.addClass('disabled');
762 * sets the active state on/off,
763 * @param {Boolean} state (optional) Force a particular state
765 setActive : function(v) {
767 this.el[v ? 'addClass' : 'removeClass']('active');
770 * toggles the current active state
772 toggleActive : function()
774 var active = this.el.hasClass('active');
775 this.setActive(!active);
779 setText : function(str)
781 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
785 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
808 * @class Roo.bootstrap.Column
809 * @extends Roo.bootstrap.Component
810 * Bootstrap Column class
811 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
812 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
813 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
814 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
815 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
816 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
817 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
818 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
821 * @cfg {Boolean} hidden (true|false) hide the element
822 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
823 * @cfg {String} fa (ban|check|...) font awesome icon
824 * @cfg {Number} fasize (1|2|....) font awsome size
826 * @cfg {String} icon (info-sign|check|...) glyphicon name
828 * @cfg {String} html content of column.
831 * Create a new Column
832 * @param {Object} config The config object
835 Roo.bootstrap.Column = function(config){
836 Roo.bootstrap.Column.superclass.constructor.call(this, config);
839 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
857 getAutoCreate : function(){
858 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
866 ['xs','sm','md','lg'].map(function(size){
867 //Roo.log( size + ':' + settings[size]);
869 if (settings[size+'off'] !== false) {
870 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
873 if (settings[size] === false) {
876 Roo.log(settings[size]);
877 if (!settings[size]) { // 0 = hidden
878 cfg.cls += ' hidden-' + size;
881 cfg.cls += ' col-' + size + '-' + settings[size];
886 cfg.cls += ' hidden';
889 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
890 cfg.cls +=' alert alert-' + this.alert;
894 if (this.html.length) {
895 cfg.html = this.html;
899 if (this.fasize > 1) {
900 fasize = ' fa-' + this.fasize + 'x';
902 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
907 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
926 * @class Roo.bootstrap.Container
927 * @extends Roo.bootstrap.Component
928 * Bootstrap Container class
929 * @cfg {Boolean} jumbotron is it a jumbotron element
930 * @cfg {String} html content of element
931 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
932 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
933 * @cfg {String} header content of header (for panel)
934 * @cfg {String} footer content of footer (for panel)
935 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
936 * @cfg {String} tag (header|aside|section) type of HTML tag.
937 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
938 * @cfg {String} fa (ban|check|...) font awesome icon
939 * @cfg {String} icon (info-sign|check|...) glyphicon name
940 * @cfg {Boolean} hidden (true|false) hide the element
944 * Create a new Container
945 * @param {Object} config The config object
948 Roo.bootstrap.Container = function(config){
949 Roo.bootstrap.Container.superclass.constructor.call(this, config);
952 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
966 getChildContainer : function() {
972 if (this.panel.length) {
973 return this.el.select('.panel-body',true).first();
980 getAutoCreate : function(){
983 tag : this.tag || 'div',
987 if (this.jumbotron) {
988 cfg.cls = 'jumbotron';
993 // - this is applied by the parent..
995 // cfg.cls = this.cls + '';
998 if (this.sticky.length) {
1000 var bd = Roo.get(document.body);
1001 if (!bd.hasClass('bootstrap-sticky')) {
1002 bd.addClass('bootstrap-sticky');
1003 Roo.select('html',true).setStyle('height', '100%');
1006 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1010 if (this.well.length) {
1011 switch (this.well) {
1014 cfg.cls +=' well well-' +this.well;
1023 cfg.cls += ' hidden';
1027 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1028 cfg.cls +=' alert alert-' + this.alert;
1033 if (this.panel.length) {
1034 cfg.cls += ' panel panel-' + this.panel;
1036 if (this.header.length) {
1039 cls : 'panel-heading',
1042 cls : 'panel-title',
1055 if (this.footer.length) {
1057 cls : 'panel-footer',
1066 body.html = this.html || cfg.html;
1067 // prefix with the icons..
1069 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1072 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1077 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1078 cfg.cls = 'container';
1084 titleEl : function()
1086 if(!this.el || !this.panel.length || !this.header.length){
1090 return this.el.select('.panel-title',true).first();
1093 setTitle : function(v)
1095 var titleEl = this.titleEl();
1101 titleEl.dom.innerHTML = v;
1104 getTitle : function()
1107 var titleEl = this.titleEl();
1113 return titleEl.dom.innerHTML;
1127 * @class Roo.bootstrap.Img
1128 * @extends Roo.bootstrap.Component
1129 * Bootstrap Img class
1130 * @cfg {Boolean} imgResponsive false | true
1131 * @cfg {String} border rounded | circle | thumbnail
1132 * @cfg {String} src image source
1133 * @cfg {String} alt image alternative text
1134 * @cfg {String} href a tag href
1135 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1138 * Create a new Input
1139 * @param {Object} config The config object
1142 Roo.bootstrap.Img = function(config){
1143 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1149 * The img click event for the img.
1150 * @param {Roo.EventObject} e
1156 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1158 imgResponsive: true,
1164 getAutoCreate : function(){
1168 cls: (this.imgResponsive) ? 'img-responsive' : '',
1172 cfg.html = this.html || cfg.html;
1174 cfg.src = this.src || cfg.src;
1176 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1177 cfg.cls += ' img-' + this.border;
1194 a.target = this.target;
1200 return (this.href) ? a : cfg;
1203 initEvents: function() {
1206 this.el.on('click', this.onClick, this);
1210 onClick : function(e)
1212 Roo.log('img onclick');
1213 this.fireEvent('click', this, e);
1227 * @class Roo.bootstrap.Link
1228 * @extends Roo.bootstrap.Component
1229 * Bootstrap Link Class
1230 * @cfg {String} alt image alternative text
1231 * @cfg {String} href a tag href
1232 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1233 * @cfg {String} html the content of the link.
1234 * @cfg {String} anchor name for the anchor link
1236 * @cfg {Boolean} preventDefault (true | false) default false
1240 * Create a new Input
1241 * @param {Object} config The config object
1244 Roo.bootstrap.Link = function(config){
1245 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1251 * The img click event for the img.
1252 * @param {Roo.EventObject} e
1258 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1262 preventDefault: false,
1266 getAutoCreate : function()
1272 // anchor's do not require html/href...
1273 if (this.anchor === false) {
1274 cfg.html = this.html || 'html-missing';
1275 cfg.href = this.href || '#';
1277 cfg.name = this.anchor;
1278 if (this.html !== false) {
1279 cfg.html = this.html;
1281 if (this.href !== false) {
1282 cfg.href = this.href;
1286 if(this.alt !== false){
1291 if(this.target !== false) {
1292 cfg.target = this.target;
1298 initEvents: function() {
1300 if(!this.href || this.preventDefault){
1301 this.el.on('click', this.onClick, this);
1305 onClick : function(e)
1307 if(this.preventDefault){
1310 //Roo.log('img onclick');
1311 this.fireEvent('click', this, e);
1324 * @class Roo.bootstrap.Header
1325 * @extends Roo.bootstrap.Component
1326 * Bootstrap Header class
1327 * @cfg {String} html content of header
1328 * @cfg {Number} level (1|2|3|4|5|6) default 1
1331 * Create a new Header
1332 * @param {Object} config The config object
1336 Roo.bootstrap.Header = function(config){
1337 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1340 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1348 getAutoCreate : function(){
1351 tag: 'h' + (1 *this.level),
1352 html: this.html || 'fill in html'
1364 * Ext JS Library 1.1.1
1365 * Copyright(c) 2006-2007, Ext JS, LLC.
1367 * Originally Released Under LGPL - original licence link has changed is not relivant.
1370 * <script type="text/javascript">
1374 * @class Roo.bootstrap.MenuMgr
1375 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1378 Roo.bootstrap.MenuMgr = function(){
1379 var menus, active, groups = {}, attached = false, lastShow = new Date();
1381 // private - called when first menu is created
1384 active = new Roo.util.MixedCollection();
1385 Roo.get(document).addKeyListener(27, function(){
1386 if(active.length > 0){
1394 if(active && active.length > 0){
1395 var c = active.clone();
1405 if(active.length < 1){
1406 Roo.get(document).un("mouseup", onMouseDown);
1414 var last = active.last();
1415 lastShow = new Date();
1418 Roo.get(document).on("mouseup", onMouseDown);
1423 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1424 m.parentMenu.activeChild = m;
1425 }else if(last && last.isVisible()){
1426 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1431 function onBeforeHide(m){
1433 m.activeChild.hide();
1435 if(m.autoHideTimer){
1436 clearTimeout(m.autoHideTimer);
1437 delete m.autoHideTimer;
1442 function onBeforeShow(m){
1443 var pm = m.parentMenu;
1444 if(!pm && !m.allowOtherMenus){
1446 }else if(pm && pm.activeChild && active != m){
1447 pm.activeChild.hide();
1452 function onMouseDown(e){
1453 Roo.log("on MouseDown");
1454 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1462 function onBeforeCheck(mi, state){
1464 var g = groups[mi.group];
1465 for(var i = 0, l = g.length; i < l; i++){
1467 g[i].setChecked(false);
1476 * Hides all menus that are currently visible
1478 hideAll : function(){
1483 register : function(menu){
1487 menus[menu.id] = menu;
1488 menu.on("beforehide", onBeforeHide);
1489 menu.on("hide", onHide);
1490 menu.on("beforeshow", onBeforeShow);
1491 menu.on("show", onShow);
1493 if(g && menu.events["checkchange"]){
1497 groups[g].push(menu);
1498 menu.on("checkchange", onCheck);
1503 * Returns a {@link Roo.menu.Menu} object
1504 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1505 * be used to generate and return a new Menu instance.
1507 get : function(menu){
1508 if(typeof menu == "string"){ // menu id
1510 }else if(menu.events){ // menu instance
1513 /*else if(typeof menu.length == 'number'){ // array of menu items?
1514 return new Roo.bootstrap.Menu({items:menu});
1515 }else{ // otherwise, must be a config
1516 return new Roo.bootstrap.Menu(menu);
1523 unregister : function(menu){
1524 delete menus[menu.id];
1525 menu.un("beforehide", onBeforeHide);
1526 menu.un("hide", onHide);
1527 menu.un("beforeshow", onBeforeShow);
1528 menu.un("show", onShow);
1530 if(g && menu.events["checkchange"]){
1531 groups[g].remove(menu);
1532 menu.un("checkchange", onCheck);
1537 registerCheckable : function(menuItem){
1538 var g = menuItem.group;
1543 groups[g].push(menuItem);
1544 menuItem.on("beforecheckchange", onBeforeCheck);
1549 unregisterCheckable : function(menuItem){
1550 var g = menuItem.group;
1552 groups[g].remove(menuItem);
1553 menuItem.un("beforecheckchange", onBeforeCheck);
1565 * @class Roo.bootstrap.Menu
1566 * @extends Roo.bootstrap.Component
1567 * Bootstrap Menu class - container for MenuItems
1568 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1572 * @param {Object} config The config object
1576 Roo.bootstrap.Menu = function(config){
1577 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1578 if (this.registerMenu) {
1579 Roo.bootstrap.MenuMgr.register(this);
1584 * Fires before this menu is displayed
1585 * @param {Roo.menu.Menu} this
1590 * Fires before this menu is hidden
1591 * @param {Roo.menu.Menu} this
1596 * Fires after this menu is displayed
1597 * @param {Roo.menu.Menu} this
1602 * Fires after this menu is hidden
1603 * @param {Roo.menu.Menu} this
1608 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1609 * @param {Roo.menu.Menu} this
1610 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1611 * @param {Roo.EventObject} e
1616 * Fires when the mouse is hovering over this menu
1617 * @param {Roo.menu.Menu} this
1618 * @param {Roo.EventObject} e
1619 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1624 * Fires when the mouse exits this menu
1625 * @param {Roo.menu.Menu} this
1626 * @param {Roo.EventObject} e
1627 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1632 * Fires when a menu item contained in this menu is clicked
1633 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1634 * @param {Roo.EventObject} e
1638 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1641 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1645 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1648 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1650 registerMenu : true,
1652 menuItems :false, // stores the menu items..
1658 getChildContainer : function() {
1662 getAutoCreate : function(){
1664 //if (['right'].indexOf(this.align)!==-1) {
1665 // cfg.cn[1].cls += ' pull-right'
1671 cls : 'dropdown-menu' ,
1672 style : 'z-index:1000'
1676 if (this.type === 'submenu') {
1677 cfg.cls = 'submenu active';
1679 if (this.type === 'treeview') {
1680 cfg.cls = 'treeview-menu';
1685 initEvents : function() {
1687 // Roo.log("ADD event");
1688 // Roo.log(this.triggerEl.dom);
1689 this.triggerEl.on('click', this.onTriggerPress, this);
1690 this.triggerEl.addClass('dropdown-toggle');
1691 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1693 this.el.on("mouseover", this.onMouseOver, this);
1694 this.el.on("mouseout", this.onMouseOut, this);
1698 findTargetItem : function(e){
1699 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1703 //Roo.log(t); Roo.log(t.id);
1705 //Roo.log(this.menuitems);
1706 return this.menuitems.get(t.id);
1708 //return this.items.get(t.menuItemId);
1713 onClick : function(e){
1714 Roo.log("menu.onClick");
1715 var t = this.findTargetItem(e);
1716 if(!t || t.isContainer){
1721 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1722 if(t == this.activeItem && t.shouldDeactivate(e)){
1723 this.activeItem.deactivate();
1724 delete this.activeItem;
1728 this.setActiveItem(t, true);
1736 Roo.log('pass click event');
1740 this.fireEvent("click", this, t, e);
1744 onMouseOver : function(e){
1745 var t = this.findTargetItem(e);
1748 // if(t.canActivate && !t.disabled){
1749 // this.setActiveItem(t, true);
1753 this.fireEvent("mouseover", this, e, t);
1755 isVisible : function(){
1756 return !this.hidden;
1758 onMouseOut : function(e){
1759 var t = this.findTargetItem(e);
1762 // if(t == this.activeItem && t.shouldDeactivate(e)){
1763 // this.activeItem.deactivate();
1764 // delete this.activeItem;
1767 this.fireEvent("mouseout", this, e, t);
1772 * Displays this menu relative to another element
1773 * @param {String/HTMLElement/Roo.Element} element The element to align to
1774 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1775 * the element (defaults to this.defaultAlign)
1776 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1778 show : function(el, pos, parentMenu){
1779 this.parentMenu = parentMenu;
1783 this.fireEvent("beforeshow", this);
1784 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1787 * Displays this menu at a specific xy position
1788 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1789 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1791 showAt : function(xy, parentMenu, /* private: */_e){
1792 this.parentMenu = parentMenu;
1797 this.fireEvent("beforeshow", this);
1799 //xy = this.el.adjustForConstraints(xy);
1801 //this.el.setXY(xy);
1803 this.hideMenuItems();
1804 this.hidden = false;
1805 this.triggerEl.addClass('open');
1807 this.fireEvent("show", this);
1813 this.doFocus.defer(50, this);
1817 doFocus : function(){
1819 this.focusEl.focus();
1824 * Hides this menu and optionally all parent menus
1825 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1827 hide : function(deep){
1829 this.hideMenuItems();
1830 if(this.el && this.isVisible()){
1831 this.fireEvent("beforehide", this);
1832 if(this.activeItem){
1833 this.activeItem.deactivate();
1834 this.activeItem = null;
1836 this.triggerEl.removeClass('open');;
1838 this.fireEvent("hide", this);
1840 if(deep === true && this.parentMenu){
1841 this.parentMenu.hide(true);
1845 onTriggerPress : function(e)
1848 Roo.log('trigger press');
1849 //Roo.log(e.getTarget());
1850 // Roo.log(this.triggerEl.dom);
1851 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1854 if (this.isVisible()) {
1858 this.show(this.triggerEl, false, false);
1867 hideMenuItems : function()
1869 //$(backdrop).remove()
1870 Roo.select('.open',true).each(function(aa) {
1872 aa.removeClass('open');
1873 //var parent = getParent($(this))
1874 //var relatedTarget = { relatedTarget: this }
1876 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1877 //if (e.isDefaultPrevented()) return
1878 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1881 addxtypeChild : function (tree, cntr) {
1882 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1884 this.menuitems.add(comp);
1905 * @class Roo.bootstrap.MenuItem
1906 * @extends Roo.bootstrap.Component
1907 * Bootstrap MenuItem class
1908 * @cfg {String} html the menu label
1909 * @cfg {String} href the link
1910 * @cfg {Boolean} preventDefault (true | false) default true
1911 * @cfg {Boolean} isContainer (true | false) default false
1915 * Create a new MenuItem
1916 * @param {Object} config The config object
1920 Roo.bootstrap.MenuItem = function(config){
1921 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1926 * The raw click event for the entire grid.
1927 * @param {Roo.EventObject} e
1933 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1937 preventDefault: true,
1938 isContainer : false,
1940 getAutoCreate : function(){
1942 if(this.isContainer){
1945 cls: 'dropdown-menu-item'
1951 cls: 'dropdown-menu-item',
1960 if (this.parent().type == 'treeview') {
1961 cfg.cls = 'treeview-menu';
1964 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1965 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1969 initEvents: function() {
1971 //this.el.select('a').on('click', this.onClick, this);
1974 onClick : function(e)
1976 Roo.log('item on click ');
1977 //if(this.preventDefault){
1978 // e.preventDefault();
1980 //this.parent().hideMenuItems();
1982 this.fireEvent('click', this, e);
2001 * @class Roo.bootstrap.MenuSeparator
2002 * @extends Roo.bootstrap.Component
2003 * Bootstrap MenuSeparator class
2006 * Create a new MenuItem
2007 * @param {Object} config The config object
2011 Roo.bootstrap.MenuSeparator = function(config){
2012 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2015 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2017 getAutoCreate : function(){
2032 <div class="modal fade">
2033 <div class="modal-dialog">
2034 <div class="modal-content">
2035 <div class="modal-header">
2036 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
2037 <h4 class="modal-title">Modal title</h4>
2039 <div class="modal-body">
2040 <p>One fine body…</p>
2042 <div class="modal-footer">
2043 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2044 <button type="button" class="btn btn-primary">Save changes</button>
2046 </div><!-- /.modal-content -->
2047 </div><!-- /.modal-dialog -->
2048 </div><!-- /.modal -->
2058 * @class Roo.bootstrap.Modal
2059 * @extends Roo.bootstrap.Component
2060 * Bootstrap Modal class
2061 * @cfg {String} title Title of dialog
2062 * @cfg {Boolean} specificTitle (true|false) default false
2063 * @cfg {Array} buttons Array of buttons or standard button set..
2064 * @cfg {String} buttonPosition (left|right|center) default right
2065 * @cfg {Boolean} animate (true | false) default true
2068 * Create a new Modal Dialog
2069 * @param {Object} config The config object
2072 Roo.bootstrap.Modal = function(config){
2073 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2078 * The raw btnclick event for the button
2079 * @param {Roo.EventObject} e
2083 this.buttons = this.buttons || [];
2086 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2088 title : 'test dialog',
2095 specificTitle: false,
2097 buttonPosition: 'right',
2101 onRender : function(ct, position)
2103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2106 var cfg = Roo.apply({}, this.getAutoCreate());
2109 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2111 //if (!cfg.name.length) {
2115 cfg.cls += ' ' + this.cls;
2118 cfg.style = this.style;
2120 this.el = Roo.get(document.body).createChild(cfg, position);
2122 //var type = this.el.dom.type;
2124 if(this.tabIndex !== undefined){
2125 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2130 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2131 this.maskEl.enableDisplayMode("block");
2133 //this.el.addClass("x-dlg-modal");
2135 if (this.buttons.length) {
2136 Roo.each(this.buttons, function(bb) {
2137 b = Roo.apply({}, bb);
2138 b.xns = b.xns || Roo.bootstrap;
2139 b.xtype = b.xtype || 'Button';
2140 if (typeof(b.listeners) == 'undefined') {
2141 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2144 var btn = Roo.factory(b);
2146 btn.onRender(this.el.select('.modal-footer div').first());
2150 // render the children.
2153 if(typeof(this.items) != 'undefined'){
2154 var items = this.items;
2157 for(var i =0;i < items.length;i++) {
2158 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2162 this.items = nitems;
2164 this.body = this.el.select('.modal-body',true).first();
2165 this.close = this.el.select('.modal-header .close', true).first();
2166 this.footer = this.el.select('.modal-footer',true).first();
2168 //this.el.addClass([this.fieldClass, this.cls]);
2171 getAutoCreate : function(){
2176 html : this.html || ''
2181 cls : 'modal-title',
2185 if(this.specificTitle){
2191 style : 'display: none',
2194 cls: "modal-dialog",
2197 cls : "modal-content",
2200 cls : 'modal-header',
2212 cls : 'modal-footer',
2216 cls: 'btn-' + this.buttonPosition
2233 modal.cls += ' fade';
2239 getChildContainer : function() {
2241 return this.el.select('.modal-body',true).first();
2244 getButtonContainer : function() {
2245 return this.el.select('.modal-footer div',true).first();
2248 initEvents : function()
2250 this.el.select('.modal-header .close').on('click', this.hide, this);
2252 // this.addxtype(this);
2256 if (!this.rendered) {
2260 this.el.setStyle('display', 'block');
2264 (function(){ _this.el.addClass('in'); }).defer(50);
2266 this.el.addClass('in');
2269 Roo.get(document.body).addClass("x-body-masked");
2270 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2272 this.el.setStyle('zIndex', '10001');
2273 this.fireEvent('show', this);
2280 Roo.get(document.body).removeClass("x-body-masked");
2281 this.el.removeClass('in');
2285 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2287 this.el.setStyle('display', 'none');
2290 this.fireEvent('hide', this);
2293 addButton : function(str, cb)
2297 var b = Roo.apply({}, { html : str } );
2298 b.xns = b.xns || Roo.bootstrap;
2299 b.xtype = b.xtype || 'Button';
2300 if (typeof(b.listeners) == 'undefined') {
2301 b.listeners = { click : cb.createDelegate(this) };
2304 var btn = Roo.factory(b);
2306 btn.onRender(this.el.select('.modal-footer div').first());
2312 setDefaultButton : function(btn)
2314 //this.el.select('.modal-footer').()
2316 resizeTo: function(w,h)
2320 setContentSize : function(w, h)
2324 onButtonClick: function(btn,e)
2327 this.fireEvent('btnclick', btn.name, e);
2329 setTitle: function(str) {
2330 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2336 Roo.apply(Roo.bootstrap.Modal, {
2338 * Button config that displays a single OK button
2347 * Button config that displays Yes and No buttons
2363 * Button config that displays OK and Cancel buttons
2378 * Button config that displays Yes, No and Cancel buttons
2400 * messagebox - can be used as a replace
2404 * @class Roo.MessageBox
2405 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2409 Roo.Msg.alert('Status', 'Changes saved successfully.');
2411 // Prompt for user data:
2412 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2414 // process text value...
2418 // Show a dialog using config options:
2420 title:'Save Changes?',
2421 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2422 buttons: Roo.Msg.YESNOCANCEL,
2429 Roo.bootstrap.MessageBox = function(){
2430 var dlg, opt, mask, waitTimer;
2431 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2432 var buttons, activeTextEl, bwidth;
2436 var handleButton = function(button){
2438 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2442 var handleHide = function(){
2444 dlg.el.removeClass(opt.cls);
2447 // Roo.TaskMgr.stop(waitTimer);
2448 // waitTimer = null;
2453 var updateButtons = function(b){
2456 buttons["ok"].hide();
2457 buttons["cancel"].hide();
2458 buttons["yes"].hide();
2459 buttons["no"].hide();
2460 //dlg.footer.dom.style.display = 'none';
2463 dlg.footer.dom.style.display = '';
2464 for(var k in buttons){
2465 if(typeof buttons[k] != "function"){
2468 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2469 width += buttons[k].el.getWidth()+15;
2479 var handleEsc = function(d, k, e){
2480 if(opt && opt.closable !== false){
2490 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2491 * @return {Roo.BasicDialog} The BasicDialog element
2493 getDialog : function(){
2495 dlg = new Roo.bootstrap.Modal( {
2498 //constraintoviewport:false,
2500 //collapsible : false,
2505 //buttonAlign:"center",
2506 closeClick : function(){
2507 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2510 handleButton("cancel");
2515 dlg.on("hide", handleHide);
2517 //dlg.addKeyListener(27, handleEsc);
2519 this.buttons = buttons;
2520 var bt = this.buttonText;
2521 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2522 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2523 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2524 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2526 bodyEl = dlg.body.createChild({
2528 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2529 '<textarea class="roo-mb-textarea"></textarea>' +
2530 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2532 msgEl = bodyEl.dom.firstChild;
2533 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2534 textboxEl.enableDisplayMode();
2535 textboxEl.addKeyListener([10,13], function(){
2536 if(dlg.isVisible() && opt && opt.buttons){
2539 }else if(opt.buttons.yes){
2540 handleButton("yes");
2544 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2545 textareaEl.enableDisplayMode();
2546 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2547 progressEl.enableDisplayMode();
2548 var pf = progressEl.dom.firstChild;
2550 pp = Roo.get(pf.firstChild);
2551 pp.setHeight(pf.offsetHeight);
2559 * Updates the message box body text
2560 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2561 * the XHTML-compliant non-breaking space character '&#160;')
2562 * @return {Roo.MessageBox} This message box
2564 updateText : function(text){
2565 if(!dlg.isVisible() && !opt.width){
2566 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2568 msgEl.innerHTML = text || ' ';
2570 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2571 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2573 Math.min(opt.width || cw , this.maxWidth),
2574 Math.max(opt.minWidth || this.minWidth, bwidth)
2577 activeTextEl.setWidth(w);
2579 if(dlg.isVisible()){
2580 dlg.fixedcenter = false;
2582 // to big, make it scroll. = But as usual stupid IE does not support
2585 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2586 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2587 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2589 bodyEl.dom.style.height = '';
2590 bodyEl.dom.style.overflowY = '';
2593 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2595 bodyEl.dom.style.overflowX = '';
2598 dlg.setContentSize(w, bodyEl.getHeight());
2599 if(dlg.isVisible()){
2600 dlg.fixedcenter = true;
2606 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2607 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2608 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2609 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2610 * @return {Roo.MessageBox} This message box
2612 updateProgress : function(value, text){
2614 this.updateText(text);
2616 if (pp) { // weird bug on my firefox - for some reason this is not defined
2617 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2623 * Returns true if the message box is currently displayed
2624 * @return {Boolean} True if the message box is visible, else false
2626 isVisible : function(){
2627 return dlg && dlg.isVisible();
2631 * Hides the message box if it is displayed
2634 if(this.isVisible()){
2640 * Displays a new message box, or reinitializes an existing message box, based on the config options
2641 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2642 * The following config object properties are supported:
2644 Property Type Description
2645 ---------- --------------- ------------------------------------------------------------------------------------
2646 animEl String/Element An id or Element from which the message box should animate as it opens and
2647 closes (defaults to undefined)
2648 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2649 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2650 closable Boolean False to hide the top-right close button (defaults to true). Note that
2651 progress and wait dialogs will ignore this property and always hide the
2652 close button as they can only be closed programmatically.
2653 cls String A custom CSS class to apply to the message box element
2654 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2655 displayed (defaults to 75)
2656 fn Function A callback function to execute after closing the dialog. The arguments to the
2657 function will be btn (the name of the button that was clicked, if applicable,
2658 e.g. "ok"), and text (the value of the active text field, if applicable).
2659 Progress and wait dialogs will ignore this option since they do not respond to
2660 user actions and can only be closed programmatically, so any required function
2661 should be called by the same code after it closes the dialog.
2662 icon String A CSS class that provides a background image to be used as an icon for
2663 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2664 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2665 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2666 modal Boolean False to allow user interaction with the page while the message box is
2667 displayed (defaults to true)
2668 msg String A string that will replace the existing message box body text (defaults
2669 to the XHTML-compliant non-breaking space character ' ')
2670 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2671 progress Boolean True to display a progress bar (defaults to false)
2672 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2673 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2674 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2675 title String The title text
2676 value String The string value to set into the active textbox element if displayed
2677 wait Boolean True to display a progress bar (defaults to false)
2678 width Number The width of the dialog in pixels
2685 msg: 'Please enter your address:',
2687 buttons: Roo.MessageBox.OKCANCEL,
2690 animEl: 'addAddressBtn'
2693 * @param {Object} config Configuration options
2694 * @return {Roo.MessageBox} This message box
2696 show : function(options)
2699 // this causes nightmares if you show one dialog after another
2700 // especially on callbacks..
2702 if(this.isVisible()){
2705 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2706 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2707 Roo.log("New Dialog Message:" + options.msg )
2708 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2709 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2712 var d = this.getDialog();
2714 d.setTitle(opt.title || " ");
2715 d.close.setDisplayed(opt.closable !== false);
2716 activeTextEl = textboxEl;
2717 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2722 textareaEl.setHeight(typeof opt.multiline == "number" ?
2723 opt.multiline : this.defaultTextHeight);
2724 activeTextEl = textareaEl;
2733 progressEl.setDisplayed(opt.progress === true);
2734 this.updateProgress(0);
2735 activeTextEl.dom.value = opt.value || "";
2737 dlg.setDefaultButton(activeTextEl);
2739 var bs = opt.buttons;
2743 }else if(bs && bs.yes){
2744 db = buttons["yes"];
2746 dlg.setDefaultButton(db);
2748 bwidth = updateButtons(opt.buttons);
2749 this.updateText(opt.msg);
2751 d.el.addClass(opt.cls);
2753 d.proxyDrag = opt.proxyDrag === true;
2754 d.modal = opt.modal !== false;
2755 d.mask = opt.modal !== false ? mask : false;
2757 // force it to the end of the z-index stack so it gets a cursor in FF
2758 document.body.appendChild(dlg.el.dom);
2759 d.animateTarget = null;
2760 d.show(options.animEl);
2766 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2767 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2768 * and closing the message box when the process is complete.
2769 * @param {String} title The title bar text
2770 * @param {String} msg The message box body text
2771 * @return {Roo.MessageBox} This message box
2773 progress : function(title, msg){
2780 minWidth: this.minProgressWidth,
2787 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2788 * If a callback function is passed it will be called after the user clicks the button, and the
2789 * id of the button that was clicked will be passed as the only parameter to the callback
2790 * (could also be the top-right close button).
2791 * @param {String} title The title bar text
2792 * @param {String} msg The message box body text
2793 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2794 * @param {Object} scope (optional) The scope of the callback function
2795 * @return {Roo.MessageBox} This message box
2797 alert : function(title, msg, fn, scope){
2810 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2811 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2812 * You are responsible for closing the message box when the process is complete.
2813 * @param {String} msg The message box body text
2814 * @param {String} title (optional) The title bar text
2815 * @return {Roo.MessageBox} This message box
2817 wait : function(msg, title){
2828 waitTimer = Roo.TaskMgr.start({
2830 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2838 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2839 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2840 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2841 * @param {String} title The title bar text
2842 * @param {String} msg The message box body text
2843 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2844 * @param {Object} scope (optional) The scope of the callback function
2845 * @return {Roo.MessageBox} This message box
2847 confirm : function(title, msg, fn, scope){
2851 buttons: this.YESNO,
2860 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2861 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2862 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2863 * (could also be the top-right close button) and the text that was entered will be passed as the two
2864 * parameters to the callback.
2865 * @param {String} title The title bar text
2866 * @param {String} msg The message box body text
2867 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2868 * @param {Object} scope (optional) The scope of the callback function
2869 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2870 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2871 * @return {Roo.MessageBox} This message box
2873 prompt : function(title, msg, fn, scope, multiline){
2877 buttons: this.OKCANCEL,
2882 multiline: multiline,
2889 * Button config that displays a single OK button
2894 * Button config that displays Yes and No buttons
2897 YESNO : {yes:true, no:true},
2899 * Button config that displays OK and Cancel buttons
2902 OKCANCEL : {ok:true, cancel:true},
2904 * Button config that displays Yes, No and Cancel buttons
2907 YESNOCANCEL : {yes:true, no:true, cancel:true},
2910 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2913 defaultTextHeight : 75,
2915 * The maximum width in pixels of the message box (defaults to 600)
2920 * The minimum width in pixels of the message box (defaults to 100)
2925 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2926 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2929 minProgressWidth : 250,
2931 * An object containing the default button text strings that can be overriden for localized language support.
2932 * Supported properties are: ok, cancel, yes and no.
2933 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2946 * Shorthand for {@link Roo.MessageBox}
2948 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2949 Roo.Msg = Roo.Msg || Roo.MessageBox;
2958 * @class Roo.bootstrap.Navbar
2959 * @extends Roo.bootstrap.Component
2960 * Bootstrap Navbar class
2963 * Create a new Navbar
2964 * @param {Object} config The config object
2968 Roo.bootstrap.Navbar = function(config){
2969 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2973 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2982 getAutoCreate : function(){
2985 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2989 initEvents :function ()
2991 //Roo.log(this.el.select('.navbar-toggle',true));
2992 this.el.select('.navbar-toggle',true).on('click', function() {
2993 // Roo.log('click');
2994 this.el.select('.navbar-collapse',true).toggleClass('in');
3002 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3004 var size = this.el.getSize();
3005 this.maskEl.setSize(size.width, size.height);
3006 this.maskEl.enableDisplayMode("block");
3015 getChildContainer : function()
3017 if (this.el.select('.collapse').getCount()) {
3018 return this.el.select('.collapse',true).first();
3051 * @class Roo.bootstrap.NavSimplebar
3052 * @extends Roo.bootstrap.Navbar
3053 * Bootstrap Sidebar class
3055 * @cfg {Boolean} inverse is inverted color
3057 * @cfg {String} type (nav | pills | tabs)
3058 * @cfg {Boolean} arrangement stacked | justified
3059 * @cfg {String} align (left | right) alignment
3061 * @cfg {Boolean} main (true|false) main nav bar? default false
3062 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3064 * @cfg {String} tag (header|footer|nav|div) default is nav
3070 * Create a new Sidebar
3071 * @param {Object} config The config object
3075 Roo.bootstrap.NavSimplebar = function(config){
3076 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3079 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3095 getAutoCreate : function(){
3099 tag : this.tag || 'div',
3112 this.type = this.type || 'nav';
3113 if (['tabs','pills'].indexOf(this.type)!==-1) {
3114 cfg.cn[0].cls += ' nav-' + this.type
3118 if (this.type!=='nav') {
3119 Roo.log('nav type must be nav/tabs/pills')
3121 cfg.cn[0].cls += ' navbar-nav'
3127 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3128 cfg.cn[0].cls += ' nav-' + this.arrangement;
3132 if (this.align === 'right') {
3133 cfg.cn[0].cls += ' navbar-right';
3137 cfg.cls += ' navbar-inverse';
3164 * @class Roo.bootstrap.NavHeaderbar
3165 * @extends Roo.bootstrap.NavSimplebar
3166 * Bootstrap Sidebar class
3168 * @cfg {String} brand what is brand
3169 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3170 * @cfg {String} brand_href href of the brand
3171 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3172 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3175 * Create a new Sidebar
3176 * @param {Object} config The config object
3180 Roo.bootstrap.NavHeaderbar = function(config){
3181 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3184 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3192 getAutoCreate : function(){
3195 tag: this.nav || 'nav',
3204 cls: 'navbar-header',
3209 cls: 'navbar-toggle',
3210 'data-toggle': 'collapse',
3215 html: 'Toggle navigation'
3237 cls: 'collapse navbar-collapse',
3241 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3243 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3244 cfg.cls += ' navbar-' + this.position;
3246 // tag can override this..
3248 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3251 if (this.brand !== '') {
3254 href: this.brand_href ? this.brand_href : '#',
3255 cls: 'navbar-brand',
3263 cfg.cls += ' main-nav';
3271 initEvents : function()
3273 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3275 if (this.autohide) {
3280 Roo.get(document).on('scroll',function(e) {
3281 var ns = Roo.get(document).getScroll().top;
3282 var os = prevScroll;
3286 ft.removeClass('slideDown');
3287 ft.addClass('slideUp');
3290 ft.removeClass('slideUp');
3291 ft.addClass('slideDown');
3315 * @class Roo.bootstrap.NavSidebar
3316 * @extends Roo.bootstrap.Navbar
3317 * Bootstrap Sidebar class
3320 * Create a new Sidebar
3321 * @param {Object} config The config object
3325 Roo.bootstrap.NavSidebar = function(config){
3326 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3329 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3331 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3333 getAutoCreate : function(){
3338 cls: 'sidebar sidebar-nav'
3360 * @class Roo.bootstrap.NavGroup
3361 * @extends Roo.bootstrap.Component
3362 * Bootstrap NavGroup class
3363 * @cfg {String} align left | right
3364 * @cfg {Boolean} inverse false | true
3365 * @cfg {String} type (nav|pills|tab) default nav
3366 * @cfg {String} navId - reference Id for navbar.
3370 * Create a new nav group
3371 * @param {Object} config The config object
3374 Roo.bootstrap.NavGroup = function(config){
3375 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3378 Roo.bootstrap.NavGroup.register(this);
3382 * Fires when the active item changes
3383 * @param {Roo.bootstrap.NavGroup} this
3384 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3385 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3392 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3403 getAutoCreate : function()
3405 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3412 if (['tabs','pills'].indexOf(this.type)!==-1) {
3413 cfg.cls += ' nav-' + this.type
3415 if (this.type!=='nav') {
3416 Roo.log('nav type must be nav/tabs/pills')
3418 cfg.cls += ' navbar-nav'
3421 if (this.parent().sidebar) {
3424 cls: 'dashboard-menu sidebar-menu'
3430 if (this.form === true) {
3436 if (this.align === 'right') {
3437 cfg.cls += ' navbar-right';
3439 cfg.cls += ' navbar-left';
3443 if (this.align === 'right') {
3444 cfg.cls += ' navbar-right';
3448 cfg.cls += ' navbar-inverse';
3456 * sets the active Navigation item
3457 * @param {Roo.bootstrap.NavItem} the new current navitem
3459 setActiveItem : function(item)
3462 Roo.each(this.navItems, function(v){
3467 v.setActive(false, true);
3474 item.setActive(true, true);
3475 this.fireEvent('changed', this, item, prev);
3480 * gets the active Navigation item
3481 * @return {Roo.bootstrap.NavItem} the current navitem
3483 getActive : function()
3487 Roo.each(this.navItems, function(v){
3498 indexOfNav : function()
3502 Roo.each(this.navItems, function(v,i){
3513 * adds a Navigation item
3514 * @param {Roo.bootstrap.NavItem} the navitem to add
3516 addItem : function(cfg)
3518 var cn = new Roo.bootstrap.NavItem(cfg);
3520 cn.parentId = this.id;
3521 cn.onRender(this.el, null);
3525 * register a Navigation item
3526 * @param {Roo.bootstrap.NavItem} the navitem to add
3528 register : function(item)
3530 this.navItems.push( item);
3531 item.navId = this.navId;
3536 * clear all the Navigation item
3539 clearAll : function()
3542 this.el.dom.innerHTML = '';
3545 getNavItem: function(tabId)
3548 Roo.each(this.navItems, function(e) {
3549 if (e.tabId == tabId) {
3559 setActiveNext : function()
3561 var i = this.indexOfNav(this.getActive());
3562 if (i > this.navItems.length) {
3565 this.setActiveItem(this.navItems[i+1]);
3567 setActivePrev : function()
3569 var i = this.indexOfNav(this.getActive());
3573 this.setActiveItem(this.navItems[i-1]);
3575 clearWasActive : function(except) {
3576 Roo.each(this.navItems, function(e) {
3577 if (e.tabId != except.tabId && e.was_active) {
3578 e.was_active = false;
3585 getWasActive : function ()
3588 Roo.each(this.navItems, function(e) {
3603 Roo.apply(Roo.bootstrap.NavGroup, {
3607 * register a Navigation Group
3608 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3610 register : function(navgrp)
3612 this.groups[navgrp.navId] = navgrp;
3616 * fetch a Navigation Group based on the navigation ID
3617 * @param {string} the navgroup to add
3618 * @returns {Roo.bootstrap.NavGroup} the navgroup
3620 get: function(navId) {
3621 if (typeof(this.groups[navId]) == 'undefined') {
3623 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3625 return this.groups[navId] ;
3640 * @class Roo.bootstrap.NavItem
3641 * @extends Roo.bootstrap.Component
3642 * Bootstrap Navbar.NavItem class
3643 * @cfg {String} href link to
3644 * @cfg {String} html content of button
3645 * @cfg {String} badge text inside badge
3646 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3647 * @cfg {String} glyphicon name of glyphicon
3648 * @cfg {String} icon name of font awesome icon
3649 * @cfg {Boolean} active Is item active
3650 * @cfg {Boolean} disabled Is item disabled
3652 * @cfg {Boolean} preventDefault (true | false) default false
3653 * @cfg {String} tabId the tab that this item activates.
3654 * @cfg {String} tagtype (a|span) render as a href or span?
3657 * Create a new Navbar Item
3658 * @param {Object} config The config object
3660 Roo.bootstrap.NavItem = function(config){
3661 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3666 * The raw click event for the entire grid.
3667 * @param {Roo.EventObject} e
3672 * Fires when the active item active state changes
3673 * @param {Roo.bootstrap.NavItem} this
3674 * @param {boolean} state the new state
3682 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3690 preventDefault : false,
3697 getAutoCreate : function(){
3705 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3707 if (this.disabled) {
3708 cfg.cls += ' disabled';
3711 if (this.href || this.html || this.glyphicon || this.icon) {
3715 href : this.href || "#",
3716 html: this.html || ''
3721 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3724 if(this.glyphicon) {
3725 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3730 cfg.cn[0].html += " <span class='caret'></span>";
3734 if (this.badge !== '') {
3736 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3744 initEvents: function()
3746 if (typeof (this.menu) != 'undefined') {
3747 this.menu.parentType = this.xtype;
3748 this.menu.triggerEl = this.el;
3749 this.addxtype(Roo.apply({}, this.menu));
3752 this.el.select('a',true).on('click', this.onClick, this);
3754 if(this.tagtype == 'span'){
3755 this.el.select('span',true).on('click', this.onClick, this);
3758 // at this point parent should be available..
3759 this.parent().register(this);
3762 onClick : function(e)
3765 if(this.preventDefault){
3768 if (this.disabled) {
3772 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3773 if (tg && tg.transition) {
3774 Roo.log("waiting for the transitionend");
3778 Roo.log("fire event clicked");
3779 if(this.fireEvent('click', this, e) === false){
3783 if(this.tagtype == 'span'){
3787 var p = this.parent();
3788 if (['tabs','pills'].indexOf(p.type)!==-1) {
3789 if (typeof(p.setActiveItem) !== 'undefined') {
3790 p.setActiveItem(this);
3793 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3794 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3795 // remove the collapsed menu expand...
3796 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3801 isActive: function () {
3804 setActive : function(state, fire, is_was_active)
3806 if (this.active && !state & this.navId) {
3807 this.was_active = true;
3808 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3810 nv.clearWasActive(this);
3814 this.active = state;
3817 this.el.removeClass('active');
3818 } else if (!this.el.hasClass('active')) {
3819 this.el.addClass('active');
3822 this.fireEvent('changed', this, state);
3825 // show a panel if it's registered and related..
3827 if (!this.navId || !this.tabId || !state || is_was_active) {
3831 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3835 var pan = tg.getPanelByName(this.tabId);
3839 // if we can not flip to new panel - go back to old nav highlight..
3840 if (false == tg.showPanel(pan)) {
3841 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3843 var onav = nv.getWasActive();
3845 onav.setActive(true, false, true);
3854 // this should not be here...
3855 setDisabled : function(state)
3857 this.disabled = state;
3859 this.el.removeClass('disabled');
3860 } else if (!this.el.hasClass('disabled')) {
3861 this.el.addClass('disabled');
3874 * <span> icon </span>
3875 * <span> text </span>
3876 * <span>badge </span>
3880 * @class Roo.bootstrap.NavSidebarItem
3881 * @extends Roo.bootstrap.NavItem
3882 * Bootstrap Navbar.NavSidebarItem class
3884 * Create a new Navbar Button
3885 * @param {Object} config The config object
3887 Roo.bootstrap.NavSidebarItem = function(config){
3888 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3893 * The raw click event for the entire grid.
3894 * @param {Roo.EventObject} e
3899 * Fires when the active item active state changes
3900 * @param {Roo.bootstrap.NavSidebarItem} this
3901 * @param {boolean} state the new state
3909 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3912 getAutoCreate : function(){
3917 href : this.href || '#',
3929 html : this.html || ''
3934 cfg.cls += ' active';
3938 if (this.glyphicon || this.icon) {
3939 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3940 a.cn.push({ tag : 'i', cls : c }) ;
3945 if (this.badge !== '') {
3946 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3950 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3951 a.cls += 'dropdown-toggle treeview' ;
3975 * @class Roo.bootstrap.Row
3976 * @extends Roo.bootstrap.Component
3977 * Bootstrap Row class (contains columns...)
3981 * @param {Object} config The config object
3984 Roo.bootstrap.Row = function(config){
3985 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3988 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3990 getAutoCreate : function(){
4009 * @class Roo.bootstrap.Element
4010 * @extends Roo.bootstrap.Component
4011 * Bootstrap Element class
4012 * @cfg {String} html contents of the element
4013 * @cfg {String} tag tag of the element
4014 * @cfg {String} cls class of the element
4017 * Create a new Element
4018 * @param {Object} config The config object
4021 Roo.bootstrap.Element = function(config){
4022 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4025 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4032 getAutoCreate : function(){
4057 * @class Roo.bootstrap.Pagination
4058 * @extends Roo.bootstrap.Component
4059 * Bootstrap Pagination class
4060 * @cfg {String} size xs | sm | md | lg
4061 * @cfg {Boolean} inverse false | true
4064 * Create a new Pagination
4065 * @param {Object} config The config object
4068 Roo.bootstrap.Pagination = function(config){
4069 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4072 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4078 getAutoCreate : function(){
4084 cfg.cls += ' inverse';
4090 cfg.cls += " " + this.cls;
4108 * @class Roo.bootstrap.PaginationItem
4109 * @extends Roo.bootstrap.Component
4110 * Bootstrap PaginationItem class
4111 * @cfg {String} html text
4112 * @cfg {String} href the link
4113 * @cfg {Boolean} preventDefault (true | false) default true
4114 * @cfg {Boolean} active (true | false) default false
4118 * Create a new PaginationItem
4119 * @param {Object} config The config object
4123 Roo.bootstrap.PaginationItem = function(config){
4124 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4129 * The raw click event for the entire grid.
4130 * @param {Roo.EventObject} e
4136 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4140 preventDefault: true,
4144 getAutoCreate : function(){
4150 href : this.href ? this.href : '#',
4151 html : this.html ? this.html : ''
4161 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4167 initEvents: function() {
4169 this.el.on('click', this.onClick, this);
4172 onClick : function(e)
4174 Roo.log('PaginationItem on click ');
4175 if(this.preventDefault){
4179 this.fireEvent('click', this, e);
4195 * @class Roo.bootstrap.Slider
4196 * @extends Roo.bootstrap.Component
4197 * Bootstrap Slider class
4200 * Create a new Slider
4201 * @param {Object} config The config object
4204 Roo.bootstrap.Slider = function(config){
4205 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4208 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4210 getAutoCreate : function(){
4214 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4218 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4230 * Ext JS Library 1.1.1
4231 * Copyright(c) 2006-2007, Ext JS, LLC.
4233 * Originally Released Under LGPL - original licence link has changed is not relivant.
4236 * <script type="text/javascript">
4241 * @class Roo.grid.ColumnModel
4242 * @extends Roo.util.Observable
4243 * This is the default implementation of a ColumnModel used by the Grid. It defines
4244 * the columns in the grid.
4247 var colModel = new Roo.grid.ColumnModel([
4248 {header: "Ticker", width: 60, sortable: true, locked: true},
4249 {header: "Company Name", width: 150, sortable: true},
4250 {header: "Market Cap.", width: 100, sortable: true},
4251 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4252 {header: "Employees", width: 100, sortable: true, resizable: false}
4257 * The config options listed for this class are options which may appear in each
4258 * individual column definition.
4259 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4261 * @param {Object} config An Array of column config objects. See this class's
4262 * config objects for details.
4264 Roo.grid.ColumnModel = function(config){
4266 * The config passed into the constructor
4268 this.config = config;
4271 // if no id, create one
4272 // if the column does not have a dataIndex mapping,
4273 // map it to the order it is in the config
4274 for(var i = 0, len = config.length; i < len; i++){
4276 if(typeof c.dataIndex == "undefined"){
4279 if(typeof c.renderer == "string"){
4280 c.renderer = Roo.util.Format[c.renderer];
4282 if(typeof c.id == "undefined"){
4285 if(c.editor && c.editor.xtype){
4286 c.editor = Roo.factory(c.editor, Roo.grid);
4288 if(c.editor && c.editor.isFormField){
4289 c.editor = new Roo.grid.GridEditor(c.editor);
4291 this.lookup[c.id] = c;
4295 * The width of columns which have no width specified (defaults to 100)
4298 this.defaultWidth = 100;
4301 * Default sortable of columns which have no sortable specified (defaults to false)
4304 this.defaultSortable = false;
4308 * @event widthchange
4309 * Fires when the width of a column changes.
4310 * @param {ColumnModel} this
4311 * @param {Number} columnIndex The column index
4312 * @param {Number} newWidth The new width
4314 "widthchange": true,
4316 * @event headerchange
4317 * Fires when the text of a header changes.
4318 * @param {ColumnModel} this
4319 * @param {Number} columnIndex The column index
4320 * @param {Number} newText The new header text
4322 "headerchange": true,
4324 * @event hiddenchange
4325 * Fires when a column is hidden or "unhidden".
4326 * @param {ColumnModel} this
4327 * @param {Number} columnIndex The column index
4328 * @param {Boolean} hidden true if hidden, false otherwise
4330 "hiddenchange": true,
4332 * @event columnmoved
4333 * Fires when a column is moved.
4334 * @param {ColumnModel} this
4335 * @param {Number} oldIndex
4336 * @param {Number} newIndex
4338 "columnmoved" : true,
4340 * @event columlockchange
4341 * Fires when a column's locked state is changed
4342 * @param {ColumnModel} this
4343 * @param {Number} colIndex
4344 * @param {Boolean} locked true if locked
4346 "columnlockchange" : true
4348 Roo.grid.ColumnModel.superclass.constructor.call(this);
4350 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4352 * @cfg {String} header The header text to display in the Grid view.
4355 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4356 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4357 * specified, the column's index is used as an index into the Record's data Array.
4360 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4361 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4364 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4365 * Defaults to the value of the {@link #defaultSortable} property.
4366 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4369 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4372 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4375 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4378 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4381 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4382 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4383 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4384 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4387 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4390 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4394 * Returns the id of the column at the specified index.
4395 * @param {Number} index The column index
4396 * @return {String} the id
4398 getColumnId : function(index){
4399 return this.config[index].id;
4403 * Returns the column for a specified id.
4404 * @param {String} id The column id
4405 * @return {Object} the column
4407 getColumnById : function(id){
4408 return this.lookup[id];
4413 * Returns the column for a specified dataIndex.
4414 * @param {String} dataIndex The column dataIndex
4415 * @return {Object|Boolean} the column or false if not found
4417 getColumnByDataIndex: function(dataIndex){
4418 var index = this.findColumnIndex(dataIndex);
4419 return index > -1 ? this.config[index] : false;
4423 * Returns the index for a specified column id.
4424 * @param {String} id The column id
4425 * @return {Number} the index, or -1 if not found
4427 getIndexById : function(id){
4428 for(var i = 0, len = this.config.length; i < len; i++){
4429 if(this.config[i].id == id){
4437 * Returns the index for a specified column dataIndex.
4438 * @param {String} dataIndex The column dataIndex
4439 * @return {Number} the index, or -1 if not found
4442 findColumnIndex : function(dataIndex){
4443 for(var i = 0, len = this.config.length; i < len; i++){
4444 if(this.config[i].dataIndex == dataIndex){
4452 moveColumn : function(oldIndex, newIndex){
4453 var c = this.config[oldIndex];
4454 this.config.splice(oldIndex, 1);
4455 this.config.splice(newIndex, 0, c);
4456 this.dataMap = null;
4457 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4460 isLocked : function(colIndex){
4461 return this.config[colIndex].locked === true;
4464 setLocked : function(colIndex, value, suppressEvent){
4465 if(this.isLocked(colIndex) == value){
4468 this.config[colIndex].locked = value;
4470 this.fireEvent("columnlockchange", this, colIndex, value);
4474 getTotalLockedWidth : function(){
4476 for(var i = 0; i < this.config.length; i++){
4477 if(this.isLocked(i) && !this.isHidden(i)){
4478 this.totalWidth += this.getColumnWidth(i);
4484 getLockedCount : function(){
4485 for(var i = 0, len = this.config.length; i < len; i++){
4486 if(!this.isLocked(i)){
4493 * Returns the number of columns.
4496 getColumnCount : function(visibleOnly){
4497 if(visibleOnly === true){
4499 for(var i = 0, len = this.config.length; i < len; i++){
4500 if(!this.isHidden(i)){
4506 return this.config.length;
4510 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4511 * @param {Function} fn
4512 * @param {Object} scope (optional)
4513 * @return {Array} result
4515 getColumnsBy : function(fn, scope){
4517 for(var i = 0, len = this.config.length; i < len; i++){
4518 var c = this.config[i];
4519 if(fn.call(scope||this, c, i) === true){
4527 * Returns true if the specified column is sortable.
4528 * @param {Number} col The column index
4531 isSortable : function(col){
4532 if(typeof this.config[col].sortable == "undefined"){
4533 return this.defaultSortable;
4535 return this.config[col].sortable;
4539 * Returns the rendering (formatting) function defined for the column.
4540 * @param {Number} col The column index.
4541 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4543 getRenderer : function(col){
4544 if(!this.config[col].renderer){
4545 return Roo.grid.ColumnModel.defaultRenderer;
4547 return this.config[col].renderer;
4551 * Sets the rendering (formatting) function for a column.
4552 * @param {Number} col The column index
4553 * @param {Function} fn The function to use to process the cell's raw data
4554 * to return HTML markup for the grid view. The render function is called with
4555 * the following parameters:<ul>
4556 * <li>Data value.</li>
4557 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4558 * <li>css A CSS style string to apply to the table cell.</li>
4559 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4560 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4561 * <li>Row index</li>
4562 * <li>Column index</li>
4563 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4565 setRenderer : function(col, fn){
4566 this.config[col].renderer = fn;
4570 * Returns the width for the specified column.
4571 * @param {Number} col The column index
4574 getColumnWidth : function(col){
4575 return this.config[col].width * 1 || this.defaultWidth;
4579 * Sets the width for a column.
4580 * @param {Number} col The column index
4581 * @param {Number} width The new width
4583 setColumnWidth : function(col, width, suppressEvent){
4584 this.config[col].width = width;
4585 this.totalWidth = null;
4587 this.fireEvent("widthchange", this, col, width);
4592 * Returns the total width of all columns.
4593 * @param {Boolean} includeHidden True to include hidden column widths
4596 getTotalWidth : function(includeHidden){
4597 if(!this.totalWidth){
4598 this.totalWidth = 0;
4599 for(var i = 0, len = this.config.length; i < len; i++){
4600 if(includeHidden || !this.isHidden(i)){
4601 this.totalWidth += this.getColumnWidth(i);
4605 return this.totalWidth;
4609 * Returns the header for the specified column.
4610 * @param {Number} col The column index
4613 getColumnHeader : function(col){
4614 return this.config[col].header;
4618 * Sets the header for a column.
4619 * @param {Number} col The column index
4620 * @param {String} header The new header
4622 setColumnHeader : function(col, header){
4623 this.config[col].header = header;
4624 this.fireEvent("headerchange", this, col, header);
4628 * Returns the tooltip for the specified column.
4629 * @param {Number} col The column index
4632 getColumnTooltip : function(col){
4633 return this.config[col].tooltip;
4636 * Sets the tooltip for a column.
4637 * @param {Number} col The column index
4638 * @param {String} tooltip The new tooltip
4640 setColumnTooltip : function(col, tooltip){
4641 this.config[col].tooltip = tooltip;
4645 * Returns the dataIndex for the specified column.
4646 * @param {Number} col The column index
4649 getDataIndex : function(col){
4650 return this.config[col].dataIndex;
4654 * Sets the dataIndex for a column.
4655 * @param {Number} col The column index
4656 * @param {Number} dataIndex The new dataIndex
4658 setDataIndex : function(col, dataIndex){
4659 this.config[col].dataIndex = dataIndex;
4665 * Returns true if the cell is editable.
4666 * @param {Number} colIndex The column index
4667 * @param {Number} rowIndex The row index
4670 isCellEditable : function(colIndex, rowIndex){
4671 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4675 * Returns the editor defined for the cell/column.
4676 * return false or null to disable editing.
4677 * @param {Number} colIndex The column index
4678 * @param {Number} rowIndex The row index
4681 getCellEditor : function(colIndex, rowIndex){
4682 return this.config[colIndex].editor;
4686 * Sets if a column is editable.
4687 * @param {Number} col The column index
4688 * @param {Boolean} editable True if the column is editable
4690 setEditable : function(col, editable){
4691 this.config[col].editable = editable;
4696 * Returns true if the column is hidden.
4697 * @param {Number} colIndex The column index
4700 isHidden : function(colIndex){
4701 return this.config[colIndex].hidden;
4706 * Returns true if the column width cannot be changed
4708 isFixed : function(colIndex){
4709 return this.config[colIndex].fixed;
4713 * Returns true if the column can be resized
4716 isResizable : function(colIndex){
4717 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4720 * Sets if a column is hidden.
4721 * @param {Number} colIndex The column index
4722 * @param {Boolean} hidden True if the column is hidden
4724 setHidden : function(colIndex, hidden){
4725 this.config[colIndex].hidden = hidden;
4726 this.totalWidth = null;
4727 this.fireEvent("hiddenchange", this, colIndex, hidden);
4731 * Sets the editor for a column.
4732 * @param {Number} col The column index
4733 * @param {Object} editor The editor object
4735 setEditor : function(col, editor){
4736 this.config[col].editor = editor;
4740 Roo.grid.ColumnModel.defaultRenderer = function(value){
4741 if(typeof value == "string" && value.length < 1){
4747 // Alias for backwards compatibility
4748 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4751 * Ext JS Library 1.1.1
4752 * Copyright(c) 2006-2007, Ext JS, LLC.
4754 * Originally Released Under LGPL - original licence link has changed is not relivant.
4757 * <script type="text/javascript">
4761 * @class Roo.LoadMask
4762 * A simple utility class for generically masking elements while loading data. If the element being masked has
4763 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4764 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4765 * element's UpdateManager load indicator and will be destroyed after the initial load.
4767 * Create a new LoadMask
4768 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4769 * @param {Object} config The config object
4771 Roo.LoadMask = function(el, config){
4772 this.el = Roo.get(el);
4773 Roo.apply(this, config);
4775 this.store.on('beforeload', this.onBeforeLoad, this);
4776 this.store.on('load', this.onLoad, this);
4777 this.store.on('loadexception', this.onLoadException, this);
4778 this.removeMask = false;
4780 var um = this.el.getUpdateManager();
4781 um.showLoadIndicator = false; // disable the default indicator
4782 um.on('beforeupdate', this.onBeforeLoad, this);
4783 um.on('update', this.onLoad, this);
4784 um.on('failure', this.onLoad, this);
4785 this.removeMask = true;
4789 Roo.LoadMask.prototype = {
4791 * @cfg {Boolean} removeMask
4792 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4793 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4797 * The text to display in a centered loading message box (defaults to 'Loading...')
4801 * @cfg {String} msgCls
4802 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4804 msgCls : 'x-mask-loading',
4807 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4813 * Disables the mask to prevent it from being displayed
4815 disable : function(){
4816 this.disabled = true;
4820 * Enables the mask so that it can be displayed
4822 enable : function(){
4823 this.disabled = false;
4826 onLoadException : function()
4830 if (typeof(arguments[3]) != 'undefined') {
4831 Roo.MessageBox.alert("Error loading",arguments[3]);
4835 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4836 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4845 this.el.unmask(this.removeMask);
4850 this.el.unmask(this.removeMask);
4854 onBeforeLoad : function(){
4856 this.el.mask(this.msg, this.msgCls);
4861 destroy : function(){
4863 this.store.un('beforeload', this.onBeforeLoad, this);
4864 this.store.un('load', this.onLoad, this);
4865 this.store.un('loadexception', this.onLoadException, this);
4867 var um = this.el.getUpdateManager();
4868 um.un('beforeupdate', this.onBeforeLoad, this);
4869 um.un('update', this.onLoad, this);
4870 um.un('failure', this.onLoad, this);
4881 * @class Roo.bootstrap.Table
4882 * @extends Roo.bootstrap.Component
4883 * Bootstrap Table class
4884 * @cfg {String} cls table class
4885 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4886 * @cfg {String} bgcolor Specifies the background color for a table
4887 * @cfg {Number} border Specifies whether the table cells should have borders or not
4888 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4889 * @cfg {Number} cellspacing Specifies the space between cells
4890 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4891 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4892 * @cfg {String} sortable Specifies that the table should be sortable
4893 * @cfg {String} summary Specifies a summary of the content of a table
4894 * @cfg {Number} width Specifies the width of a table
4895 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4897 * @cfg {boolean} striped Should the rows be alternative striped
4898 * @cfg {boolean} bordered Add borders to the table
4899 * @cfg {boolean} hover Add hover highlighting
4900 * @cfg {boolean} condensed Format condensed
4901 * @cfg {boolean} responsive Format condensed
4902 * @cfg {Boolean} loadMask (true|false) default false
4903 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4904 * @cfg {Boolean} thead (true|false) generate thead, default true
4905 * @cfg {Boolean} RowSelection (true|false) default false
4906 * @cfg {Boolean} CellSelection (true|false) default false
4908 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4912 * Create a new Table
4913 * @param {Object} config The config object
4916 Roo.bootstrap.Table = function(config){
4917 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4920 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4921 this.sm = this.selModel;
4922 this.sm.xmodule = this.xmodule || false;
4924 if (this.cm && typeof(this.cm.config) == 'undefined') {
4925 this.colModel = new Roo.grid.ColumnModel(this.cm);
4926 this.cm = this.colModel;
4927 this.cm.xmodule = this.xmodule || false;
4930 this.store= Roo.factory(this.store, Roo.data);
4931 this.ds = this.store;
4932 this.ds.xmodule = this.xmodule || false;
4935 if (this.footer && this.store) {
4936 this.footer.dataSource = this.ds;
4937 this.footer = Roo.factory(this.footer);
4944 * Fires when a cell is clicked
4945 * @param {Roo.bootstrap.Table} this
4946 * @param {Roo.Element} el
4947 * @param {Number} rowIndex
4948 * @param {Number} columnIndex
4949 * @param {Roo.EventObject} e
4953 * @event celldblclick
4954 * Fires when a cell is double clicked
4955 * @param {Roo.bootstrap.Table} this
4956 * @param {Roo.Element} el
4957 * @param {Number} rowIndex
4958 * @param {Number} columnIndex
4959 * @param {Roo.EventObject} e
4961 "celldblclick" : true,
4964 * Fires when a row is clicked
4965 * @param {Roo.bootstrap.Table} this
4966 * @param {Roo.Element} el
4967 * @param {Number} rowIndex
4968 * @param {Roo.EventObject} e
4972 * @event rowdblclick
4973 * Fires when a row is double clicked
4974 * @param {Roo.bootstrap.Table} this
4975 * @param {Roo.Element} el
4976 * @param {Number} rowIndex
4977 * @param {Roo.EventObject} e
4979 "rowdblclick" : true,
4982 * Fires when a mouseover occur
4983 * @param {Roo.bootstrap.Table} this
4984 * @param {Roo.Element} el
4985 * @param {Number} rowIndex
4986 * @param {Number} columnIndex
4987 * @param {Roo.EventObject} e
4992 * Fires when a mouseout occur
4993 * @param {Roo.bootstrap.Table} this
4994 * @param {Roo.Element} el
4995 * @param {Number} rowIndex
4996 * @param {Number} columnIndex
4997 * @param {Roo.EventObject} e
5002 * Fires when a row is rendered, so you can change add a style to it.
5003 * @param {Roo.bootstrap.Table} this
5004 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5011 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5035 RowSelection : false,
5036 CellSelection : false,
5039 // Roo.Element - the tbody
5042 getAutoCreate : function(){
5043 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5052 cfg.cls += ' table-striped';
5056 cfg.cls += ' table-hover';
5058 if (this.bordered) {
5059 cfg.cls += ' table-bordered';
5061 if (this.condensed) {
5062 cfg.cls += ' table-condensed';
5064 if (this.responsive) {
5065 cfg.cls += ' table-responsive';
5069 cfg.cls+= ' ' +this.cls;
5072 // this lot should be simplifed...
5075 cfg.align=this.align;
5078 cfg.bgcolor=this.bgcolor;
5081 cfg.border=this.border;
5083 if (this.cellpadding) {
5084 cfg.cellpadding=this.cellpadding;
5086 if (this.cellspacing) {
5087 cfg.cellspacing=this.cellspacing;
5090 cfg.frame=this.frame;
5093 cfg.rules=this.rules;
5095 if (this.sortable) {
5096 cfg.sortable=this.sortable;
5099 cfg.summary=this.summary;
5102 cfg.width=this.width;
5105 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5108 if(this.store || this.cm){
5110 cfg.cn.push(this.renderHeader());
5113 cfg.cn.push(this.renderBody());
5116 cfg.cn.push(this.renderFooter());
5119 cfg.cls+= ' TableGrid';
5122 return { cn : [ cfg ] };
5125 initEvents : function()
5127 if(!this.store || !this.cm){
5131 //Roo.log('initEvents with ds!!!!');
5133 this.mainBody = this.el.select('tbody', true).first();
5138 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5139 e.on('click', _this.sort, _this);
5142 this.el.on("click", this.onClick, this);
5143 this.el.on("dblclick", this.onDblClick, this);
5145 this.parent().el.setStyle('position', 'relative');
5147 this.footer.parentId = this.id;
5148 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5151 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5153 this.store.on('load', this.onLoad, this);
5154 this.store.on('beforeload', this.onBeforeLoad, this);
5155 this.store.on('update', this.onUpdate, this);
5159 onMouseover : function(e, el)
5161 var cell = Roo.get(el);
5167 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5168 cell = cell.findParent('td', false, true);
5171 var row = cell.findParent('tr', false, true);
5172 var cellIndex = cell.dom.cellIndex;
5173 var rowIndex = row.dom.rowIndex - 1; // start from 0
5175 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5179 onMouseout : function(e, el)
5181 var cell = Roo.get(el);
5187 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5188 cell = cell.findParent('td', false, true);
5191 var row = cell.findParent('tr', false, true);
5192 var cellIndex = cell.dom.cellIndex;
5193 var rowIndex = row.dom.rowIndex - 1; // start from 0
5195 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5199 onClick : function(e, el)
5201 var cell = Roo.get(el);
5203 if(!cell || (!this.CellSelection && !this.RowSelection)){
5208 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5209 cell = cell.findParent('td', false, true);
5212 var row = cell.findParent('tr', false, true);
5213 var cellIndex = cell.dom.cellIndex;
5214 var rowIndex = row.dom.rowIndex - 1;
5216 if(this.CellSelection){
5217 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5220 if(this.RowSelection){
5221 this.fireEvent('rowclick', this, row, rowIndex, e);
5227 onDblClick : function(e,el)
5229 var cell = Roo.get(el);
5231 if(!cell || (!this.CellSelection && !this.RowSelection)){
5235 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5236 cell = cell.findParent('td', false, true);
5239 var row = cell.findParent('tr', false, true);
5240 var cellIndex = cell.dom.cellIndex;
5241 var rowIndex = row.dom.rowIndex - 1;
5243 if(this.CellSelection){
5244 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5247 if(this.RowSelection){
5248 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5252 sort : function(e,el)
5254 var col = Roo.get(el)
5256 if(!col.hasClass('sortable')){
5260 var sort = col.attr('sort');
5263 if(col.hasClass('glyphicon-arrow-up')){
5267 this.store.sortInfo = {field : sort, direction : dir};
5270 Roo.log("calling footer first");
5271 this.footer.onClick('first');
5274 this.store.load({ params : { start : 0 } });
5278 renderHeader : function()
5287 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5289 var config = cm.config[i];
5294 html: cm.getColumnHeader(i)
5297 if(typeof(config.hidden) != 'undefined' && config.hidden){
5298 c.style += ' display:none;';
5301 if(typeof(config.dataIndex) != 'undefined'){
5302 c.sort = config.dataIndex;
5305 if(typeof(config.sortable) != 'undefined' && config.sortable){
5309 if(typeof(config.align) != 'undefined' && config.align.length){
5310 c.style += ' text-align:' + config.align + ';';
5313 if(typeof(config.width) != 'undefined'){
5314 c.style += ' width:' + config.width + 'px;';
5323 renderBody : function()
5333 colspan : this.cm.getColumnCount()
5343 renderFooter : function()
5353 colspan : this.cm.getColumnCount()
5367 Roo.log('ds onload');
5372 var ds = this.store;
5374 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5375 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5377 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5378 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5381 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5382 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5386 var tbody = this.mainBody;
5388 if(ds.getCount() > 0){
5389 ds.data.each(function(d,rowIndex){
5390 var row = this.renderRow(cm, ds, rowIndex);
5392 tbody.createChild(row);
5396 if(row.cellObjects.length){
5397 Roo.each(row.cellObjects, function(r){
5398 _this.renderCellObject(r);
5405 Roo.each(this.el.select('tbody td', true).elements, function(e){
5406 e.on('mouseover', _this.onMouseover, _this);
5409 Roo.each(this.el.select('tbody td', true).elements, function(e){
5410 e.on('mouseout', _this.onMouseout, _this);
5413 //if(this.loadMask){
5414 // this.maskEl.hide();
5419 onUpdate : function(ds,record)
5421 this.refreshRow(record);
5423 onRemove : function(ds, record, index, isUpdate){
5424 if(isUpdate !== true){
5425 this.fireEvent("beforerowremoved", this, index, record);
5427 var bt = this.mainBody.dom;
5429 bt.removeChild(bt.rows[index]);
5432 if(isUpdate !== true){
5433 //this.stripeRows(index);
5434 //this.syncRowHeights(index, index);
5436 this.fireEvent("rowremoved", this, index, record);
5441 refreshRow : function(record){
5442 var ds = this.store, index;
5443 if(typeof record == 'number'){
5445 record = ds.getAt(index);
5447 index = ds.indexOf(record);
5449 this.insertRow(ds, index, true);
5450 this.onRemove(ds, record, index+1, true);
5451 //this.syncRowHeights(index, index);
5453 this.fireEvent("rowupdated", this, index, record);
5456 insertRow : function(dm, rowIndex, isUpdate){
5459 this.fireEvent("beforerowsinserted", this, rowIndex);
5461 //var s = this.getScrollState();
5462 var row = this.renderRow(this.cm, this.store, rowIndex);
5463 // insert before rowIndex..
5464 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5468 if(row.cellObjects.length){
5469 Roo.each(row.cellObjects, function(r){
5470 _this.renderCellObject(r);
5475 this.fireEvent("rowsinserted", this, rowIndex);
5476 //this.syncRowHeights(firstRow, lastRow);
5477 //this.stripeRows(firstRow);
5484 getRowDom : function(rowIndex)
5486 // not sure if I need to check this.. but let's do it anyway..
5487 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5488 this.mainBody.dom.rows[rowIndex] : false
5490 // returns the object tree for a tr..
5493 renderRow : function(cm, ds, rowIndex) {
5495 var d = ds.getAt(rowIndex);
5502 var cellObjects = [];
5504 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5505 var config = cm.config[i];
5507 var renderer = cm.getRenderer(i);
5511 if(typeof(renderer) !== 'undefined'){
5512 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5514 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5515 // and are rendered into the cells after the row is rendered - using the id for the element.
5517 if(typeof(value) === 'object'){
5527 rowIndex : rowIndex,
5532 this.fireEvent('rowclass', this, rowcfg);
5536 cls : rowcfg.rowClass,
5538 html: (typeof(value) === 'object') ? '' : value
5545 if(typeof(config.hidden) != 'undefined' && config.hidden){
5546 td.style += ' display:none;';
5549 if(typeof(config.align) != 'undefined' && config.align.length){
5550 td.style += ' text-align:' + config.align + ';';
5553 if(typeof(config.width) != 'undefined'){
5554 td.style += ' width:' + config.width + 'px;';
5561 row.cellObjects = cellObjects;
5569 onBeforeLoad : function()
5571 //Roo.log('ds onBeforeLoad');
5575 //if(this.loadMask){
5576 // this.maskEl.show();
5582 this.el.select('tbody', true).first().dom.innerHTML = '';
5585 getSelectionModel : function(){
5587 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5589 return this.selModel;
5592 * Render the Roo.bootstrap object from renderder
5594 renderCellObject : function(r)
5598 var t = r.cfg.render(r.container);
5601 Roo.each(r.cfg.cn, function(c){
5603 container: t.getChildContainer(),
5606 _this.renderCellObject(child);
5623 * @class Roo.bootstrap.TableCell
5624 * @extends Roo.bootstrap.Component
5625 * Bootstrap TableCell class
5626 * @cfg {String} html cell contain text
5627 * @cfg {String} cls cell class
5628 * @cfg {String} tag cell tag (td|th) default td
5629 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5630 * @cfg {String} align Aligns the content in a cell
5631 * @cfg {String} axis Categorizes cells
5632 * @cfg {String} bgcolor Specifies the background color of a cell
5633 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5634 * @cfg {Number} colspan Specifies the number of columns a cell should span
5635 * @cfg {String} headers Specifies one or more header cells a cell is related to
5636 * @cfg {Number} height Sets the height of a cell
5637 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5638 * @cfg {Number} rowspan Sets the number of rows a cell should span
5639 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5640 * @cfg {String} valign Vertical aligns the content in a cell
5641 * @cfg {Number} width Specifies the width of a cell
5644 * Create a new TableCell
5645 * @param {Object} config The config object
5648 Roo.bootstrap.TableCell = function(config){
5649 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5652 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5672 getAutoCreate : function(){
5673 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5693 cfg.align=this.align
5699 cfg.bgcolor=this.bgcolor
5702 cfg.charoff=this.charoff
5705 cfg.colspan=this.colspan
5708 cfg.headers=this.headers
5711 cfg.height=this.height
5714 cfg.nowrap=this.nowrap
5717 cfg.rowspan=this.rowspan
5720 cfg.scope=this.scope
5723 cfg.valign=this.valign
5726 cfg.width=this.width
5745 * @class Roo.bootstrap.TableRow
5746 * @extends Roo.bootstrap.Component
5747 * Bootstrap TableRow class
5748 * @cfg {String} cls row class
5749 * @cfg {String} align Aligns the content in a table row
5750 * @cfg {String} bgcolor Specifies a background color for a table row
5751 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5752 * @cfg {String} valign Vertical aligns the content in a table row
5755 * Create a new TableRow
5756 * @param {Object} config The config object
5759 Roo.bootstrap.TableRow = function(config){
5760 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5763 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5771 getAutoCreate : function(){
5772 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5782 cfg.align = this.align;
5785 cfg.bgcolor = this.bgcolor;
5788 cfg.charoff = this.charoff;
5791 cfg.valign = this.valign;
5809 * @class Roo.bootstrap.TableBody
5810 * @extends Roo.bootstrap.Component
5811 * Bootstrap TableBody class
5812 * @cfg {String} cls element class
5813 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5814 * @cfg {String} align Aligns the content inside the element
5815 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5816 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5819 * Create a new TableBody
5820 * @param {Object} config The config object
5823 Roo.bootstrap.TableBody = function(config){
5824 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5827 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5835 getAutoCreate : function(){
5836 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5850 cfg.align = this.align;
5853 cfg.charoff = this.charoff;
5856 cfg.valign = this.valign;
5863 // initEvents : function()
5870 // this.store = Roo.factory(this.store, Roo.data);
5871 // this.store.on('load', this.onLoad, this);
5873 // this.store.load();
5877 // onLoad: function ()
5879 // this.fireEvent('load', this);
5889 * Ext JS Library 1.1.1
5890 * Copyright(c) 2006-2007, Ext JS, LLC.
5892 * Originally Released Under LGPL - original licence link has changed is not relivant.
5895 * <script type="text/javascript">
5898 // as we use this in bootstrap.
5899 Roo.namespace('Roo.form');
5901 * @class Roo.form.Action
5902 * Internal Class used to handle form actions
5904 * @param {Roo.form.BasicForm} el The form element or its id
5905 * @param {Object} config Configuration options
5910 // define the action interface
5911 Roo.form.Action = function(form, options){
5913 this.options = options || {};
5916 * Client Validation Failed
5919 Roo.form.Action.CLIENT_INVALID = 'client';
5921 * Server Validation Failed
5924 Roo.form.Action.SERVER_INVALID = 'server';
5926 * Connect to Server Failed
5929 Roo.form.Action.CONNECT_FAILURE = 'connect';
5931 * Reading Data from Server Failed
5934 Roo.form.Action.LOAD_FAILURE = 'load';
5936 Roo.form.Action.prototype = {
5938 failureType : undefined,
5939 response : undefined,
5943 run : function(options){
5948 success : function(response){
5953 handleResponse : function(response){
5957 // default connection failure
5958 failure : function(response){
5960 this.response = response;
5961 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5962 this.form.afterAction(this, false);
5965 processResponse : function(response){
5966 this.response = response;
5967 if(!response.responseText){
5970 this.result = this.handleResponse(response);
5974 // utility functions used internally
5975 getUrl : function(appendParams){
5976 var url = this.options.url || this.form.url || this.form.el.dom.action;
5978 var p = this.getParams();
5980 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5986 getMethod : function(){
5987 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5990 getParams : function(){
5991 var bp = this.form.baseParams;
5992 var p = this.options.params;
5994 if(typeof p == "object"){
5995 p = Roo.urlEncode(Roo.applyIf(p, bp));
5996 }else if(typeof p == 'string' && bp){
5997 p += '&' + Roo.urlEncode(bp);
6000 p = Roo.urlEncode(bp);
6005 createCallback : function(){
6007 success: this.success,
6008 failure: this.failure,
6010 timeout: (this.form.timeout*1000),
6011 upload: this.form.fileUpload ? this.success : undefined
6016 Roo.form.Action.Submit = function(form, options){
6017 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6020 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6023 haveProgress : false,
6024 uploadComplete : false,
6026 // uploadProgress indicator.
6027 uploadProgress : function()
6029 if (!this.form.progressUrl) {
6033 if (!this.haveProgress) {
6034 Roo.MessageBox.progress("Uploading", "Uploading");
6036 if (this.uploadComplete) {
6037 Roo.MessageBox.hide();
6041 this.haveProgress = true;
6043 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6045 var c = new Roo.data.Connection();
6047 url : this.form.progressUrl,
6052 success : function(req){
6053 //console.log(data);
6057 rdata = Roo.decode(req.responseText)
6059 Roo.log("Invalid data from server..");
6063 if (!rdata || !rdata.success) {
6065 Roo.MessageBox.alert(Roo.encode(rdata));
6068 var data = rdata.data;
6070 if (this.uploadComplete) {
6071 Roo.MessageBox.hide();
6076 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6077 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6080 this.uploadProgress.defer(2000,this);
6083 failure: function(data) {
6084 Roo.log('progress url failed ');
6095 // run get Values on the form, so it syncs any secondary forms.
6096 this.form.getValues();
6098 var o = this.options;
6099 var method = this.getMethod();
6100 var isPost = method == 'POST';
6101 if(o.clientValidation === false || this.form.isValid()){
6103 if (this.form.progressUrl) {
6104 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6105 (new Date() * 1) + '' + Math.random());
6110 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6111 form:this.form.el.dom,
6112 url:this.getUrl(!isPost),
6114 params:isPost ? this.getParams() : null,
6115 isUpload: this.form.fileUpload
6118 this.uploadProgress();
6120 }else if (o.clientValidation !== false){ // client validation failed
6121 this.failureType = Roo.form.Action.CLIENT_INVALID;
6122 this.form.afterAction(this, false);
6126 success : function(response)
6128 this.uploadComplete= true;
6129 if (this.haveProgress) {
6130 Roo.MessageBox.hide();
6134 var result = this.processResponse(response);
6135 if(result === true || result.success){
6136 this.form.afterAction(this, true);
6140 this.form.markInvalid(result.errors);
6141 this.failureType = Roo.form.Action.SERVER_INVALID;
6143 this.form.afterAction(this, false);
6145 failure : function(response)
6147 this.uploadComplete= true;
6148 if (this.haveProgress) {
6149 Roo.MessageBox.hide();
6152 this.response = response;
6153 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6154 this.form.afterAction(this, false);
6157 handleResponse : function(response){
6158 if(this.form.errorReader){
6159 var rs = this.form.errorReader.read(response);
6162 for(var i = 0, len = rs.records.length; i < len; i++) {
6163 var r = rs.records[i];
6167 if(errors.length < 1){
6171 success : rs.success,
6177 ret = Roo.decode(response.responseText);
6181 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6191 Roo.form.Action.Load = function(form, options){
6192 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6193 this.reader = this.form.reader;
6196 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6201 Roo.Ajax.request(Roo.apply(
6202 this.createCallback(), {
6203 method:this.getMethod(),
6204 url:this.getUrl(false),
6205 params:this.getParams()
6209 success : function(response){
6211 var result = this.processResponse(response);
6212 if(result === true || !result.success || !result.data){
6213 this.failureType = Roo.form.Action.LOAD_FAILURE;
6214 this.form.afterAction(this, false);
6217 this.form.clearInvalid();
6218 this.form.setValues(result.data);
6219 this.form.afterAction(this, true);
6222 handleResponse : function(response){
6223 if(this.form.reader){
6224 var rs = this.form.reader.read(response);
6225 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6227 success : rs.success,
6231 return Roo.decode(response.responseText);
6235 Roo.form.Action.ACTION_TYPES = {
6236 'load' : Roo.form.Action.Load,
6237 'submit' : Roo.form.Action.Submit
6246 * @class Roo.bootstrap.Form
6247 * @extends Roo.bootstrap.Component
6248 * Bootstrap Form class
6249 * @cfg {String} method GET | POST (default POST)
6250 * @cfg {String} labelAlign top | left (default top)
6251 * @cfg {String} align left | right - for navbars
6252 * @cfg {Boolean} loadMask load mask when submit (default true)
6257 * @param {Object} config The config object
6261 Roo.bootstrap.Form = function(config){
6262 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6265 * @event clientvalidation
6266 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6267 * @param {Form} this
6268 * @param {Boolean} valid true if the form has passed client-side validation
6270 clientvalidation: true,
6272 * @event beforeaction
6273 * Fires before any action is performed. Return false to cancel the action.
6274 * @param {Form} this
6275 * @param {Action} action The action to be performed
6279 * @event actionfailed
6280 * Fires when an action fails.
6281 * @param {Form} this
6282 * @param {Action} action The action that failed
6284 actionfailed : true,
6286 * @event actioncomplete
6287 * Fires when an action is completed.
6288 * @param {Form} this
6289 * @param {Action} action The action that completed
6291 actioncomplete : true
6296 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6299 * @cfg {String} method
6300 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6305 * The URL to use for form actions if one isn't supplied in the action options.
6308 * @cfg {Boolean} fileUpload
6309 * Set to true if this form is a file upload.
6313 * @cfg {Object} baseParams
6314 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6318 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6322 * @cfg {Sting} align (left|right) for navbar forms
6327 activeAction : null,
6330 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6331 * element by passing it or its id or mask the form itself by passing in true.
6334 waitMsgTarget : false,
6338 getAutoCreate : function(){
6342 method : this.method || 'POST',
6343 id : this.id || Roo.id(),
6346 if (this.parent().xtype.match(/^Nav/)) {
6347 cfg.cls = 'navbar-form navbar-' + this.align;
6351 if (this.labelAlign == 'left' ) {
6352 cfg.cls += ' form-horizontal';
6358 initEvents : function()
6360 this.el.on('submit', this.onSubmit, this);
6361 // this was added as random key presses on the form where triggering form submit.
6362 this.el.on('keypress', function(e) {
6363 if (e.getCharCode() != 13) {
6366 // we might need to allow it for textareas.. and some other items.
6367 // check e.getTarget().
6369 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6373 Roo.log("keypress blocked");
6381 onSubmit : function(e){
6386 * Returns true if client-side validation on the form is successful.
6389 isValid : function(){
6390 var items = this.getItems();
6392 items.each(function(f){
6401 * Returns true if any fields in this form have changed since their original load.
6404 isDirty : function(){
6406 var items = this.getItems();
6407 items.each(function(f){
6417 * Performs a predefined action (submit or load) or custom actions you define on this form.
6418 * @param {String} actionName The name of the action type
6419 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6420 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6421 * accept other config options):
6423 Property Type Description
6424 ---------------- --------------- ----------------------------------------------------------------------------------
6425 url String The url for the action (defaults to the form's url)
6426 method String The form method to use (defaults to the form's method, or POST if not defined)
6427 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6428 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6429 validate the form on the client (defaults to false)
6431 * @return {BasicForm} this
6433 doAction : function(action, options){
6434 if(typeof action == 'string'){
6435 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6437 if(this.fireEvent('beforeaction', this, action) !== false){
6438 this.beforeAction(action);
6439 action.run.defer(100, action);
6445 beforeAction : function(action){
6446 var o = action.options;
6449 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6451 // not really supported yet.. ??
6453 //if(this.waitMsgTarget === true){
6454 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6455 //}else if(this.waitMsgTarget){
6456 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6457 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6459 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6465 afterAction : function(action, success){
6466 this.activeAction = null;
6467 var o = action.options;
6469 //if(this.waitMsgTarget === true){
6471 //}else if(this.waitMsgTarget){
6472 // this.waitMsgTarget.unmask();
6474 // Roo.MessageBox.updateProgress(1);
6475 // Roo.MessageBox.hide();
6482 Roo.callback(o.success, o.scope, [this, action]);
6483 this.fireEvent('actioncomplete', this, action);
6487 // failure condition..
6488 // we have a scenario where updates need confirming.
6489 // eg. if a locking scenario exists..
6490 // we look for { errors : { needs_confirm : true }} in the response.
6492 (typeof(action.result) != 'undefined') &&
6493 (typeof(action.result.errors) != 'undefined') &&
6494 (typeof(action.result.errors.needs_confirm) != 'undefined')
6497 Roo.log("not supported yet");
6500 Roo.MessageBox.confirm(
6501 "Change requires confirmation",
6502 action.result.errorMsg,
6507 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6517 Roo.callback(o.failure, o.scope, [this, action]);
6518 // show an error message if no failed handler is set..
6519 if (!this.hasListener('actionfailed')) {
6520 Roo.log("need to add dialog support");
6522 Roo.MessageBox.alert("Error",
6523 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6524 action.result.errorMsg :
6525 "Saving Failed, please check your entries or try again"
6530 this.fireEvent('actionfailed', this, action);
6535 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6536 * @param {String} id The value to search for
6539 findField : function(id){
6540 var items = this.getItems();
6541 var field = items.get(id);
6543 items.each(function(f){
6544 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6551 return field || null;
6554 * Mark fields in this form invalid in bulk.
6555 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6556 * @return {BasicForm} this
6558 markInvalid : function(errors){
6559 if(errors instanceof Array){
6560 for(var i = 0, len = errors.length; i < len; i++){
6561 var fieldError = errors[i];
6562 var f = this.findField(fieldError.id);
6564 f.markInvalid(fieldError.msg);
6570 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6571 field.markInvalid(errors[id]);
6575 //Roo.each(this.childForms || [], function (f) {
6576 // f.markInvalid(errors);
6583 * Set values for fields in this form in bulk.
6584 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6585 * @return {BasicForm} this
6587 setValues : function(values){
6588 if(values instanceof Array){ // array of objects
6589 for(var i = 0, len = values.length; i < len; i++){
6591 var f = this.findField(v.id);
6593 f.setValue(v.value);
6594 if(this.trackResetOnLoad){
6595 f.originalValue = f.getValue();
6599 }else{ // object hash
6602 if(typeof values[id] != 'function' && (field = this.findField(id))){
6604 if (field.setFromData &&
6606 field.displayField &&
6607 // combos' with local stores can
6608 // be queried via setValue()
6609 // to set their value..
6610 (field.store && !field.store.isLocal)
6614 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6615 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6616 field.setFromData(sd);
6619 field.setValue(values[id]);
6623 if(this.trackResetOnLoad){
6624 field.originalValue = field.getValue();
6630 //Roo.each(this.childForms || [], function (f) {
6631 // f.setValues(values);
6638 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6639 * they are returned as an array.
6640 * @param {Boolean} asString
6643 getValues : function(asString){
6644 //if (this.childForms) {
6645 // copy values from the child forms
6646 // Roo.each(this.childForms, function (f) {
6647 // this.setValues(f.getValues());
6653 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6654 if(asString === true){
6657 return Roo.urlDecode(fs);
6661 * Returns the fields in this form as an object with key/value pairs.
6662 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6665 getFieldValues : function(with_hidden)
6667 var items = this.getItems();
6669 items.each(function(f){
6673 var v = f.getValue();
6674 if (f.inputType =='radio') {
6675 if (typeof(ret[f.getName()]) == 'undefined') {
6676 ret[f.getName()] = ''; // empty..
6679 if (!f.el.dom.checked) {
6687 // not sure if this supported any more..
6688 if ((typeof(v) == 'object') && f.getRawValue) {
6689 v = f.getRawValue() ; // dates..
6691 // combo boxes where name != hiddenName...
6692 if (f.name != f.getName()) {
6693 ret[f.name] = f.getRawValue();
6695 ret[f.getName()] = v;
6702 * Clears all invalid messages in this form.
6703 * @return {BasicForm} this
6705 clearInvalid : function(){
6706 var items = this.getItems();
6708 items.each(function(f){
6719 * @return {BasicForm} this
6722 var items = this.getItems();
6723 items.each(function(f){
6727 Roo.each(this.childForms || [], function (f) {
6734 getItems : function()
6736 var r=new Roo.util.MixedCollection(false, function(o){
6737 return o.id || (o.id = Roo.id());
6739 var iter = function(el) {
6746 Roo.each(el.items,function(e) {
6765 * Ext JS Library 1.1.1
6766 * Copyright(c) 2006-2007, Ext JS, LLC.
6768 * Originally Released Under LGPL - original licence link has changed is not relivant.
6771 * <script type="text/javascript">
6774 * @class Roo.form.VTypes
6775 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6778 Roo.form.VTypes = function(){
6779 // closure these in so they are only created once.
6780 var alpha = /^[a-zA-Z_]+$/;
6781 var alphanum = /^[a-zA-Z0-9_]+$/;
6782 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6783 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6785 // All these messages and functions are configurable
6788 * The function used to validate email addresses
6789 * @param {String} value The email address
6791 'email' : function(v){
6792 return email.test(v);
6795 * The error text to display when the email validation function returns false
6798 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6800 * The keystroke filter mask to be applied on email input
6803 'emailMask' : /[a-z0-9_\.\-@]/i,
6806 * The function used to validate URLs
6807 * @param {String} value The URL
6809 'url' : function(v){
6813 * The error text to display when the url validation function returns false
6816 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6819 * The function used to validate alpha values
6820 * @param {String} value The value
6822 'alpha' : function(v){
6823 return alpha.test(v);
6826 * The error text to display when the alpha validation function returns false
6829 'alphaText' : 'This field should only contain letters and _',
6831 * The keystroke filter mask to be applied on alpha input
6834 'alphaMask' : /[a-z_]/i,
6837 * The function used to validate alphanumeric values
6838 * @param {String} value The value
6840 'alphanum' : function(v){
6841 return alphanum.test(v);
6844 * The error text to display when the alphanumeric validation function returns false
6847 'alphanumText' : 'This field should only contain letters, numbers and _',
6849 * The keystroke filter mask to be applied on alphanumeric input
6852 'alphanumMask' : /[a-z0-9_]/i
6862 * @class Roo.bootstrap.Input
6863 * @extends Roo.bootstrap.Component
6864 * Bootstrap Input class
6865 * @cfg {Boolean} disabled is it disabled
6866 * @cfg {String} fieldLabel - the label associated
6867 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6868 * @cfg {String} name name of the input
6869 * @cfg {string} fieldLabel - the label associated
6870 * @cfg {string} inputType - input / file submit ...
6871 * @cfg {string} placeholder - placeholder to put in text.
6872 * @cfg {string} before - input group add on before
6873 * @cfg {string} after - input group add on after
6874 * @cfg {string} size - (lg|sm) or leave empty..
6875 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6876 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6877 * @cfg {Number} md colspan out of 12 for computer-sized screens
6878 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6879 * @cfg {string} value default value of the input
6880 * @cfg {Number} labelWidth set the width of label (0-12)
6881 * @cfg {String} labelAlign (top|left)
6882 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6883 * @cfg {String} align (left|center|right) Default left
6887 * Create a new Input
6888 * @param {Object} config The config object
6891 Roo.bootstrap.Input = function(config){
6892 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6897 * Fires when this field receives input focus.
6898 * @param {Roo.form.Field} this
6903 * Fires when this field loses input focus.
6904 * @param {Roo.form.Field} this
6909 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6910 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6911 * @param {Roo.form.Field} this
6912 * @param {Roo.EventObject} e The event object
6917 * Fires just before the field blurs if the field value has changed.
6918 * @param {Roo.form.Field} this
6919 * @param {Mixed} newValue The new value
6920 * @param {Mixed} oldValue The original value
6925 * Fires after the field has been marked as invalid.
6926 * @param {Roo.form.Field} this
6927 * @param {String} msg The validation message
6932 * Fires after the field has been validated with no errors.
6933 * @param {Roo.form.Field} this
6938 * Fires after the key up
6939 * @param {Roo.form.Field} this
6940 * @param {Roo.EventObject} e The event Object
6946 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6948 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6949 automatic validation (defaults to "keyup").
6951 validationEvent : "keyup",
6953 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6955 validateOnBlur : true,
6957 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6959 validationDelay : 250,
6961 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6963 focusClass : "x-form-focus", // not needed???
6967 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6969 invalidClass : "has-error",
6972 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6974 selectOnFocus : false,
6977 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6981 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6986 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6988 disableKeyFilter : false,
6991 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6995 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6999 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7001 blankText : "This field is required",
7004 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7008 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7010 maxLength : Number.MAX_VALUE,
7012 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7014 minLengthText : "The minimum length for this field is {0}",
7016 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7018 maxLengthText : "The maximum length for this field is {0}",
7022 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7023 * If available, this function will be called only after the basic validators all return true, and will be passed the
7024 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7028 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7029 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7030 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7034 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7057 formatedValue : false,
7059 parentLabelAlign : function()
7062 while (parent.parent()) {
7063 parent = parent.parent();
7064 if (typeof(parent.labelAlign) !='undefined') {
7065 return parent.labelAlign;
7072 getAutoCreate : function(){
7074 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7080 if(this.inputType != 'hidden'){
7081 cfg.cls = 'form-group' //input-group
7087 type : this.inputType,
7089 cls : 'form-control',
7090 placeholder : this.placeholder || ''
7095 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7098 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7099 input.maxLength = this.maxLength;
7102 if (this.disabled) {
7103 input.disabled=true;
7106 if (this.readOnly) {
7107 input.readonly=true;
7111 input.name = this.name;
7114 input.cls += ' input-' + this.size;
7117 ['xs','sm','md','lg'].map(function(size){
7118 if (settings[size]) {
7119 cfg.cls += ' col-' + size + '-' + settings[size];
7123 var inputblock = input;
7125 if (this.before || this.after) {
7128 cls : 'input-group',
7131 if (this.before && typeof(this.before) == 'string') {
7133 inputblock.cn.push({
7135 cls : 'roo-input-before input-group-addon',
7139 if (this.before && typeof(this.before) == 'object') {
7140 this.before = Roo.factory(this.before);
7141 Roo.log(this.before);
7142 inputblock.cn.push({
7144 cls : 'roo-input-before input-group-' +
7145 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7149 inputblock.cn.push(input);
7151 if (this.after && typeof(this.after) == 'string') {
7152 inputblock.cn.push({
7154 cls : 'roo-input-after input-group-addon',
7158 if (this.after && typeof(this.after) == 'object') {
7159 this.after = Roo.factory(this.after);
7160 Roo.log(this.after);
7161 inputblock.cn.push({
7163 cls : 'roo-input-after input-group-' +
7164 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7169 if (align ==='left' && this.fieldLabel.length) {
7170 Roo.log("left and has label");
7176 cls : 'control-label col-sm-' + this.labelWidth,
7177 html : this.fieldLabel
7181 cls : "col-sm-" + (12 - this.labelWidth),
7188 } else if ( this.fieldLabel.length) {
7194 //cls : 'input-group-addon',
7195 html : this.fieldLabel
7205 Roo.log(" no label && no align");
7214 Roo.log('input-parentType: ' + this.parentType);
7216 if (this.parentType === 'Navbar' && this.parent().bar) {
7217 cfg.cls += ' navbar-form';
7225 * return the real input element.
7227 inputEl: function ()
7229 return this.el.select('input.form-control',true).first();
7232 tooltipEl : function()
7234 return this.inputEl();
7237 setDisabled : function(v)
7239 var i = this.inputEl().dom;
7241 i.removeAttribute('disabled');
7245 i.setAttribute('disabled','true');
7247 initEvents : function()
7249 Roo.bootstrap.Input.superclass.initEvents();
7251 this.inputEl().on("keydown" , this.fireKey, this);
7252 this.inputEl().on("focus", this.onFocus, this);
7253 this.inputEl().on("blur", this.onBlur, this);
7255 this.inputEl().relayEvent('keyup', this);
7257 // reference to original value for reset
7258 this.originalValue = this.getValue();
7259 //Roo.form.TextField.superclass.initEvents.call(this);
7260 if(this.validationEvent == 'keyup'){
7261 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7262 this.inputEl().on('keyup', this.filterValidation, this);
7264 else if(this.validationEvent !== false){
7265 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7268 if(this.selectOnFocus){
7269 this.on("focus", this.preFocus, this);
7272 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7273 this.inputEl().on("keypress", this.filterKeys, this);
7276 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7277 this.el.on("click", this.autoSize, this);
7280 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7281 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7284 if (typeof(this.before) == 'object') {
7285 this.before.render(this.el.select('.roo-input-before',true).first());
7287 if (typeof(this.after) == 'object') {
7288 this.after.render(this.el.select('.roo-input-after',true).first());
7293 filterValidation : function(e){
7294 if(!e.isNavKeyPress()){
7295 this.validationTask.delay(this.validationDelay);
7299 * Validates the field value
7300 * @return {Boolean} True if the value is valid, else false
7302 validate : function(){
7303 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7304 if(this.disabled || this.validateValue(this.getRawValue())){
7305 this.clearInvalid();
7313 * Validates a value according to the field's validation rules and marks the field as invalid
7314 * if the validation fails
7315 * @param {Mixed} value The value to validate
7316 * @return {Boolean} True if the value is valid, else false
7318 validateValue : function(value){
7319 if(value.length < 1) { // if it's blank
7320 if(this.allowBlank){
7321 this.clearInvalid();
7324 this.markInvalid(this.blankText);
7328 if(value.length < this.minLength){
7329 this.markInvalid(String.format(this.minLengthText, this.minLength));
7332 if(value.length > this.maxLength){
7333 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7337 var vt = Roo.form.VTypes;
7338 if(!vt[this.vtype](value, this)){
7339 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7343 if(typeof this.validator == "function"){
7344 var msg = this.validator(value);
7346 this.markInvalid(msg);
7350 if(this.regex && !this.regex.test(value)){
7351 this.markInvalid(this.regexText);
7360 fireKey : function(e){
7361 //Roo.log('field ' + e.getKey());
7362 if(e.isNavKeyPress()){
7363 this.fireEvent("specialkey", this, e);
7366 focus : function (selectText){
7368 this.inputEl().focus();
7369 if(selectText === true){
7370 this.inputEl().dom.select();
7376 onFocus : function(){
7377 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7378 // this.el.addClass(this.focusClass);
7381 this.hasFocus = true;
7382 this.startValue = this.getValue();
7383 this.fireEvent("focus", this);
7387 beforeBlur : Roo.emptyFn,
7391 onBlur : function(){
7393 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7394 //this.el.removeClass(this.focusClass);
7396 this.hasFocus = false;
7397 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7400 var v = this.getValue();
7401 if(String(v) !== String(this.startValue)){
7402 this.fireEvent('change', this, v, this.startValue);
7404 this.fireEvent("blur", this);
7408 * Resets the current field value to the originally loaded value and clears any validation messages
7411 this.setValue(this.originalValue);
7412 this.clearInvalid();
7415 * Returns the name of the field
7416 * @return {Mixed} name The name field
7418 getName: function(){
7422 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7423 * @return {Mixed} value The field value
7425 getValue : function(){
7427 var v = this.inputEl().getValue();
7432 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7433 * @return {Mixed} value The field value
7435 getRawValue : function(){
7436 var v = this.inputEl().getValue();
7442 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7443 * @param {Mixed} value The value to set
7445 setRawValue : function(v){
7446 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7449 selectText : function(start, end){
7450 var v = this.getRawValue();
7452 start = start === undefined ? 0 : start;
7453 end = end === undefined ? v.length : end;
7454 var d = this.inputEl().dom;
7455 if(d.setSelectionRange){
7456 d.setSelectionRange(start, end);
7457 }else if(d.createTextRange){
7458 var range = d.createTextRange();
7459 range.moveStart("character", start);
7460 range.moveEnd("character", v.length-end);
7467 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7468 * @param {Mixed} value The value to set
7470 setValue : function(v){
7473 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7479 processValue : function(value){
7480 if(this.stripCharsRe){
7481 var newValue = value.replace(this.stripCharsRe, '');
7482 if(newValue !== value){
7483 this.setRawValue(newValue);
7490 preFocus : function(){
7492 if(this.selectOnFocus){
7493 this.inputEl().dom.select();
7496 filterKeys : function(e){
7498 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7501 var c = e.getCharCode(), cc = String.fromCharCode(c);
7502 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7505 if(!this.maskRe.test(cc)){
7510 * Clear any invalid styles/messages for this field
7512 clearInvalid : function(){
7514 if(!this.el || this.preventMark){ // not rendered
7517 this.el.removeClass(this.invalidClass);
7519 switch(this.msgTarget){
7521 this.el.dom.qtip = '';
7524 this.el.dom.title = '';
7528 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7533 this.errorIcon.dom.qtip = '';
7534 this.errorIcon.hide();
7535 this.un('resize', this.alignErrorIcon, this);
7539 var t = Roo.getDom(this.msgTarget);
7541 t.style.display = 'none';
7545 this.fireEvent('valid', this);
7548 * Mark this field as invalid
7549 * @param {String} msg The validation message
7551 markInvalid : function(msg){
7552 if(!this.el || this.preventMark){ // not rendered
7555 this.el.addClass(this.invalidClass);
7557 msg = msg || this.invalidText;
7558 switch(this.msgTarget){
7560 this.el.dom.qtip = msg;
7561 this.el.dom.qclass = 'x-form-invalid-tip';
7562 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7563 Roo.QuickTips.enable();
7567 this.el.dom.title = msg;
7571 var elp = this.el.findParent('.x-form-element', 5, true);
7572 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7573 this.errorEl.setWidth(elp.getWidth(true)-20);
7575 this.errorEl.update(msg);
7576 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7579 if(!this.errorIcon){
7580 var elp = this.el.findParent('.x-form-element', 5, true);
7581 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7583 this.alignErrorIcon();
7584 this.errorIcon.dom.qtip = msg;
7585 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7586 this.errorIcon.show();
7587 this.on('resize', this.alignErrorIcon, this);
7590 var t = Roo.getDom(this.msgTarget);
7592 t.style.display = this.msgDisplay;
7596 this.fireEvent('invalid', this, msg);
7599 SafariOnKeyDown : function(event)
7601 // this is a workaround for a password hang bug on chrome/ webkit.
7603 var isSelectAll = false;
7605 if(this.inputEl().dom.selectionEnd > 0){
7606 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7608 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7609 event.preventDefault();
7614 if(isSelectAll){ // backspace and delete key
7616 event.preventDefault();
7617 // this is very hacky as keydown always get's upper case.
7619 var cc = String.fromCharCode(event.getCharCode());
7620 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7624 adjustWidth : function(tag, w){
7625 tag = tag.toLowerCase();
7626 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7627 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7631 if(tag == 'textarea'){
7634 }else if(Roo.isOpera){
7638 if(tag == 'textarea'){
7657 * @class Roo.bootstrap.TextArea
7658 * @extends Roo.bootstrap.Input
7659 * Bootstrap TextArea class
7660 * @cfg {Number} cols Specifies the visible width of a text area
7661 * @cfg {Number} rows Specifies the visible number of lines in a text area
7662 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7663 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7664 * @cfg {string} html text
7667 * Create a new TextArea
7668 * @param {Object} config The config object
7671 Roo.bootstrap.TextArea = function(config){
7672 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7676 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7686 getAutoCreate : function(){
7688 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7699 value : this.value || '',
7700 html: this.html || '',
7701 cls : 'form-control',
7702 placeholder : this.placeholder || ''
7706 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7707 input.maxLength = this.maxLength;
7711 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7715 input.cols = this.cols;
7718 if (this.readOnly) {
7719 input.readonly = true;
7723 input.name = this.name;
7727 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7731 ['xs','sm','md','lg'].map(function(size){
7732 if (settings[size]) {
7733 cfg.cls += ' col-' + size + '-' + settings[size];
7737 var inputblock = input;
7739 if (this.before || this.after) {
7742 cls : 'input-group',
7746 inputblock.cn.push({
7748 cls : 'input-group-addon',
7752 inputblock.cn.push(input);
7754 inputblock.cn.push({
7756 cls : 'input-group-addon',
7763 if (align ==='left' && this.fieldLabel.length) {
7764 Roo.log("left and has label");
7770 cls : 'control-label col-sm-' + this.labelWidth,
7771 html : this.fieldLabel
7775 cls : "col-sm-" + (12 - this.labelWidth),
7782 } else if ( this.fieldLabel.length) {
7788 //cls : 'input-group-addon',
7789 html : this.fieldLabel
7799 Roo.log(" no label && no align");
7809 if (this.disabled) {
7810 input.disabled=true;
7817 * return the real textarea element.
7819 inputEl: function ()
7821 return this.el.select('textarea.form-control',true).first();
7829 * trigger field - base class for combo..
7834 * @class Roo.bootstrap.TriggerField
7835 * @extends Roo.bootstrap.Input
7836 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7837 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7838 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7839 * for which you can provide a custom implementation. For example:
7841 var trigger = new Roo.bootstrap.TriggerField();
7842 trigger.onTriggerClick = myTriggerFn;
7843 trigger.applyTo('my-field');
7846 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7847 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7848 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7849 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7851 * Create a new TriggerField.
7852 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7853 * to the base TextField)
7855 Roo.bootstrap.TriggerField = function(config){
7856 this.mimicing = false;
7857 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7860 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7862 * @cfg {String} triggerClass A CSS class to apply to the trigger
7865 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7869 /** @cfg {Boolean} grow @hide */
7870 /** @cfg {Number} growMin @hide */
7871 /** @cfg {Number} growMax @hide */
7877 autoSize: Roo.emptyFn,
7884 actionMode : 'wrap',
7888 getAutoCreate : function(){
7890 var align = this.labelAlign || this.parentLabelAlign();
7895 cls: 'form-group' //input-group
7902 type : this.inputType,
7903 cls : 'form-control',
7904 autocomplete: 'off',
7905 placeholder : this.placeholder || ''
7909 input.name = this.name;
7912 input.cls += ' input-' + this.size;
7915 if (this.disabled) {
7916 input.disabled=true;
7919 var inputblock = input;
7921 if (this.before || this.after) {
7924 cls : 'input-group',
7928 inputblock.cn.push({
7930 cls : 'input-group-addon',
7934 inputblock.cn.push(input);
7936 inputblock.cn.push({
7938 cls : 'input-group-addon',
7951 cls: 'form-hidden-field'
7959 Roo.log('multiple');
7967 cls: 'form-hidden-field'
7971 cls: 'select2-choices',
7975 cls: 'select2-search-field',
7988 cls: 'select2-container input-group',
7993 // cls: 'typeahead typeahead-long dropdown-menu',
7994 // style: 'display:none'
7999 if(!this.multiple && this.showToggleBtn){
8002 cls : 'input-group-addon btn dropdown-toggle',
8010 cls: 'combobox-clear',
8024 combobox.cls += ' select2-container-multi';
8027 if (align ==='left' && this.fieldLabel.length) {
8029 Roo.log("left and has label");
8035 cls : 'control-label col-sm-' + this.labelWidth,
8036 html : this.fieldLabel
8040 cls : "col-sm-" + (12 - this.labelWidth),
8047 } else if ( this.fieldLabel.length) {
8053 //cls : 'input-group-addon',
8054 html : this.fieldLabel
8064 Roo.log(" no label && no align");
8071 ['xs','sm','md','lg'].map(function(size){
8072 if (settings[size]) {
8073 cfg.cls += ' col-' + size + '-' + settings[size];
8084 onResize : function(w, h){
8085 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8086 // if(typeof w == 'number'){
8087 // var x = w - this.trigger.getWidth();
8088 // this.inputEl().setWidth(this.adjustWidth('input', x));
8089 // this.trigger.setStyle('left', x+'px');
8094 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8097 getResizeEl : function(){
8098 return this.inputEl();
8102 getPositionEl : function(){
8103 return this.inputEl();
8107 alignErrorIcon : function(){
8108 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8112 initEvents : function(){
8116 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8117 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8118 if(!this.multiple && this.showToggleBtn){
8119 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8120 if(this.hideTrigger){
8121 this.trigger.setDisplayed(false);
8123 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8127 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8130 //this.trigger.addClassOnOver('x-form-trigger-over');
8131 //this.trigger.addClassOnClick('x-form-trigger-click');
8134 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8138 createList : function()
8140 this.list = Roo.get(document.body).createChild({
8142 cls: 'typeahead typeahead-long dropdown-menu',
8143 style: 'display:none'
8146 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8151 initTrigger : function(){
8156 onDestroy : function(){
8158 this.trigger.removeAllListeners();
8159 // this.trigger.remove();
8162 // this.wrap.remove();
8164 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8168 onFocus : function(){
8169 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8172 this.wrap.addClass('x-trigger-wrap-focus');
8173 this.mimicing = true;
8174 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8175 if(this.monitorTab){
8176 this.el.on("keydown", this.checkTab, this);
8183 checkTab : function(e){
8184 if(e.getKey() == e.TAB){
8190 onBlur : function(){
8195 mimicBlur : function(e, t){
8197 if(!this.wrap.contains(t) && this.validateBlur()){
8204 triggerBlur : function(){
8205 this.mimicing = false;
8206 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8207 if(this.monitorTab){
8208 this.el.un("keydown", this.checkTab, this);
8210 //this.wrap.removeClass('x-trigger-wrap-focus');
8211 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8215 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8216 validateBlur : function(e, t){
8221 onDisable : function(){
8222 this.inputEl().dom.disabled = true;
8223 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8225 // this.wrap.addClass('x-item-disabled');
8230 onEnable : function(){
8231 this.inputEl().dom.disabled = false;
8232 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8234 // this.el.removeClass('x-item-disabled');
8239 onShow : function(){
8240 var ae = this.getActionEl();
8243 ae.dom.style.display = '';
8244 ae.dom.style.visibility = 'visible';
8250 onHide : function(){
8251 var ae = this.getActionEl();
8252 ae.dom.style.display = 'none';
8256 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8257 * by an implementing function.
8259 * @param {EventObject} e
8261 onTriggerClick : Roo.emptyFn
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">
8276 * @class Roo.data.SortTypes
8278 * Defines the default sorting (casting?) comparison functions used when sorting data.
8280 Roo.data.SortTypes = {
8282 * Default sort that does nothing
8283 * @param {Mixed} s The value being converted
8284 * @return {Mixed} The comparison value
8291 * The regular expression used to strip tags
8295 stripTagsRE : /<\/?[^>]+>/gi,
8298 * Strips all HTML tags to sort on text only
8299 * @param {Mixed} s The value being converted
8300 * @return {String} The comparison value
8302 asText : function(s){
8303 return String(s).replace(this.stripTagsRE, "");
8307 * Strips all HTML tags to sort on text only - Case insensitive
8308 * @param {Mixed} s The value being converted
8309 * @return {String} The comparison value
8311 asUCText : function(s){
8312 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8316 * Case insensitive string
8317 * @param {Mixed} s The value being converted
8318 * @return {String} The comparison value
8320 asUCString : function(s) {
8321 return String(s).toUpperCase();
8326 * @param {Mixed} s The value being converted
8327 * @return {Number} The comparison value
8329 asDate : function(s) {
8333 if(s instanceof Date){
8336 return Date.parse(String(s));
8341 * @param {Mixed} s The value being converted
8342 * @return {Float} The comparison value
8344 asFloat : function(s) {
8345 var val = parseFloat(String(s).replace(/,/g, ""));
8346 if(isNaN(val)) val = 0;
8352 * @param {Mixed} s The value being converted
8353 * @return {Number} The comparison value
8355 asInt : function(s) {
8356 var val = parseInt(String(s).replace(/,/g, ""));
8357 if(isNaN(val)) val = 0;
8362 * Ext JS Library 1.1.1
8363 * Copyright(c) 2006-2007, Ext JS, LLC.
8365 * Originally Released Under LGPL - original licence link has changed is not relivant.
8368 * <script type="text/javascript">
8372 * @class Roo.data.Record
8373 * Instances of this class encapsulate both record <em>definition</em> information, and record
8374 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8375 * to access Records cached in an {@link Roo.data.Store} object.<br>
8377 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8378 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8381 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8383 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8384 * {@link #create}. The parameters are the same.
8385 * @param {Array} data An associative Array of data values keyed by the field name.
8386 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8387 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8388 * not specified an integer id is generated.
8390 Roo.data.Record = function(data, id){
8391 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8396 * Generate a constructor for a specific record layout.
8397 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8398 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8399 * Each field definition object may contain the following properties: <ul>
8400 * <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,
8401 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8402 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8403 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8404 * is being used, then this is a string containing the javascript expression to reference the data relative to
8405 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8406 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8407 * this may be omitted.</p></li>
8408 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8409 * <ul><li>auto (Default, implies no conversion)</li>
8414 * <li>date</li></ul></p></li>
8415 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8416 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8417 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8418 * by the Reader into an object that will be stored in the Record. It is passed the
8419 * following parameters:<ul>
8420 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8422 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8424 * <br>usage:<br><pre><code>
8425 var TopicRecord = Roo.data.Record.create(
8426 {name: 'title', mapping: 'topic_title'},
8427 {name: 'author', mapping: 'username'},
8428 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8429 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8430 {name: 'lastPoster', mapping: 'user2'},
8431 {name: 'excerpt', mapping: 'post_text'}
8434 var myNewRecord = new TopicRecord({
8435 title: 'Do my job please',
8438 lastPost: new Date(),
8439 lastPoster: 'Animal',
8440 excerpt: 'No way dude!'
8442 myStore.add(myNewRecord);
8447 Roo.data.Record.create = function(o){
8449 f.superclass.constructor.apply(this, arguments);
8451 Roo.extend(f, Roo.data.Record);
8452 var p = f.prototype;
8453 p.fields = new Roo.util.MixedCollection(false, function(field){
8456 for(var i = 0, len = o.length; i < len; i++){
8457 p.fields.add(new Roo.data.Field(o[i]));
8459 f.getField = function(name){
8460 return p.fields.get(name);
8465 Roo.data.Record.AUTO_ID = 1000;
8466 Roo.data.Record.EDIT = 'edit';
8467 Roo.data.Record.REJECT = 'reject';
8468 Roo.data.Record.COMMIT = 'commit';
8470 Roo.data.Record.prototype = {
8472 * Readonly flag - true if this record has been modified.
8481 join : function(store){
8486 * Set the named field to the specified value.
8487 * @param {String} name The name of the field to set.
8488 * @param {Object} value The value to set the field to.
8490 set : function(name, value){
8491 if(this.data[name] == value){
8498 if(typeof this.modified[name] == 'undefined'){
8499 this.modified[name] = this.data[name];
8501 this.data[name] = value;
8502 if(!this.editing && this.store){
8503 this.store.afterEdit(this);
8508 * Get the value of the named field.
8509 * @param {String} name The name of the field to get the value of.
8510 * @return {Object} The value of the field.
8512 get : function(name){
8513 return this.data[name];
8517 beginEdit : function(){
8518 this.editing = true;
8523 cancelEdit : function(){
8524 this.editing = false;
8525 delete this.modified;
8529 endEdit : function(){
8530 this.editing = false;
8531 if(this.dirty && this.store){
8532 this.store.afterEdit(this);
8537 * Usually called by the {@link Roo.data.Store} which owns the Record.
8538 * Rejects all changes made to the Record since either creation, or the last commit operation.
8539 * Modified fields are reverted to their original values.
8541 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8542 * of reject operations.
8544 reject : function(){
8545 var m = this.modified;
8547 if(typeof m[n] != "function"){
8548 this.data[n] = m[n];
8552 delete this.modified;
8553 this.editing = false;
8555 this.store.afterReject(this);
8560 * Usually called by the {@link Roo.data.Store} which owns the Record.
8561 * Commits all changes made to the Record since either creation, or the last commit operation.
8563 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8564 * of commit operations.
8566 commit : function(){
8568 delete this.modified;
8569 this.editing = false;
8571 this.store.afterCommit(this);
8576 hasError : function(){
8577 return this.error != null;
8581 clearError : function(){
8586 * Creates a copy of this record.
8587 * @param {String} id (optional) A new record id if you don't want to use this record's id
8590 copy : function(newId) {
8591 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8595 * Ext JS Library 1.1.1
8596 * Copyright(c) 2006-2007, Ext JS, LLC.
8598 * Originally Released Under LGPL - original licence link has changed is not relivant.
8601 * <script type="text/javascript">
8607 * @class Roo.data.Store
8608 * @extends Roo.util.Observable
8609 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8610 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8612 * 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
8613 * has no knowledge of the format of the data returned by the Proxy.<br>
8615 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8616 * instances from the data object. These records are cached and made available through accessor functions.
8618 * Creates a new Store.
8619 * @param {Object} config A config object containing the objects needed for the Store to access data,
8620 * and read the data into Records.
8622 Roo.data.Store = function(config){
8623 this.data = new Roo.util.MixedCollection(false);
8624 this.data.getKey = function(o){
8627 this.baseParams = {};
8634 "multisort" : "_multisort"
8637 if(config && config.data){
8638 this.inlineData = config.data;
8642 Roo.apply(this, config);
8644 if(this.reader){ // reader passed
8645 this.reader = Roo.factory(this.reader, Roo.data);
8646 this.reader.xmodule = this.xmodule || false;
8647 if(!this.recordType){
8648 this.recordType = this.reader.recordType;
8650 if(this.reader.onMetaChange){
8651 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8655 if(this.recordType){
8656 this.fields = this.recordType.prototype.fields;
8662 * @event datachanged
8663 * Fires when the data cache has changed, and a widget which is using this Store
8664 * as a Record cache should refresh its view.
8665 * @param {Store} this
8670 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8671 * @param {Store} this
8672 * @param {Object} meta The JSON metadata
8677 * Fires when Records have been added to the Store
8678 * @param {Store} this
8679 * @param {Roo.data.Record[]} records The array of Records added
8680 * @param {Number} index The index at which the record(s) were added
8685 * Fires when a Record has been removed from the Store
8686 * @param {Store} this
8687 * @param {Roo.data.Record} record The Record that was removed
8688 * @param {Number} index The index at which the record was removed
8693 * Fires when a Record has been updated
8694 * @param {Store} this
8695 * @param {Roo.data.Record} record The Record that was updated
8696 * @param {String} operation The update operation being performed. Value may be one of:
8698 Roo.data.Record.EDIT
8699 Roo.data.Record.REJECT
8700 Roo.data.Record.COMMIT
8706 * Fires when the data cache has been cleared.
8707 * @param {Store} this
8712 * Fires before a request is made for a new data object. If the beforeload handler returns false
8713 * the load action will be canceled.
8714 * @param {Store} this
8715 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8719 * @event beforeloadadd
8720 * Fires after a new set of Records has been loaded.
8721 * @param {Store} this
8722 * @param {Roo.data.Record[]} records The Records that were loaded
8723 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8725 beforeloadadd : true,
8728 * Fires after a new set of Records has been loaded, before they are added to the store.
8729 * @param {Store} this
8730 * @param {Roo.data.Record[]} records The Records that were loaded
8731 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8732 * @params {Object} return from reader
8736 * @event loadexception
8737 * Fires if an exception occurs in the Proxy during loading.
8738 * Called with the signature of the Proxy's "loadexception" event.
8739 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8742 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8743 * @param {Object} load options
8744 * @param {Object} jsonData from your request (normally this contains the Exception)
8746 loadexception : true
8750 this.proxy = Roo.factory(this.proxy, Roo.data);
8751 this.proxy.xmodule = this.xmodule || false;
8752 this.relayEvents(this.proxy, ["loadexception"]);
8754 this.sortToggle = {};
8755 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8757 Roo.data.Store.superclass.constructor.call(this);
8759 if(this.inlineData){
8760 this.loadData(this.inlineData);
8761 delete this.inlineData;
8765 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8767 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8768 * without a remote query - used by combo/forms at present.
8772 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8775 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8778 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8779 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8782 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8783 * on any HTTP request
8786 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8789 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8793 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8794 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8799 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8800 * loaded or when a record is removed. (defaults to false).
8802 pruneModifiedRecords : false,
8808 * Add Records to the Store and fires the add event.
8809 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8811 add : function(records){
8812 records = [].concat(records);
8813 for(var i = 0, len = records.length; i < len; i++){
8814 records[i].join(this);
8816 var index = this.data.length;
8817 this.data.addAll(records);
8818 this.fireEvent("add", this, records, index);
8822 * Remove a Record from the Store and fires the remove event.
8823 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8825 remove : function(record){
8826 var index = this.data.indexOf(record);
8827 this.data.removeAt(index);
8828 if(this.pruneModifiedRecords){
8829 this.modified.remove(record);
8831 this.fireEvent("remove", this, record, index);
8835 * Remove all Records from the Store and fires the clear event.
8837 removeAll : function(){
8839 if(this.pruneModifiedRecords){
8842 this.fireEvent("clear", this);
8846 * Inserts Records to the Store at the given index and fires the add event.
8847 * @param {Number} index The start index at which to insert the passed Records.
8848 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8850 insert : function(index, records){
8851 records = [].concat(records);
8852 for(var i = 0, len = records.length; i < len; i++){
8853 this.data.insert(index, records[i]);
8854 records[i].join(this);
8856 this.fireEvent("add", this, records, index);
8860 * Get the index within the cache of the passed Record.
8861 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8862 * @return {Number} The index of the passed Record. Returns -1 if not found.
8864 indexOf : function(record){
8865 return this.data.indexOf(record);
8869 * Get the index within the cache of the Record with the passed id.
8870 * @param {String} id The id of the Record to find.
8871 * @return {Number} The index of the Record. Returns -1 if not found.
8873 indexOfId : function(id){
8874 return this.data.indexOfKey(id);
8878 * Get the Record with the specified id.
8879 * @param {String} id The id of the Record to find.
8880 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8882 getById : function(id){
8883 return this.data.key(id);
8887 * Get the Record at the specified index.
8888 * @param {Number} index The index of the Record to find.
8889 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8891 getAt : function(index){
8892 return this.data.itemAt(index);
8896 * Returns a range of Records between specified indices.
8897 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8898 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8899 * @return {Roo.data.Record[]} An array of Records
8901 getRange : function(start, end){
8902 return this.data.getRange(start, end);
8906 storeOptions : function(o){
8907 o = Roo.apply({}, o);
8910 this.lastOptions = o;
8914 * Loads the Record cache from the configured Proxy using the configured Reader.
8916 * If using remote paging, then the first load call must specify the <em>start</em>
8917 * and <em>limit</em> properties in the options.params property to establish the initial
8918 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8920 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8921 * and this call will return before the new data has been loaded. Perform any post-processing
8922 * in a callback function, or in a "load" event handler.</strong>
8924 * @param {Object} options An object containing properties which control loading options:<ul>
8925 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8926 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8927 * passed the following arguments:<ul>
8928 * <li>r : Roo.data.Record[]</li>
8929 * <li>options: Options object from the load call</li>
8930 * <li>success: Boolean success indicator</li></ul></li>
8931 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8932 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8935 load : function(options){
8936 options = options || {};
8937 if(this.fireEvent("beforeload", this, options) !== false){
8938 this.storeOptions(options);
8939 var p = Roo.apply(options.params || {}, this.baseParams);
8940 // if meta was not loaded from remote source.. try requesting it.
8941 if (!this.reader.metaFromRemote) {
8944 if(this.sortInfo && this.remoteSort){
8945 var pn = this.paramNames;
8946 p[pn["sort"]] = this.sortInfo.field;
8947 p[pn["dir"]] = this.sortInfo.direction;
8949 if (this.multiSort) {
8950 var pn = this.paramNames;
8951 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8954 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8959 * Reloads the Record cache from the configured Proxy using the configured Reader and
8960 * the options from the last load operation performed.
8961 * @param {Object} options (optional) An object containing properties which may override the options
8962 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8963 * the most recently used options are reused).
8965 reload : function(options){
8966 this.load(Roo.applyIf(options||{}, this.lastOptions));
8970 // Called as a callback by the Reader during a load operation.
8971 loadRecords : function(o, options, success){
8972 if(!o || success === false){
8973 if(success !== false){
8974 this.fireEvent("load", this, [], options, o);
8976 if(options.callback){
8977 options.callback.call(options.scope || this, [], options, false);
8981 // if data returned failure - throw an exception.
8982 if (o.success === false) {
8983 // show a message if no listener is registered.
8984 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8985 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8987 // loadmask wil be hooked into this..
8988 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8991 var r = o.records, t = o.totalRecords || r.length;
8993 this.fireEvent("beforeloadadd", this, r, options, o);
8995 if(!options || options.add !== true){
8996 if(this.pruneModifiedRecords){
8999 for(var i = 0, len = r.length; i < len; i++){
9003 this.data = this.snapshot;
9004 delete this.snapshot;
9007 this.data.addAll(r);
9008 this.totalLength = t;
9010 this.fireEvent("datachanged", this);
9012 this.totalLength = Math.max(t, this.data.length+r.length);
9015 this.fireEvent("load", this, r, options, o);
9016 if(options.callback){
9017 options.callback.call(options.scope || this, r, options, true);
9023 * Loads data from a passed data block. A Reader which understands the format of the data
9024 * must have been configured in the constructor.
9025 * @param {Object} data The data block from which to read the Records. The format of the data expected
9026 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9027 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9029 loadData : function(o, append){
9030 var r = this.reader.readRecords(o);
9031 this.loadRecords(r, {add: append}, true);
9035 * Gets the number of cached records.
9037 * <em>If using paging, this may not be the total size of the dataset. If the data object
9038 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9039 * the data set size</em>
9041 getCount : function(){
9042 return this.data.length || 0;
9046 * Gets the total number of records in the dataset as returned by the server.
9048 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9049 * the dataset size</em>
9051 getTotalCount : function(){
9052 return this.totalLength || 0;
9056 * Returns the sort state of the Store as an object with two properties:
9058 field {String} The name of the field by which the Records are sorted
9059 direction {String} The sort order, "ASC" or "DESC"
9062 getSortState : function(){
9063 return this.sortInfo;
9067 applySort : function(){
9068 if(this.sortInfo && !this.remoteSort){
9069 var s = this.sortInfo, f = s.field;
9070 var st = this.fields.get(f).sortType;
9071 var fn = function(r1, r2){
9072 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9073 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9075 this.data.sort(s.direction, fn);
9076 if(this.snapshot && this.snapshot != this.data){
9077 this.snapshot.sort(s.direction, fn);
9083 * Sets the default sort column and order to be used by the next load operation.
9084 * @param {String} fieldName The name of the field to sort by.
9085 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9087 setDefaultSort : function(field, dir){
9088 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9093 * If remote sorting is used, the sort is performed on the server, and the cache is
9094 * reloaded. If local sorting is used, the cache is sorted internally.
9095 * @param {String} fieldName The name of the field to sort by.
9096 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9098 sort : function(fieldName, dir){
9099 var f = this.fields.get(fieldName);
9101 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9103 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9104 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9109 this.sortToggle[f.name] = dir;
9110 this.sortInfo = {field: f.name, direction: dir};
9111 if(!this.remoteSort){
9113 this.fireEvent("datachanged", this);
9115 this.load(this.lastOptions);
9120 * Calls the specified function for each of the Records in the cache.
9121 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9122 * Returning <em>false</em> aborts and exits the iteration.
9123 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9125 each : function(fn, scope){
9126 this.data.each(fn, scope);
9130 * Gets all records modified since the last commit. Modified records are persisted across load operations
9131 * (e.g., during paging).
9132 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9134 getModifiedRecords : function(){
9135 return this.modified;
9139 createFilterFn : function(property, value, anyMatch){
9140 if(!value.exec){ // not a regex
9141 value = String(value);
9142 if(value.length == 0){
9145 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9148 return value.test(r.data[property]);
9153 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9154 * @param {String} property A field on your records
9155 * @param {Number} start The record index to start at (defaults to 0)
9156 * @param {Number} end The last record index to include (defaults to length - 1)
9157 * @return {Number} The sum
9159 sum : function(property, start, end){
9160 var rs = this.data.items, v = 0;
9162 end = (end || end === 0) ? end : rs.length-1;
9164 for(var i = start; i <= end; i++){
9165 v += (rs[i].data[property] || 0);
9171 * Filter the records by a specified property.
9172 * @param {String} field A field on your records
9173 * @param {String/RegExp} value Either a string that the field
9174 * should start with or a RegExp to test against the field
9175 * @param {Boolean} anyMatch True to match any part not just the beginning
9177 filter : function(property, value, anyMatch){
9178 var fn = this.createFilterFn(property, value, anyMatch);
9179 return fn ? this.filterBy(fn) : this.clearFilter();
9183 * Filter by a function. The specified function will be called with each
9184 * record in this data source. If the function returns true the record is included,
9185 * otherwise it is filtered.
9186 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9187 * @param {Object} scope (optional) The scope of the function (defaults to this)
9189 filterBy : function(fn, scope){
9190 this.snapshot = this.snapshot || this.data;
9191 this.data = this.queryBy(fn, scope||this);
9192 this.fireEvent("datachanged", this);
9196 * Query the records by a specified property.
9197 * @param {String} field A field on your records
9198 * @param {String/RegExp} value Either a string that the field
9199 * should start with or a RegExp to test against the field
9200 * @param {Boolean} anyMatch True to match any part not just the beginning
9201 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9203 query : function(property, value, anyMatch){
9204 var fn = this.createFilterFn(property, value, anyMatch);
9205 return fn ? this.queryBy(fn) : this.data.clone();
9209 * Query by a function. The specified function will be called with each
9210 * record in this data source. If the function returns true the record is included
9212 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9213 * @param {Object} scope (optional) The scope of the function (defaults to this)
9214 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9216 queryBy : function(fn, scope){
9217 var data = this.snapshot || this.data;
9218 return data.filterBy(fn, scope||this);
9222 * Collects unique values for a particular dataIndex from this store.
9223 * @param {String} dataIndex The property to collect
9224 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9225 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9226 * @return {Array} An array of the unique values
9228 collect : function(dataIndex, allowNull, bypassFilter){
9229 var d = (bypassFilter === true && this.snapshot) ?
9230 this.snapshot.items : this.data.items;
9231 var v, sv, r = [], l = {};
9232 for(var i = 0, len = d.length; i < len; i++){
9233 v = d[i].data[dataIndex];
9235 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9244 * Revert to a view of the Record cache with no filtering applied.
9245 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9247 clearFilter : function(suppressEvent){
9248 if(this.snapshot && this.snapshot != this.data){
9249 this.data = this.snapshot;
9250 delete this.snapshot;
9251 if(suppressEvent !== true){
9252 this.fireEvent("datachanged", this);
9258 afterEdit : function(record){
9259 if(this.modified.indexOf(record) == -1){
9260 this.modified.push(record);
9262 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9266 afterReject : function(record){
9267 this.modified.remove(record);
9268 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9272 afterCommit : function(record){
9273 this.modified.remove(record);
9274 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9278 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9279 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9281 commitChanges : function(){
9282 var m = this.modified.slice(0);
9284 for(var i = 0, len = m.length; i < len; i++){
9290 * Cancel outstanding changes on all changed records.
9292 rejectChanges : function(){
9293 var m = this.modified.slice(0);
9295 for(var i = 0, len = m.length; i < len; i++){
9300 onMetaChange : function(meta, rtype, o){
9301 this.recordType = rtype;
9302 this.fields = rtype.prototype.fields;
9303 delete this.snapshot;
9304 this.sortInfo = meta.sortInfo || this.sortInfo;
9306 this.fireEvent('metachange', this, this.reader.meta);
9309 moveIndex : function(data, type)
9311 var index = this.indexOf(data);
9313 var newIndex = index + type;
9317 this.insert(newIndex, data);
9322 * Ext JS Library 1.1.1
9323 * Copyright(c) 2006-2007, Ext JS, LLC.
9325 * Originally Released Under LGPL - original licence link has changed is not relivant.
9328 * <script type="text/javascript">
9332 * @class Roo.data.SimpleStore
9333 * @extends Roo.data.Store
9334 * Small helper class to make creating Stores from Array data easier.
9335 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9336 * @cfg {Array} fields An array of field definition objects, or field name strings.
9337 * @cfg {Array} data The multi-dimensional array of data
9339 * @param {Object} config
9341 Roo.data.SimpleStore = function(config){
9342 Roo.data.SimpleStore.superclass.constructor.call(this, {
9344 reader: new Roo.data.ArrayReader({
9347 Roo.data.Record.create(config.fields)
9349 proxy : new Roo.data.MemoryProxy(config.data)
9353 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9355 * Ext JS Library 1.1.1
9356 * Copyright(c) 2006-2007, Ext JS, LLC.
9358 * Originally Released Under LGPL - original licence link has changed is not relivant.
9361 * <script type="text/javascript">
9366 * @extends Roo.data.Store
9367 * @class Roo.data.JsonStore
9368 * Small helper class to make creating Stores for JSON data easier. <br/>
9370 var store = new Roo.data.JsonStore({
9371 url: 'get-images.php',
9373 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9376 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9377 * JsonReader and HttpProxy (unless inline data is provided).</b>
9378 * @cfg {Array} fields An array of field definition objects, or field name strings.
9380 * @param {Object} config
9382 Roo.data.JsonStore = function(c){
9383 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9384 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9385 reader: new Roo.data.JsonReader(c, c.fields)
9388 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9390 * Ext JS Library 1.1.1
9391 * Copyright(c) 2006-2007, Ext JS, LLC.
9393 * Originally Released Under LGPL - original licence link has changed is not relivant.
9396 * <script type="text/javascript">
9400 Roo.data.Field = function(config){
9401 if(typeof config == "string"){
9402 config = {name: config};
9404 Roo.apply(this, config);
9410 var st = Roo.data.SortTypes;
9411 // named sortTypes are supported, here we look them up
9412 if(typeof this.sortType == "string"){
9413 this.sortType = st[this.sortType];
9416 // set default sortType for strings and dates
9420 this.sortType = st.asUCString;
9423 this.sortType = st.asDate;
9426 this.sortType = st.none;
9431 var stripRe = /[\$,%]/g;
9433 // prebuilt conversion function for this field, instead of
9434 // switching every time we're reading a value
9436 var cv, dateFormat = this.dateFormat;
9441 cv = function(v){ return v; };
9444 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9448 return v !== undefined && v !== null && v !== '' ?
9449 parseInt(String(v).replace(stripRe, ""), 10) : '';
9454 return v !== undefined && v !== null && v !== '' ?
9455 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9460 cv = function(v){ return v === true || v === "true" || v == 1; };
9467 if(v instanceof Date){
9471 if(dateFormat == "timestamp"){
9472 return new Date(v*1000);
9474 return Date.parseDate(v, dateFormat);
9476 var parsed = Date.parse(v);
9477 return parsed ? new Date(parsed) : null;
9486 Roo.data.Field.prototype = {
9494 * Ext JS Library 1.1.1
9495 * Copyright(c) 2006-2007, Ext JS, LLC.
9497 * Originally Released Under LGPL - original licence link has changed is not relivant.
9500 * <script type="text/javascript">
9503 // Base class for reading structured data from a data source. This class is intended to be
9504 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9507 * @class Roo.data.DataReader
9508 * Base class for reading structured data from a data source. This class is intended to be
9509 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9512 Roo.data.DataReader = function(meta, recordType){
9516 this.recordType = recordType instanceof Array ?
9517 Roo.data.Record.create(recordType) : recordType;
9520 Roo.data.DataReader.prototype = {
9522 * Create an empty record
9523 * @param {Object} data (optional) - overlay some values
9524 * @return {Roo.data.Record} record created.
9526 newRow : function(d) {
9528 this.recordType.prototype.fields.each(function(c) {
9530 case 'int' : da[c.name] = 0; break;
9531 case 'date' : da[c.name] = new Date(); break;
9532 case 'float' : da[c.name] = 0.0; break;
9533 case 'boolean' : da[c.name] = false; break;
9534 default : da[c.name] = ""; break;
9538 return new this.recordType(Roo.apply(da, d));
9543 * Ext JS Library 1.1.1
9544 * Copyright(c) 2006-2007, Ext JS, LLC.
9546 * Originally Released Under LGPL - original licence link has changed is not relivant.
9549 * <script type="text/javascript">
9553 * @class Roo.data.DataProxy
9554 * @extends Roo.data.Observable
9555 * This class is an abstract base class for implementations which provide retrieval of
9556 * unformatted data objects.<br>
9558 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9559 * (of the appropriate type which knows how to parse the data object) to provide a block of
9560 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9562 * Custom implementations must implement the load method as described in
9563 * {@link Roo.data.HttpProxy#load}.
9565 Roo.data.DataProxy = function(){
9569 * Fires before a network request is made to retrieve a data object.
9570 * @param {Object} This DataProxy object.
9571 * @param {Object} params The params parameter to the load function.
9576 * Fires before the load method's callback is called.
9577 * @param {Object} This DataProxy object.
9578 * @param {Object} o The data object.
9579 * @param {Object} arg The callback argument object passed to the load function.
9583 * @event loadexception
9584 * Fires if an Exception occurs during data retrieval.
9585 * @param {Object} This DataProxy object.
9586 * @param {Object} o The data object.
9587 * @param {Object} arg The callback argument object passed to the load function.
9588 * @param {Object} e The Exception.
9590 loadexception : true
9592 Roo.data.DataProxy.superclass.constructor.call(this);
9595 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9598 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9602 * Ext JS Library 1.1.1
9603 * Copyright(c) 2006-2007, Ext JS, LLC.
9605 * Originally Released Under LGPL - original licence link has changed is not relivant.
9608 * <script type="text/javascript">
9611 * @class Roo.data.MemoryProxy
9612 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9613 * to the Reader when its load method is called.
9615 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9617 Roo.data.MemoryProxy = function(data){
9621 Roo.data.MemoryProxy.superclass.constructor.call(this);
9625 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9627 * Load data from the requested source (in this case an in-memory
9628 * data object passed to the constructor), read the data object into
9629 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9630 * process that block using the passed callback.
9631 * @param {Object} params This parameter is not used by the MemoryProxy class.
9632 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9633 * object into a block of Roo.data.Records.
9634 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9635 * The function must be passed <ul>
9636 * <li>The Record block object</li>
9637 * <li>The "arg" argument from the load function</li>
9638 * <li>A boolean success indicator</li>
9640 * @param {Object} scope The scope in which to call the callback
9641 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9643 load : function(params, reader, callback, scope, arg){
9644 params = params || {};
9647 result = reader.readRecords(this.data);
9649 this.fireEvent("loadexception", this, arg, null, e);
9650 callback.call(scope, null, arg, false);
9653 callback.call(scope, result, arg, true);
9657 update : function(params, records){
9662 * Ext JS Library 1.1.1
9663 * Copyright(c) 2006-2007, Ext JS, LLC.
9665 * Originally Released Under LGPL - original licence link has changed is not relivant.
9668 * <script type="text/javascript">
9671 * @class Roo.data.HttpProxy
9672 * @extends Roo.data.DataProxy
9673 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9674 * configured to reference a certain URL.<br><br>
9676 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9677 * from which the running page was served.<br><br>
9679 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9681 * Be aware that to enable the browser to parse an XML document, the server must set
9682 * the Content-Type header in the HTTP response to "text/xml".
9684 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9685 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9686 * will be used to make the request.
9688 Roo.data.HttpProxy = function(conn){
9689 Roo.data.HttpProxy.superclass.constructor.call(this);
9690 // is conn a conn config or a real conn?
9692 this.useAjax = !conn || !conn.events;
9696 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9697 // thse are take from connection...
9700 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9703 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9704 * extra parameters to each request made by this object. (defaults to undefined)
9707 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9708 * to each request made by this object. (defaults to undefined)
9711 * @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)
9714 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9717 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9723 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9727 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9728 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9729 * a finer-grained basis than the DataProxy events.
9731 getConnection : function(){
9732 return this.useAjax ? Roo.Ajax : this.conn;
9736 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9737 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9738 * process that block using the passed callback.
9739 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9740 * for the request to the remote server.
9741 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9742 * object into a block of Roo.data.Records.
9743 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9744 * The function must be passed <ul>
9745 * <li>The Record block object</li>
9746 * <li>The "arg" argument from the load function</li>
9747 * <li>A boolean success indicator</li>
9749 * @param {Object} scope The scope in which to call the callback
9750 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9752 load : function(params, reader, callback, scope, arg){
9753 if(this.fireEvent("beforeload", this, params) !== false){
9755 params : params || {},
9757 callback : callback,
9762 callback : this.loadResponse,
9766 Roo.applyIf(o, this.conn);
9767 if(this.activeRequest){
9768 Roo.Ajax.abort(this.activeRequest);
9770 this.activeRequest = Roo.Ajax.request(o);
9772 this.conn.request(o);
9775 callback.call(scope||this, null, arg, false);
9780 loadResponse : function(o, success, response){
9781 delete this.activeRequest;
9783 this.fireEvent("loadexception", this, o, response);
9784 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9789 result = o.reader.read(response);
9791 this.fireEvent("loadexception", this, o, response, e);
9792 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9796 this.fireEvent("load", this, o, o.request.arg);
9797 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9801 update : function(dataSet){
9806 updateResponse : function(dataSet){
9811 * Ext JS Library 1.1.1
9812 * Copyright(c) 2006-2007, Ext JS, LLC.
9814 * Originally Released Under LGPL - original licence link has changed is not relivant.
9817 * <script type="text/javascript">
9821 * @class Roo.data.ScriptTagProxy
9822 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9823 * other than the originating domain of the running page.<br><br>
9825 * <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
9826 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9828 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9829 * source code that is used as the source inside a <script> tag.<br><br>
9831 * In order for the browser to process the returned data, the server must wrap the data object
9832 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9833 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9834 * depending on whether the callback name was passed:
9837 boolean scriptTag = false;
9838 String cb = request.getParameter("callback");
9841 response.setContentType("text/javascript");
9843 response.setContentType("application/x-json");
9845 Writer out = response.getWriter();
9847 out.write(cb + "(");
9849 out.print(dataBlock.toJsonString());
9856 * @param {Object} config A configuration object.
9858 Roo.data.ScriptTagProxy = function(config){
9859 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9860 Roo.apply(this, config);
9861 this.head = document.getElementsByTagName("head")[0];
9864 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9866 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9868 * @cfg {String} url The URL from which to request the data object.
9871 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9875 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9876 * the server the name of the callback function set up by the load call to process the returned data object.
9877 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9878 * javascript output which calls this named function passing the data object as its only parameter.
9880 callbackParam : "callback",
9882 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9883 * name to the request.
9888 * Load data from the configured URL, read the data object into
9889 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9890 * process that block using the passed callback.
9891 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9892 * for the request to the remote server.
9893 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9894 * object into a block of Roo.data.Records.
9895 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9896 * The function must be passed <ul>
9897 * <li>The Record block object</li>
9898 * <li>The "arg" argument from the load function</li>
9899 * <li>A boolean success indicator</li>
9901 * @param {Object} scope The scope in which to call the callback
9902 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9904 load : function(params, reader, callback, scope, arg){
9905 if(this.fireEvent("beforeload", this, params) !== false){
9907 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9910 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9912 url += "&_dc=" + (new Date().getTime());
9914 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9917 cb : "stcCallback"+transId,
9918 scriptId : "stcScript"+transId,
9922 callback : callback,
9928 window[trans.cb] = function(o){
9929 conn.handleResponse(o, trans);
9932 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9934 if(this.autoAbort !== false){
9938 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9940 var script = document.createElement("script");
9941 script.setAttribute("src", url);
9942 script.setAttribute("type", "text/javascript");
9943 script.setAttribute("id", trans.scriptId);
9944 this.head.appendChild(script);
9948 callback.call(scope||this, null, arg, false);
9953 isLoading : function(){
9954 return this.trans ? true : false;
9958 * Abort the current server request.
9961 if(this.isLoading()){
9962 this.destroyTrans(this.trans);
9967 destroyTrans : function(trans, isLoaded){
9968 this.head.removeChild(document.getElementById(trans.scriptId));
9969 clearTimeout(trans.timeoutId);
9971 window[trans.cb] = undefined;
9973 delete window[trans.cb];
9976 // if hasn't been loaded, wait for load to remove it to prevent script error
9977 window[trans.cb] = function(){
9978 window[trans.cb] = undefined;
9980 delete window[trans.cb];
9987 handleResponse : function(o, trans){
9989 this.destroyTrans(trans, true);
9992 result = trans.reader.readRecords(o);
9994 this.fireEvent("loadexception", this, o, trans.arg, e);
9995 trans.callback.call(trans.scope||window, null, trans.arg, false);
9998 this.fireEvent("load", this, o, trans.arg);
9999 trans.callback.call(trans.scope||window, result, trans.arg, true);
10003 handleFailure : function(trans){
10004 this.trans = false;
10005 this.destroyTrans(trans, false);
10006 this.fireEvent("loadexception", this, null, trans.arg);
10007 trans.callback.call(trans.scope||window, null, trans.arg, false);
10011 * Ext JS Library 1.1.1
10012 * Copyright(c) 2006-2007, Ext JS, LLC.
10014 * Originally Released Under LGPL - original licence link has changed is not relivant.
10017 * <script type="text/javascript">
10021 * @class Roo.data.JsonReader
10022 * @extends Roo.data.DataReader
10023 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10024 * based on mappings in a provided Roo.data.Record constructor.
10026 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10027 * in the reply previously.
10032 var RecordDef = Roo.data.Record.create([
10033 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10034 {name: 'occupation'} // This field will use "occupation" as the mapping.
10036 var myReader = new Roo.data.JsonReader({
10037 totalProperty: "results", // The property which contains the total dataset size (optional)
10038 root: "rows", // The property which contains an Array of row objects
10039 id: "id" // The property within each row object that provides an ID for the record (optional)
10043 * This would consume a JSON file like this:
10045 { 'results': 2, 'rows': [
10046 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10047 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10050 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10051 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10052 * paged from the remote server.
10053 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10054 * @cfg {String} root name of the property which contains the Array of row objects.
10055 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10057 * Create a new JsonReader
10058 * @param {Object} meta Metadata configuration options
10059 * @param {Object} recordType Either an Array of field definition objects,
10060 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10062 Roo.data.JsonReader = function(meta, recordType){
10065 // set some defaults:
10066 Roo.applyIf(meta, {
10067 totalProperty: 'total',
10068 successProperty : 'success',
10073 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10075 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10078 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10079 * Used by Store query builder to append _requestMeta to params.
10082 metaFromRemote : false,
10084 * This method is only used by a DataProxy which has retrieved data from a remote server.
10085 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10086 * @return {Object} data A data block which is used by an Roo.data.Store object as
10087 * a cache of Roo.data.Records.
10089 read : function(response){
10090 var json = response.responseText;
10092 var o = /* eval:var:o */ eval("("+json+")");
10094 throw {message: "JsonReader.read: Json object not found"};
10100 this.metaFromRemote = true;
10101 this.meta = o.metaData;
10102 this.recordType = Roo.data.Record.create(o.metaData.fields);
10103 this.onMetaChange(this.meta, this.recordType, o);
10105 return this.readRecords(o);
10108 // private function a store will implement
10109 onMetaChange : function(meta, recordType, o){
10116 simpleAccess: function(obj, subsc) {
10123 getJsonAccessor: function(){
10125 return function(expr) {
10127 return(re.test(expr))
10128 ? new Function("obj", "return obj." + expr)
10133 return Roo.emptyFn;
10138 * Create a data block containing Roo.data.Records from an XML document.
10139 * @param {Object} o An object which contains an Array of row objects in the property specified
10140 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10141 * which contains the total size of the dataset.
10142 * @return {Object} data A data block which is used by an Roo.data.Store object as
10143 * a cache of Roo.data.Records.
10145 readRecords : function(o){
10147 * After any data loads, the raw JSON data is available for further custom processing.
10151 var s = this.meta, Record = this.recordType,
10152 f = Record.prototype.fields, fi = f.items, fl = f.length;
10154 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10156 if(s.totalProperty) {
10157 this.getTotal = this.getJsonAccessor(s.totalProperty);
10159 if(s.successProperty) {
10160 this.getSuccess = this.getJsonAccessor(s.successProperty);
10162 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10164 var g = this.getJsonAccessor(s.id);
10165 this.getId = function(rec) {
10167 return (r === undefined || r === "") ? null : r;
10170 this.getId = function(){return null;};
10173 for(var jj = 0; jj < fl; jj++){
10175 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10176 this.ef[jj] = this.getJsonAccessor(map);
10180 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10181 if(s.totalProperty){
10182 var vt = parseInt(this.getTotal(o), 10);
10187 if(s.successProperty){
10188 var vs = this.getSuccess(o);
10189 if(vs === false || vs === 'false'){
10194 for(var i = 0; i < c; i++){
10197 var id = this.getId(n);
10198 for(var j = 0; j < fl; j++){
10200 var v = this.ef[j](n);
10202 Roo.log('missing convert for ' + f.name);
10206 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10208 var record = new Record(values, id);
10210 records[i] = record;
10216 totalRecords : totalRecords
10221 * Ext JS Library 1.1.1
10222 * Copyright(c) 2006-2007, Ext JS, LLC.
10224 * Originally Released Under LGPL - original licence link has changed is not relivant.
10227 * <script type="text/javascript">
10231 * @class Roo.data.ArrayReader
10232 * @extends Roo.data.DataReader
10233 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10234 * Each element of that Array represents a row of data fields. The
10235 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10236 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10240 var RecordDef = Roo.data.Record.create([
10241 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10242 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10244 var myReader = new Roo.data.ArrayReader({
10245 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10249 * This would consume an Array like this:
10251 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10253 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10255 * Create a new JsonReader
10256 * @param {Object} meta Metadata configuration options.
10257 * @param {Object} recordType Either an Array of field definition objects
10258 * as specified to {@link Roo.data.Record#create},
10259 * or an {@link Roo.data.Record} object
10260 * created using {@link Roo.data.Record#create}.
10262 Roo.data.ArrayReader = function(meta, recordType){
10263 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10266 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10268 * Create a data block containing Roo.data.Records from an XML document.
10269 * @param {Object} o An Array of row objects which represents the dataset.
10270 * @return {Object} data A data block which is used by an Roo.data.Store object as
10271 * a cache of Roo.data.Records.
10273 readRecords : function(o){
10274 var sid = this.meta ? this.meta.id : null;
10275 var recordType = this.recordType, fields = recordType.prototype.fields;
10278 for(var i = 0; i < root.length; i++){
10281 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10282 for(var j = 0, jlen = fields.length; j < jlen; j++){
10283 var f = fields.items[j];
10284 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10285 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10287 values[f.name] = v;
10289 var record = new recordType(values, id);
10291 records[records.length] = record;
10295 totalRecords : records.length
10304 * @class Roo.bootstrap.ComboBox
10305 * @extends Roo.bootstrap.TriggerField
10306 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10307 * @cfg {Boolean} append (true|false) default false
10308 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10309 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10310 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10311 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10312 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10314 * Create a new ComboBox.
10315 * @param {Object} config Configuration options
10317 Roo.bootstrap.ComboBox = function(config){
10318 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10322 * Fires when the dropdown list is expanded
10323 * @param {Roo.bootstrap.ComboBox} combo This combo box
10328 * Fires when the dropdown list is collapsed
10329 * @param {Roo.bootstrap.ComboBox} combo This combo box
10333 * @event beforeselect
10334 * Fires before a list item is selected. Return false to cancel the selection.
10335 * @param {Roo.bootstrap.ComboBox} combo This combo box
10336 * @param {Roo.data.Record} record The data record returned from the underlying store
10337 * @param {Number} index The index of the selected item in the dropdown list
10339 'beforeselect' : true,
10342 * Fires when a list item is selected
10343 * @param {Roo.bootstrap.ComboBox} combo This combo box
10344 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10345 * @param {Number} index The index of the selected item in the dropdown list
10349 * @event beforequery
10350 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10351 * The event object passed has these properties:
10352 * @param {Roo.bootstrap.ComboBox} combo This combo box
10353 * @param {String} query The query
10354 * @param {Boolean} forceAll true to force "all" query
10355 * @param {Boolean} cancel true to cancel the query
10356 * @param {Object} e The query event object
10358 'beforequery': true,
10361 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10362 * @param {Roo.bootstrap.ComboBox} combo This combo box
10367 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10368 * @param {Roo.bootstrap.ComboBox} combo This combo box
10369 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10374 * Fires when the remove value from the combobox array
10375 * @param {Roo.bootstrap.ComboBox} combo This combo box
10382 this.tickItems = [];
10384 this.selectedIndex = -1;
10385 if(this.mode == 'local'){
10386 if(config.queryDelay === undefined){
10387 this.queryDelay = 10;
10389 if(config.minChars === undefined){
10395 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10398 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10399 * rendering into an Roo.Editor, defaults to false)
10402 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10403 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10406 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10409 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10410 * the dropdown list (defaults to undefined, with no header element)
10414 * @cfg {String/Roo.Template} tpl The template to use to render the output
10418 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10420 listWidth: undefined,
10422 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10423 * mode = 'remote' or 'text' if mode = 'local')
10425 displayField: undefined,
10427 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10428 * mode = 'remote' or 'value' if mode = 'local').
10429 * Note: use of a valueField requires the user make a selection
10430 * in order for a value to be mapped.
10432 valueField: undefined,
10436 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10437 * field's data value (defaults to the underlying DOM element's name)
10439 hiddenName: undefined,
10441 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10445 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10447 selectedClass: 'active',
10450 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10454 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10455 * anchor positions (defaults to 'tl-bl')
10457 listAlign: 'tl-bl?',
10459 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10463 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10464 * query specified by the allQuery config option (defaults to 'query')
10466 triggerAction: 'query',
10468 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10469 * (defaults to 4, does not apply if editable = false)
10473 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10474 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10478 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10479 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10483 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10484 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10488 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10489 * when editable = true (defaults to false)
10491 selectOnFocus:false,
10493 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10495 queryParam: 'query',
10497 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10498 * when mode = 'remote' (defaults to 'Loading...')
10500 loadingText: 'Loading...',
10502 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10506 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10510 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10511 * traditional select (defaults to true)
10515 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10519 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10523 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10524 * listWidth has a higher value)
10528 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10529 * allow the user to set arbitrary text into the field (defaults to false)
10531 forceSelection:false,
10533 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10534 * if typeAhead = true (defaults to 250)
10536 typeAheadDelay : 250,
10538 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10539 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10541 valueNotFoundText : undefined,
10543 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10545 blockFocus : false,
10548 * @cfg {Boolean} disableClear Disable showing of clear button.
10550 disableClear : false,
10552 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10554 alwaysQuery : false,
10557 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10571 btnPosition : 'right',
10572 triggerList : true,
10573 showToggleBtn : true,
10574 // element that contains real text value.. (when hidden is used..)
10576 getAutoCreate : function()
10583 if(!this.tickable){
10584 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10589 * ComboBox with tickable selections
10592 var align = this.labelAlign || this.parentLabelAlign();
10595 cls : 'form-group roo-combobox-tickable' //input-group
10601 cls : 'tickable-buttons',
10606 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10613 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10620 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10627 Roo.each(buttons.cn, function(c){
10629 c.cls += ' btn-' + _this.size;
10632 if (_this.disabled) {
10643 cls: 'form-hidden-field'
10647 cls: 'select2-choices',
10651 cls: 'select2-search-field',
10663 cls: 'select2-container input-group select2-container-multi',
10668 // cls: 'typeahead typeahead-long dropdown-menu',
10669 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10674 if (align ==='left' && this.fieldLabel.length) {
10676 Roo.log("left and has label");
10682 cls : 'control-label col-sm-' + this.labelWidth,
10683 html : this.fieldLabel
10687 cls : "col-sm-" + (12 - this.labelWidth),
10694 } else if ( this.fieldLabel.length) {
10700 //cls : 'input-group-addon',
10701 html : this.fieldLabel
10711 Roo.log(" no label && no align");
10718 ['xs','sm','md','lg'].map(function(size){
10719 if (settings[size]) {
10720 cfg.cls += ' col-' + size + '-' + settings[size];
10729 initEvents: function()
10733 throw "can not find store for combo";
10735 this.store = Roo.factory(this.store, Roo.data);
10738 this.initTickableEvents();
10742 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10744 if(this.hiddenName){
10746 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10748 this.hiddenField.dom.value =
10749 this.hiddenValue !== undefined ? this.hiddenValue :
10750 this.value !== undefined ? this.value : '';
10752 // prevent input submission
10753 this.el.dom.removeAttribute('name');
10754 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10759 // this.el.dom.setAttribute('autocomplete', 'off');
10762 var cls = 'x-combo-list';
10764 //this.list = new Roo.Layer({
10765 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10771 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10772 _this.list.setWidth(lw);
10775 this.list.on('mouseover', this.onViewOver, this);
10776 this.list.on('mousemove', this.onViewMove, this);
10778 this.list.on('scroll', this.onViewScroll, this);
10781 this.list.swallowEvent('mousewheel');
10782 this.assetHeight = 0;
10785 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10786 this.assetHeight += this.header.getHeight();
10789 this.innerList = this.list.createChild({cls:cls+'-inner'});
10790 this.innerList.on('mouseover', this.onViewOver, this);
10791 this.innerList.on('mousemove', this.onViewMove, this);
10792 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10794 if(this.allowBlank && !this.pageSize && !this.disableClear){
10795 this.footer = this.list.createChild({cls:cls+'-ft'});
10796 this.pageTb = new Roo.Toolbar(this.footer);
10800 this.footer = this.list.createChild({cls:cls+'-ft'});
10801 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10802 {pageSize: this.pageSize});
10806 if (this.pageTb && this.allowBlank && !this.disableClear) {
10808 this.pageTb.add(new Roo.Toolbar.Fill(), {
10809 cls: 'x-btn-icon x-btn-clear',
10811 handler: function()
10814 _this.clearValue();
10815 _this.onSelect(false, -1);
10820 this.assetHeight += this.footer.getHeight();
10825 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10828 this.view = new Roo.View(this.list, this.tpl, {
10829 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10831 //this.view.wrapEl.setDisplayed(false);
10832 this.view.on('click', this.onViewClick, this);
10836 this.store.on('beforeload', this.onBeforeLoad, this);
10837 this.store.on('load', this.onLoad, this);
10838 this.store.on('loadexception', this.onLoadException, this);
10840 if(this.resizable){
10841 this.resizer = new Roo.Resizable(this.list, {
10842 pinned:true, handles:'se'
10844 this.resizer.on('resize', function(r, w, h){
10845 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10846 this.listWidth = w;
10847 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10848 this.restrictHeight();
10850 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10853 if(!this.editable){
10854 this.editable = true;
10855 this.setEditable(false);
10860 if (typeof(this.events.add.listeners) != 'undefined') {
10862 this.addicon = this.wrap.createChild(
10863 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10865 this.addicon.on('click', function(e) {
10866 this.fireEvent('add', this);
10869 if (typeof(this.events.edit.listeners) != 'undefined') {
10871 this.editicon = this.wrap.createChild(
10872 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10873 if (this.addicon) {
10874 this.editicon.setStyle('margin-left', '40px');
10876 this.editicon.on('click', function(e) {
10878 // we fire even if inothing is selected..
10879 this.fireEvent('edit', this, this.lastData );
10885 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10886 "up" : function(e){
10887 this.inKeyMode = true;
10891 "down" : function(e){
10892 if(!this.isExpanded()){
10893 this.onTriggerClick();
10895 this.inKeyMode = true;
10900 "enter" : function(e){
10901 // this.onViewClick();
10905 if(this.fireEvent("specialkey", this, e)){
10906 this.onViewClick(false);
10912 "esc" : function(e){
10916 "tab" : function(e){
10919 if(this.fireEvent("specialkey", this, e)){
10920 this.onViewClick(false);
10928 doRelay : function(foo, bar, hname){
10929 if(hname == 'down' || this.scope.isExpanded()){
10930 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10939 this.queryDelay = Math.max(this.queryDelay || 10,
10940 this.mode == 'local' ? 10 : 250);
10943 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10945 if(this.typeAhead){
10946 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10948 if(this.editable !== false){
10949 this.inputEl().on("keyup", this.onKeyUp, this);
10951 if(this.forceSelection){
10952 this.inputEl().on('blur', this.doForce, this);
10956 this.choices = this.el.select('ul.select2-choices', true).first();
10957 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10961 initTickableEvents: function()
10965 if(this.hiddenName){
10967 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10969 this.hiddenField.dom.value =
10970 this.hiddenValue !== undefined ? this.hiddenValue :
10971 this.value !== undefined ? this.value : '';
10973 // prevent input submission
10974 this.el.dom.removeAttribute('name');
10975 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10980 // this.list = this.el.select('ul.dropdown-menu',true).first();
10982 this.choices = this.el.select('ul.select2-choices', true).first();
10983 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10984 if(this.triggerList){
10985 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10988 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10989 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10991 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10992 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10994 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10995 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10997 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10998 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10999 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11002 this.cancelBtn.hide();
11007 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11008 _this.list.setWidth(lw);
11011 this.list.on('mouseover', this.onViewOver, this);
11012 this.list.on('mousemove', this.onViewMove, this);
11014 this.list.on('scroll', this.onViewScroll, this);
11017 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>';
11020 this.view = new Roo.View(this.list, this.tpl, {
11021 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11024 //this.view.wrapEl.setDisplayed(false);
11025 this.view.on('click', this.onViewClick, this);
11029 this.store.on('beforeload', this.onBeforeLoad, this);
11030 this.store.on('load', this.onLoad, this);
11031 this.store.on('loadexception', this.onLoadException, this);
11033 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11034 // "up" : function(e){
11035 // this.inKeyMode = true;
11036 // this.selectPrev();
11039 // "down" : function(e){
11040 // if(!this.isExpanded()){
11041 // this.onTriggerClick();
11043 // this.inKeyMode = true;
11044 // this.selectNext();
11048 // "enter" : function(e){
11049 //// this.onViewClick();
11051 // this.collapse();
11053 // if(this.fireEvent("specialkey", this, e)){
11054 // this.onViewClick(false);
11060 // "esc" : function(e){
11061 // this.collapse();
11064 // "tab" : function(e){
11065 // this.collapse();
11067 // if(this.fireEvent("specialkey", this, e)){
11068 // this.onViewClick(false);
11076 // doRelay : function(foo, bar, hname){
11077 // if(hname == 'down' || this.scope.isExpanded()){
11078 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11083 // forceKeyDown: true
11087 this.queryDelay = Math.max(this.queryDelay || 10,
11088 this.mode == 'local' ? 10 : 250);
11091 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11093 if(this.typeAhead){
11094 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11098 onDestroy : function(){
11100 this.view.setStore(null);
11101 this.view.el.removeAllListeners();
11102 this.view.el.remove();
11103 this.view.purgeListeners();
11106 this.list.dom.innerHTML = '';
11110 this.store.un('beforeload', this.onBeforeLoad, this);
11111 this.store.un('load', this.onLoad, this);
11112 this.store.un('loadexception', this.onLoadException, this);
11114 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11118 fireKey : function(e){
11119 if(e.isNavKeyPress() && !this.list.isVisible()){
11120 this.fireEvent("specialkey", this, e);
11125 onResize: function(w, h){
11126 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11128 // if(typeof w != 'number'){
11129 // // we do not handle it!?!?
11132 // var tw = this.trigger.getWidth();
11133 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11134 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11136 // this.inputEl().setWidth( this.adjustWidth('input', x));
11138 // //this.trigger.setStyle('left', x+'px');
11140 // if(this.list && this.listWidth === undefined){
11141 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11142 // this.list.setWidth(lw);
11143 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11151 * Allow or prevent the user from directly editing the field text. If false is passed,
11152 * the user will only be able to select from the items defined in the dropdown list. This method
11153 * is the runtime equivalent of setting the 'editable' config option at config time.
11154 * @param {Boolean} value True to allow the user to directly edit the field text
11156 setEditable : function(value){
11157 if(value == this.editable){
11160 this.editable = value;
11162 this.inputEl().dom.setAttribute('readOnly', true);
11163 this.inputEl().on('mousedown', this.onTriggerClick, this);
11164 this.inputEl().addClass('x-combo-noedit');
11166 this.inputEl().dom.setAttribute('readOnly', false);
11167 this.inputEl().un('mousedown', this.onTriggerClick, this);
11168 this.inputEl().removeClass('x-combo-noedit');
11174 onBeforeLoad : function(combo,opts){
11175 if(!this.hasFocus){
11179 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11181 this.restrictHeight();
11182 this.selectedIndex = -1;
11186 onLoad : function(){
11188 this.hasQuery = false;
11190 if(!this.hasFocus){
11194 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11195 this.loading.hide();
11198 if(this.store.getCount() > 0){
11200 // this.restrictHeight();
11201 if(this.lastQuery == this.allQuery){
11202 if(this.editable && !this.tickable){
11203 this.inputEl().dom.select();
11207 !this.selectByValue(this.value, true) &&
11208 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11209 this.store.lastOptions.add != true)
11211 this.select(0, true);
11214 if(this.autoFocus){
11217 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11218 this.taTask.delay(this.typeAheadDelay);
11222 this.onEmptyResults();
11228 onLoadException : function()
11230 this.hasQuery = false;
11232 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11233 this.loading.hide();
11237 Roo.log(this.store.reader.jsonData);
11238 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11240 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11246 onTypeAhead : function(){
11247 if(this.store.getCount() > 0){
11248 var r = this.store.getAt(0);
11249 var newValue = r.data[this.displayField];
11250 var len = newValue.length;
11251 var selStart = this.getRawValue().length;
11253 if(selStart != len){
11254 this.setRawValue(newValue);
11255 this.selectText(selStart, newValue.length);
11261 onSelect : function(record, index){
11263 if(this.fireEvent('beforeselect', this, record, index) !== false){
11265 this.setFromData(index > -1 ? record.data : false);
11268 this.fireEvent('select', this, record, index);
11273 * Returns the currently selected field value or empty string if no value is set.
11274 * @return {String} value The selected value
11276 getValue : function(){
11279 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11282 if(this.valueField){
11283 return typeof this.value != 'undefined' ? this.value : '';
11285 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11290 * Clears any text/value currently set in the field
11292 clearValue : function(){
11293 if(this.hiddenField){
11294 this.hiddenField.dom.value = '';
11297 this.setRawValue('');
11298 this.lastSelectionText = '';
11303 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11304 * will be displayed in the field. If the value does not match the data value of an existing item,
11305 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11306 * Otherwise the field will be blank (although the value will still be set).
11307 * @param {String} value The value to match
11309 setValue : function(v){
11316 if(this.valueField){
11317 var r = this.findRecord(this.valueField, v);
11319 text = r.data[this.displayField];
11320 }else if(this.valueNotFoundText !== undefined){
11321 text = this.valueNotFoundText;
11324 this.lastSelectionText = text;
11325 if(this.hiddenField){
11326 this.hiddenField.dom.value = v;
11328 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11332 * @property {Object} the last set data for the element
11337 * Sets the value of the field based on a object which is related to the record format for the store.
11338 * @param {Object} value the value to set as. or false on reset?
11340 setFromData : function(o){
11347 var dv = ''; // display value
11348 var vv = ''; // value value..
11350 if (this.displayField) {
11351 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11353 // this is an error condition!!!
11354 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11357 if(this.valueField){
11358 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11361 if(this.hiddenField){
11362 this.hiddenField.dom.value = vv;
11364 this.lastSelectionText = dv;
11365 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11369 // no hidden field.. - we store the value in 'value', but still display
11370 // display field!!!!
11371 this.lastSelectionText = dv;
11372 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11378 reset : function(){
11379 // overridden so that last data is reset..
11380 this.setValue(this.originalValue);
11381 this.clearInvalid();
11382 this.lastData = false;
11384 this.view.clearSelections();
11388 findRecord : function(prop, value){
11390 if(this.store.getCount() > 0){
11391 this.store.each(function(r){
11392 if(r.data[prop] == value){
11402 getName: function()
11404 // returns hidden if it's set..
11405 if (!this.rendered) {return ''};
11406 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11410 onViewMove : function(e, t){
11411 this.inKeyMode = false;
11415 onViewOver : function(e, t){
11416 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11419 var item = this.view.findItemFromChild(t);
11422 var index = this.view.indexOf(item);
11423 this.select(index, false);
11428 onViewClick : function(view, doFocus, el, e)
11430 var index = this.view.getSelectedIndexes()[0];
11432 var r = this.store.getAt(index);
11436 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11443 Roo.each(this.tickItems, function(v,k){
11445 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11446 _this.tickItems.splice(k, 1);
11456 this.tickItems.push(r.data);
11461 this.onSelect(r, index);
11463 if(doFocus !== false && !this.blockFocus){
11464 this.inputEl().focus();
11469 restrictHeight : function(){
11470 //this.innerList.dom.style.height = '';
11471 //var inner = this.innerList.dom;
11472 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11473 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11474 //this.list.beginUpdate();
11475 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11476 this.list.alignTo(this.inputEl(), this.listAlign);
11477 this.list.alignTo(this.inputEl(), this.listAlign);
11478 //this.list.endUpdate();
11482 onEmptyResults : function(){
11487 * Returns true if the dropdown list is expanded, else false.
11489 isExpanded : function(){
11490 return this.list.isVisible();
11494 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11495 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11496 * @param {String} value The data value of the item to select
11497 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11498 * selected item if it is not currently in view (defaults to true)
11499 * @return {Boolean} True if the value matched an item in the list, else false
11501 selectByValue : function(v, scrollIntoView){
11502 if(v !== undefined && v !== null){
11503 var r = this.findRecord(this.valueField || this.displayField, v);
11505 this.select(this.store.indexOf(r), scrollIntoView);
11513 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11514 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11515 * @param {Number} index The zero-based index of the list item to select
11516 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11517 * selected item if it is not currently in view (defaults to true)
11519 select : function(index, scrollIntoView){
11520 this.selectedIndex = index;
11521 this.view.select(index);
11522 if(scrollIntoView !== false){
11523 var el = this.view.getNode(index);
11524 if(el && !this.multiple && !this.tickable){
11525 this.list.scrollChildIntoView(el, false);
11531 selectNext : function(){
11532 var ct = this.store.getCount();
11534 if(this.selectedIndex == -1){
11536 }else if(this.selectedIndex < ct-1){
11537 this.select(this.selectedIndex+1);
11543 selectPrev : function(){
11544 var ct = this.store.getCount();
11546 if(this.selectedIndex == -1){
11548 }else if(this.selectedIndex != 0){
11549 this.select(this.selectedIndex-1);
11555 onKeyUp : function(e){
11556 if(this.editable !== false && !e.isSpecialKey()){
11557 this.lastKey = e.getKey();
11558 this.dqTask.delay(this.queryDelay);
11563 validateBlur : function(){
11564 return !this.list || !this.list.isVisible();
11568 initQuery : function(){
11569 this.doQuery(this.getRawValue());
11573 doForce : function(){
11574 if(this.inputEl().dom.value.length > 0){
11575 this.inputEl().dom.value =
11576 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11582 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11583 * query allowing the query action to be canceled if needed.
11584 * @param {String} query The SQL query to execute
11585 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11586 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11587 * saved in the current store (defaults to false)
11589 doQuery : function(q, forceAll){
11591 if(q === undefined || q === null){
11596 forceAll: forceAll,
11600 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11605 forceAll = qe.forceAll;
11606 if(forceAll === true || (q.length >= this.minChars)){
11608 this.hasQuery = true;
11610 if(this.lastQuery != q || this.alwaysQuery){
11611 this.lastQuery = q;
11612 if(this.mode == 'local'){
11613 this.selectedIndex = -1;
11615 this.store.clearFilter();
11617 this.store.filter(this.displayField, q);
11621 this.store.baseParams[this.queryParam] = q;
11623 var options = {params : this.getParams(q)};
11626 options.add = true;
11627 options.params.start = this.page * this.pageSize;
11630 this.store.load(options);
11632 * this code will make the page width larger, at the beginning, the list not align correctly,
11633 * we should expand the list on onLoad
11634 * so command out it
11639 this.selectedIndex = -1;
11644 this.loadNext = false;
11648 getParams : function(q){
11650 //p[this.queryParam] = q;
11654 p.limit = this.pageSize;
11660 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11662 collapse : function(){
11663 if(!this.isExpanded()){
11671 this.cancelBtn.hide();
11672 this.trigger.show();
11675 Roo.get(document).un('mousedown', this.collapseIf, this);
11676 Roo.get(document).un('mousewheel', this.collapseIf, this);
11677 if (!this.editable) {
11678 Roo.get(document).un('keydown', this.listKeyPress, this);
11680 this.fireEvent('collapse', this);
11684 collapseIf : function(e){
11685 var in_combo = e.within(this.el);
11686 var in_list = e.within(this.list);
11687 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11689 if (in_combo || in_list || is_list) {
11690 //e.stopPropagation();
11695 this.onTickableFooterButtonClick(e, false, false);
11703 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11705 expand : function(){
11707 if(this.isExpanded() || !this.hasFocus){
11711 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11712 this.list.setWidth(lw);
11719 this.restrictHeight();
11723 this.tickItems = Roo.apply([], this.item);
11726 this.cancelBtn.show();
11727 this.trigger.hide();
11731 Roo.get(document).on('mousedown', this.collapseIf, this);
11732 Roo.get(document).on('mousewheel', this.collapseIf, this);
11733 if (!this.editable) {
11734 Roo.get(document).on('keydown', this.listKeyPress, this);
11737 this.fireEvent('expand', this);
11741 // Implements the default empty TriggerField.onTriggerClick function
11742 onTriggerClick : function(e)
11744 Roo.log('trigger click');
11746 if(this.disabled || !this.triggerList){
11751 this.loadNext = false;
11753 if(this.isExpanded()){
11755 if (!this.blockFocus) {
11756 this.inputEl().focus();
11760 this.hasFocus = true;
11761 if(this.triggerAction == 'all') {
11762 this.doQuery(this.allQuery, true);
11764 this.doQuery(this.getRawValue());
11766 if (!this.blockFocus) {
11767 this.inputEl().focus();
11772 onTickableTriggerClick : function(e)
11779 this.loadNext = false;
11780 this.hasFocus = true;
11782 if(this.triggerAction == 'all') {
11783 this.doQuery(this.allQuery, true);
11785 this.doQuery(this.getRawValue());
11789 onSearchFieldClick : function(e)
11791 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11796 this.loadNext = false;
11797 this.hasFocus = true;
11799 if(this.triggerAction == 'all') {
11800 this.doQuery(this.allQuery, true);
11802 this.doQuery(this.getRawValue());
11806 listKeyPress : function(e)
11808 //Roo.log('listkeypress');
11809 // scroll to first matching element based on key pres..
11810 if (e.isSpecialKey()) {
11813 var k = String.fromCharCode(e.getKey()).toUpperCase();
11816 var csel = this.view.getSelectedNodes();
11817 var cselitem = false;
11819 var ix = this.view.indexOf(csel[0]);
11820 cselitem = this.store.getAt(ix);
11821 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11827 this.store.each(function(v) {
11829 // start at existing selection.
11830 if (cselitem.id == v.id) {
11836 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11837 match = this.store.indexOf(v);
11843 if (match === false) {
11844 return true; // no more action?
11847 this.view.select(match);
11848 var sn = Roo.get(this.view.getSelectedNodes()[0])
11849 //sn.scrollIntoView(sn.dom.parentNode, false);
11852 onViewScroll : function(e, t){
11854 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){
11858 this.hasQuery = true;
11860 this.loading = this.list.select('.loading', true).first();
11862 if(this.loading === null){
11863 this.list.createChild({
11865 cls: 'loading select2-more-results select2-active',
11866 html: 'Loading more results...'
11869 this.loading = this.list.select('.loading', true).first();
11871 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11873 this.loading.hide();
11876 this.loading.show();
11881 this.loadNext = true;
11883 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11888 addItem : function(o)
11890 var dv = ''; // display value
11892 if (this.displayField) {
11893 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11895 // this is an error condition!!!
11896 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11903 var choice = this.choices.createChild({
11905 cls: 'select2-search-choice',
11914 cls: 'select2-search-choice-close',
11919 }, this.searchField);
11921 var close = choice.select('a.select2-search-choice-close', true).first()
11923 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11931 this.inputEl().dom.value = '';
11935 onRemoveItem : function(e, _self, o)
11937 e.preventDefault();
11938 var index = this.item.indexOf(o.data) * 1;
11941 Roo.log('not this item?!');
11945 this.item.splice(index, 1);
11950 this.fireEvent('remove', this, e);
11954 syncValue : function()
11956 if(!this.item.length){
11963 Roo.each(this.item, function(i){
11964 if(_this.valueField){
11965 value.push(i[_this.valueField]);
11972 this.value = value.join(',');
11974 if(this.hiddenField){
11975 this.hiddenField.dom.value = this.value;
11979 clearItem : function()
11981 if(!this.multiple){
11987 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11994 inputEl: function ()
11997 return this.searchField;
11999 return this.el.select('input.form-control',true).first();
12003 onTickableFooterButtonClick : function(e, btn, el)
12005 e.preventDefault();
12007 if(btn && btn.name == 'cancel'){
12008 this.tickItems = Roo.apply([], this.item);
12017 Roo.each(this.tickItems, function(o){
12028 * @cfg {Boolean} grow
12032 * @cfg {Number} growMin
12036 * @cfg {Number} growMax
12046 * Ext JS Library 1.1.1
12047 * Copyright(c) 2006-2007, Ext JS, LLC.
12049 * Originally Released Under LGPL - original licence link has changed is not relivant.
12052 * <script type="text/javascript">
12057 * @extends Roo.util.Observable
12058 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12059 * This class also supports single and multi selection modes. <br>
12060 * Create a data model bound view:
12062 var store = new Roo.data.Store(...);
12064 var view = new Roo.View({
12066 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12068 singleSelect: true,
12069 selectedClass: "ydataview-selected",
12073 // listen for node click?
12074 view.on("click", function(vw, index, node, e){
12075 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12079 dataModel.load("foobar.xml");
12081 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12083 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12084 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12086 * Note: old style constructor is still suported (container, template, config)
12089 * Create a new View
12090 * @param {Object} config The config object
12093 Roo.View = function(config, depreciated_tpl, depreciated_config){
12095 this.parent = false;
12097 if (typeof(depreciated_tpl) == 'undefined') {
12098 // new way.. - universal constructor.
12099 Roo.apply(this, config);
12100 this.el = Roo.get(this.el);
12103 this.el = Roo.get(config);
12104 this.tpl = depreciated_tpl;
12105 Roo.apply(this, depreciated_config);
12107 this.wrapEl = this.el.wrap().wrap();
12108 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12111 if(typeof(this.tpl) == "string"){
12112 this.tpl = new Roo.Template(this.tpl);
12114 // support xtype ctors..
12115 this.tpl = new Roo.factory(this.tpl, Roo);
12119 this.tpl.compile();
12124 * @event beforeclick
12125 * Fires before a click is processed. Returns false to cancel the default action.
12126 * @param {Roo.View} this
12127 * @param {Number} index The index of the target node
12128 * @param {HTMLElement} node The target node
12129 * @param {Roo.EventObject} e The raw event object
12131 "beforeclick" : true,
12134 * Fires when a template node is clicked.
12135 * @param {Roo.View} this
12136 * @param {Number} index The index of the target node
12137 * @param {HTMLElement} node The target node
12138 * @param {Roo.EventObject} e The raw event object
12143 * Fires when a template node is double clicked.
12144 * @param {Roo.View} this
12145 * @param {Number} index The index of the target node
12146 * @param {HTMLElement} node The target node
12147 * @param {Roo.EventObject} e The raw event object
12151 * @event contextmenu
12152 * Fires when a template node is right clicked.
12153 * @param {Roo.View} this
12154 * @param {Number} index The index of the target node
12155 * @param {HTMLElement} node The target node
12156 * @param {Roo.EventObject} e The raw event object
12158 "contextmenu" : true,
12160 * @event selectionchange
12161 * Fires when the selected nodes change.
12162 * @param {Roo.View} this
12163 * @param {Array} selections Array of the selected nodes
12165 "selectionchange" : true,
12168 * @event beforeselect
12169 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12170 * @param {Roo.View} this
12171 * @param {HTMLElement} node The node to be selected
12172 * @param {Array} selections Array of currently selected nodes
12174 "beforeselect" : true,
12176 * @event preparedata
12177 * Fires on every row to render, to allow you to change the data.
12178 * @param {Roo.View} this
12179 * @param {Object} data to be rendered (change this)
12181 "preparedata" : true
12189 "click": this.onClick,
12190 "dblclick": this.onDblClick,
12191 "contextmenu": this.onContextMenu,
12195 this.selections = [];
12197 this.cmp = new Roo.CompositeElementLite([]);
12199 this.store = Roo.factory(this.store, Roo.data);
12200 this.setStore(this.store, true);
12203 if ( this.footer && this.footer.xtype) {
12205 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12207 this.footer.dataSource = this.store
12208 this.footer.container = fctr;
12209 this.footer = Roo.factory(this.footer, Roo);
12210 fctr.insertFirst(this.el);
12212 // this is a bit insane - as the paging toolbar seems to detach the el..
12213 // dom.parentNode.parentNode.parentNode
12214 // they get detached?
12218 Roo.View.superclass.constructor.call(this);
12223 Roo.extend(Roo.View, Roo.util.Observable, {
12226 * @cfg {Roo.data.Store} store Data store to load data from.
12231 * @cfg {String|Roo.Element} el The container element.
12236 * @cfg {String|Roo.Template} tpl The template used by this View
12240 * @cfg {String} dataName the named area of the template to use as the data area
12241 * Works with domtemplates roo-name="name"
12245 * @cfg {String} selectedClass The css class to add to selected nodes
12247 selectedClass : "x-view-selected",
12249 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12254 * @cfg {String} text to display on mask (default Loading)
12258 * @cfg {Boolean} multiSelect Allow multiple selection
12260 multiSelect : false,
12262 * @cfg {Boolean} singleSelect Allow single selection
12264 singleSelect: false,
12267 * @cfg {Boolean} toggleSelect - selecting
12269 toggleSelect : false,
12272 * @cfg {Boolean} tickable - selecting
12277 * Returns the element this view is bound to.
12278 * @return {Roo.Element}
12280 getEl : function(){
12281 return this.wrapEl;
12287 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12289 refresh : function(){
12290 Roo.log('refresh');
12293 // if we are using something like 'domtemplate', then
12294 // the what gets used is:
12295 // t.applySubtemplate(NAME, data, wrapping data..)
12296 // the outer template then get' applied with
12297 // the store 'extra data'
12298 // and the body get's added to the
12299 // roo-name="data" node?
12300 // <span class='roo-tpl-{name}'></span> ?????
12304 this.clearSelections();
12305 this.el.update("");
12307 var records = this.store.getRange();
12308 if(records.length < 1) {
12310 // is this valid?? = should it render a template??
12312 this.el.update(this.emptyText);
12316 if (this.dataName) {
12317 this.el.update(t.apply(this.store.meta)); //????
12318 el = this.el.child('.roo-tpl-' + this.dataName);
12321 for(var i = 0, len = records.length; i < len; i++){
12322 var data = this.prepareData(records[i].data, i, records[i]);
12323 this.fireEvent("preparedata", this, data, i, records[i]);
12325 var d = Roo.apply({}, data);
12328 Roo.apply(d, {'roo-id' : Roo.id()});
12332 Roo.each(this.parent.item, function(item){
12333 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12336 Roo.apply(d, {'roo-data-checked' : 'checked'});
12340 html[html.length] = Roo.util.Format.trim(
12342 t.applySubtemplate(this.dataName, d, this.store.meta) :
12349 el.update(html.join(""));
12350 this.nodes = el.dom.childNodes;
12351 this.updateIndexes(0);
12356 * Function to override to reformat the data that is sent to
12357 * the template for each node.
12358 * DEPRICATED - use the preparedata event handler.
12359 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12360 * a JSON object for an UpdateManager bound view).
12362 prepareData : function(data, index, record)
12364 this.fireEvent("preparedata", this, data, index, record);
12368 onUpdate : function(ds, record){
12369 Roo.log('on update');
12370 this.clearSelections();
12371 var index = this.store.indexOf(record);
12372 var n = this.nodes[index];
12373 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12374 n.parentNode.removeChild(n);
12375 this.updateIndexes(index, index);
12381 onAdd : function(ds, records, index)
12383 Roo.log(['on Add', ds, records, index] );
12384 this.clearSelections();
12385 if(this.nodes.length == 0){
12389 var n = this.nodes[index];
12390 for(var i = 0, len = records.length; i < len; i++){
12391 var d = this.prepareData(records[i].data, i, records[i]);
12393 this.tpl.insertBefore(n, d);
12396 this.tpl.append(this.el, d);
12399 this.updateIndexes(index);
12402 onRemove : function(ds, record, index){
12403 Roo.log('onRemove');
12404 this.clearSelections();
12405 var el = this.dataName ?
12406 this.el.child('.roo-tpl-' + this.dataName) :
12409 el.dom.removeChild(this.nodes[index]);
12410 this.updateIndexes(index);
12414 * Refresh an individual node.
12415 * @param {Number} index
12417 refreshNode : function(index){
12418 this.onUpdate(this.store, this.store.getAt(index));
12421 updateIndexes : function(startIndex, endIndex){
12422 var ns = this.nodes;
12423 startIndex = startIndex || 0;
12424 endIndex = endIndex || ns.length - 1;
12425 for(var i = startIndex; i <= endIndex; i++){
12426 ns[i].nodeIndex = i;
12431 * Changes the data store this view uses and refresh the view.
12432 * @param {Store} store
12434 setStore : function(store, initial){
12435 if(!initial && this.store){
12436 this.store.un("datachanged", this.refresh);
12437 this.store.un("add", this.onAdd);
12438 this.store.un("remove", this.onRemove);
12439 this.store.un("update", this.onUpdate);
12440 this.store.un("clear", this.refresh);
12441 this.store.un("beforeload", this.onBeforeLoad);
12442 this.store.un("load", this.onLoad);
12443 this.store.un("loadexception", this.onLoad);
12447 store.on("datachanged", this.refresh, this);
12448 store.on("add", this.onAdd, this);
12449 store.on("remove", this.onRemove, this);
12450 store.on("update", this.onUpdate, this);
12451 store.on("clear", this.refresh, this);
12452 store.on("beforeload", this.onBeforeLoad, this);
12453 store.on("load", this.onLoad, this);
12454 store.on("loadexception", this.onLoad, this);
12462 * onbeforeLoad - masks the loading area.
12465 onBeforeLoad : function(store,opts)
12467 Roo.log('onBeforeLoad');
12469 this.el.update("");
12471 this.el.mask(this.mask ? this.mask : "Loading" );
12473 onLoad : function ()
12480 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12481 * @param {HTMLElement} node
12482 * @return {HTMLElement} The template node
12484 findItemFromChild : function(node){
12485 var el = this.dataName ?
12486 this.el.child('.roo-tpl-' + this.dataName,true) :
12489 if(!node || node.parentNode == el){
12492 var p = node.parentNode;
12493 while(p && p != el){
12494 if(p.parentNode == el){
12503 onClick : function(e){
12504 var item = this.findItemFromChild(e.getTarget());
12506 var index = this.indexOf(item);
12507 if(this.onItemClick(item, index, e) !== false){
12508 this.fireEvent("click", this, index, item, e);
12511 this.clearSelections();
12516 onContextMenu : function(e){
12517 var item = this.findItemFromChild(e.getTarget());
12519 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12524 onDblClick : function(e){
12525 var item = this.findItemFromChild(e.getTarget());
12527 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12531 onItemClick : function(item, index, e)
12533 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12536 if (this.toggleSelect) {
12537 var m = this.isSelected(item) ? 'unselect' : 'select';
12540 _t[m](item, true, false);
12543 if(this.multiSelect || this.singleSelect){
12544 if(this.multiSelect && e.shiftKey && this.lastSelection){
12545 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12547 this.select(item, this.multiSelect && e.ctrlKey);
12548 this.lastSelection = item;
12551 if(!this.tickable){
12552 e.preventDefault();
12560 * Get the number of selected nodes.
12563 getSelectionCount : function(){
12564 return this.selections.length;
12568 * Get the currently selected nodes.
12569 * @return {Array} An array of HTMLElements
12571 getSelectedNodes : function(){
12572 return this.selections;
12576 * Get the indexes of the selected nodes.
12579 getSelectedIndexes : function(){
12580 var indexes = [], s = this.selections;
12581 for(var i = 0, len = s.length; i < len; i++){
12582 indexes.push(s[i].nodeIndex);
12588 * Clear all selections
12589 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12591 clearSelections : function(suppressEvent){
12592 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12593 this.cmp.elements = this.selections;
12594 this.cmp.removeClass(this.selectedClass);
12595 this.selections = [];
12596 if(!suppressEvent){
12597 this.fireEvent("selectionchange", this, this.selections);
12603 * Returns true if the passed node is selected
12604 * @param {HTMLElement/Number} node The node or node index
12605 * @return {Boolean}
12607 isSelected : function(node){
12608 var s = this.selections;
12612 node = this.getNode(node);
12613 return s.indexOf(node) !== -1;
12618 * @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
12619 * @param {Boolean} keepExisting (optional) true to keep existing selections
12620 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12622 select : function(nodeInfo, keepExisting, suppressEvent){
12623 if(nodeInfo instanceof Array){
12625 this.clearSelections(true);
12627 for(var i = 0, len = nodeInfo.length; i < len; i++){
12628 this.select(nodeInfo[i], true, true);
12632 var node = this.getNode(nodeInfo);
12633 if(!node || this.isSelected(node)){
12634 return; // already selected.
12637 this.clearSelections(true);
12639 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12640 Roo.fly(node).addClass(this.selectedClass);
12641 this.selections.push(node);
12642 if(!suppressEvent){
12643 this.fireEvent("selectionchange", this, this.selections);
12651 * @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
12652 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12653 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12655 unselect : function(nodeInfo, keepExisting, suppressEvent)
12657 if(nodeInfo instanceof Array){
12658 Roo.each(this.selections, function(s) {
12659 this.unselect(s, nodeInfo);
12663 var node = this.getNode(nodeInfo);
12664 if(!node || !this.isSelected(node)){
12665 Roo.log("not selected");
12666 return; // not selected.
12670 Roo.each(this.selections, function(s) {
12672 Roo.fly(node).removeClass(this.selectedClass);
12679 this.selections= ns;
12680 this.fireEvent("selectionchange", this, this.selections);
12684 * Gets a template node.
12685 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12686 * @return {HTMLElement} The node or null if it wasn't found
12688 getNode : function(nodeInfo){
12689 if(typeof nodeInfo == "string"){
12690 return document.getElementById(nodeInfo);
12691 }else if(typeof nodeInfo == "number"){
12692 return this.nodes[nodeInfo];
12698 * Gets a range template nodes.
12699 * @param {Number} startIndex
12700 * @param {Number} endIndex
12701 * @return {Array} An array of nodes
12703 getNodes : function(start, end){
12704 var ns = this.nodes;
12705 start = start || 0;
12706 end = typeof end == "undefined" ? ns.length - 1 : end;
12709 for(var i = start; i <= end; i++){
12713 for(var i = start; i >= end; i--){
12721 * Finds the index of the passed node
12722 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12723 * @return {Number} The index of the node or -1
12725 indexOf : function(node){
12726 node = this.getNode(node);
12727 if(typeof node.nodeIndex == "number"){
12728 return node.nodeIndex;
12730 var ns = this.nodes;
12731 for(var i = 0, len = ns.length; i < len; i++){
12742 * based on jquery fullcalendar
12746 Roo.bootstrap = Roo.bootstrap || {};
12748 * @class Roo.bootstrap.Calendar
12749 * @extends Roo.bootstrap.Component
12750 * Bootstrap Calendar class
12751 * @cfg {Boolean} loadMask (true|false) default false
12752 * @cfg {Object} header generate the user specific header of the calendar, default false
12755 * Create a new Container
12756 * @param {Object} config The config object
12761 Roo.bootstrap.Calendar = function(config){
12762 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12766 * Fires when a date is selected
12767 * @param {DatePicker} this
12768 * @param {Date} date The selected date
12772 * @event monthchange
12773 * Fires when the displayed month changes
12774 * @param {DatePicker} this
12775 * @param {Date} date The selected month
12777 'monthchange': true,
12779 * @event evententer
12780 * Fires when mouse over an event
12781 * @param {Calendar} this
12782 * @param {event} Event
12784 'evententer': true,
12786 * @event eventleave
12787 * Fires when the mouse leaves an
12788 * @param {Calendar} this
12791 'eventleave': true,
12793 * @event eventclick
12794 * Fires when the mouse click an
12795 * @param {Calendar} this
12804 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12807 * @cfg {Number} startDay
12808 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12816 getAutoCreate : function(){
12819 var fc_button = function(name, corner, style, content ) {
12820 return Roo.apply({},{
12822 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12824 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12827 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12838 style : 'width:100%',
12845 cls : 'fc-header-left',
12847 fc_button('prev', 'left', 'arrow', '‹' ),
12848 fc_button('next', 'right', 'arrow', '›' ),
12849 { tag: 'span', cls: 'fc-header-space' },
12850 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12858 cls : 'fc-header-center',
12862 cls: 'fc-header-title',
12865 html : 'month / year'
12873 cls : 'fc-header-right',
12875 /* fc_button('month', 'left', '', 'month' ),
12876 fc_button('week', '', '', 'week' ),
12877 fc_button('day', 'right', '', 'day' )
12889 header = this.header;
12892 var cal_heads = function() {
12894 // fixme - handle this.
12896 for (var i =0; i < Date.dayNames.length; i++) {
12897 var d = Date.dayNames[i];
12900 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12901 html : d.substring(0,3)
12905 ret[0].cls += ' fc-first';
12906 ret[6].cls += ' fc-last';
12909 var cal_cell = function(n) {
12912 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12917 cls: 'fc-day-number',
12921 cls: 'fc-day-content',
12925 style: 'position: relative;' // height: 17px;
12937 var cal_rows = function() {
12940 for (var r = 0; r < 6; r++) {
12947 for (var i =0; i < Date.dayNames.length; i++) {
12948 var d = Date.dayNames[i];
12949 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12952 row.cn[0].cls+=' fc-first';
12953 row.cn[0].cn[0].style = 'min-height:90px';
12954 row.cn[6].cls+=' fc-last';
12958 ret[0].cls += ' fc-first';
12959 ret[4].cls += ' fc-prev-last';
12960 ret[5].cls += ' fc-last';
12967 cls: 'fc-border-separate',
12968 style : 'width:100%',
12976 cls : 'fc-first fc-last',
12994 cls : 'fc-content',
12995 style : "position: relative;",
12998 cls : 'fc-view fc-view-month fc-grid',
12999 style : 'position: relative',
13000 unselectable : 'on',
13003 cls : 'fc-event-container',
13004 style : 'position:absolute;z-index:8;top:0;left:0;'
13022 initEvents : function()
13025 throw "can not find store for calendar";
13031 style: "text-align:center",
13035 style: "background-color:white;width:50%;margin:250 auto",
13039 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13050 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13052 var size = this.el.select('.fc-content', true).first().getSize();
13053 this.maskEl.setSize(size.width, size.height);
13054 this.maskEl.enableDisplayMode("block");
13055 if(!this.loadMask){
13056 this.maskEl.hide();
13059 this.store = Roo.factory(this.store, Roo.data);
13060 this.store.on('load', this.onLoad, this);
13061 this.store.on('beforeload', this.onBeforeLoad, this);
13065 this.cells = this.el.select('.fc-day',true);
13066 //Roo.log(this.cells);
13067 this.textNodes = this.el.query('.fc-day-number');
13068 this.cells.addClassOnOver('fc-state-hover');
13070 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13071 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13072 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13073 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13075 this.on('monthchange', this.onMonthChange, this);
13077 this.update(new Date().clearTime());
13080 resize : function() {
13081 var sz = this.el.getSize();
13083 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13084 this.el.select('.fc-day-content div',true).setHeight(34);
13089 showPrevMonth : function(e){
13090 this.update(this.activeDate.add("mo", -1));
13092 showToday : function(e){
13093 this.update(new Date().clearTime());
13096 showNextMonth : function(e){
13097 this.update(this.activeDate.add("mo", 1));
13101 showPrevYear : function(){
13102 this.update(this.activeDate.add("y", -1));
13106 showNextYear : function(){
13107 this.update(this.activeDate.add("y", 1));
13112 update : function(date)
13114 var vd = this.activeDate;
13115 this.activeDate = date;
13116 // if(vd && this.el){
13117 // var t = date.getTime();
13118 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13119 // Roo.log('using add remove');
13121 // this.fireEvent('monthchange', this, date);
13123 // this.cells.removeClass("fc-state-highlight");
13124 // this.cells.each(function(c){
13125 // if(c.dateValue == t){
13126 // c.addClass("fc-state-highlight");
13127 // setTimeout(function(){
13128 // try{c.dom.firstChild.focus();}catch(e){}
13138 var days = date.getDaysInMonth();
13140 var firstOfMonth = date.getFirstDateOfMonth();
13141 var startingPos = firstOfMonth.getDay()-this.startDay;
13143 if(startingPos < this.startDay){
13147 var pm = date.add(Date.MONTH, -1);
13148 var prevStart = pm.getDaysInMonth()-startingPos;
13150 this.cells = this.el.select('.fc-day',true);
13151 this.textNodes = this.el.query('.fc-day-number');
13152 this.cells.addClassOnOver('fc-state-hover');
13154 var cells = this.cells.elements;
13155 var textEls = this.textNodes;
13157 Roo.each(cells, function(cell){
13158 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13161 days += startingPos;
13163 // convert everything to numbers so it's fast
13164 var day = 86400000;
13165 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13168 //Roo.log(prevStart);
13170 var today = new Date().clearTime().getTime();
13171 var sel = date.clearTime().getTime();
13172 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13173 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13174 var ddMatch = this.disabledDatesRE;
13175 var ddText = this.disabledDatesText;
13176 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13177 var ddaysText = this.disabledDaysText;
13178 var format = this.format;
13180 var setCellClass = function(cal, cell){
13184 //Roo.log('set Cell Class');
13186 var t = d.getTime();
13190 cell.dateValue = t;
13192 cell.className += " fc-today";
13193 cell.className += " fc-state-highlight";
13194 cell.title = cal.todayText;
13197 // disable highlight in other month..
13198 //cell.className += " fc-state-highlight";
13203 cell.className = " fc-state-disabled";
13204 cell.title = cal.minText;
13208 cell.className = " fc-state-disabled";
13209 cell.title = cal.maxText;
13213 if(ddays.indexOf(d.getDay()) != -1){
13214 cell.title = ddaysText;
13215 cell.className = " fc-state-disabled";
13218 if(ddMatch && format){
13219 var fvalue = d.dateFormat(format);
13220 if(ddMatch.test(fvalue)){
13221 cell.title = ddText.replace("%0", fvalue);
13222 cell.className = " fc-state-disabled";
13226 if (!cell.initialClassName) {
13227 cell.initialClassName = cell.dom.className;
13230 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13235 for(; i < startingPos; i++) {
13236 textEls[i].innerHTML = (++prevStart);
13237 d.setDate(d.getDate()+1);
13239 cells[i].className = "fc-past fc-other-month";
13240 setCellClass(this, cells[i]);
13245 for(; i < days; i++){
13246 intDay = i - startingPos + 1;
13247 textEls[i].innerHTML = (intDay);
13248 d.setDate(d.getDate()+1);
13250 cells[i].className = ''; // "x-date-active";
13251 setCellClass(this, cells[i]);
13255 for(; i < 42; i++) {
13256 textEls[i].innerHTML = (++extraDays);
13257 d.setDate(d.getDate()+1);
13259 cells[i].className = "fc-future fc-other-month";
13260 setCellClass(this, cells[i]);
13263 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13265 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13267 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13268 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13270 if(totalRows != 6){
13271 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13272 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13275 this.fireEvent('monthchange', this, date);
13279 if(!this.internalRender){
13280 var main = this.el.dom.firstChild;
13281 var w = main.offsetWidth;
13282 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13283 Roo.fly(main).setWidth(w);
13284 this.internalRender = true;
13285 // opera does not respect the auto grow header center column
13286 // then, after it gets a width opera refuses to recalculate
13287 // without a second pass
13288 if(Roo.isOpera && !this.secondPass){
13289 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13290 this.secondPass = true;
13291 this.update.defer(10, this, [date]);
13298 findCell : function(dt) {
13299 dt = dt.clearTime().getTime();
13301 this.cells.each(function(c){
13302 //Roo.log("check " +c.dateValue + '?=' + dt);
13303 if(c.dateValue == dt){
13313 findCells : function(ev) {
13314 var s = ev.start.clone().clearTime().getTime();
13316 var e= ev.end.clone().clearTime().getTime();
13319 this.cells.each(function(c){
13320 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13322 if(c.dateValue > e){
13325 if(c.dateValue < s){
13334 // findBestRow: function(cells)
13338 // for (var i =0 ; i < cells.length;i++) {
13339 // ret = Math.max(cells[i].rows || 0,ret);
13346 addItem : function(ev)
13348 // look for vertical location slot in
13349 var cells = this.findCells(ev);
13351 // ev.row = this.findBestRow(cells);
13353 // work out the location.
13357 for(var i =0; i < cells.length; i++) {
13359 cells[i].row = cells[0].row;
13362 cells[i].row = cells[i].row + 1;
13372 if (crow.start.getY() == cells[i].getY()) {
13374 crow.end = cells[i];
13391 cells[0].events.push(ev);
13393 this.calevents.push(ev);
13396 clearEvents: function() {
13398 if(!this.calevents){
13402 Roo.each(this.cells.elements, function(c){
13408 Roo.each(this.calevents, function(e) {
13409 Roo.each(e.els, function(el) {
13410 el.un('mouseenter' ,this.onEventEnter, this);
13411 el.un('mouseleave' ,this.onEventLeave, this);
13416 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13422 renderEvents: function()
13426 this.cells.each(function(c) {
13435 if(c.row != c.events.length){
13436 r = 4 - (4 - (c.row - c.events.length));
13439 c.events = ev.slice(0, r);
13440 c.more = ev.slice(r);
13442 if(c.more.length && c.more.length == 1){
13443 c.events.push(c.more.pop());
13446 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13450 this.cells.each(function(c) {
13452 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13455 for (var e = 0; e < c.events.length; e++){
13456 var ev = c.events[e];
13457 var rows = ev.rows;
13459 for(var i = 0; i < rows.length; i++) {
13461 // how many rows should it span..
13464 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13465 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13467 unselectable : "on",
13470 cls: 'fc-event-inner',
13474 // cls: 'fc-event-time',
13475 // html : cells.length > 1 ? '' : ev.time
13479 cls: 'fc-event-title',
13480 html : String.format('{0}', ev.title)
13487 cls: 'ui-resizable-handle ui-resizable-e',
13488 html : '  '
13495 cfg.cls += ' fc-event-start';
13497 if ((i+1) == rows.length) {
13498 cfg.cls += ' fc-event-end';
13501 var ctr = _this.el.select('.fc-event-container',true).first();
13502 var cg = ctr.createChild(cfg);
13504 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13505 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13507 var r = (c.more.length) ? 1 : 0;
13508 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13509 cg.setWidth(ebox.right - sbox.x -2);
13511 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13512 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13513 cg.on('click', _this.onEventClick, _this, ev);
13524 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13525 style : 'position: absolute',
13526 unselectable : "on",
13529 cls: 'fc-event-inner',
13533 cls: 'fc-event-title',
13541 cls: 'ui-resizable-handle ui-resizable-e',
13542 html : '  '
13548 var ctr = _this.el.select('.fc-event-container',true).first();
13549 var cg = ctr.createChild(cfg);
13551 var sbox = c.select('.fc-day-content',true).first().getBox();
13552 var ebox = c.select('.fc-day-content',true).first().getBox();
13554 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13555 cg.setWidth(ebox.right - sbox.x -2);
13557 cg.on('click', _this.onMoreEventClick, _this, c.more);
13567 onEventEnter: function (e, el,event,d) {
13568 this.fireEvent('evententer', this, el, event);
13571 onEventLeave: function (e, el,event,d) {
13572 this.fireEvent('eventleave', this, el, event);
13575 onEventClick: function (e, el,event,d) {
13576 this.fireEvent('eventclick', this, el, event);
13579 onMonthChange: function () {
13583 onMoreEventClick: function(e, el, more)
13587 this.calpopover.placement = 'right';
13588 this.calpopover.setTitle('More');
13590 this.calpopover.setContent('');
13592 var ctr = this.calpopover.el.select('.popover-content', true).first();
13594 Roo.each(more, function(m){
13596 cls : 'fc-event-hori fc-event-draggable',
13599 var cg = ctr.createChild(cfg);
13601 cg.on('click', _this.onEventClick, _this, m);
13604 this.calpopover.show(el);
13609 onLoad: function ()
13611 this.calevents = [];
13614 if(this.store.getCount() > 0){
13615 this.store.data.each(function(d){
13618 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13619 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13620 time : d.data.start_time,
13621 title : d.data.title,
13622 description : d.data.description,
13623 venue : d.data.venue
13628 this.renderEvents();
13630 if(this.calevents.length && this.loadMask){
13631 this.maskEl.hide();
13635 onBeforeLoad: function()
13637 this.clearEvents();
13639 this.maskEl.show();
13653 * @class Roo.bootstrap.Popover
13654 * @extends Roo.bootstrap.Component
13655 * Bootstrap Popover class
13656 * @cfg {String} html contents of the popover (or false to use children..)
13657 * @cfg {String} title of popover (or false to hide)
13658 * @cfg {String} placement how it is placed
13659 * @cfg {String} trigger click || hover (or false to trigger manually)
13660 * @cfg {String} over what (parent or false to trigger manually.)
13661 * @cfg {Number} delay - delay before showing
13664 * Create a new Popover
13665 * @param {Object} config The config object
13668 Roo.bootstrap.Popover = function(config){
13669 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13672 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13674 title: 'Fill in a title',
13677 placement : 'right',
13678 trigger : 'hover', // hover
13684 can_build_overlaid : false,
13686 getChildContainer : function()
13688 return this.el.select('.popover-content',true).first();
13691 getAutoCreate : function(){
13692 Roo.log('make popover?');
13694 cls : 'popover roo-dynamic',
13695 style: 'display:block',
13701 cls : 'popover-inner',
13705 cls: 'popover-title',
13709 cls : 'popover-content',
13720 setTitle: function(str)
13722 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13724 setContent: function(str)
13726 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13728 // as it get's added to the bottom of the page.
13729 onRender : function(ct, position)
13731 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13733 var cfg = Roo.apply({}, this.getAutoCreate());
13737 cfg.cls += ' ' + this.cls;
13740 cfg.style = this.style;
13742 Roo.log("adding to ")
13743 this.el = Roo.get(document.body).createChild(cfg, position);
13749 initEvents : function()
13751 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13752 this.el.enableDisplayMode('block');
13754 if (this.over === false) {
13757 if (this.triggers === false) {
13760 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13761 var triggers = this.trigger ? this.trigger.split(' ') : [];
13762 Roo.each(triggers, function(trigger) {
13764 if (trigger == 'click') {
13765 on_el.on('click', this.toggle, this);
13766 } else if (trigger != 'manual') {
13767 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13768 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13770 on_el.on(eventIn ,this.enter, this);
13771 on_el.on(eventOut, this.leave, this);
13782 toggle : function () {
13783 this.hoverState == 'in' ? this.leave() : this.enter();
13786 enter : function () {
13789 clearTimeout(this.timeout);
13791 this.hoverState = 'in'
13793 if (!this.delay || !this.delay.show) {
13798 this.timeout = setTimeout(function () {
13799 if (_t.hoverState == 'in') {
13802 }, this.delay.show)
13804 leave : function() {
13805 clearTimeout(this.timeout);
13807 this.hoverState = 'out'
13809 if (!this.delay || !this.delay.hide) {
13814 this.timeout = setTimeout(function () {
13815 if (_t.hoverState == 'out') {
13818 }, this.delay.hide)
13821 show : function (on_el)
13824 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13827 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13828 if (this.html !== false) {
13829 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13831 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13832 if (!this.title.length) {
13833 this.el.select('.popover-title',true).hide();
13836 var placement = typeof this.placement == 'function' ?
13837 this.placement.call(this, this.el, on_el) :
13840 var autoToken = /\s?auto?\s?/i;
13841 var autoPlace = autoToken.test(placement);
13843 placement = placement.replace(autoToken, '') || 'top';
13847 //this.el.setXY([0,0]);
13849 this.el.dom.style.display='block';
13850 this.el.addClass(placement);
13852 //this.el.appendTo(on_el);
13854 var p = this.getPosition();
13855 var box = this.el.getBox();
13860 var align = Roo.bootstrap.Popover.alignment[placement]
13861 this.el.alignTo(on_el, align[0],align[1]);
13862 //var arrow = this.el.select('.arrow',true).first();
13863 //arrow.set(align[2],
13865 this.el.addClass('in');
13866 this.hoverState = null;
13868 if (this.el.hasClass('fade')) {
13875 this.el.setXY([0,0]);
13876 this.el.removeClass('in');
13883 Roo.bootstrap.Popover.alignment = {
13884 'left' : ['r-l', [-10,0], 'right'],
13885 'right' : ['l-r', [10,0], 'left'],
13886 'bottom' : ['t-b', [0,10], 'top'],
13887 'top' : [ 'b-t', [0,-10], 'bottom']
13898 * @class Roo.bootstrap.Progress
13899 * @extends Roo.bootstrap.Component
13900 * Bootstrap Progress class
13901 * @cfg {Boolean} striped striped of the progress bar
13902 * @cfg {Boolean} active animated of the progress bar
13906 * Create a new Progress
13907 * @param {Object} config The config object
13910 Roo.bootstrap.Progress = function(config){
13911 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13914 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13919 getAutoCreate : function(){
13927 cfg.cls += ' progress-striped';
13931 cfg.cls += ' active';
13950 * @class Roo.bootstrap.ProgressBar
13951 * @extends Roo.bootstrap.Component
13952 * Bootstrap ProgressBar class
13953 * @cfg {Number} aria_valuenow aria-value now
13954 * @cfg {Number} aria_valuemin aria-value min
13955 * @cfg {Number} aria_valuemax aria-value max
13956 * @cfg {String} label label for the progress bar
13957 * @cfg {String} panel (success | info | warning | danger )
13958 * @cfg {String} role role of the progress bar
13959 * @cfg {String} sr_only text
13963 * Create a new ProgressBar
13964 * @param {Object} config The config object
13967 Roo.bootstrap.ProgressBar = function(config){
13968 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13971 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13975 aria_valuemax : 100,
13981 getAutoCreate : function()
13986 cls: 'progress-bar',
13987 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13999 cfg.role = this.role;
14002 if(this.aria_valuenow){
14003 cfg['aria-valuenow'] = this.aria_valuenow;
14006 if(this.aria_valuemin){
14007 cfg['aria-valuemin'] = this.aria_valuemin;
14010 if(this.aria_valuemax){
14011 cfg['aria-valuemax'] = this.aria_valuemax;
14014 if(this.label && !this.sr_only){
14015 cfg.html = this.label;
14019 cfg.cls += ' progress-bar-' + this.panel;
14025 update : function(aria_valuenow)
14027 this.aria_valuenow = aria_valuenow;
14029 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14044 * @class Roo.bootstrap.TabGroup
14045 * @extends Roo.bootstrap.Column
14046 * Bootstrap Column class
14047 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14048 * @cfg {Boolean} carousel true to make the group behave like a carousel
14051 * Create a new TabGroup
14052 * @param {Object} config The config object
14055 Roo.bootstrap.TabGroup = function(config){
14056 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14058 this.navId = Roo.id();
14061 Roo.bootstrap.TabGroup.register(this);
14065 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14068 transition : false,
14070 getAutoCreate : function()
14072 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14074 cfg.cls += ' tab-content';
14076 if (this.carousel) {
14077 cfg.cls += ' carousel slide';
14079 cls : 'carousel-inner'
14086 getChildContainer : function()
14088 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14092 * register a Navigation item
14093 * @param {Roo.bootstrap.NavItem} the navitem to add
14095 register : function(item)
14097 this.tabs.push( item);
14098 item.navId = this.navId; // not really needed..
14102 getActivePanel : function()
14105 Roo.each(this.tabs, function(t) {
14115 getPanelByName : function(n)
14118 Roo.each(this.tabs, function(t) {
14119 if (t.tabId == n) {
14127 indexOfPanel : function(p)
14130 Roo.each(this.tabs, function(t,i) {
14131 if (t.tabId == p.tabId) {
14140 * show a specific panel
14141 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14142 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14144 showPanel : function (pan)
14147 if (typeof(pan) == 'number') {
14148 pan = this.tabs[pan];
14150 if (typeof(pan) == 'string') {
14151 pan = this.getPanelByName(pan);
14153 if (pan.tabId == this.getActivePanel().tabId) {
14156 var cur = this.getActivePanel();
14158 if (false === cur.fireEvent('beforedeactivate')) {
14162 if (this.carousel) {
14163 this.transition = true;
14164 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14165 var lr = dir == 'next' ? 'left' : 'right';
14166 pan.el.addClass(dir); // or prev
14167 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14168 cur.el.addClass(lr); // or right
14169 pan.el.addClass(lr);
14172 cur.el.on('transitionend', function() {
14173 Roo.log("trans end?");
14175 pan.el.removeClass([lr,dir]);
14176 pan.setActive(true);
14178 cur.el.removeClass([lr]);
14179 cur.setActive(false);
14181 _this.transition = false;
14183 }, this, { single: true } );
14187 cur.setActive(false);
14188 pan.setActive(true);
14192 showPanelNext : function()
14194 var i = this.indexOfPanel(this.getActivePanel());
14195 if (i > this.tabs.length) {
14198 this.showPanel(this.tabs[i+1]);
14200 showPanelPrev : function()
14202 var i = this.indexOfPanel(this.getActivePanel());
14206 this.showPanel(this.tabs[i-1]);
14217 Roo.apply(Roo.bootstrap.TabGroup, {
14221 * register a Navigation Group
14222 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14224 register : function(navgrp)
14226 this.groups[navgrp.navId] = navgrp;
14230 * fetch a Navigation Group based on the navigation ID
14231 * if one does not exist , it will get created.
14232 * @param {string} the navgroup to add
14233 * @returns {Roo.bootstrap.NavGroup} the navgroup
14235 get: function(navId) {
14236 if (typeof(this.groups[navId]) == 'undefined') {
14237 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14239 return this.groups[navId] ;
14254 * @class Roo.bootstrap.TabPanel
14255 * @extends Roo.bootstrap.Component
14256 * Bootstrap TabPanel class
14257 * @cfg {Boolean} active panel active
14258 * @cfg {String} html panel content
14259 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14260 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14264 * Create a new TabPanel
14265 * @param {Object} config The config object
14268 Roo.bootstrap.TabPanel = function(config){
14269 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14273 * Fires when the active status changes
14274 * @param {Roo.bootstrap.TabPanel} this
14275 * @param {Boolean} state the new state
14280 * @event beforedeactivate
14281 * Fires before a tab is de-activated - can be used to do validation on a form.
14282 * @param {Roo.bootstrap.TabPanel} this
14283 * @return {Boolean} false if there is an error
14286 'beforedeactivate': true
14289 this.tabId = this.tabId || Roo.id();
14293 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14300 getAutoCreate : function(){
14303 // item is needed for carousel - not sure if it has any effect otherwise
14304 cls: 'tab-pane item',
14305 html: this.html || ''
14309 cfg.cls += ' active';
14313 cfg.tabId = this.tabId;
14320 initEvents: function()
14322 Roo.log('-------- init events on tab panel ---------');
14324 var p = this.parent();
14325 this.navId = this.navId || p.navId;
14327 if (typeof(this.navId) != 'undefined') {
14328 // not really needed.. but just in case.. parent should be a NavGroup.
14329 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14330 Roo.log(['register', tg, this]);
14336 onRender : function(ct, position)
14338 // Roo.log("Call onRender: " + this.xtype);
14340 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14348 setActive: function(state)
14350 Roo.log("panel - set active " + this.tabId + "=" + state);
14352 this.active = state;
14354 this.el.removeClass('active');
14356 } else if (!this.el.hasClass('active')) {
14357 this.el.addClass('active');
14359 this.fireEvent('changed', this, state);
14376 * @class Roo.bootstrap.DateField
14377 * @extends Roo.bootstrap.Input
14378 * Bootstrap DateField class
14379 * @cfg {Number} weekStart default 0
14380 * @cfg {Number} weekStart default 0
14381 * @cfg {Number} viewMode default empty, (months|years)
14382 * @cfg {Number} minViewMode default empty, (months|years)
14383 * @cfg {Number} startDate default -Infinity
14384 * @cfg {Number} endDate default Infinity
14385 * @cfg {Boolean} todayHighlight default false
14386 * @cfg {Boolean} todayBtn default false
14387 * @cfg {Boolean} calendarWeeks default false
14388 * @cfg {Object} daysOfWeekDisabled default empty
14390 * @cfg {Boolean} keyboardNavigation default true
14391 * @cfg {String} language default en
14394 * Create a new DateField
14395 * @param {Object} config The config object
14398 Roo.bootstrap.DateField = function(config){
14399 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14403 * Fires when this field show.
14404 * @param {Roo.bootstrap.DateField} this
14405 * @param {Mixed} date The date value
14410 * Fires when this field hide.
14411 * @param {Roo.bootstrap.DateField} this
14412 * @param {Mixed} date The date value
14417 * Fires when select a date.
14418 * @param {Roo.bootstrap.DateField} this
14419 * @param {Mixed} date The date value
14425 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14428 * @cfg {String} format
14429 * The default date format string which can be overriden for localization support. The format must be
14430 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14434 * @cfg {String} altFormats
14435 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14436 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14438 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14446 todayHighlight : false,
14452 keyboardNavigation: true,
14454 calendarWeeks: false,
14456 startDate: -Infinity,
14460 daysOfWeekDisabled: [],
14464 UTCDate: function()
14466 return new Date(Date.UTC.apply(Date, arguments));
14469 UTCToday: function()
14471 var today = new Date();
14472 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14475 getDate: function() {
14476 var d = this.getUTCDate();
14477 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14480 getUTCDate: function() {
14484 setDate: function(d) {
14485 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14488 setUTCDate: function(d) {
14490 this.setValue(this.formatDate(this.date));
14493 onRender: function(ct, position)
14496 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14498 this.language = this.language || 'en';
14499 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14500 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14502 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14503 this.format = this.format || 'm/d/y';
14504 this.isInline = false;
14505 this.isInput = true;
14506 this.component = this.el.select('.add-on', true).first() || false;
14507 this.component = (this.component && this.component.length === 0) ? false : this.component;
14508 this.hasInput = this.component && this.inputEL().length;
14510 if (typeof(this.minViewMode === 'string')) {
14511 switch (this.minViewMode) {
14513 this.minViewMode = 1;
14516 this.minViewMode = 2;
14519 this.minViewMode = 0;
14524 if (typeof(this.viewMode === 'string')) {
14525 switch (this.viewMode) {
14538 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14540 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14542 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14544 this.picker().on('mousedown', this.onMousedown, this);
14545 this.picker().on('click', this.onClick, this);
14547 this.picker().addClass('datepicker-dropdown');
14549 this.startViewMode = this.viewMode;
14552 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14553 if(!this.calendarWeeks){
14558 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14559 v.attr('colspan', function(i, val){
14560 return parseInt(val) + 1;
14565 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14567 this.setStartDate(this.startDate);
14568 this.setEndDate(this.endDate);
14570 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14577 if(this.isInline) {
14582 picker : function()
14584 return this.pickerEl;
14585 // return this.el.select('.datepicker', true).first();
14588 fillDow: function()
14590 var dowCnt = this.weekStart;
14599 if(this.calendarWeeks){
14607 while (dowCnt < this.weekStart + 7) {
14611 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14615 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14618 fillMonths: function()
14621 var months = this.picker().select('>.datepicker-months td', true).first();
14623 months.dom.innerHTML = '';
14629 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14632 months.createChild(month);
14639 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;
14641 if (this.date < this.startDate) {
14642 this.viewDate = new Date(this.startDate);
14643 } else if (this.date > this.endDate) {
14644 this.viewDate = new Date(this.endDate);
14646 this.viewDate = new Date(this.date);
14654 var d = new Date(this.viewDate),
14655 year = d.getUTCFullYear(),
14656 month = d.getUTCMonth(),
14657 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14658 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14659 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14660 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14661 currentDate = this.date && this.date.valueOf(),
14662 today = this.UTCToday();
14664 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14666 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14668 // this.picker.select('>tfoot th.today').
14669 // .text(dates[this.language].today)
14670 // .toggle(this.todayBtn !== false);
14672 this.updateNavArrows();
14675 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14677 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14679 prevMonth.setUTCDate(day);
14681 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14683 var nextMonth = new Date(prevMonth);
14685 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14687 nextMonth = nextMonth.valueOf();
14689 var fillMonths = false;
14691 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14693 while(prevMonth.valueOf() < nextMonth) {
14696 if (prevMonth.getUTCDay() === this.weekStart) {
14698 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14706 if(this.calendarWeeks){
14707 // ISO 8601: First week contains first thursday.
14708 // ISO also states week starts on Monday, but we can be more abstract here.
14710 // Start of current week: based on weekstart/current date
14711 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14712 // Thursday of this week
14713 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14714 // First Thursday of year, year from thursday
14715 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14716 // Calendar week: ms between thursdays, div ms per day, div 7 days
14717 calWeek = (th - yth) / 864e5 / 7 + 1;
14719 fillMonths.cn.push({
14727 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14729 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14732 if (this.todayHighlight &&
14733 prevMonth.getUTCFullYear() == today.getFullYear() &&
14734 prevMonth.getUTCMonth() == today.getMonth() &&
14735 prevMonth.getUTCDate() == today.getDate()) {
14736 clsName += ' today';
14739 if (currentDate && prevMonth.valueOf() === currentDate) {
14740 clsName += ' active';
14743 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14744 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14745 clsName += ' disabled';
14748 fillMonths.cn.push({
14750 cls: 'day ' + clsName,
14751 html: prevMonth.getDate()
14754 prevMonth.setDate(prevMonth.getDate()+1);
14757 var currentYear = this.date && this.date.getUTCFullYear();
14758 var currentMonth = this.date && this.date.getUTCMonth();
14760 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14762 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14763 v.removeClass('active');
14765 if(currentYear === year && k === currentMonth){
14766 v.addClass('active');
14769 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14770 v.addClass('disabled');
14776 year = parseInt(year/10, 10) * 10;
14778 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14780 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14783 for (var i = -1; i < 11; i++) {
14784 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14786 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14794 showMode: function(dir)
14797 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14799 Roo.each(this.picker().select('>div',true).elements, function(v){
14800 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14803 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14808 if(this.isInline) return;
14810 this.picker().removeClass(['bottom', 'top']);
14812 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14814 * place to the top of element!
14818 this.picker().addClass('top');
14819 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14824 this.picker().addClass('bottom');
14826 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14829 parseDate : function(value)
14831 if(!value || value instanceof Date){
14834 var v = Date.parseDate(value, this.format);
14835 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
14836 v = Date.parseDate(value, 'Y-m-d');
14838 if(!v && this.altFormats){
14839 if(!this.altFormatsArray){
14840 this.altFormatsArray = this.altFormats.split("|");
14842 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14843 v = Date.parseDate(value, this.altFormatsArray[i]);
14849 formatDate : function(date, fmt)
14851 return (!date || !(date instanceof Date)) ?
14852 date : date.dateFormat(fmt || this.format);
14855 onFocus : function()
14857 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14861 onBlur : function()
14863 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14865 var d = this.inputEl().getValue();
14874 this.picker().show();
14878 this.fireEvent('show', this, this.date);
14883 if(this.isInline) return;
14884 this.picker().hide();
14885 this.viewMode = this.startViewMode;
14888 this.fireEvent('hide', this, this.date);
14892 onMousedown: function(e)
14894 e.stopPropagation();
14895 e.preventDefault();
14900 Roo.bootstrap.DateField.superclass.keyup.call(this);
14904 setValue: function(v)
14907 // v can be a string or a date..
14910 var d = new Date(this.parseDate(v) ).clearTime();
14914 if(isNaN(d.getTime())){
14915 this.date = this.viewDate = '';
14916 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14920 v = this.formatDate(d);
14922 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14924 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14928 this.fireEvent('select', this, this.date);
14932 getValue: function()
14934 return this.formatDate(this.date);
14937 fireKey: function(e)
14939 if (!this.picker().isVisible()){
14940 if (e.keyCode == 27) // allow escape to hide and re-show picker
14945 var dateChanged = false,
14947 newDate, newViewDate;
14952 e.preventDefault();
14956 if (!this.keyboardNavigation) break;
14957 dir = e.keyCode == 37 ? -1 : 1;
14960 newDate = this.moveYear(this.date, dir);
14961 newViewDate = this.moveYear(this.viewDate, dir);
14962 } else if (e.shiftKey){
14963 newDate = this.moveMonth(this.date, dir);
14964 newViewDate = this.moveMonth(this.viewDate, dir);
14966 newDate = new Date(this.date);
14967 newDate.setUTCDate(this.date.getUTCDate() + dir);
14968 newViewDate = new Date(this.viewDate);
14969 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14971 if (this.dateWithinRange(newDate)){
14972 this.date = newDate;
14973 this.viewDate = newViewDate;
14974 this.setValue(this.formatDate(this.date));
14976 e.preventDefault();
14977 dateChanged = true;
14982 if (!this.keyboardNavigation) break;
14983 dir = e.keyCode == 38 ? -1 : 1;
14985 newDate = this.moveYear(this.date, dir);
14986 newViewDate = this.moveYear(this.viewDate, dir);
14987 } else if (e.shiftKey){
14988 newDate = this.moveMonth(this.date, dir);
14989 newViewDate = this.moveMonth(this.viewDate, dir);
14991 newDate = new Date(this.date);
14992 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14993 newViewDate = new Date(this.viewDate);
14994 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14996 if (this.dateWithinRange(newDate)){
14997 this.date = newDate;
14998 this.viewDate = newViewDate;
14999 this.setValue(this.formatDate(this.date));
15001 e.preventDefault();
15002 dateChanged = true;
15006 this.setValue(this.formatDate(this.date));
15008 e.preventDefault();
15011 this.setValue(this.formatDate(this.date));
15025 onClick: function(e)
15027 e.stopPropagation();
15028 e.preventDefault();
15030 var target = e.getTarget();
15032 if(target.nodeName.toLowerCase() === 'i'){
15033 target = Roo.get(target).dom.parentNode;
15036 var nodeName = target.nodeName;
15037 var className = target.className;
15038 var html = target.innerHTML;
15039 //Roo.log(nodeName);
15041 switch(nodeName.toLowerCase()) {
15043 switch(className) {
15049 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15050 switch(this.viewMode){
15052 this.viewDate = this.moveMonth(this.viewDate, dir);
15056 this.viewDate = this.moveYear(this.viewDate, dir);
15062 var date = new Date();
15063 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15065 this.setValue(this.formatDate(this.date));
15072 if (className.indexOf('disabled') < 0) {
15073 this.viewDate.setUTCDate(1);
15074 if (className.indexOf('month') > -1) {
15075 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15077 var year = parseInt(html, 10) || 0;
15078 this.viewDate.setUTCFullYear(year);
15087 //Roo.log(className);
15088 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15089 var day = parseInt(html, 10) || 1;
15090 var year = this.viewDate.getUTCFullYear(),
15091 month = this.viewDate.getUTCMonth();
15093 if (className.indexOf('old') > -1) {
15100 } else if (className.indexOf('new') > -1) {
15108 //Roo.log([year,month,day]);
15109 this.date = this.UTCDate(year, month, day,0,0,0,0);
15110 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15112 //Roo.log(this.formatDate(this.date));
15113 this.setValue(this.formatDate(this.date));
15120 setStartDate: function(startDate)
15122 this.startDate = startDate || -Infinity;
15123 if (this.startDate !== -Infinity) {
15124 this.startDate = this.parseDate(this.startDate);
15127 this.updateNavArrows();
15130 setEndDate: function(endDate)
15132 this.endDate = endDate || Infinity;
15133 if (this.endDate !== Infinity) {
15134 this.endDate = this.parseDate(this.endDate);
15137 this.updateNavArrows();
15140 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15142 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15143 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15144 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15146 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15147 return parseInt(d, 10);
15150 this.updateNavArrows();
15153 updateNavArrows: function()
15155 var d = new Date(this.viewDate),
15156 year = d.getUTCFullYear(),
15157 month = d.getUTCMonth();
15159 Roo.each(this.picker().select('.prev', true).elements, function(v){
15161 switch (this.viewMode) {
15164 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15170 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15177 Roo.each(this.picker().select('.next', true).elements, function(v){
15179 switch (this.viewMode) {
15182 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15188 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15196 moveMonth: function(date, dir)
15198 if (!dir) return date;
15199 var new_date = new Date(date.valueOf()),
15200 day = new_date.getUTCDate(),
15201 month = new_date.getUTCMonth(),
15202 mag = Math.abs(dir),
15204 dir = dir > 0 ? 1 : -1;
15207 // If going back one month, make sure month is not current month
15208 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15210 return new_date.getUTCMonth() == month;
15212 // If going forward one month, make sure month is as expected
15213 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15215 return new_date.getUTCMonth() != new_month;
15217 new_month = month + dir;
15218 new_date.setUTCMonth(new_month);
15219 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15220 if (new_month < 0 || new_month > 11)
15221 new_month = (new_month + 12) % 12;
15223 // For magnitudes >1, move one month at a time...
15224 for (var i=0; i<mag; i++)
15225 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15226 new_date = this.moveMonth(new_date, dir);
15227 // ...then reset the day, keeping it in the new month
15228 new_month = new_date.getUTCMonth();
15229 new_date.setUTCDate(day);
15231 return new_month != new_date.getUTCMonth();
15234 // Common date-resetting loop -- if date is beyond end of month, make it
15237 new_date.setUTCDate(--day);
15238 new_date.setUTCMonth(new_month);
15243 moveYear: function(date, dir)
15245 return this.moveMonth(date, dir*12);
15248 dateWithinRange: function(date)
15250 return date >= this.startDate && date <= this.endDate;
15256 this.picker().remove();
15261 Roo.apply(Roo.bootstrap.DateField, {
15272 html: '<i class="fa fa-arrow-left"/>'
15282 html: '<i class="fa fa-arrow-right"/>'
15324 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15325 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15326 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15327 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15328 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15341 navFnc: 'FullYear',
15346 navFnc: 'FullYear',
15351 Roo.apply(Roo.bootstrap.DateField, {
15355 cls: 'datepicker dropdown-menu',
15359 cls: 'datepicker-days',
15363 cls: 'table-condensed',
15365 Roo.bootstrap.DateField.head,
15369 Roo.bootstrap.DateField.footer
15376 cls: 'datepicker-months',
15380 cls: 'table-condensed',
15382 Roo.bootstrap.DateField.head,
15383 Roo.bootstrap.DateField.content,
15384 Roo.bootstrap.DateField.footer
15391 cls: 'datepicker-years',
15395 cls: 'table-condensed',
15397 Roo.bootstrap.DateField.head,
15398 Roo.bootstrap.DateField.content,
15399 Roo.bootstrap.DateField.footer
15418 * @class Roo.bootstrap.TimeField
15419 * @extends Roo.bootstrap.Input
15420 * Bootstrap DateField class
15424 * Create a new TimeField
15425 * @param {Object} config The config object
15428 Roo.bootstrap.TimeField = function(config){
15429 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15433 * Fires when this field show.
15434 * @param {Roo.bootstrap.DateField} this
15435 * @param {Mixed} date The date value
15440 * Fires when this field hide.
15441 * @param {Roo.bootstrap.DateField} this
15442 * @param {Mixed} date The date value
15447 * Fires when select a date.
15448 * @param {Roo.bootstrap.DateField} this
15449 * @param {Mixed} date The date value
15455 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15458 * @cfg {String} format
15459 * The default time format string which can be overriden for localization support. The format must be
15460 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15464 onRender: function(ct, position)
15467 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15469 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15471 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15473 this.pop = this.picker().select('>.datepicker-time',true).first();
15474 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15476 this.picker().on('mousedown', this.onMousedown, this);
15477 this.picker().on('click', this.onClick, this);
15479 this.picker().addClass('datepicker-dropdown');
15484 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15485 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15486 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15487 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15488 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15489 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15493 fireKey: function(e){
15494 if (!this.picker().isVisible()){
15495 if (e.keyCode == 27) // allow escape to hide and re-show picker
15500 e.preventDefault();
15508 this.onTogglePeriod();
15511 this.onIncrementMinutes();
15514 this.onDecrementMinutes();
15523 onClick: function(e) {
15524 e.stopPropagation();
15525 e.preventDefault();
15528 picker : function()
15530 return this.el.select('.datepicker', true).first();
15533 fillTime: function()
15535 var time = this.pop.select('tbody', true).first();
15537 time.dom.innerHTML = '';
15552 cls: 'hours-up glyphicon glyphicon-chevron-up'
15572 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15593 cls: 'timepicker-hour',
15608 cls: 'timepicker-minute',
15623 cls: 'btn btn-primary period',
15645 cls: 'hours-down glyphicon glyphicon-chevron-down'
15665 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15683 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15690 var hours = this.time.getHours();
15691 var minutes = this.time.getMinutes();
15704 hours = hours - 12;
15708 hours = '0' + hours;
15712 minutes = '0' + minutes;
15715 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15716 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15717 this.pop.select('button', true).first().dom.innerHTML = period;
15723 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15725 var cls = ['bottom'];
15727 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15734 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15739 this.picker().addClass(cls.join('-'));
15743 Roo.each(cls, function(c){
15745 _this.picker().setTop(_this.inputEl().getHeight());
15749 _this.picker().setTop(0 - _this.picker().getHeight());
15754 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15758 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15765 onFocus : function()
15767 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15771 onBlur : function()
15773 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15779 this.picker().show();
15784 this.fireEvent('show', this, this.date);
15789 this.picker().hide();
15792 this.fireEvent('hide', this, this.date);
15795 setTime : function()
15798 this.setValue(this.time.format(this.format));
15800 this.fireEvent('select', this, this.date);
15805 onMousedown: function(e){
15806 e.stopPropagation();
15807 e.preventDefault();
15810 onIncrementHours: function()
15812 Roo.log('onIncrementHours');
15813 this.time = this.time.add(Date.HOUR, 1);
15818 onDecrementHours: function()
15820 Roo.log('onDecrementHours');
15821 this.time = this.time.add(Date.HOUR, -1);
15825 onIncrementMinutes: function()
15827 Roo.log('onIncrementMinutes');
15828 this.time = this.time.add(Date.MINUTE, 1);
15832 onDecrementMinutes: function()
15834 Roo.log('onDecrementMinutes');
15835 this.time = this.time.add(Date.MINUTE, -1);
15839 onTogglePeriod: function()
15841 Roo.log('onTogglePeriod');
15842 this.time = this.time.add(Date.HOUR, 12);
15849 Roo.apply(Roo.bootstrap.TimeField, {
15879 cls: 'btn btn-info ok',
15891 Roo.apply(Roo.bootstrap.TimeField, {
15895 cls: 'datepicker dropdown-menu',
15899 cls: 'datepicker-time',
15903 cls: 'table-condensed',
15905 Roo.bootstrap.TimeField.content,
15906 Roo.bootstrap.TimeField.footer
15925 * @class Roo.bootstrap.CheckBox
15926 * @extends Roo.bootstrap.Input
15927 * Bootstrap CheckBox class
15929 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15930 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15931 * @cfg {String} boxLabel The text that appears beside the checkbox
15932 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15933 * @cfg {Boolean} checked initnal the element
15937 * Create a new CheckBox
15938 * @param {Object} config The config object
15941 Roo.bootstrap.CheckBox = function(config){
15942 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15947 * Fires when the element is checked or unchecked.
15948 * @param {Roo.bootstrap.CheckBox} this This input
15949 * @param {Boolean} checked The new checked value
15955 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15957 inputType: 'checkbox',
15964 getAutoCreate : function()
15966 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15972 cfg.cls = 'form-group checkbox' //input-group
15980 type : this.inputType,
15981 value : (!this.checked) ? this.valueOff : this.inputValue,
15982 cls : 'roo-checkbox', //'form-box',
15983 placeholder : this.placeholder || ''
15987 if (this.weight) { // Validity check?
15988 cfg.cls += " checkbox-" + this.weight;
15991 if (this.disabled) {
15992 input.disabled=true;
15996 input.checked = this.checked;
16000 input.name = this.name;
16004 input.cls += ' input-' + this.size;
16008 ['xs','sm','md','lg'].map(function(size){
16009 if (settings[size]) {
16010 cfg.cls += ' col-' + size + '-' + settings[size];
16016 var inputblock = input;
16021 if (this.before || this.after) {
16024 cls : 'input-group',
16028 inputblock.cn.push({
16030 cls : 'input-group-addon',
16034 inputblock.cn.push(input);
16036 inputblock.cn.push({
16038 cls : 'input-group-addon',
16045 if (align ==='left' && this.fieldLabel.length) {
16046 Roo.log("left and has label");
16052 cls : 'control-label col-md-' + this.labelWidth,
16053 html : this.fieldLabel
16057 cls : "col-md-" + (12 - this.labelWidth),
16064 } else if ( this.fieldLabel.length) {
16069 tag: this.boxLabel ? 'span' : 'label',
16071 cls: 'control-label box-input-label',
16072 //cls : 'input-group-addon',
16073 html : this.fieldLabel
16083 Roo.log(" no label && no align");
16084 cfg.cn = [ inputblock ] ;
16093 html: this.boxLabel
16105 * return the real input element.
16107 inputEl: function ()
16109 return this.el.select('input.roo-checkbox',true).first();
16114 return this.el.select('label.control-label',true).first();
16117 initEvents : function()
16119 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16121 this.inputEl().on('click', this.onClick, this);
16125 onClick : function()
16127 this.setChecked(!this.checked);
16130 setChecked : function(state,suppressEvent)
16132 this.checked = state;
16134 this.inputEl().dom.checked = state;
16136 if(suppressEvent !== true){
16137 this.fireEvent('check', this, state);
16140 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16144 setValue : function(v,suppressEvent)
16146 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16160 * @class Roo.bootstrap.Radio
16161 * @extends Roo.bootstrap.CheckBox
16162 * Bootstrap Radio class
16165 * Create a new Radio
16166 * @param {Object} config The config object
16169 Roo.bootstrap.Radio = function(config){
16170 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16174 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16176 inputType: 'radio',
16180 getAutoCreate : function()
16182 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16188 cfg.cls = 'form-group radio' //input-group
16193 type : this.inputType,
16194 value : (!this.checked) ? this.valueOff : this.inputValue,
16196 placeholder : this.placeholder || ''
16199 if (this.weight) { // Validity check?
16200 cfg.cls += " radio-" + this.weight;
16202 if (this.disabled) {
16203 input.disabled=true;
16207 input.checked = this.checked;
16211 input.name = this.name;
16215 input.cls += ' input-' + this.size;
16219 ['xs','sm','md','lg'].map(function(size){
16220 if (settings[size]) {
16221 cfg.cls += ' col-' + size + '-' + settings[size];
16225 var inputblock = input;
16227 if (this.before || this.after) {
16230 cls : 'input-group',
16234 inputblock.cn.push({
16236 cls : 'input-group-addon',
16240 inputblock.cn.push(input);
16242 inputblock.cn.push({
16244 cls : 'input-group-addon',
16251 if (align ==='left' && this.fieldLabel.length) {
16252 Roo.log("left and has label");
16258 cls : 'control-label col-md-' + this.labelWidth,
16259 html : this.fieldLabel
16263 cls : "col-md-" + (12 - this.labelWidth),
16270 } else if ( this.fieldLabel.length) {
16277 cls: 'control-label box-input-label',
16278 //cls : 'input-group-addon',
16279 html : this.fieldLabel
16289 Roo.log(" no label && no align");
16304 html: this.boxLabel
16311 inputEl: function ()
16313 return this.el.select('input.roo-radio',true).first();
16315 onClick : function()
16317 this.setChecked(true);
16320 setChecked : function(state,suppressEvent)
16323 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16324 v.dom.checked = false;
16328 this.checked = state;
16329 this.inputEl().dom.checked = state;
16331 if(suppressEvent !== true){
16332 this.fireEvent('check', this, state);
16335 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16339 getGroupValue : function()
16342 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16343 if(v.dom.checked == true){
16344 value = v.dom.value;
16352 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16353 * @return {Mixed} value The field value
16355 getValue : function(){
16356 return this.getGroupValue();
16362 //<script type="text/javascript">
16365 * Based Ext JS Library 1.1.1
16366 * Copyright(c) 2006-2007, Ext JS, LLC.
16372 * @class Roo.HtmlEditorCore
16373 * @extends Roo.Component
16374 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16376 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16379 Roo.HtmlEditorCore = function(config){
16382 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16387 * @event initialize
16388 * Fires when the editor is fully initialized (including the iframe)
16389 * @param {Roo.HtmlEditorCore} this
16394 * Fires when the editor is first receives the focus. Any insertion must wait
16395 * until after this event.
16396 * @param {Roo.HtmlEditorCore} this
16400 * @event beforesync
16401 * Fires before the textarea is updated with content from the editor iframe. Return false
16402 * to cancel the sync.
16403 * @param {Roo.HtmlEditorCore} this
16404 * @param {String} html
16408 * @event beforepush
16409 * Fires before the iframe editor is updated with content from the textarea. Return false
16410 * to cancel the push.
16411 * @param {Roo.HtmlEditorCore} this
16412 * @param {String} html
16417 * Fires when the textarea is updated with content from the editor iframe.
16418 * @param {Roo.HtmlEditorCore} this
16419 * @param {String} html
16424 * Fires when the iframe editor is updated with content from the textarea.
16425 * @param {Roo.HtmlEditorCore} this
16426 * @param {String} html
16431 * @event editorevent
16432 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16433 * @param {Roo.HtmlEditorCore} this
16438 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16440 // defaults : white / black...
16441 this.applyBlacklists();
16448 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16452 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16458 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16463 * @cfg {Number} height (in pixels)
16467 * @cfg {Number} width (in pixels)
16472 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16475 stylesheets: false,
16480 // private properties
16481 validationEvent : false,
16483 initialized : false,
16485 sourceEditMode : false,
16486 onFocus : Roo.emptyFn,
16488 hideMode:'offsets',
16492 // blacklist + whitelisted elements..
16499 * Protected method that will not generally be called directly. It
16500 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16501 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16503 getDocMarkup : function(){
16506 Roo.log(this.stylesheets);
16508 // inherit styels from page...??
16509 if (this.stylesheets === false) {
16511 Roo.get(document.head).select('style').each(function(node) {
16512 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16515 Roo.get(document.head).select('link').each(function(node) {
16516 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16519 } else if (!this.stylesheets.length) {
16521 st = '<style type="text/css">' +
16522 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16525 Roo.each(this.stylesheets, function(s) {
16526 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16531 st += '<style type="text/css">' +
16532 'IMG { cursor: pointer } ' +
16536 return '<html><head>' + st +
16537 //<style type="text/css">' +
16538 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16540 ' </head><body class="roo-htmleditor-body"></body></html>';
16544 onRender : function(ct, position)
16547 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16548 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16551 this.el.dom.style.border = '0 none';
16552 this.el.dom.setAttribute('tabIndex', -1);
16553 this.el.addClass('x-hidden hide');
16557 if(Roo.isIE){ // fix IE 1px bogus margin
16558 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16562 this.frameId = Roo.id();
16566 var iframe = this.owner.wrap.createChild({
16568 cls: 'form-control', // bootstrap..
16570 name: this.frameId,
16571 frameBorder : 'no',
16572 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16577 this.iframe = iframe.dom;
16579 this.assignDocWin();
16581 this.doc.designMode = 'on';
16584 this.doc.write(this.getDocMarkup());
16588 var task = { // must defer to wait for browser to be ready
16590 //console.log("run task?" + this.doc.readyState);
16591 this.assignDocWin();
16592 if(this.doc.body || this.doc.readyState == 'complete'){
16594 this.doc.designMode="on";
16598 Roo.TaskMgr.stop(task);
16599 this.initEditor.defer(10, this);
16606 Roo.TaskMgr.start(task);
16613 onResize : function(w, h)
16615 Roo.log('resize: ' +w + ',' + h );
16616 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16620 if(typeof w == 'number'){
16622 this.iframe.style.width = w + 'px';
16624 if(typeof h == 'number'){
16626 this.iframe.style.height = h + 'px';
16628 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16635 * Toggles the editor between standard and source edit mode.
16636 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16638 toggleSourceEdit : function(sourceEditMode){
16640 this.sourceEditMode = sourceEditMode === true;
16642 if(this.sourceEditMode){
16644 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16647 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16648 //this.iframe.className = '';
16651 //this.setSize(this.owner.wrap.getSize());
16652 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16659 * Protected method that will not generally be called directly. If you need/want
16660 * custom HTML cleanup, this is the method you should override.
16661 * @param {String} html The HTML to be cleaned
16662 * return {String} The cleaned HTML
16664 cleanHtml : function(html){
16665 html = String(html);
16666 if(html.length > 5){
16667 if(Roo.isSafari){ // strip safari nonsense
16668 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16671 if(html == ' '){
16678 * HTML Editor -> Textarea
16679 * Protected method that will not generally be called directly. Syncs the contents
16680 * of the editor iframe with the textarea.
16682 syncValue : function(){
16683 if(this.initialized){
16684 var bd = (this.doc.body || this.doc.documentElement);
16685 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16686 var html = bd.innerHTML;
16688 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16689 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16691 html = '<div style="'+m[0]+'">' + html + '</div>';
16694 html = this.cleanHtml(html);
16695 // fix up the special chars.. normaly like back quotes in word...
16696 // however we do not want to do this with chinese..
16697 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16698 var cc = b.charCodeAt();
16700 (cc >= 0x4E00 && cc < 0xA000 ) ||
16701 (cc >= 0x3400 && cc < 0x4E00 ) ||
16702 (cc >= 0xf900 && cc < 0xfb00 )
16708 if(this.owner.fireEvent('beforesync', this, html) !== false){
16709 this.el.dom.value = html;
16710 this.owner.fireEvent('sync', this, html);
16716 * Protected method that will not generally be called directly. Pushes the value of the textarea
16717 * into the iframe editor.
16719 pushValue : function(){
16720 if(this.initialized){
16721 var v = this.el.dom.value.trim();
16723 // if(v.length < 1){
16727 if(this.owner.fireEvent('beforepush', this, v) !== false){
16728 var d = (this.doc.body || this.doc.documentElement);
16730 this.cleanUpPaste();
16731 this.el.dom.value = d.innerHTML;
16732 this.owner.fireEvent('push', this, v);
16738 deferFocus : function(){
16739 this.focus.defer(10, this);
16743 focus : function(){
16744 if(this.win && !this.sourceEditMode){
16751 assignDocWin: function()
16753 var iframe = this.iframe;
16756 this.doc = iframe.contentWindow.document;
16757 this.win = iframe.contentWindow;
16759 // if (!Roo.get(this.frameId)) {
16762 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16763 // this.win = Roo.get(this.frameId).dom.contentWindow;
16765 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16769 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16770 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16775 initEditor : function(){
16776 //console.log("INIT EDITOR");
16777 this.assignDocWin();
16781 this.doc.designMode="on";
16783 this.doc.write(this.getDocMarkup());
16786 var dbody = (this.doc.body || this.doc.documentElement);
16787 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16788 // this copies styles from the containing element into thsi one..
16789 // not sure why we need all of this..
16790 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16792 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16793 //ss['background-attachment'] = 'fixed'; // w3c
16794 dbody.bgProperties = 'fixed'; // ie
16795 //Roo.DomHelper.applyStyles(dbody, ss);
16796 Roo.EventManager.on(this.doc, {
16797 //'mousedown': this.onEditorEvent,
16798 'mouseup': this.onEditorEvent,
16799 'dblclick': this.onEditorEvent,
16800 'click': this.onEditorEvent,
16801 'keyup': this.onEditorEvent,
16806 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16808 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16809 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16811 this.initialized = true;
16813 this.owner.fireEvent('initialize', this);
16818 onDestroy : function(){
16824 //for (var i =0; i < this.toolbars.length;i++) {
16825 // // fixme - ask toolbars for heights?
16826 // this.toolbars[i].onDestroy();
16829 //this.wrap.dom.innerHTML = '';
16830 //this.wrap.remove();
16835 onFirstFocus : function(){
16837 this.assignDocWin();
16840 this.activated = true;
16843 if(Roo.isGecko){ // prevent silly gecko errors
16845 var s = this.win.getSelection();
16846 if(!s.focusNode || s.focusNode.nodeType != 3){
16847 var r = s.getRangeAt(0);
16848 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16853 this.execCmd('useCSS', true);
16854 this.execCmd('styleWithCSS', false);
16857 this.owner.fireEvent('activate', this);
16861 adjustFont: function(btn){
16862 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16863 //if(Roo.isSafari){ // safari
16866 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16867 if(Roo.isSafari){ // safari
16868 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16869 v = (v < 10) ? 10 : v;
16870 v = (v > 48) ? 48 : v;
16871 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16876 v = Math.max(1, v+adjust);
16878 this.execCmd('FontSize', v );
16881 onEditorEvent : function(e){
16882 this.owner.fireEvent('editorevent', this, e);
16883 // this.updateToolbar();
16884 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16887 insertTag : function(tg)
16889 // could be a bit smarter... -> wrap the current selected tRoo..
16890 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16892 range = this.createRange(this.getSelection());
16893 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16894 wrappingNode.appendChild(range.extractContents());
16895 range.insertNode(wrappingNode);
16902 this.execCmd("formatblock", tg);
16906 insertText : function(txt)
16910 var range = this.createRange();
16911 range.deleteContents();
16912 //alert(Sender.getAttribute('label'));
16914 range.insertNode(this.doc.createTextNode(txt));
16920 * Executes a Midas editor command on the editor document and performs necessary focus and
16921 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16922 * @param {String} cmd The Midas command
16923 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16925 relayCmd : function(cmd, value){
16927 this.execCmd(cmd, value);
16928 this.owner.fireEvent('editorevent', this);
16929 //this.updateToolbar();
16930 this.owner.deferFocus();
16934 * Executes a Midas editor command directly on the editor document.
16935 * For visual commands, you should use {@link #relayCmd} instead.
16936 * <b>This should only be called after the editor is initialized.</b>
16937 * @param {String} cmd The Midas command
16938 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16940 execCmd : function(cmd, value){
16941 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16948 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16950 * @param {String} text | dom node..
16952 insertAtCursor : function(text)
16957 if(!this.activated){
16963 var r = this.doc.selection.createRange();
16974 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16978 // from jquery ui (MIT licenced)
16980 var win = this.win;
16982 if (win.getSelection && win.getSelection().getRangeAt) {
16983 range = win.getSelection().getRangeAt(0);
16984 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16985 range.insertNode(node);
16986 } else if (win.document.selection && win.document.selection.createRange) {
16987 // no firefox support
16988 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16989 win.document.selection.createRange().pasteHTML(txt);
16991 // no firefox support
16992 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16993 this.execCmd('InsertHTML', txt);
17002 mozKeyPress : function(e){
17004 var c = e.getCharCode(), cmd;
17007 c = String.fromCharCode(c).toLowerCase();
17021 this.cleanUpPaste.defer(100, this);
17029 e.preventDefault();
17037 fixKeys : function(){ // load time branching for fastest keydown performance
17039 return function(e){
17040 var k = e.getKey(), r;
17043 r = this.doc.selection.createRange();
17046 r.pasteHTML('    ');
17053 r = this.doc.selection.createRange();
17055 var target = r.parentElement();
17056 if(!target || target.tagName.toLowerCase() != 'li'){
17058 r.pasteHTML('<br />');
17064 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17065 this.cleanUpPaste.defer(100, this);
17071 }else if(Roo.isOpera){
17072 return function(e){
17073 var k = e.getKey();
17077 this.execCmd('InsertHTML','    ');
17080 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17081 this.cleanUpPaste.defer(100, this);
17086 }else if(Roo.isSafari){
17087 return function(e){
17088 var k = e.getKey();
17092 this.execCmd('InsertText','\t');
17096 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17097 this.cleanUpPaste.defer(100, this);
17105 getAllAncestors: function()
17107 var p = this.getSelectedNode();
17110 a.push(p); // push blank onto stack..
17111 p = this.getParentElement();
17115 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17119 a.push(this.doc.body);
17123 lastSelNode : false,
17126 getSelection : function()
17128 this.assignDocWin();
17129 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17132 getSelectedNode: function()
17134 // this may only work on Gecko!!!
17136 // should we cache this!!!!
17141 var range = this.createRange(this.getSelection()).cloneRange();
17144 var parent = range.parentElement();
17146 var testRange = range.duplicate();
17147 testRange.moveToElementText(parent);
17148 if (testRange.inRange(range)) {
17151 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17154 parent = parent.parentElement;
17159 // is ancestor a text element.
17160 var ac = range.commonAncestorContainer;
17161 if (ac.nodeType == 3) {
17162 ac = ac.parentNode;
17165 var ar = ac.childNodes;
17168 var other_nodes = [];
17169 var has_other_nodes = false;
17170 for (var i=0;i<ar.length;i++) {
17171 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17174 // fullly contained node.
17176 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17181 // probably selected..
17182 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17183 other_nodes.push(ar[i]);
17187 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17192 has_other_nodes = true;
17194 if (!nodes.length && other_nodes.length) {
17195 nodes= other_nodes;
17197 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17203 createRange: function(sel)
17205 // this has strange effects when using with
17206 // top toolbar - not sure if it's a great idea.
17207 //this.editor.contentWindow.focus();
17208 if (typeof sel != "undefined") {
17210 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17212 return this.doc.createRange();
17215 return this.doc.createRange();
17218 getParentElement: function()
17221 this.assignDocWin();
17222 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17224 var range = this.createRange(sel);
17227 var p = range.commonAncestorContainer;
17228 while (p.nodeType == 3) { // text node
17239 * Range intersection.. the hard stuff...
17243 * [ -- selected range --- ]
17247 * if end is before start or hits it. fail.
17248 * if start is after end or hits it fail.
17250 * if either hits (but other is outside. - then it's not
17256 // @see http://www.thismuchiknow.co.uk/?p=64.
17257 rangeIntersectsNode : function(range, node)
17259 var nodeRange = node.ownerDocument.createRange();
17261 nodeRange.selectNode(node);
17263 nodeRange.selectNodeContents(node);
17266 var rangeStartRange = range.cloneRange();
17267 rangeStartRange.collapse(true);
17269 var rangeEndRange = range.cloneRange();
17270 rangeEndRange.collapse(false);
17272 var nodeStartRange = nodeRange.cloneRange();
17273 nodeStartRange.collapse(true);
17275 var nodeEndRange = nodeRange.cloneRange();
17276 nodeEndRange.collapse(false);
17278 return rangeStartRange.compareBoundaryPoints(
17279 Range.START_TO_START, nodeEndRange) == -1 &&
17280 rangeEndRange.compareBoundaryPoints(
17281 Range.START_TO_START, nodeStartRange) == 1;
17285 rangeCompareNode : function(range, node)
17287 var nodeRange = node.ownerDocument.createRange();
17289 nodeRange.selectNode(node);
17291 nodeRange.selectNodeContents(node);
17295 range.collapse(true);
17297 nodeRange.collapse(true);
17299 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17300 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17302 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17304 var nodeIsBefore = ss == 1;
17305 var nodeIsAfter = ee == -1;
17307 if (nodeIsBefore && nodeIsAfter)
17309 if (!nodeIsBefore && nodeIsAfter)
17310 return 1; //right trailed.
17312 if (nodeIsBefore && !nodeIsAfter)
17313 return 2; // left trailed.
17318 // private? - in a new class?
17319 cleanUpPaste : function()
17321 // cleans up the whole document..
17322 Roo.log('cleanuppaste');
17324 this.cleanUpChildren(this.doc.body);
17325 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17326 if (clean != this.doc.body.innerHTML) {
17327 this.doc.body.innerHTML = clean;
17332 cleanWordChars : function(input) {// change the chars to hex code
17333 var he = Roo.HtmlEditorCore;
17335 var output = input;
17336 Roo.each(he.swapCodes, function(sw) {
17337 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17339 output = output.replace(swapper, sw[1]);
17346 cleanUpChildren : function (n)
17348 if (!n.childNodes.length) {
17351 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17352 this.cleanUpChild(n.childNodes[i]);
17359 cleanUpChild : function (node)
17362 //console.log(node);
17363 if (node.nodeName == "#text") {
17364 // clean up silly Windows -- stuff?
17367 if (node.nodeName == "#comment") {
17368 node.parentNode.removeChild(node);
17369 // clean up silly Windows -- stuff?
17372 var lcname = node.tagName.toLowerCase();
17373 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17374 // whitelist of tags..
17376 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17378 node.parentNode.removeChild(node);
17383 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17385 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17386 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17388 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17389 // remove_keep_children = true;
17392 if (remove_keep_children) {
17393 this.cleanUpChildren(node);
17394 // inserts everything just before this node...
17395 while (node.childNodes.length) {
17396 var cn = node.childNodes[0];
17397 node.removeChild(cn);
17398 node.parentNode.insertBefore(cn, node);
17400 node.parentNode.removeChild(node);
17404 if (!node.attributes || !node.attributes.length) {
17405 this.cleanUpChildren(node);
17409 function cleanAttr(n,v)
17412 if (v.match(/^\./) || v.match(/^\//)) {
17415 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17418 if (v.match(/^#/)) {
17421 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17422 node.removeAttribute(n);
17426 var cwhite = this.cwhite;
17427 var cblack = this.cblack;
17429 function cleanStyle(n,v)
17431 if (v.match(/expression/)) { //XSS?? should we even bother..
17432 node.removeAttribute(n);
17436 var parts = v.split(/;/);
17439 Roo.each(parts, function(p) {
17440 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17444 var l = p.split(':').shift().replace(/\s+/g,'');
17445 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17447 if ( cwhite.length && cblack.indexOf(l) > -1) {
17448 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17449 //node.removeAttribute(n);
17453 // only allow 'c whitelisted system attributes'
17454 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17455 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17456 //node.removeAttribute(n);
17466 if (clean.length) {
17467 node.setAttribute(n, clean.join(';'));
17469 node.removeAttribute(n);
17475 for (var i = node.attributes.length-1; i > -1 ; i--) {
17476 var a = node.attributes[i];
17479 if (a.name.toLowerCase().substr(0,2)=='on') {
17480 node.removeAttribute(a.name);
17483 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17484 node.removeAttribute(a.name);
17487 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17488 cleanAttr(a.name,a.value); // fixme..
17491 if (a.name == 'style') {
17492 cleanStyle(a.name,a.value);
17495 /// clean up MS crap..
17496 // tecnically this should be a list of valid class'es..
17499 if (a.name == 'class') {
17500 if (a.value.match(/^Mso/)) {
17501 node.className = '';
17504 if (a.value.match(/body/)) {
17505 node.className = '';
17516 this.cleanUpChildren(node);
17521 * Clean up MS wordisms...
17523 cleanWord : function(node)
17526 var cleanWordChildren = function()
17528 if (!node.childNodes.length) {
17531 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17532 _t.cleanWord(node.childNodes[i]);
17538 this.cleanWord(this.doc.body);
17541 if (node.nodeName == "#text") {
17542 // clean up silly Windows -- stuff?
17545 if (node.nodeName == "#comment") {
17546 node.parentNode.removeChild(node);
17547 // clean up silly Windows -- stuff?
17551 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17552 node.parentNode.removeChild(node);
17556 // remove - but keep children..
17557 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17558 while (node.childNodes.length) {
17559 var cn = node.childNodes[0];
17560 node.removeChild(cn);
17561 node.parentNode.insertBefore(cn, node);
17563 node.parentNode.removeChild(node);
17564 cleanWordChildren();
17568 if (node.className.length) {
17570 var cn = node.className.split(/\W+/);
17572 Roo.each(cn, function(cls) {
17573 if (cls.match(/Mso[a-zA-Z]+/)) {
17578 node.className = cna.length ? cna.join(' ') : '';
17580 node.removeAttribute("class");
17584 if (node.hasAttribute("lang")) {
17585 node.removeAttribute("lang");
17588 if (node.hasAttribute("style")) {
17590 var styles = node.getAttribute("style").split(";");
17592 Roo.each(styles, function(s) {
17593 if (!s.match(/:/)) {
17596 var kv = s.split(":");
17597 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17600 // what ever is left... we allow.
17603 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17604 if (!nstyle.length) {
17605 node.removeAttribute('style');
17609 cleanWordChildren();
17613 domToHTML : function(currentElement, depth, nopadtext) {
17615 depth = depth || 0;
17616 nopadtext = nopadtext || false;
17618 if (!currentElement) {
17619 return this.domToHTML(this.doc.body);
17622 //Roo.log(currentElement);
17624 var allText = false;
17625 var nodeName = currentElement.nodeName;
17626 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17628 if (nodeName == '#text') {
17629 return currentElement.nodeValue;
17634 if (nodeName != 'BODY') {
17637 // Prints the node tagName, such as <A>, <IMG>, etc
17640 for(i = 0; i < currentElement.attributes.length;i++) {
17642 var aname = currentElement.attributes.item(i).name;
17643 if (!currentElement.attributes.item(i).value.length) {
17646 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17649 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17658 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17661 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17666 // Traverse the tree
17668 var currentElementChild = currentElement.childNodes.item(i);
17669 var allText = true;
17670 var innerHTML = '';
17672 while (currentElementChild) {
17673 // Formatting code (indent the tree so it looks nice on the screen)
17674 var nopad = nopadtext;
17675 if (lastnode == 'SPAN') {
17679 if (currentElementChild.nodeName == '#text') {
17680 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17681 if (!nopad && toadd.length > 80) {
17682 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17684 innerHTML += toadd;
17687 currentElementChild = currentElement.childNodes.item(i);
17693 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17695 // Recursively traverse the tree structure of the child node
17696 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17697 lastnode = currentElementChild.nodeName;
17699 currentElementChild=currentElement.childNodes.item(i);
17705 // The remaining code is mostly for formatting the tree
17706 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17711 ret+= "</"+tagName+">";
17717 applyBlacklists : function()
17719 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17720 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17724 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17725 if (b.indexOf(tag) > -1) {
17728 this.white.push(tag);
17732 Roo.each(w, function(tag) {
17733 if (b.indexOf(tag) > -1) {
17736 if (this.white.indexOf(tag) > -1) {
17739 this.white.push(tag);
17744 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17745 if (w.indexOf(tag) > -1) {
17748 this.black.push(tag);
17752 Roo.each(b, function(tag) {
17753 if (w.indexOf(tag) > -1) {
17756 if (this.black.indexOf(tag) > -1) {
17759 this.black.push(tag);
17764 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
17765 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
17769 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17770 if (b.indexOf(tag) > -1) {
17773 this.cwhite.push(tag);
17777 Roo.each(w, function(tag) {
17778 if (b.indexOf(tag) > -1) {
17781 if (this.cwhite.indexOf(tag) > -1) {
17784 this.cwhite.push(tag);
17789 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
17790 if (w.indexOf(tag) > -1) {
17793 this.cblack.push(tag);
17797 Roo.each(b, function(tag) {
17798 if (w.indexOf(tag) > -1) {
17801 if (this.cblack.indexOf(tag) > -1) {
17804 this.cblack.push(tag);
17809 // hide stuff that is not compatible
17823 * @event specialkey
17827 * @cfg {String} fieldClass @hide
17830 * @cfg {String} focusClass @hide
17833 * @cfg {String} autoCreate @hide
17836 * @cfg {String} inputType @hide
17839 * @cfg {String} invalidClass @hide
17842 * @cfg {String} invalidText @hide
17845 * @cfg {String} msgFx @hide
17848 * @cfg {String} validateOnBlur @hide
17852 Roo.HtmlEditorCore.white = [
17853 'area', 'br', 'img', 'input', 'hr', 'wbr',
17855 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17856 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17857 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17858 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17859 'table', 'ul', 'xmp',
17861 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17864 'dir', 'menu', 'ol', 'ul', 'dl',
17870 Roo.HtmlEditorCore.black = [
17871 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17873 'base', 'basefont', 'bgsound', 'blink', 'body',
17874 'frame', 'frameset', 'head', 'html', 'ilayer',
17875 'iframe', 'layer', 'link', 'meta', 'object',
17876 'script', 'style' ,'title', 'xml' // clean later..
17878 Roo.HtmlEditorCore.clean = [
17879 'script', 'style', 'title', 'xml'
17881 Roo.HtmlEditorCore.remove = [
17886 Roo.HtmlEditorCore.ablack = [
17890 Roo.HtmlEditorCore.aclean = [
17891 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17895 Roo.HtmlEditorCore.pwhite= [
17896 'http', 'https', 'mailto'
17899 // white listed style attributes.
17900 Roo.HtmlEditorCore.cwhite= [
17901 // 'text-align', /// default is to allow most things..
17907 // black listed style attributes.
17908 Roo.HtmlEditorCore.cblack= [
17909 // 'font-size' -- this can be set by the project
17913 Roo.HtmlEditorCore.swapCodes =[
17932 * @class Roo.bootstrap.HtmlEditor
17933 * @extends Roo.bootstrap.TextArea
17934 * Bootstrap HtmlEditor class
17937 * Create a new HtmlEditor
17938 * @param {Object} config The config object
17941 Roo.bootstrap.HtmlEditor = function(config){
17942 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17943 if (!this.toolbars) {
17944 this.toolbars = [];
17946 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17949 * @event initialize
17950 * Fires when the editor is fully initialized (including the iframe)
17951 * @param {HtmlEditor} this
17956 * Fires when the editor is first receives the focus. Any insertion must wait
17957 * until after this event.
17958 * @param {HtmlEditor} this
17962 * @event beforesync
17963 * Fires before the textarea is updated with content from the editor iframe. Return false
17964 * to cancel the sync.
17965 * @param {HtmlEditor} this
17966 * @param {String} html
17970 * @event beforepush
17971 * Fires before the iframe editor is updated with content from the textarea. Return false
17972 * to cancel the push.
17973 * @param {HtmlEditor} this
17974 * @param {String} html
17979 * Fires when the textarea is updated with content from the editor iframe.
17980 * @param {HtmlEditor} this
17981 * @param {String} html
17986 * Fires when the iframe editor is updated with content from the textarea.
17987 * @param {HtmlEditor} this
17988 * @param {String} html
17992 * @event editmodechange
17993 * Fires when the editor switches edit modes
17994 * @param {HtmlEditor} this
17995 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17997 editmodechange: true,
17999 * @event editorevent
18000 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18001 * @param {HtmlEditor} this
18005 * @event firstfocus
18006 * Fires when on first focus - needed by toolbars..
18007 * @param {HtmlEditor} this
18012 * Auto save the htmlEditor value as a file into Events
18013 * @param {HtmlEditor} this
18017 * @event savedpreview
18018 * preview the saved version of htmlEditor
18019 * @param {HtmlEditor} this
18026 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18030 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18035 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18040 * @cfg {Number} height (in pixels)
18044 * @cfg {Number} width (in pixels)
18049 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18052 stylesheets: false,
18057 // private properties
18058 validationEvent : false,
18060 initialized : false,
18063 onFocus : Roo.emptyFn,
18065 hideMode:'offsets',
18068 tbContainer : false,
18070 toolbarContainer :function() {
18071 return this.wrap.select('.x-html-editor-tb',true).first();
18075 * Protected method that will not generally be called directly. It
18076 * is called when the editor creates its toolbar. Override this method if you need to
18077 * add custom toolbar buttons.
18078 * @param {HtmlEditor} editor
18080 createToolbar : function(){
18082 Roo.log("create toolbars");
18084 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18085 this.toolbars[0].render(this.toolbarContainer());
18089 // if (!editor.toolbars || !editor.toolbars.length) {
18090 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18093 // for (var i =0 ; i < editor.toolbars.length;i++) {
18094 // editor.toolbars[i] = Roo.factory(
18095 // typeof(editor.toolbars[i]) == 'string' ?
18096 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18097 // Roo.bootstrap.HtmlEditor);
18098 // editor.toolbars[i].init(editor);
18104 onRender : function(ct, position)
18106 // Roo.log("Call onRender: " + this.xtype);
18108 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18110 this.wrap = this.inputEl().wrap({
18111 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18114 this.editorcore.onRender(ct, position);
18116 if (this.resizable) {
18117 this.resizeEl = new Roo.Resizable(this.wrap, {
18121 minHeight : this.height,
18122 height: this.height,
18123 handles : this.resizable,
18126 resize : function(r, w, h) {
18127 _t.onResize(w,h); // -something
18133 this.createToolbar(this);
18136 if(!this.width && this.resizable){
18137 this.setSize(this.wrap.getSize());
18139 if (this.resizeEl) {
18140 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18141 // should trigger onReize..
18147 onResize : function(w, h)
18149 Roo.log('resize: ' +w + ',' + h );
18150 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18154 if(this.inputEl() ){
18155 if(typeof w == 'number'){
18156 var aw = w - this.wrap.getFrameWidth('lr');
18157 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18160 if(typeof h == 'number'){
18161 var tbh = -11; // fixme it needs to tool bar size!
18162 for (var i =0; i < this.toolbars.length;i++) {
18163 // fixme - ask toolbars for heights?
18164 tbh += this.toolbars[i].el.getHeight();
18165 //if (this.toolbars[i].footer) {
18166 // tbh += this.toolbars[i].footer.el.getHeight();
18174 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18175 ah -= 5; // knock a few pixes off for look..
18176 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18180 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18181 this.editorcore.onResize(ew,eh);
18186 * Toggles the editor between standard and source edit mode.
18187 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18189 toggleSourceEdit : function(sourceEditMode)
18191 this.editorcore.toggleSourceEdit(sourceEditMode);
18193 if(this.editorcore.sourceEditMode){
18194 Roo.log('editor - showing textarea');
18197 // Roo.log(this.syncValue());
18199 this.inputEl().removeClass(['hide', 'x-hidden']);
18200 this.inputEl().dom.removeAttribute('tabIndex');
18201 this.inputEl().focus();
18203 Roo.log('editor - hiding textarea');
18205 // Roo.log(this.pushValue());
18208 this.inputEl().addClass(['hide', 'x-hidden']);
18209 this.inputEl().dom.setAttribute('tabIndex', -1);
18210 //this.deferFocus();
18213 if(this.resizable){
18214 this.setSize(this.wrap.getSize());
18217 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18220 // private (for BoxComponent)
18221 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18223 // private (for BoxComponent)
18224 getResizeEl : function(){
18228 // private (for BoxComponent)
18229 getPositionEl : function(){
18234 initEvents : function(){
18235 this.originalValue = this.getValue();
18239 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18242 // markInvalid : Roo.emptyFn,
18244 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18247 // clearInvalid : Roo.emptyFn,
18249 setValue : function(v){
18250 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18251 this.editorcore.pushValue();
18256 deferFocus : function(){
18257 this.focus.defer(10, this);
18261 focus : function(){
18262 this.editorcore.focus();
18268 onDestroy : function(){
18274 for (var i =0; i < this.toolbars.length;i++) {
18275 // fixme - ask toolbars for heights?
18276 this.toolbars[i].onDestroy();
18279 this.wrap.dom.innerHTML = '';
18280 this.wrap.remove();
18285 onFirstFocus : function(){
18286 //Roo.log("onFirstFocus");
18287 this.editorcore.onFirstFocus();
18288 for (var i =0; i < this.toolbars.length;i++) {
18289 this.toolbars[i].onFirstFocus();
18295 syncValue : function()
18297 this.editorcore.syncValue();
18300 pushValue : function()
18302 this.editorcore.pushValue();
18306 // hide stuff that is not compatible
18320 * @event specialkey
18324 * @cfg {String} fieldClass @hide
18327 * @cfg {String} focusClass @hide
18330 * @cfg {String} autoCreate @hide
18333 * @cfg {String} inputType @hide
18336 * @cfg {String} invalidClass @hide
18339 * @cfg {String} invalidText @hide
18342 * @cfg {String} msgFx @hide
18345 * @cfg {String} validateOnBlur @hide
18354 Roo.namespace('Roo.bootstrap.htmleditor');
18356 * @class Roo.bootstrap.HtmlEditorToolbar1
18361 new Roo.bootstrap.HtmlEditor({
18364 new Roo.bootstrap.HtmlEditorToolbar1({
18365 disable : { fonts: 1 , format: 1, ..., ... , ...],
18371 * @cfg {Object} disable List of elements to disable..
18372 * @cfg {Array} btns List of additional buttons.
18376 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18379 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18382 Roo.apply(this, config);
18384 // default disabled, based on 'good practice'..
18385 this.disable = this.disable || {};
18386 Roo.applyIf(this.disable, {
18389 specialElements : true
18391 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18393 this.editor = config.editor;
18394 this.editorcore = config.editor.editorcore;
18396 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18398 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18399 // dont call parent... till later.
18401 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18406 editorcore : false,
18411 "h1","h2","h3","h4","h5","h6",
18413 "abbr", "acronym", "address", "cite", "samp", "var",
18417 onRender : function(ct, position)
18419 // Roo.log("Call onRender: " + this.xtype);
18421 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18423 this.el.dom.style.marginBottom = '0';
18425 var editorcore = this.editorcore;
18426 var editor= this.editor;
18429 var btn = function(id,cmd , toggle, handler){
18431 var event = toggle ? 'toggle' : 'click';
18436 xns: Roo.bootstrap,
18439 enableToggle:toggle !== false,
18441 pressed : toggle ? false : null,
18444 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18445 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18454 xns: Roo.bootstrap,
18455 glyphicon : 'font',
18459 xns: Roo.bootstrap,
18463 Roo.each(this.formats, function(f) {
18464 style.menu.items.push({
18466 xns: Roo.bootstrap,
18467 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18472 editorcore.insertTag(this.tagname);
18479 children.push(style);
18482 btn('bold',false,true);
18483 btn('italic',false,true);
18484 btn('align-left', 'justifyleft',true);
18485 btn('align-center', 'justifycenter',true);
18486 btn('align-right' , 'justifyright',true);
18487 btn('link', false, false, function(btn) {
18488 //Roo.log("create link?");
18489 var url = prompt(this.createLinkText, this.defaultLinkValue);
18490 if(url && url != 'http:/'+'/'){
18491 this.editorcore.relayCmd('createlink', url);
18494 btn('list','insertunorderedlist',true);
18495 btn('pencil', false,true, function(btn){
18498 this.toggleSourceEdit(btn.pressed);
18504 xns: Roo.bootstrap,
18509 xns: Roo.bootstrap,
18514 cog.menu.items.push({
18516 xns: Roo.bootstrap,
18517 html : Clean styles,
18522 editorcore.insertTag(this.tagname);
18531 this.xtype = 'NavSimplebar';
18533 for(var i=0;i< children.length;i++) {
18535 this.buttons.add(this.addxtypeChild(children[i]));
18539 editor.on('editorevent', this.updateToolbar, this);
18541 onBtnClick : function(id)
18543 this.editorcore.relayCmd(id);
18544 this.editorcore.focus();
18548 * Protected method that will not generally be called directly. It triggers
18549 * a toolbar update by reading the markup state of the current selection in the editor.
18551 updateToolbar: function(){
18553 if(!this.editorcore.activated){
18554 this.editor.onFirstFocus(); // is this neeed?
18558 var btns = this.buttons;
18559 var doc = this.editorcore.doc;
18560 btns.get('bold').setActive(doc.queryCommandState('bold'));
18561 btns.get('italic').setActive(doc.queryCommandState('italic'));
18562 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18564 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18565 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18566 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18568 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18569 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18572 var ans = this.editorcore.getAllAncestors();
18573 if (this.formatCombo) {
18576 var store = this.formatCombo.store;
18577 this.formatCombo.setValue("");
18578 for (var i =0; i < ans.length;i++) {
18579 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18581 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18589 // hides menus... - so this cant be on a menu...
18590 Roo.bootstrap.MenuMgr.hideAll();
18592 Roo.bootstrap.MenuMgr.hideAll();
18593 //this.editorsyncValue();
18595 onFirstFocus: function() {
18596 this.buttons.each(function(item){
18600 toggleSourceEdit : function(sourceEditMode){
18603 if(sourceEditMode){
18604 Roo.log("disabling buttons");
18605 this.buttons.each( function(item){
18606 if(item.cmd != 'pencil'){
18612 Roo.log("enabling buttons");
18613 if(this.editorcore.initialized){
18614 this.buttons.each( function(item){
18620 Roo.log("calling toggole on editor");
18621 // tell the editor that it's been pressed..
18622 this.editor.toggleSourceEdit(sourceEditMode);
18632 * @class Roo.bootstrap.Table.AbstractSelectionModel
18633 * @extends Roo.util.Observable
18634 * Abstract base class for grid SelectionModels. It provides the interface that should be
18635 * implemented by descendant classes. This class should not be directly instantiated.
18638 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18639 this.locked = false;
18640 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18644 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18645 /** @ignore Called by the grid automatically. Do not call directly. */
18646 init : function(grid){
18652 * Locks the selections.
18655 this.locked = true;
18659 * Unlocks the selections.
18661 unlock : function(){
18662 this.locked = false;
18666 * Returns true if the selections are locked.
18667 * @return {Boolean}
18669 isLocked : function(){
18670 return this.locked;
18674 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18675 * @class Roo.bootstrap.Table.RowSelectionModel
18676 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18677 * It supports multiple selections and keyboard selection/navigation.
18679 * @param {Object} config
18682 Roo.bootstrap.Table.RowSelectionModel = function(config){
18683 Roo.apply(this, config);
18684 this.selections = new Roo.util.MixedCollection(false, function(o){
18689 this.lastActive = false;
18693 * @event selectionchange
18694 * Fires when the selection changes
18695 * @param {SelectionModel} this
18697 "selectionchange" : true,
18699 * @event afterselectionchange
18700 * Fires after the selection changes (eg. by key press or clicking)
18701 * @param {SelectionModel} this
18703 "afterselectionchange" : true,
18705 * @event beforerowselect
18706 * Fires when a row is selected being selected, return false to cancel.
18707 * @param {SelectionModel} this
18708 * @param {Number} rowIndex The selected index
18709 * @param {Boolean} keepExisting False if other selections will be cleared
18711 "beforerowselect" : true,
18714 * Fires when a row is selected.
18715 * @param {SelectionModel} this
18716 * @param {Number} rowIndex The selected index
18717 * @param {Roo.data.Record} r The record
18719 "rowselect" : true,
18721 * @event rowdeselect
18722 * Fires when a row is deselected.
18723 * @param {SelectionModel} this
18724 * @param {Number} rowIndex The selected index
18726 "rowdeselect" : true
18728 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18729 this.locked = false;
18732 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18734 * @cfg {Boolean} singleSelect
18735 * True to allow selection of only one row at a time (defaults to false)
18737 singleSelect : false,
18740 initEvents : function(){
18742 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18743 this.grid.on("mousedown", this.handleMouseDown, this);
18744 }else{ // allow click to work like normal
18745 this.grid.on("rowclick", this.handleDragableRowClick, this);
18748 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18749 "up" : function(e){
18751 this.selectPrevious(e.shiftKey);
18752 }else if(this.last !== false && this.lastActive !== false){
18753 var last = this.last;
18754 this.selectRange(this.last, this.lastActive-1);
18755 this.grid.getView().focusRow(this.lastActive);
18756 if(last !== false){
18760 this.selectFirstRow();
18762 this.fireEvent("afterselectionchange", this);
18764 "down" : function(e){
18766 this.selectNext(e.shiftKey);
18767 }else if(this.last !== false && this.lastActive !== false){
18768 var last = this.last;
18769 this.selectRange(this.last, this.lastActive+1);
18770 this.grid.getView().focusRow(this.lastActive);
18771 if(last !== false){
18775 this.selectFirstRow();
18777 this.fireEvent("afterselectionchange", this);
18782 var view = this.grid.view;
18783 view.on("refresh", this.onRefresh, this);
18784 view.on("rowupdated", this.onRowUpdated, this);
18785 view.on("rowremoved", this.onRemove, this);
18789 onRefresh : function(){
18790 var ds = this.grid.dataSource, i, v = this.grid.view;
18791 var s = this.selections;
18792 s.each(function(r){
18793 if((i = ds.indexOfId(r.id)) != -1){
18802 onRemove : function(v, index, r){
18803 this.selections.remove(r);
18807 onRowUpdated : function(v, index, r){
18808 if(this.isSelected(r)){
18809 v.onRowSelect(index);
18815 * @param {Array} records The records to select
18816 * @param {Boolean} keepExisting (optional) True to keep existing selections
18818 selectRecords : function(records, keepExisting){
18820 this.clearSelections();
18822 var ds = this.grid.dataSource;
18823 for(var i = 0, len = records.length; i < len; i++){
18824 this.selectRow(ds.indexOf(records[i]), true);
18829 * Gets the number of selected rows.
18832 getCount : function(){
18833 return this.selections.length;
18837 * Selects the first row in the grid.
18839 selectFirstRow : function(){
18844 * Select the last row.
18845 * @param {Boolean} keepExisting (optional) True to keep existing selections
18847 selectLastRow : function(keepExisting){
18848 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18852 * Selects the row immediately following the last selected row.
18853 * @param {Boolean} keepExisting (optional) True to keep existing selections
18855 selectNext : function(keepExisting){
18856 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18857 this.selectRow(this.last+1, keepExisting);
18858 this.grid.getView().focusRow(this.last);
18863 * Selects the row that precedes the last selected row.
18864 * @param {Boolean} keepExisting (optional) True to keep existing selections
18866 selectPrevious : function(keepExisting){
18868 this.selectRow(this.last-1, keepExisting);
18869 this.grid.getView().focusRow(this.last);
18874 * Returns the selected records
18875 * @return {Array} Array of selected records
18877 getSelections : function(){
18878 return [].concat(this.selections.items);
18882 * Returns the first selected record.
18885 getSelected : function(){
18886 return this.selections.itemAt(0);
18891 * Clears all selections.
18893 clearSelections : function(fast){
18894 if(this.locked) return;
18896 var ds = this.grid.dataSource;
18897 var s = this.selections;
18898 s.each(function(r){
18899 this.deselectRow(ds.indexOfId(r.id));
18903 this.selections.clear();
18910 * Selects all rows.
18912 selectAll : function(){
18913 if(this.locked) return;
18914 this.selections.clear();
18915 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18916 this.selectRow(i, true);
18921 * Returns True if there is a selection.
18922 * @return {Boolean}
18924 hasSelection : function(){
18925 return this.selections.length > 0;
18929 * Returns True if the specified row is selected.
18930 * @param {Number/Record} record The record or index of the record to check
18931 * @return {Boolean}
18933 isSelected : function(index){
18934 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18935 return (r && this.selections.key(r.id) ? true : false);
18939 * Returns True if the specified record id is selected.
18940 * @param {String} id The id of record to check
18941 * @return {Boolean}
18943 isIdSelected : function(id){
18944 return (this.selections.key(id) ? true : false);
18948 handleMouseDown : function(e, t){
18949 var view = this.grid.getView(), rowIndex;
18950 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18953 if(e.shiftKey && this.last !== false){
18954 var last = this.last;
18955 this.selectRange(last, rowIndex, e.ctrlKey);
18956 this.last = last; // reset the last
18957 view.focusRow(rowIndex);
18959 var isSelected = this.isSelected(rowIndex);
18960 if(e.button !== 0 && isSelected){
18961 view.focusRow(rowIndex);
18962 }else if(e.ctrlKey && isSelected){
18963 this.deselectRow(rowIndex);
18964 }else if(!isSelected){
18965 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18966 view.focusRow(rowIndex);
18969 this.fireEvent("afterselectionchange", this);
18972 handleDragableRowClick : function(grid, rowIndex, e)
18974 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18975 this.selectRow(rowIndex, false);
18976 grid.view.focusRow(rowIndex);
18977 this.fireEvent("afterselectionchange", this);
18982 * Selects multiple rows.
18983 * @param {Array} rows Array of the indexes of the row to select
18984 * @param {Boolean} keepExisting (optional) True to keep existing selections
18986 selectRows : function(rows, keepExisting){
18988 this.clearSelections();
18990 for(var i = 0, len = rows.length; i < len; i++){
18991 this.selectRow(rows[i], true);
18996 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18997 * @param {Number} startRow The index of the first row in the range
18998 * @param {Number} endRow The index of the last row in the range
18999 * @param {Boolean} keepExisting (optional) True to retain existing selections
19001 selectRange : function(startRow, endRow, keepExisting){
19002 if(this.locked) return;
19004 this.clearSelections();
19006 if(startRow <= endRow){
19007 for(var i = startRow; i <= endRow; i++){
19008 this.selectRow(i, true);
19011 for(var i = startRow; i >= endRow; i--){
19012 this.selectRow(i, true);
19018 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19019 * @param {Number} startRow The index of the first row in the range
19020 * @param {Number} endRow The index of the last row in the range
19022 deselectRange : function(startRow, endRow, preventViewNotify){
19023 if(this.locked) return;
19024 for(var i = startRow; i <= endRow; i++){
19025 this.deselectRow(i, preventViewNotify);
19031 * @param {Number} row The index of the row to select
19032 * @param {Boolean} keepExisting (optional) True to keep existing selections
19034 selectRow : function(index, keepExisting, preventViewNotify){
19035 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19036 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19037 if(!keepExisting || this.singleSelect){
19038 this.clearSelections();
19040 var r = this.grid.dataSource.getAt(index);
19041 this.selections.add(r);
19042 this.last = this.lastActive = index;
19043 if(!preventViewNotify){
19044 this.grid.getView().onRowSelect(index);
19046 this.fireEvent("rowselect", this, index, r);
19047 this.fireEvent("selectionchange", this);
19053 * @param {Number} row The index of the row to deselect
19055 deselectRow : function(index, preventViewNotify){
19056 if(this.locked) return;
19057 if(this.last == index){
19060 if(this.lastActive == index){
19061 this.lastActive = false;
19063 var r = this.grid.dataSource.getAt(index);
19064 this.selections.remove(r);
19065 if(!preventViewNotify){
19066 this.grid.getView().onRowDeselect(index);
19068 this.fireEvent("rowdeselect", this, index);
19069 this.fireEvent("selectionchange", this);
19073 restoreLast : function(){
19075 this.last = this._last;
19080 acceptsNav : function(row, col, cm){
19081 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19085 onEditorKey : function(field, e){
19086 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19091 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19093 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19095 }else if(k == e.ENTER && !e.ctrlKey){
19099 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19101 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19103 }else if(k == e.ESC){
19107 g.startEditing(newCell[0], newCell[1]);
19112 * Ext JS Library 1.1.1
19113 * Copyright(c) 2006-2007, Ext JS, LLC.
19115 * Originally Released Under LGPL - original licence link has changed is not relivant.
19118 * <script type="text/javascript">
19122 * @class Roo.bootstrap.PagingToolbar
19124 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19126 * Create a new PagingToolbar
19127 * @param {Object} config The config object
19129 Roo.bootstrap.PagingToolbar = function(config)
19131 // old args format still supported... - xtype is prefered..
19132 // created from xtype...
19133 var ds = config.dataSource;
19134 this.toolbarItems = [];
19135 if (config.items) {
19136 this.toolbarItems = config.items;
19137 // config.items = [];
19140 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19147 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19151 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19153 * @cfg {Roo.data.Store} dataSource
19154 * The underlying data store providing the paged data
19157 * @cfg {String/HTMLElement/Element} container
19158 * container The id or element that will contain the toolbar
19161 * @cfg {Boolean} displayInfo
19162 * True to display the displayMsg (defaults to false)
19165 * @cfg {Number} pageSize
19166 * The number of records to display per page (defaults to 20)
19170 * @cfg {String} displayMsg
19171 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19173 displayMsg : 'Displaying {0} - {1} of {2}',
19175 * @cfg {String} emptyMsg
19176 * The message to display when no records are found (defaults to "No data to display")
19178 emptyMsg : 'No data to display',
19180 * Customizable piece of the default paging text (defaults to "Page")
19183 beforePageText : "Page",
19185 * Customizable piece of the default paging text (defaults to "of %0")
19188 afterPageText : "of {0}",
19190 * Customizable piece of the default paging text (defaults to "First Page")
19193 firstText : "First Page",
19195 * Customizable piece of the default paging text (defaults to "Previous Page")
19198 prevText : "Previous Page",
19200 * Customizable piece of the default paging text (defaults to "Next Page")
19203 nextText : "Next Page",
19205 * Customizable piece of the default paging text (defaults to "Last Page")
19208 lastText : "Last Page",
19210 * Customizable piece of the default paging text (defaults to "Refresh")
19213 refreshText : "Refresh",
19217 onRender : function(ct, position)
19219 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19220 this.navgroup.parentId = this.id;
19221 this.navgroup.onRender(this.el, null);
19222 // add the buttons to the navgroup
19224 if(this.displayInfo){
19225 Roo.log(this.el.select('ul.navbar-nav',true).first());
19226 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19227 this.displayEl = this.el.select('.x-paging-info', true).first();
19228 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19229 // this.displayEl = navel.el.select('span',true).first();
19235 Roo.each(_this.buttons, function(e){
19236 Roo.factory(e).onRender(_this.el, null);
19240 Roo.each(_this.toolbarItems, function(e) {
19241 _this.navgroup.addItem(e);
19244 this.first = this.navgroup.addItem({
19245 tooltip: this.firstText,
19247 icon : 'fa fa-backward',
19249 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19252 this.prev = this.navgroup.addItem({
19253 tooltip: this.prevText,
19255 icon : 'fa fa-step-backward',
19257 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19259 //this.addSeparator();
19262 var field = this.navgroup.addItem( {
19264 cls : 'x-paging-position',
19266 html : this.beforePageText +
19267 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19268 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19271 this.field = field.el.select('input', true).first();
19272 this.field.on("keydown", this.onPagingKeydown, this);
19273 this.field.on("focus", function(){this.dom.select();});
19276 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19277 //this.field.setHeight(18);
19278 //this.addSeparator();
19279 this.next = this.navgroup.addItem({
19280 tooltip: this.nextText,
19282 html : ' <i class="fa fa-step-forward">',
19284 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19286 this.last = this.navgroup.addItem({
19287 tooltip: this.lastText,
19288 icon : 'fa fa-forward',
19291 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19293 //this.addSeparator();
19294 this.loading = this.navgroup.addItem({
19295 tooltip: this.refreshText,
19296 icon: 'fa fa-refresh',
19298 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19304 updateInfo : function(){
19305 if(this.displayEl){
19306 var count = this.ds.getCount();
19307 var msg = count == 0 ?
19311 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19313 this.displayEl.update(msg);
19318 onLoad : function(ds, r, o){
19319 this.cursor = o.params ? o.params.start : 0;
19320 var d = this.getPageData(),
19324 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19325 this.field.dom.value = ap;
19326 this.first.setDisabled(ap == 1);
19327 this.prev.setDisabled(ap == 1);
19328 this.next.setDisabled(ap == ps);
19329 this.last.setDisabled(ap == ps);
19330 this.loading.enable();
19335 getPageData : function(){
19336 var total = this.ds.getTotalCount();
19339 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19340 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19345 onLoadError : function(){
19346 this.loading.enable();
19350 onPagingKeydown : function(e){
19351 var k = e.getKey();
19352 var d = this.getPageData();
19354 var v = this.field.dom.value, pageNum;
19355 if(!v || isNaN(pageNum = parseInt(v, 10))){
19356 this.field.dom.value = d.activePage;
19359 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19360 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19363 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))
19365 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19366 this.field.dom.value = pageNum;
19367 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19370 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19372 var v = this.field.dom.value, pageNum;
19373 var increment = (e.shiftKey) ? 10 : 1;
19374 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19376 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19377 this.field.dom.value = d.activePage;
19380 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19382 this.field.dom.value = parseInt(v, 10) + increment;
19383 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19384 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19391 beforeLoad : function(){
19393 this.loading.disable();
19398 onClick : function(which){
19405 ds.load({params:{start: 0, limit: this.pageSize}});
19408 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19411 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19414 var total = ds.getTotalCount();
19415 var extra = total % this.pageSize;
19416 var lastStart = extra ? (total - extra) : total-this.pageSize;
19417 ds.load({params:{start: lastStart, limit: this.pageSize}});
19420 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19426 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19427 * @param {Roo.data.Store} store The data store to unbind
19429 unbind : function(ds){
19430 ds.un("beforeload", this.beforeLoad, this);
19431 ds.un("load", this.onLoad, this);
19432 ds.un("loadexception", this.onLoadError, this);
19433 ds.un("remove", this.updateInfo, this);
19434 ds.un("add", this.updateInfo, this);
19435 this.ds = undefined;
19439 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19440 * @param {Roo.data.Store} store The data store to bind
19442 bind : function(ds){
19443 ds.on("beforeload", this.beforeLoad, this);
19444 ds.on("load", this.onLoad, this);
19445 ds.on("loadexception", this.onLoadError, this);
19446 ds.on("remove", this.updateInfo, this);
19447 ds.on("add", this.updateInfo, this);
19458 * @class Roo.bootstrap.MessageBar
19459 * @extends Roo.bootstrap.Component
19460 * Bootstrap MessageBar class
19461 * @cfg {String} html contents of the MessageBar
19462 * @cfg {String} weight (info | success | warning | danger) default info
19463 * @cfg {String} beforeClass insert the bar before the given class
19464 * @cfg {Boolean} closable (true | false) default false
19465 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19468 * Create a new Element
19469 * @param {Object} config The config object
19472 Roo.bootstrap.MessageBar = function(config){
19473 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19476 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19482 beforeClass: 'bootstrap-sticky-wrap',
19484 getAutoCreate : function(){
19488 cls: 'alert alert-dismissable alert-' + this.weight,
19493 html: this.html || ''
19499 cfg.cls += ' alert-messages-fixed';
19513 onRender : function(ct, position)
19515 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19518 var cfg = Roo.apply({}, this.getAutoCreate());
19522 cfg.cls += ' ' + this.cls;
19525 cfg.style = this.style;
19527 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19529 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19532 this.el.select('>button.close').on('click', this.hide, this);
19538 if (!this.rendered) {
19544 this.fireEvent('show', this);
19550 if (!this.rendered) {
19556 this.fireEvent('hide', this);
19559 update : function()
19561 // var e = this.el.dom.firstChild;
19563 // if(this.closable){
19564 // e = e.nextSibling;
19567 // e.data = this.html || '';
19569 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19585 * @class Roo.bootstrap.Graph
19586 * @extends Roo.bootstrap.Component
19587 * Bootstrap Graph class
19591 @cfg {String} graphtype bar | vbar | pie
19592 @cfg {number} g_x coodinator | centre x (pie)
19593 @cfg {number} g_y coodinator | centre y (pie)
19594 @cfg {number} g_r radius (pie)
19595 @cfg {number} g_height height of the chart (respected by all elements in the set)
19596 @cfg {number} g_width width of the chart (respected by all elements in the set)
19597 @cfg {Object} title The title of the chart
19600 -opts (object) options for the chart
19602 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19603 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19605 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.
19606 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19608 o stretch (boolean)
19610 -opts (object) options for the pie
19613 o startAngle (number)
19614 o endAngle (number)
19618 * Create a new Input
19619 * @param {Object} config The config object
19622 Roo.bootstrap.Graph = function(config){
19623 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19629 * The img click event for the img.
19630 * @param {Roo.EventObject} e
19636 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19647 //g_colors: this.colors,
19654 getAutoCreate : function(){
19665 onRender : function(ct,position){
19666 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19667 this.raphael = Raphael(this.el.dom);
19669 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19670 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19671 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19672 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19674 r.text(160, 10, "Single Series Chart").attr(txtattr);
19675 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19676 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19677 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19679 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19680 r.barchart(330, 10, 300, 220, data1);
19681 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19682 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19685 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19686 // r.barchart(30, 30, 560, 250, xdata, {
19687 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19688 // axis : "0 0 1 1",
19689 // axisxlabels : xdata
19690 // //yvalues : cols,
19693 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19695 // this.load(null,xdata,{
19696 // axis : "0 0 1 1",
19697 // axisxlabels : xdata
19702 load : function(graphtype,xdata,opts){
19703 this.raphael.clear();
19705 graphtype = this.graphtype;
19710 var r = this.raphael,
19711 fin = function () {
19712 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19714 fout = function () {
19715 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19717 pfin = function() {
19718 this.sector.stop();
19719 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19722 this.label[0].stop();
19723 this.label[0].attr({ r: 7.5 });
19724 this.label[1].attr({ "font-weight": 800 });
19727 pfout = function() {
19728 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19731 this.label[0].animate({ r: 5 }, 500, "bounce");
19732 this.label[1].attr({ "font-weight": 400 });
19738 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19741 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19744 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19745 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19747 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19754 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19759 setTitle: function(o)
19764 initEvents: function() {
19767 this.el.on('click', this.onClick, this);
19771 onClick : function(e)
19773 Roo.log('img onclick');
19774 this.fireEvent('click', this, e);
19786 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19789 * @class Roo.bootstrap.dash.NumberBox
19790 * @extends Roo.bootstrap.Component
19791 * Bootstrap NumberBox class
19792 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19793 * @cfg {String} headline Box headline
19794 * @cfg {String} content Box content
19795 * @cfg {String} icon Box icon
19796 * @cfg {String} footer Footer text
19797 * @cfg {String} fhref Footer href
19800 * Create a new NumberBox
19801 * @param {Object} config The config object
19805 Roo.bootstrap.dash.NumberBox = function(config){
19806 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19810 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19820 getAutoCreate : function(){
19824 cls : 'small-box bg-' + this.bgcolor,
19832 cls : 'roo-headline',
19833 html : this.headline
19837 cls : 'roo-content',
19838 html : this.content
19852 cls : 'ion ' + this.icon
19861 cls : 'small-box-footer',
19862 href : this.fhref || '#',
19866 cfg.cn.push(footer);
19873 onRender : function(ct,position){
19874 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19881 setHeadline: function (value)
19883 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19886 setFooter: function (value, href)
19888 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19891 this.el.select('a.small-box-footer',true).first().attr('href', href);
19896 setContent: function (value)
19898 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19901 initEvents: function()
19915 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19918 * @class Roo.bootstrap.dash.TabBox
19919 * @extends Roo.bootstrap.Component
19920 * Bootstrap TabBox class
19921 * @cfg {String} title Title of the TabBox
19922 * @cfg {String} icon Icon of the TabBox
19923 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19924 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
19927 * Create a new TabBox
19928 * @param {Object} config The config object
19932 Roo.bootstrap.dash.TabBox = function(config){
19933 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19938 * When a pane is added
19939 * @param {Roo.bootstrap.dash.TabPane} pane
19943 * @event activatepane
19944 * When a pane is activated
19945 * @param {Roo.bootstrap.dash.TabPane} pane
19947 "activatepane" : true
19955 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19960 tabScrollable : false,
19962 getChildContainer : function()
19964 return this.el.select('.tab-content', true).first();
19967 getAutoCreate : function(){
19971 cls: 'pull-left header',
19979 cls: 'fa ' + this.icon
19985 cls: 'nav nav-tabs pull-right',
19991 if(this.tabScrollable){
19998 cls: 'nav nav-tabs pull-right',
20009 cls: 'nav-tabs-custom',
20014 cls: 'tab-content no-padding',
20022 initEvents : function()
20024 //Roo.log('add add pane handler');
20025 this.on('addpane', this.onAddPane, this);
20028 * Updates the box title
20029 * @param {String} html to set the title to.
20031 setTitle : function(value)
20033 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20035 onAddPane : function(pane)
20037 this.panes.push(pane);
20038 //Roo.log('addpane');
20040 // tabs are rendere left to right..
20041 if(!this.showtabs){
20045 var ctr = this.el.select('.nav-tabs', true).first();
20048 var existing = ctr.select('.nav-tab',true);
20049 var qty = existing.getCount();;
20052 var tab = ctr.createChild({
20054 cls : 'nav-tab' + (qty ? '' : ' active'),
20062 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20065 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20067 pane.el.addClass('active');
20072 onTabClick : function(ev,un,ob,pane)
20074 //Roo.log('tab - prev default');
20075 ev.preventDefault();
20078 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20079 pane.tab.addClass('active');
20080 //Roo.log(pane.title);
20081 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20082 // technically we should have a deactivate event.. but maybe add later.
20083 // and it should not de-activate the selected tab...
20084 this.fireEvent('activatepane', pane);
20085 pane.el.addClass('active');
20086 pane.fireEvent('activate');
20091 getActivePane : function()
20094 Roo.each(this.panes, function(p) {
20095 if(p.el.hasClass('active')){
20116 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20118 * @class Roo.bootstrap.TabPane
20119 * @extends Roo.bootstrap.Component
20120 * Bootstrap TabPane class
20121 * @cfg {Boolean} active (false | true) Default false
20122 * @cfg {String} title title of panel
20126 * Create a new TabPane
20127 * @param {Object} config The config object
20130 Roo.bootstrap.dash.TabPane = function(config){
20131 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20137 * When a pane is activated
20138 * @param {Roo.bootstrap.dash.TabPane} pane
20145 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20150 // the tabBox that this is attached to.
20153 getAutoCreate : function()
20161 cfg.cls += ' active';
20166 initEvents : function()
20168 //Roo.log('trigger add pane handler');
20169 this.parent().fireEvent('addpane', this)
20173 * Updates the tab title
20174 * @param {String} html to set the title to.
20176 setTitle: function(str)
20182 this.tab.select('a', true).first().dom.innerHTML = str;
20199 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20202 * @class Roo.bootstrap.menu.Menu
20203 * @extends Roo.bootstrap.Component
20204 * Bootstrap Menu class - container for Menu
20205 * @cfg {String} html Text of the menu
20206 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20207 * @cfg {String} icon Font awesome icon
20208 * @cfg {String} pos Menu align to (top | bottom) default bottom
20212 * Create a new Menu
20213 * @param {Object} config The config object
20217 Roo.bootstrap.menu.Menu = function(config){
20218 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20222 * @event beforeshow
20223 * Fires before this menu is displayed
20224 * @param {Roo.bootstrap.menu.Menu} this
20228 * @event beforehide
20229 * Fires before this menu is hidden
20230 * @param {Roo.bootstrap.menu.Menu} this
20235 * Fires after this menu is displayed
20236 * @param {Roo.bootstrap.menu.Menu} this
20241 * Fires after this menu is hidden
20242 * @param {Roo.bootstrap.menu.Menu} this
20247 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20248 * @param {Roo.bootstrap.menu.Menu} this
20249 * @param {Roo.EventObject} e
20256 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20260 weight : 'default',
20265 getChildContainer : function() {
20266 if(this.isSubMenu){
20270 return this.el.select('ul.dropdown-menu', true).first();
20273 getAutoCreate : function()
20278 cls : 'roo-menu-text',
20286 cls : 'fa ' + this.icon
20297 cls : 'dropdown-button btn btn-' + this.weight,
20302 cls : 'dropdown-toggle btn btn-' + this.weight,
20312 cls : 'dropdown-menu'
20318 if(this.pos == 'top'){
20319 cfg.cls += ' dropup';
20322 if(this.isSubMenu){
20325 cls : 'dropdown-menu'
20332 onRender : function(ct, position)
20334 this.isSubMenu = ct.hasClass('dropdown-submenu');
20336 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20339 initEvents : function()
20341 if(this.isSubMenu){
20345 this.hidden = true;
20347 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20348 this.triggerEl.on('click', this.onTriggerPress, this);
20350 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20351 this.buttonEl.on('click', this.onClick, this);
20357 if(this.isSubMenu){
20361 return this.el.select('ul.dropdown-menu', true).first();
20364 onClick : function(e)
20366 this.fireEvent("click", this, e);
20369 onTriggerPress : function(e)
20371 if (this.isVisible()) {
20378 isVisible : function(){
20379 return !this.hidden;
20384 this.fireEvent("beforeshow", this);
20386 this.hidden = false;
20387 this.el.addClass('open');
20389 Roo.get(document).on("mouseup", this.onMouseUp, this);
20391 this.fireEvent("show", this);
20398 this.fireEvent("beforehide", this);
20400 this.hidden = true;
20401 this.el.removeClass('open');
20403 Roo.get(document).un("mouseup", this.onMouseUp);
20405 this.fireEvent("hide", this);
20408 onMouseUp : function()
20422 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20425 * @class Roo.bootstrap.menu.Item
20426 * @extends Roo.bootstrap.Component
20427 * Bootstrap MenuItem class
20428 * @cfg {Boolean} submenu (true | false) default false
20429 * @cfg {String} html text of the item
20430 * @cfg {String} href the link
20431 * @cfg {Boolean} disable (true | false) default false
20432 * @cfg {Boolean} preventDefault (true | false) default true
20433 * @cfg {String} icon Font awesome icon
20434 * @cfg {String} pos Submenu align to (left | right) default right
20438 * Create a new Item
20439 * @param {Object} config The config object
20443 Roo.bootstrap.menu.Item = function(config){
20444 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20448 * Fires when the mouse is hovering over this menu
20449 * @param {Roo.bootstrap.menu.Item} this
20450 * @param {Roo.EventObject} e
20455 * Fires when the mouse exits this menu
20456 * @param {Roo.bootstrap.menu.Item} this
20457 * @param {Roo.EventObject} e
20463 * The raw click event for the entire grid.
20464 * @param {Roo.EventObject} e
20470 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20475 preventDefault: true,
20480 getAutoCreate : function()
20485 cls : 'roo-menu-item-text',
20493 cls : 'fa ' + this.icon
20502 href : this.href || '#',
20509 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20513 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20515 if(this.pos == 'left'){
20516 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20523 initEvents : function()
20525 this.el.on('mouseover', this.onMouseOver, this);
20526 this.el.on('mouseout', this.onMouseOut, this);
20528 this.el.select('a', true).first().on('click', this.onClick, this);
20532 onClick : function(e)
20534 if(this.preventDefault){
20535 e.preventDefault();
20538 this.fireEvent("click", this, e);
20541 onMouseOver : function(e)
20543 if(this.submenu && this.pos == 'left'){
20544 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20547 this.fireEvent("mouseover", this, e);
20550 onMouseOut : function(e)
20552 this.fireEvent("mouseout", this, e);
20564 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20567 * @class Roo.bootstrap.menu.Separator
20568 * @extends Roo.bootstrap.Component
20569 * Bootstrap Separator class
20572 * Create a new Separator
20573 * @param {Object} config The config object
20577 Roo.bootstrap.menu.Separator = function(config){
20578 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20581 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20583 getAutoCreate : function(){