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() { },
52 can_build_overlaid : true,
59 // returns the parent component..
60 return Roo.ComponentMgr.get(this.parentId)
66 onRender : function(ct, position)
68 // Roo.log("Call onRender: " + this.xtype);
70 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
73 if (this.el.attr('xtype')) {
74 this.el.attr('xtypex', this.el.attr('xtype'));
75 this.el.dom.removeAttribute('xtype');
85 var cfg = Roo.apply({}, this.getAutoCreate());
88 // fill in the extra attributes
89 if (this.xattr && typeof(this.xattr) =='object') {
90 for (var i in this.xattr) {
91 cfg[i] = this.xattr[i];
96 cfg.dataId = this.dataId;
100 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
103 if (this.style) { // fixme needs to support more complex style data.
104 cfg.style = this.style;
108 cfg.name = this.name;
113 this.el = ct.createChild(cfg, position);
116 this.tooltipEl().attr('tooltip', this.tooltip);
119 if(this.tabIndex !== undefined){
120 this.el.dom.setAttribute('tabIndex', this.tabIndex);
127 * Fetch the element to add children to
128 * @return {Roo.Element} defaults to this.el
130 getChildContainer : function()
135 * Fetch the element to display the tooltip on.
136 * @return {Roo.Element} defaults to this.el
138 tooltipEl : function()
143 addxtype : function(tree,cntr)
147 cn = Roo.factory(tree);
149 cn.parentType = this.xtype; //??
150 cn.parentId = this.id;
152 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
154 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
156 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
158 var build_from_html = Roo.XComponent.build_from_html;
160 var is_body = (tree.xtype == 'Body') ;
162 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
164 var self_cntr_el = Roo.get(this[cntr](false));
166 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
167 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
168 return this.addxtypeChild(tree,cntr);
171 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
174 return this.addxtypeChild(Roo.apply({}, tree),cntr);
177 Roo.log('skipping render');
185 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
191 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
195 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
200 addxtypeChild : function (tree, cntr)
202 Roo.log('addxtypeChild:' + cntr);
204 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
207 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
208 (typeof(tree['flexy:foreach']) != 'undefined');
212 skip_children = false;
213 // render the element if it's not BODY.
214 if (tree.xtype != 'Body') {
216 cn = Roo.factory(tree);
218 cn.parentType = this.xtype; //??
219 cn.parentId = this.id;
221 var build_from_html = Roo.XComponent.build_from_html;
224 // does the container contain child eleemnts with 'xtype' attributes.
225 // that match this xtype..
226 // note - when we render we create these as well..
227 // so we should check to see if body has xtype set.
228 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
230 var self_cntr_el = Roo.get(this[cntr](false));
231 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
234 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
235 // and are not displayed -this causes this to use up the wrong element when matching.
236 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
239 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
240 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
246 //echild.dom.removeAttribute('xtype');
248 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
249 Roo.log(self_cntr_el);
257 // if object has flexy:if - then it may or may not be rendered.
258 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
259 // skip a flexy if element.
260 Roo.log('skipping render');
263 Roo.log('skipping all children');
264 skip_children = true;
269 // actually if flexy:foreach is found, we really want to create
270 // multiple copies here...
272 //Roo.log(this[cntr]());
273 cn.render(this[cntr](true));
275 // then add the element..
283 if (typeof (tree.menu) != 'undefined') {
284 tree.menu.parentType = cn.xtype;
285 tree.menu.triggerEl = cn.el;
286 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
290 if (!tree.items || !tree.items.length) {
294 var items = tree.items;
297 //Roo.log(items.length);
299 if (!skip_children) {
300 for(var i =0;i < items.length;i++) {
301 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
323 * @class Roo.bootstrap.Body
324 * @extends Roo.bootstrap.Component
325 * Bootstrap Body class
329 * @param {Object} config The config object
332 Roo.bootstrap.Body = function(config){
333 Roo.bootstrap.Body.superclass.constructor.call(this, config);
334 this.el = Roo.get(document.body);
335 if (this.cls && this.cls.length) {
336 Roo.get(document.body).addClass(this.cls);
340 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
345 onRender : function(ct, position)
347 /* Roo.log("Roo.bootstrap.Body - onRender");
348 if (this.cls && this.cls.length) {
349 Roo.get(document.body).addClass(this.cls);
369 * @class Roo.bootstrap.ButtonGroup
370 * @extends Roo.bootstrap.Component
371 * Bootstrap ButtonGroup class
372 * @cfg {String} size lg | sm | xs (default empty normal)
373 * @cfg {String} align vertical | justified (default none)
374 * @cfg {String} direction up | down (default down)
375 * @cfg {Boolean} toolbar false | true
376 * @cfg {Boolean} btn true | false
381 * @param {Object} config The config object
384 Roo.bootstrap.ButtonGroup = function(config){
385 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
388 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
396 getAutoCreate : function(){
402 cfg.html = this.html || cfg.html;
413 if (['vertical','justified'].indexOf(this.align)!==-1) {
414 cfg.cls = 'btn-group-' + this.align;
416 if (this.align == 'justified') {
417 console.log(this.items);
421 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
422 cfg.cls += ' btn-group-' + this.size;
425 if (this.direction == 'up') {
426 cfg.cls += ' dropup' ;
442 * @class Roo.bootstrap.Button
443 * @extends Roo.bootstrap.Component
444 * Bootstrap Button class
445 * @cfg {String} html The button content
446 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
447 * @cfg {String} size empty | lg | sm | xs
448 * @cfg {String} tag empty | a | input | submit
449 * @cfg {String} href empty or href
450 * @cfg {Boolean} disabled false | true
451 * @cfg {Boolean} isClose false | true
452 * @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
453 * @cfg {String} badge text for badge
454 * @cfg {String} theme default (or empty) | glow
455 * @cfg {Boolean} inverse false | true
456 * @cfg {Boolean} toggle false | true
457 * @cfg {String} ontext text for on toggle state
458 * @cfg {String} offtext text for off toggle state
459 * @cfg {Boolean} defaulton true | false
460 * @cfg {Boolean} preventDefault (true | false) default true
461 * @cfg {Boolean} removeClass true | false remove the standard class..
462 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
465 * Create a new button
466 * @param {Object} config The config object
470 Roo.bootstrap.Button = function(config){
471 Roo.bootstrap.Button.superclass.constructor.call(this, config);
476 * When a butotn is pressed
477 * @param {Roo.EventObject} e
482 * After the button has been toggles
483 * @param {Roo.EventObject} e
484 * @param {boolean} pressed (also available as button.pressed)
490 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
508 preventDefault: true,
517 getAutoCreate : function(){
525 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
526 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
531 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
533 if (this.toggle == true) {
536 cls: 'slider-frame roo-button',
541 'data-off-text':'OFF',
542 cls: 'slider-button',
548 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
549 cfg.cls += ' '+this.weight;
558 cfg["aria-hidden"] = true;
560 cfg.html = "×";
566 if (this.theme==='default') {
567 cfg.cls = 'btn roo-button';
569 //if (this.parentType != 'Navbar') {
570 this.weight = this.weight.length ? this.weight : 'default';
572 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
574 cfg.cls += ' btn-' + this.weight;
576 } else if (this.theme==='glow') {
579 cfg.cls = 'btn-glow roo-button';
581 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
583 cfg.cls += ' ' + this.weight;
589 this.cls += ' inverse';
594 cfg.cls += ' active';
598 cfg.disabled = 'disabled';
602 Roo.log('changing to ul' );
604 this.glyphicon = 'caret';
607 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
609 //gsRoo.log(this.parentType);
610 if (this.parentType === 'Navbar' && !this.parent().bar) {
611 Roo.log('changing to li?');
620 href : this.href || '#'
623 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
624 cfg.cls += ' dropdown';
631 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
633 if (this.glyphicon) {
634 cfg.html = ' ' + cfg.html;
639 cls: 'glyphicon glyphicon-' + this.glyphicon
649 // cfg.cls='btn roo-button';
653 var value = cfg.html;
658 cls: 'glyphicon glyphicon-' + this.glyphicon,
677 cfg.cls += ' dropdown';
678 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
681 if (cfg.tag !== 'a' && this.href !== '') {
682 throw "Tag must be a to set href.";
683 } else if (this.href.length > 0) {
684 cfg.href = this.href;
687 if(this.removeClass){
692 cfg.target = this.target;
697 initEvents: function() {
698 // Roo.log('init events?');
699 // Roo.log(this.el.dom);
702 if (typeof (this.menu) != 'undefined') {
703 this.menu.parentType = this.xtype;
704 this.menu.triggerEl = this.el;
705 this.addxtype(Roo.apply({}, this.menu));
709 if (this.el.hasClass('roo-button')) {
710 this.el.on('click', this.onClick, this);
712 this.el.select('.roo-button').on('click', this.onClick, this);
715 if(this.removeClass){
716 this.el.on('click', this.onClick, this);
719 this.el.enableDisplayMode();
722 onClick : function(e)
728 Roo.log('button on click ');
729 if(this.preventDefault){
732 if (this.pressed === true || this.pressed === false) {
733 this.pressed = !this.pressed;
734 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
735 this.fireEvent('toggle', this, e, this.pressed);
739 this.fireEvent('click', this, e);
743 * Enables this button
747 this.disabled = false;
748 this.el.removeClass('disabled');
752 * Disable this button
756 this.disabled = true;
757 this.el.addClass('disabled');
760 * sets the active state on/off,
761 * @param {Boolean} state (optional) Force a particular state
763 setActive : function(v) {
765 this.el[v ? 'addClass' : 'removeClass']('active');
768 * toggles the current active state
770 toggleActive : function()
772 var active = this.el.hasClass('active');
773 this.setActive(!active);
777 setText : function(str)
779 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
783 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
806 * @class Roo.bootstrap.Column
807 * @extends Roo.bootstrap.Component
808 * Bootstrap Column class
809 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
810 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
811 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
812 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
813 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
814 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
815 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
816 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
819 * @cfg {Boolean} hidden (true|false) hide the element
820 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
821 * @cfg {String} fa (ban|check|...) font awesome icon
822 * @cfg {Number} fasize (1|2|....) font awsome size
824 * @cfg {String} icon (info-sign|check|...) glyphicon name
826 * @cfg {String} html content of column.
829 * Create a new Column
830 * @param {Object} config The config object
833 Roo.bootstrap.Column = function(config){
834 Roo.bootstrap.Column.superclass.constructor.call(this, config);
837 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
855 getAutoCreate : function(){
856 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
864 ['xs','sm','md','lg'].map(function(size){
865 //Roo.log( size + ':' + settings[size]);
867 if (settings[size+'off'] !== false) {
868 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
871 if (settings[size] === false) {
874 Roo.log(settings[size]);
875 if (!settings[size]) { // 0 = hidden
876 cfg.cls += ' hidden-' + size;
879 cfg.cls += ' col-' + size + '-' + settings[size];
884 cfg.cls += ' hidden';
887 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
888 cfg.cls +=' alert alert-' + this.alert;
892 if (this.html.length) {
893 cfg.html = this.html;
897 if (this.fasize > 1) {
898 fasize = ' fa-' + this.fasize + 'x';
900 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
905 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
924 * @class Roo.bootstrap.Container
925 * @extends Roo.bootstrap.Component
926 * Bootstrap Container class
927 * @cfg {Boolean} jumbotron is it a jumbotron element
928 * @cfg {String} html content of element
929 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
930 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
931 * @cfg {String} header content of header (for panel)
932 * @cfg {String} footer content of footer (for panel)
933 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
934 * @cfg {String} tag (header|aside|section) type of HTML tag.
935 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
936 * @cfg {String} fa (ban|check|...) font awesome icon
937 * @cfg {String} icon (info-sign|check|...) glyphicon name
938 * @cfg {Boolean} hidden (true|false) hide the element
942 * Create a new Container
943 * @param {Object} config The config object
946 Roo.bootstrap.Container = function(config){
947 Roo.bootstrap.Container.superclass.constructor.call(this, config);
950 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
964 getChildContainer : function() {
970 if (this.panel.length) {
971 return this.el.select('.panel-body',true).first();
978 getAutoCreate : function(){
981 tag : this.tag || 'div',
985 if (this.jumbotron) {
986 cfg.cls = 'jumbotron';
991 // - this is applied by the parent..
993 // cfg.cls = this.cls + '';
996 if (this.sticky.length) {
998 var bd = Roo.get(document.body);
999 if (!bd.hasClass('bootstrap-sticky')) {
1000 bd.addClass('bootstrap-sticky');
1001 Roo.select('html',true).setStyle('height', '100%');
1004 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1008 if (this.well.length) {
1009 switch (this.well) {
1012 cfg.cls +=' well well-' +this.well;
1021 cfg.cls += ' hidden';
1025 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1026 cfg.cls +=' alert alert-' + this.alert;
1031 if (this.panel.length) {
1032 cfg.cls += ' panel panel-' + this.panel;
1034 if (this.header.length) {
1037 cls : 'panel-heading',
1040 cls : 'panel-title',
1053 if (this.footer.length) {
1055 cls : 'panel-footer',
1064 body.html = this.html || cfg.html;
1065 // prefix with the icons..
1067 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1070 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1075 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1076 cfg.cls = 'container';
1082 titleEl : function()
1084 if(!this.el || !this.panel.length || !this.header.length){
1088 return this.el.select('.panel-title',true).first();
1091 setTitle : function(v)
1093 var titleEl = this.titleEl();
1099 titleEl.dom.innerHTML = v;
1102 getTitle : function()
1105 var titleEl = this.titleEl();
1111 return titleEl.dom.innerHTML;
1125 * @class Roo.bootstrap.Img
1126 * @extends Roo.bootstrap.Component
1127 * Bootstrap Img class
1128 * @cfg {Boolean} imgResponsive false | true
1129 * @cfg {String} border rounded | circle | thumbnail
1130 * @cfg {String} src image source
1131 * @cfg {String} alt image alternative text
1132 * @cfg {String} href a tag href
1133 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1136 * Create a new Input
1137 * @param {Object} config The config object
1140 Roo.bootstrap.Img = function(config){
1141 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1147 * The img click event for the img.
1148 * @param {Roo.EventObject} e
1154 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1156 imgResponsive: true,
1162 getAutoCreate : function(){
1166 cls: (this.imgResponsive) ? 'img-responsive' : '',
1170 cfg.html = this.html || cfg.html;
1172 cfg.src = this.src || cfg.src;
1174 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1175 cfg.cls += ' img-' + this.border;
1192 a.target = this.target;
1198 return (this.href) ? a : cfg;
1201 initEvents: function() {
1204 this.el.on('click', this.onClick, this);
1208 onClick : function(e)
1210 Roo.log('img onclick');
1211 this.fireEvent('click', this, e);
1225 * @class Roo.bootstrap.Link
1226 * @extends Roo.bootstrap.Component
1227 * Bootstrap Link Class
1228 * @cfg {String} alt image alternative text
1229 * @cfg {String} href a tag href
1230 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1231 * @cfg {String} html the content of the link.
1232 * @cfg {String} anchor name for the anchor link
1234 * @cfg {Boolean} preventDefault (true | false) default false
1238 * Create a new Input
1239 * @param {Object} config The config object
1242 Roo.bootstrap.Link = function(config){
1243 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1249 * The img click event for the img.
1250 * @param {Roo.EventObject} e
1256 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1260 preventDefault: false,
1264 getAutoCreate : function()
1270 // anchor's do not require html/href...
1271 if (this.anchor === false) {
1272 cfg.html = this.html || 'html-missing';
1273 cfg.href = this.href || '#';
1275 cfg.name = this.anchor;
1276 if (this.html !== false) {
1277 cfg.html = this.html;
1279 if (this.href !== false) {
1280 cfg.href = this.href;
1284 if(this.alt !== false){
1289 if(this.target !== false) {
1290 cfg.target = this.target;
1296 initEvents: function() {
1298 if(!this.href || this.preventDefault){
1299 this.el.on('click', this.onClick, this);
1303 onClick : function(e)
1305 if(this.preventDefault){
1308 //Roo.log('img onclick');
1309 this.fireEvent('click', this, e);
1322 * @class Roo.bootstrap.Header
1323 * @extends Roo.bootstrap.Component
1324 * Bootstrap Header class
1325 * @cfg {String} html content of header
1326 * @cfg {Number} level (1|2|3|4|5|6) default 1
1329 * Create a new Header
1330 * @param {Object} config The config object
1334 Roo.bootstrap.Header = function(config){
1335 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1338 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1346 getAutoCreate : function(){
1349 tag: 'h' + (1 *this.level),
1350 html: this.html || 'fill in html'
1362 * Ext JS Library 1.1.1
1363 * Copyright(c) 2006-2007, Ext JS, LLC.
1365 * Originally Released Under LGPL - original licence link has changed is not relivant.
1368 * <script type="text/javascript">
1372 * @class Roo.bootstrap.MenuMgr
1373 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1376 Roo.bootstrap.MenuMgr = function(){
1377 var menus, active, groups = {}, attached = false, lastShow = new Date();
1379 // private - called when first menu is created
1382 active = new Roo.util.MixedCollection();
1383 Roo.get(document).addKeyListener(27, function(){
1384 if(active.length > 0){
1392 if(active && active.length > 0){
1393 var c = active.clone();
1403 if(active.length < 1){
1404 Roo.get(document).un("mouseup", onMouseDown);
1412 var last = active.last();
1413 lastShow = new Date();
1416 Roo.get(document).on("mouseup", onMouseDown);
1421 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1422 m.parentMenu.activeChild = m;
1423 }else if(last && last.isVisible()){
1424 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1429 function onBeforeHide(m){
1431 m.activeChild.hide();
1433 if(m.autoHideTimer){
1434 clearTimeout(m.autoHideTimer);
1435 delete m.autoHideTimer;
1440 function onBeforeShow(m){
1441 var pm = m.parentMenu;
1442 if(!pm && !m.allowOtherMenus){
1444 }else if(pm && pm.activeChild && active != m){
1445 pm.activeChild.hide();
1450 function onMouseDown(e){
1451 Roo.log("on MouseDown");
1452 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1460 function onBeforeCheck(mi, state){
1462 var g = groups[mi.group];
1463 for(var i = 0, l = g.length; i < l; i++){
1465 g[i].setChecked(false);
1474 * Hides all menus that are currently visible
1476 hideAll : function(){
1481 register : function(menu){
1485 menus[menu.id] = menu;
1486 menu.on("beforehide", onBeforeHide);
1487 menu.on("hide", onHide);
1488 menu.on("beforeshow", onBeforeShow);
1489 menu.on("show", onShow);
1491 if(g && menu.events["checkchange"]){
1495 groups[g].push(menu);
1496 menu.on("checkchange", onCheck);
1501 * Returns a {@link Roo.menu.Menu} object
1502 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1503 * be used to generate and return a new Menu instance.
1505 get : function(menu){
1506 if(typeof menu == "string"){ // menu id
1508 }else if(menu.events){ // menu instance
1511 /*else if(typeof menu.length == 'number'){ // array of menu items?
1512 return new Roo.bootstrap.Menu({items:menu});
1513 }else{ // otherwise, must be a config
1514 return new Roo.bootstrap.Menu(menu);
1521 unregister : function(menu){
1522 delete menus[menu.id];
1523 menu.un("beforehide", onBeforeHide);
1524 menu.un("hide", onHide);
1525 menu.un("beforeshow", onBeforeShow);
1526 menu.un("show", onShow);
1528 if(g && menu.events["checkchange"]){
1529 groups[g].remove(menu);
1530 menu.un("checkchange", onCheck);
1535 registerCheckable : function(menuItem){
1536 var g = menuItem.group;
1541 groups[g].push(menuItem);
1542 menuItem.on("beforecheckchange", onBeforeCheck);
1547 unregisterCheckable : function(menuItem){
1548 var g = menuItem.group;
1550 groups[g].remove(menuItem);
1551 menuItem.un("beforecheckchange", onBeforeCheck);
1563 * @class Roo.bootstrap.Menu
1564 * @extends Roo.bootstrap.Component
1565 * Bootstrap Menu class - container for MenuItems
1566 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1570 * @param {Object} config The config object
1574 Roo.bootstrap.Menu = function(config){
1575 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1576 if (this.registerMenu) {
1577 Roo.bootstrap.MenuMgr.register(this);
1582 * Fires before this menu is displayed
1583 * @param {Roo.menu.Menu} this
1588 * Fires before this menu is hidden
1589 * @param {Roo.menu.Menu} this
1594 * Fires after this menu is displayed
1595 * @param {Roo.menu.Menu} this
1600 * Fires after this menu is hidden
1601 * @param {Roo.menu.Menu} this
1606 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1607 * @param {Roo.menu.Menu} this
1608 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1609 * @param {Roo.EventObject} e
1614 * Fires when the mouse is hovering over this menu
1615 * @param {Roo.menu.Menu} this
1616 * @param {Roo.EventObject} e
1617 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1622 * Fires when the mouse exits this menu
1623 * @param {Roo.menu.Menu} this
1624 * @param {Roo.EventObject} e
1625 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1630 * Fires when a menu item contained in this menu is clicked
1631 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1632 * @param {Roo.EventObject} e
1636 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1639 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1643 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1646 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1648 registerMenu : true,
1650 menuItems :false, // stores the menu items..
1656 getChildContainer : function() {
1660 getAutoCreate : function(){
1662 //if (['right'].indexOf(this.align)!==-1) {
1663 // cfg.cn[1].cls += ' pull-right'
1669 cls : 'dropdown-menu' ,
1670 style : 'z-index:1000'
1674 if (this.type === 'submenu') {
1675 cfg.cls = 'submenu active';
1677 if (this.type === 'treeview') {
1678 cfg.cls = 'treeview-menu';
1683 initEvents : function() {
1685 // Roo.log("ADD event");
1686 // Roo.log(this.triggerEl.dom);
1687 this.triggerEl.on('click', this.onTriggerPress, this);
1688 this.triggerEl.addClass('dropdown-toggle');
1689 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1691 this.el.on("mouseover", this.onMouseOver, this);
1692 this.el.on("mouseout", this.onMouseOut, this);
1696 findTargetItem : function(e){
1697 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1701 //Roo.log(t); Roo.log(t.id);
1703 //Roo.log(this.menuitems);
1704 return this.menuitems.get(t.id);
1706 //return this.items.get(t.menuItemId);
1711 onClick : function(e){
1712 Roo.log("menu.onClick");
1713 var t = this.findTargetItem(e);
1714 if(!t || t.isContainer){
1719 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1720 if(t == this.activeItem && t.shouldDeactivate(e)){
1721 this.activeItem.deactivate();
1722 delete this.activeItem;
1726 this.setActiveItem(t, true);
1734 Roo.log('pass click event');
1738 this.fireEvent("click", this, t, e);
1742 onMouseOver : function(e){
1743 var t = this.findTargetItem(e);
1746 // if(t.canActivate && !t.disabled){
1747 // this.setActiveItem(t, true);
1751 this.fireEvent("mouseover", this, e, t);
1753 isVisible : function(){
1754 return !this.hidden;
1756 onMouseOut : function(e){
1757 var t = this.findTargetItem(e);
1760 // if(t == this.activeItem && t.shouldDeactivate(e)){
1761 // this.activeItem.deactivate();
1762 // delete this.activeItem;
1765 this.fireEvent("mouseout", this, e, t);
1770 * Displays this menu relative to another element
1771 * @param {String/HTMLElement/Roo.Element} element The element to align to
1772 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1773 * the element (defaults to this.defaultAlign)
1774 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1776 show : function(el, pos, parentMenu){
1777 this.parentMenu = parentMenu;
1781 this.fireEvent("beforeshow", this);
1782 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1785 * Displays this menu at a specific xy position
1786 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1787 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1789 showAt : function(xy, parentMenu, /* private: */_e){
1790 this.parentMenu = parentMenu;
1795 this.fireEvent("beforeshow", this);
1797 //xy = this.el.adjustForConstraints(xy);
1799 //this.el.setXY(xy);
1801 this.hideMenuItems();
1802 this.hidden = false;
1803 this.triggerEl.addClass('open');
1805 this.fireEvent("show", this);
1811 this.doFocus.defer(50, this);
1815 doFocus : function(){
1817 this.focusEl.focus();
1822 * Hides this menu and optionally all parent menus
1823 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1825 hide : function(deep){
1827 this.hideMenuItems();
1828 if(this.el && this.isVisible()){
1829 this.fireEvent("beforehide", this);
1830 if(this.activeItem){
1831 this.activeItem.deactivate();
1832 this.activeItem = null;
1834 this.triggerEl.removeClass('open');;
1836 this.fireEvent("hide", this);
1838 if(deep === true && this.parentMenu){
1839 this.parentMenu.hide(true);
1843 onTriggerPress : function(e)
1846 Roo.log('trigger press');
1847 //Roo.log(e.getTarget());
1848 // Roo.log(this.triggerEl.dom);
1849 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1852 if (this.isVisible()) {
1856 this.show(this.triggerEl, false, false);
1865 hideMenuItems : function()
1867 //$(backdrop).remove()
1868 Roo.select('.open',true).each(function(aa) {
1870 aa.removeClass('open');
1871 //var parent = getParent($(this))
1872 //var relatedTarget = { relatedTarget: this }
1874 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1875 //if (e.isDefaultPrevented()) return
1876 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1879 addxtypeChild : function (tree, cntr) {
1880 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1882 this.menuitems.add(comp);
1903 * @class Roo.bootstrap.MenuItem
1904 * @extends Roo.bootstrap.Component
1905 * Bootstrap MenuItem class
1906 * @cfg {String} html the menu label
1907 * @cfg {String} href the link
1908 * @cfg {Boolean} preventDefault (true | false) default true
1909 * @cfg {Boolean} isContainer (true | false) default false
1913 * Create a new MenuItem
1914 * @param {Object} config The config object
1918 Roo.bootstrap.MenuItem = function(config){
1919 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1924 * The raw click event for the entire grid.
1925 * @param {Roo.EventObject} e
1931 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1935 preventDefault: true,
1936 isContainer : false,
1938 getAutoCreate : function(){
1940 if(this.isContainer){
1943 cls: 'dropdown-menu-item'
1949 cls: 'dropdown-menu-item',
1958 if (this.parent().type == 'treeview') {
1959 cfg.cls = 'treeview-menu';
1962 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1963 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1967 initEvents: function() {
1969 //this.el.select('a').on('click', this.onClick, this);
1972 onClick : function(e)
1974 Roo.log('item on click ');
1975 //if(this.preventDefault){
1976 // e.preventDefault();
1978 //this.parent().hideMenuItems();
1980 this.fireEvent('click', this, e);
1999 * @class Roo.bootstrap.MenuSeparator
2000 * @extends Roo.bootstrap.Component
2001 * Bootstrap MenuSeparator class
2004 * Create a new MenuItem
2005 * @param {Object} config The config object
2009 Roo.bootstrap.MenuSeparator = function(config){
2010 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2013 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2015 getAutoCreate : function(){
2030 <div class="modal fade">
2031 <div class="modal-dialog">
2032 <div class="modal-content">
2033 <div class="modal-header">
2034 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
2035 <h4 class="modal-title">Modal title</h4>
2037 <div class="modal-body">
2038 <p>One fine body…</p>
2040 <div class="modal-footer">
2041 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2042 <button type="button" class="btn btn-primary">Save changes</button>
2044 </div><!-- /.modal-content -->
2045 </div><!-- /.modal-dialog -->
2046 </div><!-- /.modal -->
2056 * @class Roo.bootstrap.Modal
2057 * @extends Roo.bootstrap.Component
2058 * Bootstrap Modal class
2059 * @cfg {String} title Title of dialog
2060 * @cfg {Boolean} specificTitle (true|false) default false
2061 * @cfg {Array} buttons Array of buttons or standard button set..
2062 * @cfg {String} buttonPosition (left|right|center) default right
2063 * @cfg {Boolean} animate (true | false) default true
2066 * Create a new Modal Dialog
2067 * @param {Object} config The config object
2070 Roo.bootstrap.Modal = function(config){
2071 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2076 * The raw btnclick event for the button
2077 * @param {Roo.EventObject} e
2081 this.buttons = this.buttons || [];
2084 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2086 title : 'test dialog',
2093 specificTitle: false,
2095 buttonPosition: 'right',
2099 onRender : function(ct, position)
2101 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2104 var cfg = Roo.apply({}, this.getAutoCreate());
2107 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2109 //if (!cfg.name.length) {
2113 cfg.cls += ' ' + this.cls;
2116 cfg.style = this.style;
2118 this.el = Roo.get(document.body).createChild(cfg, position);
2120 //var type = this.el.dom.type;
2122 if(this.tabIndex !== undefined){
2123 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2128 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2129 this.maskEl.enableDisplayMode("block");
2131 //this.el.addClass("x-dlg-modal");
2133 if (this.buttons.length) {
2134 Roo.each(this.buttons, function(bb) {
2135 b = Roo.apply({}, bb);
2136 b.xns = b.xns || Roo.bootstrap;
2137 b.xtype = b.xtype || 'Button';
2138 if (typeof(b.listeners) == 'undefined') {
2139 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2142 var btn = Roo.factory(b);
2144 btn.onRender(this.el.select('.modal-footer div').first());
2148 // render the children.
2151 if(typeof(this.items) != 'undefined'){
2152 var items = this.items;
2155 for(var i =0;i < items.length;i++) {
2156 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2160 this.items = nitems;
2162 this.body = this.el.select('.modal-body',true).first();
2163 this.close = this.el.select('.modal-header .close', true).first();
2164 this.footer = this.el.select('.modal-footer',true).first();
2166 //this.el.addClass([this.fieldClass, this.cls]);
2169 getAutoCreate : function(){
2174 html : this.html || ''
2179 cls : 'modal-title',
2183 if(this.specificTitle){
2189 style : 'display: none',
2192 cls: "modal-dialog",
2195 cls : "modal-content",
2198 cls : 'modal-header',
2210 cls : 'modal-footer',
2214 cls: 'btn-' + this.buttonPosition
2231 modal.cls += ' fade';
2237 getChildContainer : function() {
2239 return this.el.select('.modal-body',true).first();
2242 getButtonContainer : function() {
2243 return this.el.select('.modal-footer div',true).first();
2246 initEvents : function()
2248 this.el.select('.modal-header .close').on('click', this.hide, this);
2250 // this.addxtype(this);
2254 if (!this.rendered) {
2258 this.el.setStyle('display', 'block');
2262 (function(){ _this.el.addClass('in'); }).defer(50);
2264 this.el.addClass('in');
2267 Roo.get(document.body).addClass("x-body-masked");
2268 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2270 this.el.setStyle('zIndex', '10001');
2271 this.fireEvent('show', this);
2278 Roo.get(document.body).removeClass("x-body-masked");
2279 this.el.removeClass('in');
2283 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2285 this.el.setStyle('display', 'none');
2288 this.fireEvent('hide', this);
2291 addButton : function(str, cb)
2295 var b = Roo.apply({}, { html : str } );
2296 b.xns = b.xns || Roo.bootstrap;
2297 b.xtype = b.xtype || 'Button';
2298 if (typeof(b.listeners) == 'undefined') {
2299 b.listeners = { click : cb.createDelegate(this) };
2302 var btn = Roo.factory(b);
2304 btn.onRender(this.el.select('.modal-footer div').first());
2310 setDefaultButton : function(btn)
2312 //this.el.select('.modal-footer').()
2314 resizeTo: function(w,h)
2318 setContentSize : function(w, h)
2322 onButtonClick: function(btn,e)
2325 this.fireEvent('btnclick', btn.name, e);
2327 setTitle: function(str) {
2328 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2334 Roo.apply(Roo.bootstrap.Modal, {
2336 * Button config that displays a single OK button
2345 * Button config that displays Yes and No buttons
2361 * Button config that displays OK and Cancel buttons
2376 * Button config that displays Yes, No and Cancel buttons
2398 * messagebox - can be used as a replace
2402 * @class Roo.MessageBox
2403 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2407 Roo.Msg.alert('Status', 'Changes saved successfully.');
2409 // Prompt for user data:
2410 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2412 // process text value...
2416 // Show a dialog using config options:
2418 title:'Save Changes?',
2419 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2420 buttons: Roo.Msg.YESNOCANCEL,
2427 Roo.bootstrap.MessageBox = function(){
2428 var dlg, opt, mask, waitTimer;
2429 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2430 var buttons, activeTextEl, bwidth;
2434 var handleButton = function(button){
2436 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2440 var handleHide = function(){
2442 dlg.el.removeClass(opt.cls);
2445 // Roo.TaskMgr.stop(waitTimer);
2446 // waitTimer = null;
2451 var updateButtons = function(b){
2454 buttons["ok"].hide();
2455 buttons["cancel"].hide();
2456 buttons["yes"].hide();
2457 buttons["no"].hide();
2458 //dlg.footer.dom.style.display = 'none';
2461 dlg.footer.dom.style.display = '';
2462 for(var k in buttons){
2463 if(typeof buttons[k] != "function"){
2466 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2467 width += buttons[k].el.getWidth()+15;
2477 var handleEsc = function(d, k, e){
2478 if(opt && opt.closable !== false){
2488 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2489 * @return {Roo.BasicDialog} The BasicDialog element
2491 getDialog : function(){
2493 dlg = new Roo.bootstrap.Modal( {
2496 //constraintoviewport:false,
2498 //collapsible : false,
2503 //buttonAlign:"center",
2504 closeClick : function(){
2505 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2508 handleButton("cancel");
2513 dlg.on("hide", handleHide);
2515 //dlg.addKeyListener(27, handleEsc);
2517 this.buttons = buttons;
2518 var bt = this.buttonText;
2519 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2520 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2521 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2522 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2524 bodyEl = dlg.body.createChild({
2526 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2527 '<textarea class="roo-mb-textarea"></textarea>' +
2528 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2530 msgEl = bodyEl.dom.firstChild;
2531 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2532 textboxEl.enableDisplayMode();
2533 textboxEl.addKeyListener([10,13], function(){
2534 if(dlg.isVisible() && opt && opt.buttons){
2537 }else if(opt.buttons.yes){
2538 handleButton("yes");
2542 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2543 textareaEl.enableDisplayMode();
2544 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2545 progressEl.enableDisplayMode();
2546 var pf = progressEl.dom.firstChild;
2548 pp = Roo.get(pf.firstChild);
2549 pp.setHeight(pf.offsetHeight);
2557 * Updates the message box body text
2558 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2559 * the XHTML-compliant non-breaking space character '&#160;')
2560 * @return {Roo.MessageBox} This message box
2562 updateText : function(text){
2563 if(!dlg.isVisible() && !opt.width){
2564 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2566 msgEl.innerHTML = text || ' ';
2568 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2569 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2571 Math.min(opt.width || cw , this.maxWidth),
2572 Math.max(opt.minWidth || this.minWidth, bwidth)
2575 activeTextEl.setWidth(w);
2577 if(dlg.isVisible()){
2578 dlg.fixedcenter = false;
2580 // to big, make it scroll. = But as usual stupid IE does not support
2583 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2584 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2585 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2587 bodyEl.dom.style.height = '';
2588 bodyEl.dom.style.overflowY = '';
2591 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2593 bodyEl.dom.style.overflowX = '';
2596 dlg.setContentSize(w, bodyEl.getHeight());
2597 if(dlg.isVisible()){
2598 dlg.fixedcenter = true;
2604 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2605 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2606 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2607 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2608 * @return {Roo.MessageBox} This message box
2610 updateProgress : function(value, text){
2612 this.updateText(text);
2614 if (pp) { // weird bug on my firefox - for some reason this is not defined
2615 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2621 * Returns true if the message box is currently displayed
2622 * @return {Boolean} True if the message box is visible, else false
2624 isVisible : function(){
2625 return dlg && dlg.isVisible();
2629 * Hides the message box if it is displayed
2632 if(this.isVisible()){
2638 * Displays a new message box, or reinitializes an existing message box, based on the config options
2639 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2640 * The following config object properties are supported:
2642 Property Type Description
2643 ---------- --------------- ------------------------------------------------------------------------------------
2644 animEl String/Element An id or Element from which the message box should animate as it opens and
2645 closes (defaults to undefined)
2646 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2647 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2648 closable Boolean False to hide the top-right close button (defaults to true). Note that
2649 progress and wait dialogs will ignore this property and always hide the
2650 close button as they can only be closed programmatically.
2651 cls String A custom CSS class to apply to the message box element
2652 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2653 displayed (defaults to 75)
2654 fn Function A callback function to execute after closing the dialog. The arguments to the
2655 function will be btn (the name of the button that was clicked, if applicable,
2656 e.g. "ok"), and text (the value of the active text field, if applicable).
2657 Progress and wait dialogs will ignore this option since they do not respond to
2658 user actions and can only be closed programmatically, so any required function
2659 should be called by the same code after it closes the dialog.
2660 icon String A CSS class that provides a background image to be used as an icon for
2661 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2662 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2663 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2664 modal Boolean False to allow user interaction with the page while the message box is
2665 displayed (defaults to true)
2666 msg String A string that will replace the existing message box body text (defaults
2667 to the XHTML-compliant non-breaking space character ' ')
2668 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2669 progress Boolean True to display a progress bar (defaults to false)
2670 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2671 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2672 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2673 title String The title text
2674 value String The string value to set into the active textbox element if displayed
2675 wait Boolean True to display a progress bar (defaults to false)
2676 width Number The width of the dialog in pixels
2683 msg: 'Please enter your address:',
2685 buttons: Roo.MessageBox.OKCANCEL,
2688 animEl: 'addAddressBtn'
2691 * @param {Object} config Configuration options
2692 * @return {Roo.MessageBox} This message box
2694 show : function(options)
2697 // this causes nightmares if you show one dialog after another
2698 // especially on callbacks..
2700 if(this.isVisible()){
2703 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2704 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2705 Roo.log("New Dialog Message:" + options.msg )
2706 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2707 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2710 var d = this.getDialog();
2712 d.setTitle(opt.title || " ");
2713 d.close.setDisplayed(opt.closable !== false);
2714 activeTextEl = textboxEl;
2715 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2720 textareaEl.setHeight(typeof opt.multiline == "number" ?
2721 opt.multiline : this.defaultTextHeight);
2722 activeTextEl = textareaEl;
2731 progressEl.setDisplayed(opt.progress === true);
2732 this.updateProgress(0);
2733 activeTextEl.dom.value = opt.value || "";
2735 dlg.setDefaultButton(activeTextEl);
2737 var bs = opt.buttons;
2741 }else if(bs && bs.yes){
2742 db = buttons["yes"];
2744 dlg.setDefaultButton(db);
2746 bwidth = updateButtons(opt.buttons);
2747 this.updateText(opt.msg);
2749 d.el.addClass(opt.cls);
2751 d.proxyDrag = opt.proxyDrag === true;
2752 d.modal = opt.modal !== false;
2753 d.mask = opt.modal !== false ? mask : false;
2755 // force it to the end of the z-index stack so it gets a cursor in FF
2756 document.body.appendChild(dlg.el.dom);
2757 d.animateTarget = null;
2758 d.show(options.animEl);
2764 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2765 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2766 * and closing the message box when the process is complete.
2767 * @param {String} title The title bar text
2768 * @param {String} msg The message box body text
2769 * @return {Roo.MessageBox} This message box
2771 progress : function(title, msg){
2778 minWidth: this.minProgressWidth,
2785 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2786 * If a callback function is passed it will be called after the user clicks the button, and the
2787 * id of the button that was clicked will be passed as the only parameter to the callback
2788 * (could also be the top-right close button).
2789 * @param {String} title The title bar text
2790 * @param {String} msg The message box body text
2791 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2792 * @param {Object} scope (optional) The scope of the callback function
2793 * @return {Roo.MessageBox} This message box
2795 alert : function(title, msg, fn, scope){
2808 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2809 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2810 * You are responsible for closing the message box when the process is complete.
2811 * @param {String} msg The message box body text
2812 * @param {String} title (optional) The title bar text
2813 * @return {Roo.MessageBox} This message box
2815 wait : function(msg, title){
2826 waitTimer = Roo.TaskMgr.start({
2828 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2836 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2837 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2838 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2839 * @param {String} title The title bar text
2840 * @param {String} msg The message box body text
2841 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2842 * @param {Object} scope (optional) The scope of the callback function
2843 * @return {Roo.MessageBox} This message box
2845 confirm : function(title, msg, fn, scope){
2849 buttons: this.YESNO,
2858 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2859 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2860 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2861 * (could also be the top-right close button) and the text that was entered will be passed as the two
2862 * parameters to the callback.
2863 * @param {String} title The title bar text
2864 * @param {String} msg The message box body text
2865 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2866 * @param {Object} scope (optional) The scope of the callback function
2867 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2868 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2869 * @return {Roo.MessageBox} This message box
2871 prompt : function(title, msg, fn, scope, multiline){
2875 buttons: this.OKCANCEL,
2880 multiline: multiline,
2887 * Button config that displays a single OK button
2892 * Button config that displays Yes and No buttons
2895 YESNO : {yes:true, no:true},
2897 * Button config that displays OK and Cancel buttons
2900 OKCANCEL : {ok:true, cancel:true},
2902 * Button config that displays Yes, No and Cancel buttons
2905 YESNOCANCEL : {yes:true, no:true, cancel:true},
2908 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2911 defaultTextHeight : 75,
2913 * The maximum width in pixels of the message box (defaults to 600)
2918 * The minimum width in pixels of the message box (defaults to 100)
2923 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2924 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2927 minProgressWidth : 250,
2929 * An object containing the default button text strings that can be overriden for localized language support.
2930 * Supported properties are: ok, cancel, yes and no.
2931 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2944 * Shorthand for {@link Roo.MessageBox}
2946 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2947 Roo.Msg = Roo.Msg || Roo.MessageBox;
2956 * @class Roo.bootstrap.Navbar
2957 * @extends Roo.bootstrap.Component
2958 * Bootstrap Navbar class
2961 * Create a new Navbar
2962 * @param {Object} config The config object
2966 Roo.bootstrap.Navbar = function(config){
2967 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2971 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2980 getAutoCreate : function(){
2983 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2987 initEvents :function ()
2989 //Roo.log(this.el.select('.navbar-toggle',true));
2990 this.el.select('.navbar-toggle',true).on('click', function() {
2991 // Roo.log('click');
2992 this.el.select('.navbar-collapse',true).toggleClass('in');
3000 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3002 var size = this.el.getSize();
3003 this.maskEl.setSize(size.width, size.height);
3004 this.maskEl.enableDisplayMode("block");
3013 getChildContainer : function()
3015 if (this.el.select('.collapse').getCount()) {
3016 return this.el.select('.collapse',true).first();
3049 * @class Roo.bootstrap.NavSimplebar
3050 * @extends Roo.bootstrap.Navbar
3051 * Bootstrap Sidebar class
3053 * @cfg {Boolean} inverse is inverted color
3055 * @cfg {String} type (nav | pills | tabs)
3056 * @cfg {Boolean} arrangement stacked | justified
3057 * @cfg {String} align (left | right) alignment
3059 * @cfg {Boolean} main (true|false) main nav bar? default false
3060 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3062 * @cfg {String} tag (header|footer|nav|div) default is nav
3068 * Create a new Sidebar
3069 * @param {Object} config The config object
3073 Roo.bootstrap.NavSimplebar = function(config){
3074 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3077 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3093 getAutoCreate : function(){
3097 tag : this.tag || 'div',
3110 this.type = this.type || 'nav';
3111 if (['tabs','pills'].indexOf(this.type)!==-1) {
3112 cfg.cn[0].cls += ' nav-' + this.type
3116 if (this.type!=='nav') {
3117 Roo.log('nav type must be nav/tabs/pills')
3119 cfg.cn[0].cls += ' navbar-nav'
3125 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3126 cfg.cn[0].cls += ' nav-' + this.arrangement;
3130 if (this.align === 'right') {
3131 cfg.cn[0].cls += ' navbar-right';
3135 cfg.cls += ' navbar-inverse';
3162 * @class Roo.bootstrap.NavHeaderbar
3163 * @extends Roo.bootstrap.NavSimplebar
3164 * Bootstrap Sidebar class
3166 * @cfg {String} brand what is brand
3167 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3168 * @cfg {String} brand_href href of the brand
3169 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3170 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3173 * Create a new Sidebar
3174 * @param {Object} config The config object
3178 Roo.bootstrap.NavHeaderbar = function(config){
3179 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3182 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3190 getAutoCreate : function(){
3193 tag: this.nav || 'nav',
3202 cls: 'navbar-header',
3207 cls: 'navbar-toggle',
3208 'data-toggle': 'collapse',
3213 html: 'Toggle navigation'
3235 cls: 'collapse navbar-collapse',
3239 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3241 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3242 cfg.cls += ' navbar-' + this.position;
3244 // tag can override this..
3246 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3249 if (this.brand !== '') {
3252 href: this.brand_href ? this.brand_href : '#',
3253 cls: 'navbar-brand',
3261 cfg.cls += ' main-nav';
3269 initEvents : function()
3271 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3273 if (this.autohide) {
3278 Roo.get(document).on('scroll',function(e) {
3279 var ns = Roo.get(document).getScroll().top;
3280 var os = prevScroll;
3284 ft.removeClass('slideDown');
3285 ft.addClass('slideUp');
3288 ft.removeClass('slideUp');
3289 ft.addClass('slideDown');
3313 * @class Roo.bootstrap.NavSidebar
3314 * @extends Roo.bootstrap.Navbar
3315 * Bootstrap Sidebar class
3318 * Create a new Sidebar
3319 * @param {Object} config The config object
3323 Roo.bootstrap.NavSidebar = function(config){
3324 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3327 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3329 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3331 getAutoCreate : function(){
3336 cls: 'sidebar sidebar-nav'
3358 * @class Roo.bootstrap.NavGroup
3359 * @extends Roo.bootstrap.Component
3360 * Bootstrap NavGroup class
3361 * @cfg {String} align left | right
3362 * @cfg {Boolean} inverse false | true
3363 * @cfg {String} type (nav|pills|tab) default nav
3364 * @cfg {String} navId - reference Id for navbar.
3368 * Create a new nav group
3369 * @param {Object} config The config object
3372 Roo.bootstrap.NavGroup = function(config){
3373 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3376 Roo.bootstrap.NavGroup.register(this);
3380 * Fires when the active item changes
3381 * @param {Roo.bootstrap.NavGroup} this
3382 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3383 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3390 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3401 getAutoCreate : function()
3403 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3410 if (['tabs','pills'].indexOf(this.type)!==-1) {
3411 cfg.cls += ' nav-' + this.type
3413 if (this.type!=='nav') {
3414 Roo.log('nav type must be nav/tabs/pills')
3416 cfg.cls += ' navbar-nav'
3419 if (this.parent().sidebar) {
3422 cls: 'dashboard-menu sidebar-menu'
3428 if (this.form === true) {
3434 if (this.align === 'right') {
3435 cfg.cls += ' navbar-right';
3437 cfg.cls += ' navbar-left';
3441 if (this.align === 'right') {
3442 cfg.cls += ' navbar-right';
3446 cfg.cls += ' navbar-inverse';
3454 * sets the active Navigation item
3455 * @param {Roo.bootstrap.NavItem} the new current navitem
3457 setActiveItem : function(item)
3460 Roo.each(this.navItems, function(v){
3465 v.setActive(false, true);
3472 item.setActive(true, true);
3473 this.fireEvent('changed', this, item, prev);
3478 * gets the active Navigation item
3479 * @return {Roo.bootstrap.NavItem} the current navitem
3481 getActive : function()
3485 Roo.each(this.navItems, function(v){
3496 indexOfNav : function()
3500 Roo.each(this.navItems, function(v,i){
3511 * adds a Navigation item
3512 * @param {Roo.bootstrap.NavItem} the navitem to add
3514 addItem : function(cfg)
3516 var cn = new Roo.bootstrap.NavItem(cfg);
3518 cn.parentId = this.id;
3519 cn.onRender(this.el, null);
3523 * register a Navigation item
3524 * @param {Roo.bootstrap.NavItem} the navitem to add
3526 register : function(item)
3528 this.navItems.push( item);
3529 item.navId = this.navId;
3534 * clear all the Navigation item
3537 clearAll : function()
3540 this.el.dom.innerHTML = '';
3543 getNavItem: function(tabId)
3546 Roo.each(this.navItems, function(e) {
3547 if (e.tabId == tabId) {
3557 setActiveNext : function()
3559 var i = this.indexOfNav(this.getActive());
3560 if (i > this.navItems.length) {
3563 this.setActiveItem(this.navItems[i+1]);
3565 setActivePrev : function()
3567 var i = this.indexOfNav(this.getActive());
3571 this.setActiveItem(this.navItems[i-1]);
3573 clearWasActive : function(except) {
3574 Roo.each(this.navItems, function(e) {
3575 if (e.tabId != except.tabId && e.was_active) {
3576 e.was_active = false;
3583 getWasActive : function ()
3586 Roo.each(this.navItems, function(e) {
3601 Roo.apply(Roo.bootstrap.NavGroup, {
3605 * register a Navigation Group
3606 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3608 register : function(navgrp)
3610 this.groups[navgrp.navId] = navgrp;
3614 * fetch a Navigation Group based on the navigation ID
3615 * @param {string} the navgroup to add
3616 * @returns {Roo.bootstrap.NavGroup} the navgroup
3618 get: function(navId) {
3619 if (typeof(this.groups[navId]) == 'undefined') {
3621 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3623 return this.groups[navId] ;
3638 * @class Roo.bootstrap.NavItem
3639 * @extends Roo.bootstrap.Component
3640 * Bootstrap Navbar.NavItem class
3641 * @cfg {String} href link to
3642 * @cfg {String} html content of button
3643 * @cfg {String} badge text inside badge
3644 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3645 * @cfg {String} glyphicon name of glyphicon
3646 * @cfg {String} icon name of font awesome icon
3647 * @cfg {Boolean} active Is item active
3648 * @cfg {Boolean} disabled Is item disabled
3650 * @cfg {Boolean} preventDefault (true | false) default false
3651 * @cfg {String} tabId the tab that this item activates.
3652 * @cfg {String} tagtype (a|span) render as a href or span?
3655 * Create a new Navbar Item
3656 * @param {Object} config The config object
3658 Roo.bootstrap.NavItem = function(config){
3659 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3664 * The raw click event for the entire grid.
3665 * @param {Roo.EventObject} e
3670 * Fires when the active item active state changes
3671 * @param {Roo.bootstrap.NavItem} this
3672 * @param {boolean} state the new state
3680 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3688 preventDefault : false,
3695 getAutoCreate : function(){
3703 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3705 if (this.disabled) {
3706 cfg.cls += ' disabled';
3709 if (this.href || this.html || this.glyphicon || this.icon) {
3713 href : this.href || "#",
3714 html: this.html || ''
3719 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3722 if(this.glyphicon) {
3723 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3728 cfg.cn[0].html += " <span class='caret'></span>";
3732 if (this.badge !== '') {
3734 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3742 initEvents: function()
3744 if (typeof (this.menu) != 'undefined') {
3745 this.menu.parentType = this.xtype;
3746 this.menu.triggerEl = this.el;
3747 this.addxtype(Roo.apply({}, this.menu));
3750 this.el.select('a',true).on('click', this.onClick, this);
3752 if(this.tagtype == 'span'){
3753 this.el.select('span',true).on('click', this.onClick, this);
3756 // at this point parent should be available..
3757 this.parent().register(this);
3760 onClick : function(e)
3763 if(this.preventDefault){
3766 if (this.disabled) {
3770 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3771 if (tg && tg.transition) {
3772 Roo.log("waiting for the transitionend");
3776 Roo.log("fire event clicked");
3777 if(this.fireEvent('click', this, e) === false){
3781 if(this.tagtype == 'span'){
3785 var p = this.parent();
3786 if (['tabs','pills'].indexOf(p.type)!==-1) {
3787 if (typeof(p.setActiveItem) !== 'undefined') {
3788 p.setActiveItem(this);
3791 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3792 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3793 // remove the collapsed menu expand...
3794 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3799 isActive: function () {
3802 setActive : function(state, fire, is_was_active)
3804 if (this.active && !state & this.navId) {
3805 this.was_active = true;
3806 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3808 nv.clearWasActive(this);
3812 this.active = state;
3815 this.el.removeClass('active');
3816 } else if (!this.el.hasClass('active')) {
3817 this.el.addClass('active');
3820 this.fireEvent('changed', this, state);
3823 // show a panel if it's registered and related..
3825 if (!this.navId || !this.tabId || !state || is_was_active) {
3829 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3833 var pan = tg.getPanelByName(this.tabId);
3837 // if we can not flip to new panel - go back to old nav highlight..
3838 if (false == tg.showPanel(pan)) {
3839 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3841 var onav = nv.getWasActive();
3843 onav.setActive(true, false, true);
3852 // this should not be here...
3853 setDisabled : function(state)
3855 this.disabled = state;
3857 this.el.removeClass('disabled');
3858 } else if (!this.el.hasClass('disabled')) {
3859 this.el.addClass('disabled');
3872 * <span> icon </span>
3873 * <span> text </span>
3874 * <span>badge </span>
3878 * @class Roo.bootstrap.NavSidebarItem
3879 * @extends Roo.bootstrap.NavItem
3880 * Bootstrap Navbar.NavSidebarItem class
3882 * Create a new Navbar Button
3883 * @param {Object} config The config object
3885 Roo.bootstrap.NavSidebarItem = function(config){
3886 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3891 * The raw click event for the entire grid.
3892 * @param {Roo.EventObject} e
3897 * Fires when the active item active state changes
3898 * @param {Roo.bootstrap.NavSidebarItem} this
3899 * @param {boolean} state the new state
3907 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3910 getAutoCreate : function(){
3915 href : this.href || '#',
3927 html : this.html || ''
3932 cfg.cls += ' active';
3936 if (this.glyphicon || this.icon) {
3937 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3938 a.cn.push({ tag : 'i', cls : c }) ;
3943 if (this.badge !== '') {
3944 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3948 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3949 a.cls += 'dropdown-toggle treeview' ;
3973 * @class Roo.bootstrap.Row
3974 * @extends Roo.bootstrap.Component
3975 * Bootstrap Row class (contains columns...)
3979 * @param {Object} config The config object
3982 Roo.bootstrap.Row = function(config){
3983 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3986 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3988 getAutoCreate : function(){
4007 * @class Roo.bootstrap.Element
4008 * @extends Roo.bootstrap.Component
4009 * Bootstrap Element class
4010 * @cfg {String} html contents of the element
4011 * @cfg {String} tag tag of the element
4012 * @cfg {String} cls class of the element
4015 * Create a new Element
4016 * @param {Object} config The config object
4019 Roo.bootstrap.Element = function(config){
4020 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4023 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4030 getAutoCreate : function(){
4055 * @class Roo.bootstrap.Pagination
4056 * @extends Roo.bootstrap.Component
4057 * Bootstrap Pagination class
4058 * @cfg {String} size xs | sm | md | lg
4059 * @cfg {Boolean} inverse false | true
4062 * Create a new Pagination
4063 * @param {Object} config The config object
4066 Roo.bootstrap.Pagination = function(config){
4067 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4070 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4076 getAutoCreate : function(){
4082 cfg.cls += ' inverse';
4088 cfg.cls += " " + this.cls;
4106 * @class Roo.bootstrap.PaginationItem
4107 * @extends Roo.bootstrap.Component
4108 * Bootstrap PaginationItem class
4109 * @cfg {String} html text
4110 * @cfg {String} href the link
4111 * @cfg {Boolean} preventDefault (true | false) default true
4112 * @cfg {Boolean} active (true | false) default false
4116 * Create a new PaginationItem
4117 * @param {Object} config The config object
4121 Roo.bootstrap.PaginationItem = function(config){
4122 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4127 * The raw click event for the entire grid.
4128 * @param {Roo.EventObject} e
4134 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4138 preventDefault: true,
4142 getAutoCreate : function(){
4148 href : this.href ? this.href : '#',
4149 html : this.html ? this.html : ''
4159 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4165 initEvents: function() {
4167 this.el.on('click', this.onClick, this);
4170 onClick : function(e)
4172 Roo.log('PaginationItem on click ');
4173 if(this.preventDefault){
4177 this.fireEvent('click', this, e);
4193 * @class Roo.bootstrap.Slider
4194 * @extends Roo.bootstrap.Component
4195 * Bootstrap Slider class
4198 * Create a new Slider
4199 * @param {Object} config The config object
4202 Roo.bootstrap.Slider = function(config){
4203 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4206 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4208 getAutoCreate : function(){
4212 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4216 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4228 * Ext JS Library 1.1.1
4229 * Copyright(c) 2006-2007, Ext JS, LLC.
4231 * Originally Released Under LGPL - original licence link has changed is not relivant.
4234 * <script type="text/javascript">
4239 * @class Roo.grid.ColumnModel
4240 * @extends Roo.util.Observable
4241 * This is the default implementation of a ColumnModel used by the Grid. It defines
4242 * the columns in the grid.
4245 var colModel = new Roo.grid.ColumnModel([
4246 {header: "Ticker", width: 60, sortable: true, locked: true},
4247 {header: "Company Name", width: 150, sortable: true},
4248 {header: "Market Cap.", width: 100, sortable: true},
4249 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4250 {header: "Employees", width: 100, sortable: true, resizable: false}
4255 * The config options listed for this class are options which may appear in each
4256 * individual column definition.
4257 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4259 * @param {Object} config An Array of column config objects. See this class's
4260 * config objects for details.
4262 Roo.grid.ColumnModel = function(config){
4264 * The config passed into the constructor
4266 this.config = config;
4269 // if no id, create one
4270 // if the column does not have a dataIndex mapping,
4271 // map it to the order it is in the config
4272 for(var i = 0, len = config.length; i < len; i++){
4274 if(typeof c.dataIndex == "undefined"){
4277 if(typeof c.renderer == "string"){
4278 c.renderer = Roo.util.Format[c.renderer];
4280 if(typeof c.id == "undefined"){
4283 if(c.editor && c.editor.xtype){
4284 c.editor = Roo.factory(c.editor, Roo.grid);
4286 if(c.editor && c.editor.isFormField){
4287 c.editor = new Roo.grid.GridEditor(c.editor);
4289 this.lookup[c.id] = c;
4293 * The width of columns which have no width specified (defaults to 100)
4296 this.defaultWidth = 100;
4299 * Default sortable of columns which have no sortable specified (defaults to false)
4302 this.defaultSortable = false;
4306 * @event widthchange
4307 * Fires when the width of a column changes.
4308 * @param {ColumnModel} this
4309 * @param {Number} columnIndex The column index
4310 * @param {Number} newWidth The new width
4312 "widthchange": true,
4314 * @event headerchange
4315 * Fires when the text of a header changes.
4316 * @param {ColumnModel} this
4317 * @param {Number} columnIndex The column index
4318 * @param {Number} newText The new header text
4320 "headerchange": true,
4322 * @event hiddenchange
4323 * Fires when a column is hidden or "unhidden".
4324 * @param {ColumnModel} this
4325 * @param {Number} columnIndex The column index
4326 * @param {Boolean} hidden true if hidden, false otherwise
4328 "hiddenchange": true,
4330 * @event columnmoved
4331 * Fires when a column is moved.
4332 * @param {ColumnModel} this
4333 * @param {Number} oldIndex
4334 * @param {Number} newIndex
4336 "columnmoved" : true,
4338 * @event columlockchange
4339 * Fires when a column's locked state is changed
4340 * @param {ColumnModel} this
4341 * @param {Number} colIndex
4342 * @param {Boolean} locked true if locked
4344 "columnlockchange" : true
4346 Roo.grid.ColumnModel.superclass.constructor.call(this);
4348 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4350 * @cfg {String} header The header text to display in the Grid view.
4353 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4354 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4355 * specified, the column's index is used as an index into the Record's data Array.
4358 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4359 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4362 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4363 * Defaults to the value of the {@link #defaultSortable} property.
4364 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4367 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4370 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4373 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4376 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4379 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4380 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4381 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4382 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4385 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4388 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4392 * Returns the id of the column at the specified index.
4393 * @param {Number} index The column index
4394 * @return {String} the id
4396 getColumnId : function(index){
4397 return this.config[index].id;
4401 * Returns the column for a specified id.
4402 * @param {String} id The column id
4403 * @return {Object} the column
4405 getColumnById : function(id){
4406 return this.lookup[id];
4411 * Returns the column for a specified dataIndex.
4412 * @param {String} dataIndex The column dataIndex
4413 * @return {Object|Boolean} the column or false if not found
4415 getColumnByDataIndex: function(dataIndex){
4416 var index = this.findColumnIndex(dataIndex);
4417 return index > -1 ? this.config[index] : false;
4421 * Returns the index for a specified column id.
4422 * @param {String} id The column id
4423 * @return {Number} the index, or -1 if not found
4425 getIndexById : function(id){
4426 for(var i = 0, len = this.config.length; i < len; i++){
4427 if(this.config[i].id == id){
4435 * Returns the index for a specified column dataIndex.
4436 * @param {String} dataIndex The column dataIndex
4437 * @return {Number} the index, or -1 if not found
4440 findColumnIndex : function(dataIndex){
4441 for(var i = 0, len = this.config.length; i < len; i++){
4442 if(this.config[i].dataIndex == dataIndex){
4450 moveColumn : function(oldIndex, newIndex){
4451 var c = this.config[oldIndex];
4452 this.config.splice(oldIndex, 1);
4453 this.config.splice(newIndex, 0, c);
4454 this.dataMap = null;
4455 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4458 isLocked : function(colIndex){
4459 return this.config[colIndex].locked === true;
4462 setLocked : function(colIndex, value, suppressEvent){
4463 if(this.isLocked(colIndex) == value){
4466 this.config[colIndex].locked = value;
4468 this.fireEvent("columnlockchange", this, colIndex, value);
4472 getTotalLockedWidth : function(){
4474 for(var i = 0; i < this.config.length; i++){
4475 if(this.isLocked(i) && !this.isHidden(i)){
4476 this.totalWidth += this.getColumnWidth(i);
4482 getLockedCount : function(){
4483 for(var i = 0, len = this.config.length; i < len; i++){
4484 if(!this.isLocked(i)){
4491 * Returns the number of columns.
4494 getColumnCount : function(visibleOnly){
4495 if(visibleOnly === true){
4497 for(var i = 0, len = this.config.length; i < len; i++){
4498 if(!this.isHidden(i)){
4504 return this.config.length;
4508 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4509 * @param {Function} fn
4510 * @param {Object} scope (optional)
4511 * @return {Array} result
4513 getColumnsBy : function(fn, scope){
4515 for(var i = 0, len = this.config.length; i < len; i++){
4516 var c = this.config[i];
4517 if(fn.call(scope||this, c, i) === true){
4525 * Returns true if the specified column is sortable.
4526 * @param {Number} col The column index
4529 isSortable : function(col){
4530 if(typeof this.config[col].sortable == "undefined"){
4531 return this.defaultSortable;
4533 return this.config[col].sortable;
4537 * Returns the rendering (formatting) function defined for the column.
4538 * @param {Number} col The column index.
4539 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4541 getRenderer : function(col){
4542 if(!this.config[col].renderer){
4543 return Roo.grid.ColumnModel.defaultRenderer;
4545 return this.config[col].renderer;
4549 * Sets the rendering (formatting) function for a column.
4550 * @param {Number} col The column index
4551 * @param {Function} fn The function to use to process the cell's raw data
4552 * to return HTML markup for the grid view. The render function is called with
4553 * the following parameters:<ul>
4554 * <li>Data value.</li>
4555 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4556 * <li>css A CSS style string to apply to the table cell.</li>
4557 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4558 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4559 * <li>Row index</li>
4560 * <li>Column index</li>
4561 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4563 setRenderer : function(col, fn){
4564 this.config[col].renderer = fn;
4568 * Returns the width for the specified column.
4569 * @param {Number} col The column index
4572 getColumnWidth : function(col){
4573 return this.config[col].width * 1 || this.defaultWidth;
4577 * Sets the width for a column.
4578 * @param {Number} col The column index
4579 * @param {Number} width The new width
4581 setColumnWidth : function(col, width, suppressEvent){
4582 this.config[col].width = width;
4583 this.totalWidth = null;
4585 this.fireEvent("widthchange", this, col, width);
4590 * Returns the total width of all columns.
4591 * @param {Boolean} includeHidden True to include hidden column widths
4594 getTotalWidth : function(includeHidden){
4595 if(!this.totalWidth){
4596 this.totalWidth = 0;
4597 for(var i = 0, len = this.config.length; i < len; i++){
4598 if(includeHidden || !this.isHidden(i)){
4599 this.totalWidth += this.getColumnWidth(i);
4603 return this.totalWidth;
4607 * Returns the header for the specified column.
4608 * @param {Number} col The column index
4611 getColumnHeader : function(col){
4612 return this.config[col].header;
4616 * Sets the header for a column.
4617 * @param {Number} col The column index
4618 * @param {String} header The new header
4620 setColumnHeader : function(col, header){
4621 this.config[col].header = header;
4622 this.fireEvent("headerchange", this, col, header);
4626 * Returns the tooltip for the specified column.
4627 * @param {Number} col The column index
4630 getColumnTooltip : function(col){
4631 return this.config[col].tooltip;
4634 * Sets the tooltip for a column.
4635 * @param {Number} col The column index
4636 * @param {String} tooltip The new tooltip
4638 setColumnTooltip : function(col, tooltip){
4639 this.config[col].tooltip = tooltip;
4643 * Returns the dataIndex for the specified column.
4644 * @param {Number} col The column index
4647 getDataIndex : function(col){
4648 return this.config[col].dataIndex;
4652 * Sets the dataIndex for a column.
4653 * @param {Number} col The column index
4654 * @param {Number} dataIndex The new dataIndex
4656 setDataIndex : function(col, dataIndex){
4657 this.config[col].dataIndex = dataIndex;
4663 * Returns true if the cell is editable.
4664 * @param {Number} colIndex The column index
4665 * @param {Number} rowIndex The row index
4668 isCellEditable : function(colIndex, rowIndex){
4669 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4673 * Returns the editor defined for the cell/column.
4674 * return false or null to disable editing.
4675 * @param {Number} colIndex The column index
4676 * @param {Number} rowIndex The row index
4679 getCellEditor : function(colIndex, rowIndex){
4680 return this.config[colIndex].editor;
4684 * Sets if a column is editable.
4685 * @param {Number} col The column index
4686 * @param {Boolean} editable True if the column is editable
4688 setEditable : function(col, editable){
4689 this.config[col].editable = editable;
4694 * Returns true if the column is hidden.
4695 * @param {Number} colIndex The column index
4698 isHidden : function(colIndex){
4699 return this.config[colIndex].hidden;
4704 * Returns true if the column width cannot be changed
4706 isFixed : function(colIndex){
4707 return this.config[colIndex].fixed;
4711 * Returns true if the column can be resized
4714 isResizable : function(colIndex){
4715 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4718 * Sets if a column is hidden.
4719 * @param {Number} colIndex The column index
4720 * @param {Boolean} hidden True if the column is hidden
4722 setHidden : function(colIndex, hidden){
4723 this.config[colIndex].hidden = hidden;
4724 this.totalWidth = null;
4725 this.fireEvent("hiddenchange", this, colIndex, hidden);
4729 * Sets the editor for a column.
4730 * @param {Number} col The column index
4731 * @param {Object} editor The editor object
4733 setEditor : function(col, editor){
4734 this.config[col].editor = editor;
4738 Roo.grid.ColumnModel.defaultRenderer = function(value){
4739 if(typeof value == "string" && value.length < 1){
4745 // Alias for backwards compatibility
4746 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4749 * Ext JS Library 1.1.1
4750 * Copyright(c) 2006-2007, Ext JS, LLC.
4752 * Originally Released Under LGPL - original licence link has changed is not relivant.
4755 * <script type="text/javascript">
4759 * @class Roo.LoadMask
4760 * A simple utility class for generically masking elements while loading data. If the element being masked has
4761 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4762 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4763 * element's UpdateManager load indicator and will be destroyed after the initial load.
4765 * Create a new LoadMask
4766 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4767 * @param {Object} config The config object
4769 Roo.LoadMask = function(el, config){
4770 this.el = Roo.get(el);
4771 Roo.apply(this, config);
4773 this.store.on('beforeload', this.onBeforeLoad, this);
4774 this.store.on('load', this.onLoad, this);
4775 this.store.on('loadexception', this.onLoadException, this);
4776 this.removeMask = false;
4778 var um = this.el.getUpdateManager();
4779 um.showLoadIndicator = false; // disable the default indicator
4780 um.on('beforeupdate', this.onBeforeLoad, this);
4781 um.on('update', this.onLoad, this);
4782 um.on('failure', this.onLoad, this);
4783 this.removeMask = true;
4787 Roo.LoadMask.prototype = {
4789 * @cfg {Boolean} removeMask
4790 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4791 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4795 * The text to display in a centered loading message box (defaults to 'Loading...')
4799 * @cfg {String} msgCls
4800 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4802 msgCls : 'x-mask-loading',
4805 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4811 * Disables the mask to prevent it from being displayed
4813 disable : function(){
4814 this.disabled = true;
4818 * Enables the mask so that it can be displayed
4820 enable : function(){
4821 this.disabled = false;
4824 onLoadException : function()
4828 if (typeof(arguments[3]) != 'undefined') {
4829 Roo.MessageBox.alert("Error loading",arguments[3]);
4833 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4834 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4843 this.el.unmask(this.removeMask);
4848 this.el.unmask(this.removeMask);
4852 onBeforeLoad : function(){
4854 this.el.mask(this.msg, this.msgCls);
4859 destroy : function(){
4861 this.store.un('beforeload', this.onBeforeLoad, this);
4862 this.store.un('load', this.onLoad, this);
4863 this.store.un('loadexception', this.onLoadException, this);
4865 var um = this.el.getUpdateManager();
4866 um.un('beforeupdate', this.onBeforeLoad, this);
4867 um.un('update', this.onLoad, this);
4868 um.un('failure', this.onLoad, this);
4879 * @class Roo.bootstrap.Table
4880 * @extends Roo.bootstrap.Component
4881 * Bootstrap Table class
4882 * @cfg {String} cls table class
4883 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4884 * @cfg {String} bgcolor Specifies the background color for a table
4885 * @cfg {Number} border Specifies whether the table cells should have borders or not
4886 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4887 * @cfg {Number} cellspacing Specifies the space between cells
4888 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4889 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4890 * @cfg {String} sortable Specifies that the table should be sortable
4891 * @cfg {String} summary Specifies a summary of the content of a table
4892 * @cfg {Number} width Specifies the width of a table
4893 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4895 * @cfg {boolean} striped Should the rows be alternative striped
4896 * @cfg {boolean} bordered Add borders to the table
4897 * @cfg {boolean} hover Add hover highlighting
4898 * @cfg {boolean} condensed Format condensed
4899 * @cfg {boolean} responsive Format condensed
4900 * @cfg {Boolean} loadMask (true|false) default false
4901 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4902 * @cfg {Boolean} thead (true|false) generate thead, default true
4903 * @cfg {Boolean} RowSelection (true|false) default false
4904 * @cfg {Boolean} CellSelection (true|false) default false
4906 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4910 * Create a new Table
4911 * @param {Object} config The config object
4914 Roo.bootstrap.Table = function(config){
4915 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4918 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4919 this.sm = this.selModel;
4920 this.sm.xmodule = this.xmodule || false;
4922 if (this.cm && typeof(this.cm.config) == 'undefined') {
4923 this.colModel = new Roo.grid.ColumnModel(this.cm);
4924 this.cm = this.colModel;
4925 this.cm.xmodule = this.xmodule || false;
4928 this.store= Roo.factory(this.store, Roo.data);
4929 this.ds = this.store;
4930 this.ds.xmodule = this.xmodule || false;
4933 if (this.footer && this.store) {
4934 this.footer.dataSource = this.ds;
4935 this.footer = Roo.factory(this.footer);
4942 * Fires when a cell is clicked
4943 * @param {Roo.bootstrap.Table} this
4944 * @param {Roo.Element} el
4945 * @param {Number} rowIndex
4946 * @param {Number} columnIndex
4947 * @param {Roo.EventObject} e
4951 * @event celldblclick
4952 * Fires when a cell is double clicked
4953 * @param {Roo.bootstrap.Table} this
4954 * @param {Roo.Element} el
4955 * @param {Number} rowIndex
4956 * @param {Number} columnIndex
4957 * @param {Roo.EventObject} e
4959 "celldblclick" : true,
4962 * Fires when a row is clicked
4963 * @param {Roo.bootstrap.Table} this
4964 * @param {Roo.Element} el
4965 * @param {Number} rowIndex
4966 * @param {Roo.EventObject} e
4970 * @event rowdblclick
4971 * Fires when a row is double clicked
4972 * @param {Roo.bootstrap.Table} this
4973 * @param {Roo.Element} el
4974 * @param {Number} rowIndex
4975 * @param {Roo.EventObject} e
4977 "rowdblclick" : true,
4980 * Fires when a mouseover occur
4981 * @param {Roo.bootstrap.Table} this
4982 * @param {Roo.Element} el
4983 * @param {Number} rowIndex
4984 * @param {Number} columnIndex
4985 * @param {Roo.EventObject} e
4990 * Fires when a mouseout occur
4991 * @param {Roo.bootstrap.Table} this
4992 * @param {Roo.Element} el
4993 * @param {Number} rowIndex
4994 * @param {Number} columnIndex
4995 * @param {Roo.EventObject} e
5000 * Fires when a row is rendered, so you can change add a style to it.
5001 * @param {Roo.bootstrap.Table} this
5002 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5009 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5033 RowSelection : false,
5034 CellSelection : false,
5037 // Roo.Element - the tbody
5040 getAutoCreate : function(){
5041 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5050 cfg.cls += ' table-striped';
5054 cfg.cls += ' table-hover';
5056 if (this.bordered) {
5057 cfg.cls += ' table-bordered';
5059 if (this.condensed) {
5060 cfg.cls += ' table-condensed';
5062 if (this.responsive) {
5063 cfg.cls += ' table-responsive';
5067 cfg.cls+= ' ' +this.cls;
5070 // this lot should be simplifed...
5073 cfg.align=this.align;
5076 cfg.bgcolor=this.bgcolor;
5079 cfg.border=this.border;
5081 if (this.cellpadding) {
5082 cfg.cellpadding=this.cellpadding;
5084 if (this.cellspacing) {
5085 cfg.cellspacing=this.cellspacing;
5088 cfg.frame=this.frame;
5091 cfg.rules=this.rules;
5093 if (this.sortable) {
5094 cfg.sortable=this.sortable;
5097 cfg.summary=this.summary;
5100 cfg.width=this.width;
5103 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5106 if(this.store || this.cm){
5108 cfg.cn.push(this.renderHeader());
5111 cfg.cn.push(this.renderBody());
5114 cfg.cn.push(this.renderFooter());
5117 cfg.cls+= ' TableGrid';
5120 return { cn : [ cfg ] };
5123 initEvents : function()
5125 if(!this.store || !this.cm){
5129 //Roo.log('initEvents with ds!!!!');
5131 this.mainBody = this.el.select('tbody', true).first();
5136 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5137 e.on('click', _this.sort, _this);
5140 this.el.on("click", this.onClick, this);
5141 this.el.on("dblclick", this.onDblClick, this);
5143 this.parent().el.setStyle('position', 'relative');
5145 this.footer.parentId = this.id;
5146 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5149 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5151 this.store.on('load', this.onLoad, this);
5152 this.store.on('beforeload', this.onBeforeLoad, this);
5153 this.store.on('update', this.onUpdate, this);
5157 onMouseover : function(e, el)
5159 var cell = Roo.get(el);
5165 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5166 cell = cell.findParent('td', false, true);
5169 var row = cell.findParent('tr', false, true);
5170 var cellIndex = cell.dom.cellIndex;
5171 var rowIndex = row.dom.rowIndex - 1; // start from 0
5173 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5177 onMouseout : function(e, el)
5179 var cell = Roo.get(el);
5185 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5186 cell = cell.findParent('td', false, true);
5189 var row = cell.findParent('tr', false, true);
5190 var cellIndex = cell.dom.cellIndex;
5191 var rowIndex = row.dom.rowIndex - 1; // start from 0
5193 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5197 onClick : function(e, el)
5199 var cell = Roo.get(el);
5201 if(!cell || (!this.CellSelection && !this.RowSelection)){
5206 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5207 cell = cell.findParent('td', false, true);
5210 var row = cell.findParent('tr', false, true);
5211 var cellIndex = cell.dom.cellIndex;
5212 var rowIndex = row.dom.rowIndex - 1;
5214 if(this.CellSelection){
5215 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5218 if(this.RowSelection){
5219 this.fireEvent('rowclick', this, row, rowIndex, e);
5225 onDblClick : function(e,el)
5227 var cell = Roo.get(el);
5229 if(!cell || (!this.CellSelection && !this.RowSelection)){
5233 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5234 cell = cell.findParent('td', false, true);
5237 var row = cell.findParent('tr', false, true);
5238 var cellIndex = cell.dom.cellIndex;
5239 var rowIndex = row.dom.rowIndex - 1;
5241 if(this.CellSelection){
5242 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5245 if(this.RowSelection){
5246 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5250 sort : function(e,el)
5252 var col = Roo.get(el)
5254 if(!col.hasClass('sortable')){
5258 var sort = col.attr('sort');
5261 if(col.hasClass('glyphicon-arrow-up')){
5265 this.store.sortInfo = {field : sort, direction : dir};
5268 Roo.log("calling footer first");
5269 this.footer.onClick('first');
5272 this.store.load({ params : { start : 0 } });
5276 renderHeader : function()
5285 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5287 var config = cm.config[i];
5292 html: cm.getColumnHeader(i)
5295 if(typeof(config.hidden) != 'undefined' && config.hidden){
5296 c.style += ' display:none;';
5299 if(typeof(config.dataIndex) != 'undefined'){
5300 c.sort = config.dataIndex;
5303 if(typeof(config.sortable) != 'undefined' && config.sortable){
5307 if(typeof(config.align) != 'undefined' && config.align.length){
5308 c.style += ' text-align:' + config.align + ';';
5311 if(typeof(config.width) != 'undefined'){
5312 c.style += ' width:' + config.width + 'px;';
5321 renderBody : function()
5331 colspan : this.cm.getColumnCount()
5341 renderFooter : function()
5351 colspan : this.cm.getColumnCount()
5365 Roo.log('ds onload');
5370 var ds = this.store;
5372 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5373 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5375 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5376 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5379 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5380 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5384 var tbody = this.mainBody;
5386 if(ds.getCount() > 0){
5387 ds.data.each(function(d,rowIndex){
5388 var row = this.renderRow(cm, ds, rowIndex);
5390 tbody.createChild(row);
5394 if(row.cellObjects.length){
5395 Roo.each(row.cellObjects, function(r){
5396 _this.renderCellObject(r);
5403 Roo.each(this.el.select('tbody td', true).elements, function(e){
5404 e.on('mouseover', _this.onMouseover, _this);
5407 Roo.each(this.el.select('tbody td', true).elements, function(e){
5408 e.on('mouseout', _this.onMouseout, _this);
5411 //if(this.loadMask){
5412 // this.maskEl.hide();
5417 onUpdate : function(ds,record)
5419 this.refreshRow(record);
5421 onRemove : function(ds, record, index, isUpdate){
5422 if(isUpdate !== true){
5423 this.fireEvent("beforerowremoved", this, index, record);
5425 var bt = this.mainBody.dom;
5427 bt.removeChild(bt.rows[index]);
5430 if(isUpdate !== true){
5431 //this.stripeRows(index);
5432 //this.syncRowHeights(index, index);
5434 this.fireEvent("rowremoved", this, index, record);
5439 refreshRow : function(record){
5440 var ds = this.store, index;
5441 if(typeof record == 'number'){
5443 record = ds.getAt(index);
5445 index = ds.indexOf(record);
5447 this.insertRow(ds, index, true);
5448 this.onRemove(ds, record, index+1, true);
5449 //this.syncRowHeights(index, index);
5451 this.fireEvent("rowupdated", this, index, record);
5454 insertRow : function(dm, rowIndex, isUpdate){
5457 this.fireEvent("beforerowsinserted", this, rowIndex);
5459 //var s = this.getScrollState();
5460 var row = this.renderRow(this.cm, this.store, rowIndex);
5461 // insert before rowIndex..
5462 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5466 if(row.cellObjects.length){
5467 Roo.each(row.cellObjects, function(r){
5468 _this.renderCellObject(r);
5473 this.fireEvent("rowsinserted", this, rowIndex);
5474 //this.syncRowHeights(firstRow, lastRow);
5475 //this.stripeRows(firstRow);
5482 getRowDom : function(rowIndex)
5484 // not sure if I need to check this.. but let's do it anyway..
5485 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5486 this.mainBody.dom.rows[rowIndex] : false
5488 // returns the object tree for a tr..
5491 renderRow : function(cm, ds, rowIndex) {
5493 var d = ds.getAt(rowIndex);
5500 var cellObjects = [];
5502 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5503 var config = cm.config[i];
5505 var renderer = cm.getRenderer(i);
5509 if(typeof(renderer) !== 'undefined'){
5510 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5512 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5513 // and are rendered into the cells after the row is rendered - using the id for the element.
5515 if(typeof(value) === 'object'){
5525 rowIndex : rowIndex,
5530 this.fireEvent('rowclass', this, rowcfg);
5534 cls : rowcfg.rowClass,
5536 html: (typeof(value) === 'object') ? '' : value
5543 if(typeof(config.hidden) != 'undefined' && config.hidden){
5544 td.style += ' display:none;';
5547 if(typeof(config.align) != 'undefined' && config.align.length){
5548 td.style += ' text-align:' + config.align + ';';
5551 if(typeof(config.width) != 'undefined'){
5552 td.style += ' width:' + config.width + 'px;';
5559 row.cellObjects = cellObjects;
5567 onBeforeLoad : function()
5569 //Roo.log('ds onBeforeLoad');
5573 //if(this.loadMask){
5574 // this.maskEl.show();
5580 this.el.select('tbody', true).first().dom.innerHTML = '';
5583 getSelectionModel : function(){
5585 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5587 return this.selModel;
5590 * Render the Roo.bootstrap object from renderder
5592 renderCellObject : function(r)
5596 var t = r.cfg.render(r.container);
5599 Roo.each(r.cfg.cn, function(c){
5601 container: t.getChildContainer(),
5604 _this.renderCellObject(child);
5621 * @class Roo.bootstrap.TableCell
5622 * @extends Roo.bootstrap.Component
5623 * Bootstrap TableCell class
5624 * @cfg {String} html cell contain text
5625 * @cfg {String} cls cell class
5626 * @cfg {String} tag cell tag (td|th) default td
5627 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5628 * @cfg {String} align Aligns the content in a cell
5629 * @cfg {String} axis Categorizes cells
5630 * @cfg {String} bgcolor Specifies the background color of a cell
5631 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5632 * @cfg {Number} colspan Specifies the number of columns a cell should span
5633 * @cfg {String} headers Specifies one or more header cells a cell is related to
5634 * @cfg {Number} height Sets the height of a cell
5635 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5636 * @cfg {Number} rowspan Sets the number of rows a cell should span
5637 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5638 * @cfg {String} valign Vertical aligns the content in a cell
5639 * @cfg {Number} width Specifies the width of a cell
5642 * Create a new TableCell
5643 * @param {Object} config The config object
5646 Roo.bootstrap.TableCell = function(config){
5647 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5650 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5670 getAutoCreate : function(){
5671 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5691 cfg.align=this.align
5697 cfg.bgcolor=this.bgcolor
5700 cfg.charoff=this.charoff
5703 cfg.colspan=this.colspan
5706 cfg.headers=this.headers
5709 cfg.height=this.height
5712 cfg.nowrap=this.nowrap
5715 cfg.rowspan=this.rowspan
5718 cfg.scope=this.scope
5721 cfg.valign=this.valign
5724 cfg.width=this.width
5743 * @class Roo.bootstrap.TableRow
5744 * @extends Roo.bootstrap.Component
5745 * Bootstrap TableRow class
5746 * @cfg {String} cls row class
5747 * @cfg {String} align Aligns the content in a table row
5748 * @cfg {String} bgcolor Specifies a background color for a table row
5749 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5750 * @cfg {String} valign Vertical aligns the content in a table row
5753 * Create a new TableRow
5754 * @param {Object} config The config object
5757 Roo.bootstrap.TableRow = function(config){
5758 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5761 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5769 getAutoCreate : function(){
5770 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5780 cfg.align = this.align;
5783 cfg.bgcolor = this.bgcolor;
5786 cfg.charoff = this.charoff;
5789 cfg.valign = this.valign;
5807 * @class Roo.bootstrap.TableBody
5808 * @extends Roo.bootstrap.Component
5809 * Bootstrap TableBody class
5810 * @cfg {String} cls element class
5811 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5812 * @cfg {String} align Aligns the content inside the element
5813 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5814 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5817 * Create a new TableBody
5818 * @param {Object} config The config object
5821 Roo.bootstrap.TableBody = function(config){
5822 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5825 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5833 getAutoCreate : function(){
5834 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5848 cfg.align = this.align;
5851 cfg.charoff = this.charoff;
5854 cfg.valign = this.valign;
5861 // initEvents : function()
5868 // this.store = Roo.factory(this.store, Roo.data);
5869 // this.store.on('load', this.onLoad, this);
5871 // this.store.load();
5875 // onLoad: function ()
5877 // this.fireEvent('load', this);
5887 * Ext JS Library 1.1.1
5888 * Copyright(c) 2006-2007, Ext JS, LLC.
5890 * Originally Released Under LGPL - original licence link has changed is not relivant.
5893 * <script type="text/javascript">
5896 // as we use this in bootstrap.
5897 Roo.namespace('Roo.form');
5899 * @class Roo.form.Action
5900 * Internal Class used to handle form actions
5902 * @param {Roo.form.BasicForm} el The form element or its id
5903 * @param {Object} config Configuration options
5908 // define the action interface
5909 Roo.form.Action = function(form, options){
5911 this.options = options || {};
5914 * Client Validation Failed
5917 Roo.form.Action.CLIENT_INVALID = 'client';
5919 * Server Validation Failed
5922 Roo.form.Action.SERVER_INVALID = 'server';
5924 * Connect to Server Failed
5927 Roo.form.Action.CONNECT_FAILURE = 'connect';
5929 * Reading Data from Server Failed
5932 Roo.form.Action.LOAD_FAILURE = 'load';
5934 Roo.form.Action.prototype = {
5936 failureType : undefined,
5937 response : undefined,
5941 run : function(options){
5946 success : function(response){
5951 handleResponse : function(response){
5955 // default connection failure
5956 failure : function(response){
5958 this.response = response;
5959 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5960 this.form.afterAction(this, false);
5963 processResponse : function(response){
5964 this.response = response;
5965 if(!response.responseText){
5968 this.result = this.handleResponse(response);
5972 // utility functions used internally
5973 getUrl : function(appendParams){
5974 var url = this.options.url || this.form.url || this.form.el.dom.action;
5976 var p = this.getParams();
5978 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5984 getMethod : function(){
5985 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5988 getParams : function(){
5989 var bp = this.form.baseParams;
5990 var p = this.options.params;
5992 if(typeof p == "object"){
5993 p = Roo.urlEncode(Roo.applyIf(p, bp));
5994 }else if(typeof p == 'string' && bp){
5995 p += '&' + Roo.urlEncode(bp);
5998 p = Roo.urlEncode(bp);
6003 createCallback : function(){
6005 success: this.success,
6006 failure: this.failure,
6008 timeout: (this.form.timeout*1000),
6009 upload: this.form.fileUpload ? this.success : undefined
6014 Roo.form.Action.Submit = function(form, options){
6015 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6018 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6021 haveProgress : false,
6022 uploadComplete : false,
6024 // uploadProgress indicator.
6025 uploadProgress : function()
6027 if (!this.form.progressUrl) {
6031 if (!this.haveProgress) {
6032 Roo.MessageBox.progress("Uploading", "Uploading");
6034 if (this.uploadComplete) {
6035 Roo.MessageBox.hide();
6039 this.haveProgress = true;
6041 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6043 var c = new Roo.data.Connection();
6045 url : this.form.progressUrl,
6050 success : function(req){
6051 //console.log(data);
6055 rdata = Roo.decode(req.responseText)
6057 Roo.log("Invalid data from server..");
6061 if (!rdata || !rdata.success) {
6063 Roo.MessageBox.alert(Roo.encode(rdata));
6066 var data = rdata.data;
6068 if (this.uploadComplete) {
6069 Roo.MessageBox.hide();
6074 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6075 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6078 this.uploadProgress.defer(2000,this);
6081 failure: function(data) {
6082 Roo.log('progress url failed ');
6093 // run get Values on the form, so it syncs any secondary forms.
6094 this.form.getValues();
6096 var o = this.options;
6097 var method = this.getMethod();
6098 var isPost = method == 'POST';
6099 if(o.clientValidation === false || this.form.isValid()){
6101 if (this.form.progressUrl) {
6102 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6103 (new Date() * 1) + '' + Math.random());
6108 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6109 form:this.form.el.dom,
6110 url:this.getUrl(!isPost),
6112 params:isPost ? this.getParams() : null,
6113 isUpload: this.form.fileUpload
6116 this.uploadProgress();
6118 }else if (o.clientValidation !== false){ // client validation failed
6119 this.failureType = Roo.form.Action.CLIENT_INVALID;
6120 this.form.afterAction(this, false);
6124 success : function(response)
6126 this.uploadComplete= true;
6127 if (this.haveProgress) {
6128 Roo.MessageBox.hide();
6132 var result = this.processResponse(response);
6133 if(result === true || result.success){
6134 this.form.afterAction(this, true);
6138 this.form.markInvalid(result.errors);
6139 this.failureType = Roo.form.Action.SERVER_INVALID;
6141 this.form.afterAction(this, false);
6143 failure : function(response)
6145 this.uploadComplete= true;
6146 if (this.haveProgress) {
6147 Roo.MessageBox.hide();
6150 this.response = response;
6151 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6152 this.form.afterAction(this, false);
6155 handleResponse : function(response){
6156 if(this.form.errorReader){
6157 var rs = this.form.errorReader.read(response);
6160 for(var i = 0, len = rs.records.length; i < len; i++) {
6161 var r = rs.records[i];
6165 if(errors.length < 1){
6169 success : rs.success,
6175 ret = Roo.decode(response.responseText);
6179 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6189 Roo.form.Action.Load = function(form, options){
6190 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6191 this.reader = this.form.reader;
6194 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6199 Roo.Ajax.request(Roo.apply(
6200 this.createCallback(), {
6201 method:this.getMethod(),
6202 url:this.getUrl(false),
6203 params:this.getParams()
6207 success : function(response){
6209 var result = this.processResponse(response);
6210 if(result === true || !result.success || !result.data){
6211 this.failureType = Roo.form.Action.LOAD_FAILURE;
6212 this.form.afterAction(this, false);
6215 this.form.clearInvalid();
6216 this.form.setValues(result.data);
6217 this.form.afterAction(this, true);
6220 handleResponse : function(response){
6221 if(this.form.reader){
6222 var rs = this.form.reader.read(response);
6223 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6225 success : rs.success,
6229 return Roo.decode(response.responseText);
6233 Roo.form.Action.ACTION_TYPES = {
6234 'load' : Roo.form.Action.Load,
6235 'submit' : Roo.form.Action.Submit
6244 * @class Roo.bootstrap.Form
6245 * @extends Roo.bootstrap.Component
6246 * Bootstrap Form class
6247 * @cfg {String} method GET | POST (default POST)
6248 * @cfg {String} labelAlign top | left (default top)
6249 * @cfg {String} align left | right - for navbars
6250 * @cfg {Boolean} loadMask load mask when submit (default true)
6255 * @param {Object} config The config object
6259 Roo.bootstrap.Form = function(config){
6260 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6263 * @event clientvalidation
6264 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6265 * @param {Form} this
6266 * @param {Boolean} valid true if the form has passed client-side validation
6268 clientvalidation: true,
6270 * @event beforeaction
6271 * Fires before any action is performed. Return false to cancel the action.
6272 * @param {Form} this
6273 * @param {Action} action The action to be performed
6277 * @event actionfailed
6278 * Fires when an action fails.
6279 * @param {Form} this
6280 * @param {Action} action The action that failed
6282 actionfailed : true,
6284 * @event actioncomplete
6285 * Fires when an action is completed.
6286 * @param {Form} this
6287 * @param {Action} action The action that completed
6289 actioncomplete : true
6294 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6297 * @cfg {String} method
6298 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6303 * The URL to use for form actions if one isn't supplied in the action options.
6306 * @cfg {Boolean} fileUpload
6307 * Set to true if this form is a file upload.
6311 * @cfg {Object} baseParams
6312 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6316 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6320 * @cfg {Sting} align (left|right) for navbar forms
6325 activeAction : null,
6328 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6329 * element by passing it or its id or mask the form itself by passing in true.
6332 waitMsgTarget : false,
6336 getAutoCreate : function(){
6340 method : this.method || 'POST',
6341 id : this.id || Roo.id(),
6344 if (this.parent().xtype.match(/^Nav/)) {
6345 cfg.cls = 'navbar-form navbar-' + this.align;
6349 if (this.labelAlign == 'left' ) {
6350 cfg.cls += ' form-horizontal';
6356 initEvents : function()
6358 this.el.on('submit', this.onSubmit, this);
6359 // this was added as random key presses on the form where triggering form submit.
6360 this.el.on('keypress', function(e) {
6361 if (e.getCharCode() != 13) {
6364 // we might need to allow it for textareas.. and some other items.
6365 // check e.getTarget().
6367 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6371 Roo.log("keypress blocked");
6379 onSubmit : function(e){
6384 * Returns true if client-side validation on the form is successful.
6387 isValid : function(){
6388 var items = this.getItems();
6390 items.each(function(f){
6399 * Returns true if any fields in this form have changed since their original load.
6402 isDirty : function(){
6404 var items = this.getItems();
6405 items.each(function(f){
6415 * Performs a predefined action (submit or load) or custom actions you define on this form.
6416 * @param {String} actionName The name of the action type
6417 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6418 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6419 * accept other config options):
6421 Property Type Description
6422 ---------------- --------------- ----------------------------------------------------------------------------------
6423 url String The url for the action (defaults to the form's url)
6424 method String The form method to use (defaults to the form's method, or POST if not defined)
6425 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6426 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6427 validate the form on the client (defaults to false)
6429 * @return {BasicForm} this
6431 doAction : function(action, options){
6432 if(typeof action == 'string'){
6433 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6435 if(this.fireEvent('beforeaction', this, action) !== false){
6436 this.beforeAction(action);
6437 action.run.defer(100, action);
6443 beforeAction : function(action){
6444 var o = action.options;
6447 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6449 // not really supported yet.. ??
6451 //if(this.waitMsgTarget === true){
6452 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6453 //}else if(this.waitMsgTarget){
6454 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6455 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6457 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6463 afterAction : function(action, success){
6464 this.activeAction = null;
6465 var o = action.options;
6467 //if(this.waitMsgTarget === true){
6469 //}else if(this.waitMsgTarget){
6470 // this.waitMsgTarget.unmask();
6472 // Roo.MessageBox.updateProgress(1);
6473 // Roo.MessageBox.hide();
6480 Roo.callback(o.success, o.scope, [this, action]);
6481 this.fireEvent('actioncomplete', this, action);
6485 // failure condition..
6486 // we have a scenario where updates need confirming.
6487 // eg. if a locking scenario exists..
6488 // we look for { errors : { needs_confirm : true }} in the response.
6490 (typeof(action.result) != 'undefined') &&
6491 (typeof(action.result.errors) != 'undefined') &&
6492 (typeof(action.result.errors.needs_confirm) != 'undefined')
6495 Roo.log("not supported yet");
6498 Roo.MessageBox.confirm(
6499 "Change requires confirmation",
6500 action.result.errorMsg,
6505 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6515 Roo.callback(o.failure, o.scope, [this, action]);
6516 // show an error message if no failed handler is set..
6517 if (!this.hasListener('actionfailed')) {
6518 Roo.log("need to add dialog support");
6520 Roo.MessageBox.alert("Error",
6521 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6522 action.result.errorMsg :
6523 "Saving Failed, please check your entries or try again"
6528 this.fireEvent('actionfailed', this, action);
6533 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6534 * @param {String} id The value to search for
6537 findField : function(id){
6538 var items = this.getItems();
6539 var field = items.get(id);
6541 items.each(function(f){
6542 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6549 return field || null;
6552 * Mark fields in this form invalid in bulk.
6553 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6554 * @return {BasicForm} this
6556 markInvalid : function(errors){
6557 if(errors instanceof Array){
6558 for(var i = 0, len = errors.length; i < len; i++){
6559 var fieldError = errors[i];
6560 var f = this.findField(fieldError.id);
6562 f.markInvalid(fieldError.msg);
6568 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6569 field.markInvalid(errors[id]);
6573 //Roo.each(this.childForms || [], function (f) {
6574 // f.markInvalid(errors);
6581 * Set values for fields in this form in bulk.
6582 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6583 * @return {BasicForm} this
6585 setValues : function(values){
6586 if(values instanceof Array){ // array of objects
6587 for(var i = 0, len = values.length; i < len; i++){
6589 var f = this.findField(v.id);
6591 f.setValue(v.value);
6592 if(this.trackResetOnLoad){
6593 f.originalValue = f.getValue();
6597 }else{ // object hash
6600 if(typeof values[id] != 'function' && (field = this.findField(id))){
6602 if (field.setFromData &&
6604 field.displayField &&
6605 // combos' with local stores can
6606 // be queried via setValue()
6607 // to set their value..
6608 (field.store && !field.store.isLocal)
6612 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6613 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6614 field.setFromData(sd);
6617 field.setValue(values[id]);
6621 if(this.trackResetOnLoad){
6622 field.originalValue = field.getValue();
6628 //Roo.each(this.childForms || [], function (f) {
6629 // f.setValues(values);
6636 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6637 * they are returned as an array.
6638 * @param {Boolean} asString
6641 getValues : function(asString){
6642 //if (this.childForms) {
6643 // copy values from the child forms
6644 // Roo.each(this.childForms, function (f) {
6645 // this.setValues(f.getValues());
6651 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6652 if(asString === true){
6655 return Roo.urlDecode(fs);
6659 * Returns the fields in this form as an object with key/value pairs.
6660 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6663 getFieldValues : function(with_hidden)
6665 var items = this.getItems();
6667 items.each(function(f){
6671 var v = f.getValue();
6672 if (f.inputType =='radio') {
6673 if (typeof(ret[f.getName()]) == 'undefined') {
6674 ret[f.getName()] = ''; // empty..
6677 if (!f.el.dom.checked) {
6685 // not sure if this supported any more..
6686 if ((typeof(v) == 'object') && f.getRawValue) {
6687 v = f.getRawValue() ; // dates..
6689 // combo boxes where name != hiddenName...
6690 if (f.name != f.getName()) {
6691 ret[f.name] = f.getRawValue();
6693 ret[f.getName()] = v;
6700 * Clears all invalid messages in this form.
6701 * @return {BasicForm} this
6703 clearInvalid : function(){
6704 var items = this.getItems();
6706 items.each(function(f){
6717 * @return {BasicForm} this
6720 var items = this.getItems();
6721 items.each(function(f){
6725 Roo.each(this.childForms || [], function (f) {
6732 getItems : function()
6734 var r=new Roo.util.MixedCollection(false, function(o){
6735 return o.id || (o.id = Roo.id());
6737 var iter = function(el) {
6744 Roo.each(el.items,function(e) {
6763 * Ext JS Library 1.1.1
6764 * Copyright(c) 2006-2007, Ext JS, LLC.
6766 * Originally Released Under LGPL - original licence link has changed is not relivant.
6769 * <script type="text/javascript">
6772 * @class Roo.form.VTypes
6773 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6776 Roo.form.VTypes = function(){
6777 // closure these in so they are only created once.
6778 var alpha = /^[a-zA-Z_]+$/;
6779 var alphanum = /^[a-zA-Z0-9_]+$/;
6780 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6781 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6783 // All these messages and functions are configurable
6786 * The function used to validate email addresses
6787 * @param {String} value The email address
6789 'email' : function(v){
6790 return email.test(v);
6793 * The error text to display when the email validation function returns false
6796 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6798 * The keystroke filter mask to be applied on email input
6801 'emailMask' : /[a-z0-9_\.\-@]/i,
6804 * The function used to validate URLs
6805 * @param {String} value The URL
6807 'url' : function(v){
6811 * The error text to display when the url validation function returns false
6814 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6817 * The function used to validate alpha values
6818 * @param {String} value The value
6820 'alpha' : function(v){
6821 return alpha.test(v);
6824 * The error text to display when the alpha validation function returns false
6827 'alphaText' : 'This field should only contain letters and _',
6829 * The keystroke filter mask to be applied on alpha input
6832 'alphaMask' : /[a-z_]/i,
6835 * The function used to validate alphanumeric values
6836 * @param {String} value The value
6838 'alphanum' : function(v){
6839 return alphanum.test(v);
6842 * The error text to display when the alphanumeric validation function returns false
6845 'alphanumText' : 'This field should only contain letters, numbers and _',
6847 * The keystroke filter mask to be applied on alphanumeric input
6850 'alphanumMask' : /[a-z0-9_]/i
6860 * @class Roo.bootstrap.Input
6861 * @extends Roo.bootstrap.Component
6862 * Bootstrap Input class
6863 * @cfg {Boolean} disabled is it disabled
6864 * @cfg {String} fieldLabel - the label associated
6865 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6866 * @cfg {String} name name of the input
6867 * @cfg {string} fieldLabel - the label associated
6868 * @cfg {string} inputType - input / file submit ...
6869 * @cfg {string} placeholder - placeholder to put in text.
6870 * @cfg {string} before - input group add on before
6871 * @cfg {string} after - input group add on after
6872 * @cfg {string} size - (lg|sm) or leave empty..
6873 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6874 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6875 * @cfg {Number} md colspan out of 12 for computer-sized screens
6876 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6877 * @cfg {string} value default value of the input
6878 * @cfg {Number} labelWidth set the width of label (0-12)
6879 * @cfg {String} labelAlign (top|left)
6880 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6881 * @cfg {String} align (left|center|right) Default left
6885 * Create a new Input
6886 * @param {Object} config The config object
6889 Roo.bootstrap.Input = function(config){
6890 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6895 * Fires when this field receives input focus.
6896 * @param {Roo.form.Field} this
6901 * Fires when this field loses input focus.
6902 * @param {Roo.form.Field} this
6907 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6908 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6909 * @param {Roo.form.Field} this
6910 * @param {Roo.EventObject} e The event object
6915 * Fires just before the field blurs if the field value has changed.
6916 * @param {Roo.form.Field} this
6917 * @param {Mixed} newValue The new value
6918 * @param {Mixed} oldValue The original value
6923 * Fires after the field has been marked as invalid.
6924 * @param {Roo.form.Field} this
6925 * @param {String} msg The validation message
6930 * Fires after the field has been validated with no errors.
6931 * @param {Roo.form.Field} this
6936 * Fires after the key up
6937 * @param {Roo.form.Field} this
6938 * @param {Roo.EventObject} e The event Object
6944 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6946 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6947 automatic validation (defaults to "keyup").
6949 validationEvent : "keyup",
6951 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6953 validateOnBlur : true,
6955 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6957 validationDelay : 250,
6959 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6961 focusClass : "x-form-focus", // not needed???
6965 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6967 invalidClass : "has-error",
6970 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6972 selectOnFocus : false,
6975 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6979 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6984 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6986 disableKeyFilter : false,
6989 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6993 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6997 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6999 blankText : "This field is required",
7002 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7006 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7008 maxLength : Number.MAX_VALUE,
7010 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7012 minLengthText : "The minimum length for this field is {0}",
7014 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7016 maxLengthText : "The maximum length for this field is {0}",
7020 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7021 * If available, this function will be called only after the basic validators all return true, and will be passed the
7022 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7026 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7027 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7028 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7032 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7055 formatedValue : false,
7057 parentLabelAlign : function()
7060 while (parent.parent()) {
7061 parent = parent.parent();
7062 if (typeof(parent.labelAlign) !='undefined') {
7063 return parent.labelAlign;
7070 getAutoCreate : function(){
7072 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7078 if(this.inputType != 'hidden'){
7079 cfg.cls = 'form-group' //input-group
7085 type : this.inputType,
7087 cls : 'form-control',
7088 placeholder : this.placeholder || ''
7093 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7096 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7097 input.maxLength = this.maxLength;
7100 if (this.disabled) {
7101 input.disabled=true;
7104 if (this.readOnly) {
7105 input.readonly=true;
7109 input.name = this.name;
7112 input.cls += ' input-' + this.size;
7115 ['xs','sm','md','lg'].map(function(size){
7116 if (settings[size]) {
7117 cfg.cls += ' col-' + size + '-' + settings[size];
7121 var inputblock = input;
7123 if (this.before || this.after) {
7126 cls : 'input-group',
7129 if (this.before && typeof(this.before) == 'string') {
7131 inputblock.cn.push({
7133 cls : 'roo-input-before input-group-addon',
7137 if (this.before && typeof(this.before) == 'object') {
7138 this.before = Roo.factory(this.before);
7139 Roo.log(this.before);
7140 inputblock.cn.push({
7142 cls : 'roo-input-before input-group-' +
7143 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7147 inputblock.cn.push(input);
7149 if (this.after && typeof(this.after) == 'string') {
7150 inputblock.cn.push({
7152 cls : 'roo-input-after input-group-addon',
7156 if (this.after && typeof(this.after) == 'object') {
7157 this.after = Roo.factory(this.after);
7158 Roo.log(this.after);
7159 inputblock.cn.push({
7161 cls : 'roo-input-after input-group-' +
7162 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7167 if (align ==='left' && this.fieldLabel.length) {
7168 Roo.log("left and has label");
7174 cls : 'control-label col-sm-' + this.labelWidth,
7175 html : this.fieldLabel
7179 cls : "col-sm-" + (12 - this.labelWidth),
7186 } else if ( this.fieldLabel.length) {
7192 //cls : 'input-group-addon',
7193 html : this.fieldLabel
7203 Roo.log(" no label && no align");
7212 Roo.log('input-parentType: ' + this.parentType);
7214 if (this.parentType === 'Navbar' && this.parent().bar) {
7215 cfg.cls += ' navbar-form';
7223 * return the real input element.
7225 inputEl: function ()
7227 return this.el.select('input.form-control',true).first();
7230 tooltipEl : function()
7232 return this.inputEl();
7235 setDisabled : function(v)
7237 var i = this.inputEl().dom;
7239 i.removeAttribute('disabled');
7243 i.setAttribute('disabled','true');
7245 initEvents : function()
7248 this.inputEl().on("keydown" , this.fireKey, this);
7249 this.inputEl().on("focus", this.onFocus, this);
7250 this.inputEl().on("blur", this.onBlur, this);
7252 this.inputEl().relayEvent('keyup', this);
7254 // reference to original value for reset
7255 this.originalValue = this.getValue();
7256 //Roo.form.TextField.superclass.initEvents.call(this);
7257 if(this.validationEvent == 'keyup'){
7258 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7259 this.inputEl().on('keyup', this.filterValidation, this);
7261 else if(this.validationEvent !== false){
7262 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7265 if(this.selectOnFocus){
7266 this.on("focus", this.preFocus, this);
7269 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7270 this.inputEl().on("keypress", this.filterKeys, this);
7273 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7274 this.el.on("click", this.autoSize, this);
7277 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7278 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7281 if (typeof(this.before) == 'object') {
7282 this.before.render(this.el.select('.roo-input-before',true).first());
7284 if (typeof(this.after) == 'object') {
7285 this.after.render(this.el.select('.roo-input-after',true).first());
7290 filterValidation : function(e){
7291 if(!e.isNavKeyPress()){
7292 this.validationTask.delay(this.validationDelay);
7296 * Validates the field value
7297 * @return {Boolean} True if the value is valid, else false
7299 validate : function(){
7300 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7301 if(this.disabled || this.validateValue(this.getRawValue())){
7302 this.clearInvalid();
7310 * Validates a value according to the field's validation rules and marks the field as invalid
7311 * if the validation fails
7312 * @param {Mixed} value The value to validate
7313 * @return {Boolean} True if the value is valid, else false
7315 validateValue : function(value){
7316 if(value.length < 1) { // if it's blank
7317 if(this.allowBlank){
7318 this.clearInvalid();
7321 this.markInvalid(this.blankText);
7325 if(value.length < this.minLength){
7326 this.markInvalid(String.format(this.minLengthText, this.minLength));
7329 if(value.length > this.maxLength){
7330 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7334 var vt = Roo.form.VTypes;
7335 if(!vt[this.vtype](value, this)){
7336 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7340 if(typeof this.validator == "function"){
7341 var msg = this.validator(value);
7343 this.markInvalid(msg);
7347 if(this.regex && !this.regex.test(value)){
7348 this.markInvalid(this.regexText);
7357 fireKey : function(e){
7358 //Roo.log('field ' + e.getKey());
7359 if(e.isNavKeyPress()){
7360 this.fireEvent("specialkey", this, e);
7363 focus : function (selectText){
7365 this.inputEl().focus();
7366 if(selectText === true){
7367 this.inputEl().dom.select();
7373 onFocus : function(){
7374 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7375 // this.el.addClass(this.focusClass);
7378 this.hasFocus = true;
7379 this.startValue = this.getValue();
7380 this.fireEvent("focus", this);
7384 beforeBlur : Roo.emptyFn,
7388 onBlur : function(){
7390 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7391 //this.el.removeClass(this.focusClass);
7393 this.hasFocus = false;
7394 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7397 var v = this.getValue();
7398 if(String(v) !== String(this.startValue)){
7399 this.fireEvent('change', this, v, this.startValue);
7401 this.fireEvent("blur", this);
7405 * Resets the current field value to the originally loaded value and clears any validation messages
7408 this.setValue(this.originalValue);
7409 this.clearInvalid();
7412 * Returns the name of the field
7413 * @return {Mixed} name The name field
7415 getName: function(){
7419 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7420 * @return {Mixed} value The field value
7422 getValue : function(){
7424 var v = this.inputEl().getValue();
7429 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7430 * @return {Mixed} value The field value
7432 getRawValue : function(){
7433 var v = this.inputEl().getValue();
7439 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7440 * @param {Mixed} value The value to set
7442 setRawValue : function(v){
7443 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7446 selectText : function(start, end){
7447 var v = this.getRawValue();
7449 start = start === undefined ? 0 : start;
7450 end = end === undefined ? v.length : end;
7451 var d = this.inputEl().dom;
7452 if(d.setSelectionRange){
7453 d.setSelectionRange(start, end);
7454 }else if(d.createTextRange){
7455 var range = d.createTextRange();
7456 range.moveStart("character", start);
7457 range.moveEnd("character", v.length-end);
7464 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7465 * @param {Mixed} value The value to set
7467 setValue : function(v){
7470 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7476 processValue : function(value){
7477 if(this.stripCharsRe){
7478 var newValue = value.replace(this.stripCharsRe, '');
7479 if(newValue !== value){
7480 this.setRawValue(newValue);
7487 preFocus : function(){
7489 if(this.selectOnFocus){
7490 this.inputEl().dom.select();
7493 filterKeys : function(e){
7495 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7498 var c = e.getCharCode(), cc = String.fromCharCode(c);
7499 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7502 if(!this.maskRe.test(cc)){
7507 * Clear any invalid styles/messages for this field
7509 clearInvalid : function(){
7511 if(!this.el || this.preventMark){ // not rendered
7514 this.el.removeClass(this.invalidClass);
7516 switch(this.msgTarget){
7518 this.el.dom.qtip = '';
7521 this.el.dom.title = '';
7525 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7530 this.errorIcon.dom.qtip = '';
7531 this.errorIcon.hide();
7532 this.un('resize', this.alignErrorIcon, this);
7536 var t = Roo.getDom(this.msgTarget);
7538 t.style.display = 'none';
7542 this.fireEvent('valid', this);
7545 * Mark this field as invalid
7546 * @param {String} msg The validation message
7548 markInvalid : function(msg){
7549 if(!this.el || this.preventMark){ // not rendered
7552 this.el.addClass(this.invalidClass);
7554 msg = msg || this.invalidText;
7555 switch(this.msgTarget){
7557 this.el.dom.qtip = msg;
7558 this.el.dom.qclass = 'x-form-invalid-tip';
7559 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7560 Roo.QuickTips.enable();
7564 this.el.dom.title = msg;
7568 var elp = this.el.findParent('.x-form-element', 5, true);
7569 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7570 this.errorEl.setWidth(elp.getWidth(true)-20);
7572 this.errorEl.update(msg);
7573 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7576 if(!this.errorIcon){
7577 var elp = this.el.findParent('.x-form-element', 5, true);
7578 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7580 this.alignErrorIcon();
7581 this.errorIcon.dom.qtip = msg;
7582 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7583 this.errorIcon.show();
7584 this.on('resize', this.alignErrorIcon, this);
7587 var t = Roo.getDom(this.msgTarget);
7589 t.style.display = this.msgDisplay;
7593 this.fireEvent('invalid', this, msg);
7596 SafariOnKeyDown : function(event)
7598 // this is a workaround for a password hang bug on chrome/ webkit.
7600 var isSelectAll = false;
7602 if(this.inputEl().dom.selectionEnd > 0){
7603 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7605 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7606 event.preventDefault();
7611 if(isSelectAll){ // backspace and delete key
7613 event.preventDefault();
7614 // this is very hacky as keydown always get's upper case.
7616 var cc = String.fromCharCode(event.getCharCode());
7617 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7621 adjustWidth : function(tag, w){
7622 tag = tag.toLowerCase();
7623 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7624 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7628 if(tag == 'textarea'){
7631 }else if(Roo.isOpera){
7635 if(tag == 'textarea'){
7654 * @class Roo.bootstrap.TextArea
7655 * @extends Roo.bootstrap.Input
7656 * Bootstrap TextArea class
7657 * @cfg {Number} cols Specifies the visible width of a text area
7658 * @cfg {Number} rows Specifies the visible number of lines in a text area
7659 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7660 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7661 * @cfg {string} html text
7664 * Create a new TextArea
7665 * @param {Object} config The config object
7668 Roo.bootstrap.TextArea = function(config){
7669 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7673 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7683 getAutoCreate : function(){
7685 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7696 value : this.value || '',
7697 html: this.html || '',
7698 cls : 'form-control',
7699 placeholder : this.placeholder || ''
7703 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7704 input.maxLength = this.maxLength;
7708 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7712 input.cols = this.cols;
7715 if (this.readOnly) {
7716 input.readonly = true;
7720 input.name = this.name;
7724 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7728 ['xs','sm','md','lg'].map(function(size){
7729 if (settings[size]) {
7730 cfg.cls += ' col-' + size + '-' + settings[size];
7734 var inputblock = input;
7736 if (this.before || this.after) {
7739 cls : 'input-group',
7743 inputblock.cn.push({
7745 cls : 'input-group-addon',
7749 inputblock.cn.push(input);
7751 inputblock.cn.push({
7753 cls : 'input-group-addon',
7760 if (align ==='left' && this.fieldLabel.length) {
7761 Roo.log("left and has label");
7767 cls : 'control-label col-sm-' + this.labelWidth,
7768 html : this.fieldLabel
7772 cls : "col-sm-" + (12 - this.labelWidth),
7779 } else if ( this.fieldLabel.length) {
7785 //cls : 'input-group-addon',
7786 html : this.fieldLabel
7796 Roo.log(" no label && no align");
7806 if (this.disabled) {
7807 input.disabled=true;
7814 * return the real textarea element.
7816 inputEl: function ()
7818 return this.el.select('textarea.form-control',true).first();
7826 * trigger field - base class for combo..
7831 * @class Roo.bootstrap.TriggerField
7832 * @extends Roo.bootstrap.Input
7833 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7834 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7835 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7836 * for which you can provide a custom implementation. For example:
7838 var trigger = new Roo.bootstrap.TriggerField();
7839 trigger.onTriggerClick = myTriggerFn;
7840 trigger.applyTo('my-field');
7843 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7844 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7845 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7846 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7848 * Create a new TriggerField.
7849 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7850 * to the base TextField)
7852 Roo.bootstrap.TriggerField = function(config){
7853 this.mimicing = false;
7854 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7857 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7859 * @cfg {String} triggerClass A CSS class to apply to the trigger
7862 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7866 /** @cfg {Boolean} grow @hide */
7867 /** @cfg {Number} growMin @hide */
7868 /** @cfg {Number} growMax @hide */
7874 autoSize: Roo.emptyFn,
7881 actionMode : 'wrap',
7885 getAutoCreate : function(){
7887 var align = this.labelAlign || this.parentLabelAlign();
7892 cls: 'form-group' //input-group
7899 type : this.inputType,
7900 cls : 'form-control',
7901 autocomplete: 'off',
7902 placeholder : this.placeholder || ''
7906 input.name = this.name;
7909 input.cls += ' input-' + this.size;
7912 if (this.disabled) {
7913 input.disabled=true;
7916 var inputblock = input;
7918 if (this.before || this.after) {
7921 cls : 'input-group',
7925 inputblock.cn.push({
7927 cls : 'input-group-addon',
7931 inputblock.cn.push(input);
7933 inputblock.cn.push({
7935 cls : 'input-group-addon',
7948 cls: 'form-hidden-field'
7956 Roo.log('multiple');
7964 cls: 'form-hidden-field'
7968 cls: 'select2-choices',
7972 cls: 'select2-search-field',
7985 cls: 'select2-container input-group',
7990 // cls: 'typeahead typeahead-long dropdown-menu',
7991 // style: 'display:none'
7996 if(!this.multiple && this.showToggleBtn){
7999 cls : 'input-group-addon btn dropdown-toggle',
8007 cls: 'combobox-clear',
8021 combobox.cls += ' select2-container-multi';
8024 if (align ==='left' && this.fieldLabel.length) {
8026 Roo.log("left and has label");
8032 cls : 'control-label col-sm-' + this.labelWidth,
8033 html : this.fieldLabel
8037 cls : "col-sm-" + (12 - this.labelWidth),
8044 } else if ( this.fieldLabel.length) {
8050 //cls : 'input-group-addon',
8051 html : this.fieldLabel
8061 Roo.log(" no label && no align");
8068 ['xs','sm','md','lg'].map(function(size){
8069 if (settings[size]) {
8070 cfg.cls += ' col-' + size + '-' + settings[size];
8081 onResize : function(w, h){
8082 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8083 // if(typeof w == 'number'){
8084 // var x = w - this.trigger.getWidth();
8085 // this.inputEl().setWidth(this.adjustWidth('input', x));
8086 // this.trigger.setStyle('left', x+'px');
8091 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8094 getResizeEl : function(){
8095 return this.inputEl();
8099 getPositionEl : function(){
8100 return this.inputEl();
8104 alignErrorIcon : function(){
8105 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8109 initEvents : function(){
8113 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8114 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8115 if(!this.multiple && this.showToggleBtn){
8116 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8117 if(this.hideTrigger){
8118 this.trigger.setDisplayed(false);
8120 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8124 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8127 //this.trigger.addClassOnOver('x-form-trigger-over');
8128 //this.trigger.addClassOnClick('x-form-trigger-click');
8131 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8135 createList : function()
8137 this.list = Roo.get(document.body).createChild({
8139 cls: 'typeahead typeahead-long dropdown-menu',
8140 style: 'display:none'
8143 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8148 initTrigger : function(){
8153 onDestroy : function(){
8155 this.trigger.removeAllListeners();
8156 // this.trigger.remove();
8159 // this.wrap.remove();
8161 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8165 onFocus : function(){
8166 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8169 this.wrap.addClass('x-trigger-wrap-focus');
8170 this.mimicing = true;
8171 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8172 if(this.monitorTab){
8173 this.el.on("keydown", this.checkTab, this);
8180 checkTab : function(e){
8181 if(e.getKey() == e.TAB){
8187 onBlur : function(){
8192 mimicBlur : function(e, t){
8194 if(!this.wrap.contains(t) && this.validateBlur()){
8201 triggerBlur : function(){
8202 this.mimicing = false;
8203 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8204 if(this.monitorTab){
8205 this.el.un("keydown", this.checkTab, this);
8207 //this.wrap.removeClass('x-trigger-wrap-focus');
8208 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8212 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8213 validateBlur : function(e, t){
8218 onDisable : function(){
8219 this.inputEl().dom.disabled = true;
8220 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8222 // this.wrap.addClass('x-item-disabled');
8227 onEnable : function(){
8228 this.inputEl().dom.disabled = false;
8229 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8231 // this.el.removeClass('x-item-disabled');
8236 onShow : function(){
8237 var ae = this.getActionEl();
8240 ae.dom.style.display = '';
8241 ae.dom.style.visibility = 'visible';
8247 onHide : function(){
8248 var ae = this.getActionEl();
8249 ae.dom.style.display = 'none';
8253 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8254 * by an implementing function.
8256 * @param {EventObject} e
8258 onTriggerClick : Roo.emptyFn
8262 * Ext JS Library 1.1.1
8263 * Copyright(c) 2006-2007, Ext JS, LLC.
8265 * Originally Released Under LGPL - original licence link has changed is not relivant.
8268 * <script type="text/javascript">
8273 * @class Roo.data.SortTypes
8275 * Defines the default sorting (casting?) comparison functions used when sorting data.
8277 Roo.data.SortTypes = {
8279 * Default sort that does nothing
8280 * @param {Mixed} s The value being converted
8281 * @return {Mixed} The comparison value
8288 * The regular expression used to strip tags
8292 stripTagsRE : /<\/?[^>]+>/gi,
8295 * Strips all HTML tags to sort on text only
8296 * @param {Mixed} s The value being converted
8297 * @return {String} The comparison value
8299 asText : function(s){
8300 return String(s).replace(this.stripTagsRE, "");
8304 * Strips all HTML tags to sort on text only - Case insensitive
8305 * @param {Mixed} s The value being converted
8306 * @return {String} The comparison value
8308 asUCText : function(s){
8309 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8313 * Case insensitive string
8314 * @param {Mixed} s The value being converted
8315 * @return {String} The comparison value
8317 asUCString : function(s) {
8318 return String(s).toUpperCase();
8323 * @param {Mixed} s The value being converted
8324 * @return {Number} The comparison value
8326 asDate : function(s) {
8330 if(s instanceof Date){
8333 return Date.parse(String(s));
8338 * @param {Mixed} s The value being converted
8339 * @return {Float} The comparison value
8341 asFloat : function(s) {
8342 var val = parseFloat(String(s).replace(/,/g, ""));
8343 if(isNaN(val)) val = 0;
8349 * @param {Mixed} s The value being converted
8350 * @return {Number} The comparison value
8352 asInt : function(s) {
8353 var val = parseInt(String(s).replace(/,/g, ""));
8354 if(isNaN(val)) val = 0;
8359 * Ext JS Library 1.1.1
8360 * Copyright(c) 2006-2007, Ext JS, LLC.
8362 * Originally Released Under LGPL - original licence link has changed is not relivant.
8365 * <script type="text/javascript">
8369 * @class Roo.data.Record
8370 * Instances of this class encapsulate both record <em>definition</em> information, and record
8371 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8372 * to access Records cached in an {@link Roo.data.Store} object.<br>
8374 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8375 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8378 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8380 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8381 * {@link #create}. The parameters are the same.
8382 * @param {Array} data An associative Array of data values keyed by the field name.
8383 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8384 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8385 * not specified an integer id is generated.
8387 Roo.data.Record = function(data, id){
8388 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8393 * Generate a constructor for a specific record layout.
8394 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8395 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8396 * Each field definition object may contain the following properties: <ul>
8397 * <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,
8398 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8399 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8400 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8401 * is being used, then this is a string containing the javascript expression to reference the data relative to
8402 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8403 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8404 * this may be omitted.</p></li>
8405 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8406 * <ul><li>auto (Default, implies no conversion)</li>
8411 * <li>date</li></ul></p></li>
8412 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8413 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8414 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8415 * by the Reader into an object that will be stored in the Record. It is passed the
8416 * following parameters:<ul>
8417 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8419 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8421 * <br>usage:<br><pre><code>
8422 var TopicRecord = Roo.data.Record.create(
8423 {name: 'title', mapping: 'topic_title'},
8424 {name: 'author', mapping: 'username'},
8425 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8426 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8427 {name: 'lastPoster', mapping: 'user2'},
8428 {name: 'excerpt', mapping: 'post_text'}
8431 var myNewRecord = new TopicRecord({
8432 title: 'Do my job please',
8435 lastPost: new Date(),
8436 lastPoster: 'Animal',
8437 excerpt: 'No way dude!'
8439 myStore.add(myNewRecord);
8444 Roo.data.Record.create = function(o){
8446 f.superclass.constructor.apply(this, arguments);
8448 Roo.extend(f, Roo.data.Record);
8449 var p = f.prototype;
8450 p.fields = new Roo.util.MixedCollection(false, function(field){
8453 for(var i = 0, len = o.length; i < len; i++){
8454 p.fields.add(new Roo.data.Field(o[i]));
8456 f.getField = function(name){
8457 return p.fields.get(name);
8462 Roo.data.Record.AUTO_ID = 1000;
8463 Roo.data.Record.EDIT = 'edit';
8464 Roo.data.Record.REJECT = 'reject';
8465 Roo.data.Record.COMMIT = 'commit';
8467 Roo.data.Record.prototype = {
8469 * Readonly flag - true if this record has been modified.
8478 join : function(store){
8483 * Set the named field to the specified value.
8484 * @param {String} name The name of the field to set.
8485 * @param {Object} value The value to set the field to.
8487 set : function(name, value){
8488 if(this.data[name] == value){
8495 if(typeof this.modified[name] == 'undefined'){
8496 this.modified[name] = this.data[name];
8498 this.data[name] = value;
8499 if(!this.editing && this.store){
8500 this.store.afterEdit(this);
8505 * Get the value of the named field.
8506 * @param {String} name The name of the field to get the value of.
8507 * @return {Object} The value of the field.
8509 get : function(name){
8510 return this.data[name];
8514 beginEdit : function(){
8515 this.editing = true;
8520 cancelEdit : function(){
8521 this.editing = false;
8522 delete this.modified;
8526 endEdit : function(){
8527 this.editing = false;
8528 if(this.dirty && this.store){
8529 this.store.afterEdit(this);
8534 * Usually called by the {@link Roo.data.Store} which owns the Record.
8535 * Rejects all changes made to the Record since either creation, or the last commit operation.
8536 * Modified fields are reverted to their original values.
8538 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8539 * of reject operations.
8541 reject : function(){
8542 var m = this.modified;
8544 if(typeof m[n] != "function"){
8545 this.data[n] = m[n];
8549 delete this.modified;
8550 this.editing = false;
8552 this.store.afterReject(this);
8557 * Usually called by the {@link Roo.data.Store} which owns the Record.
8558 * Commits all changes made to the Record since either creation, or the last commit operation.
8560 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8561 * of commit operations.
8563 commit : function(){
8565 delete this.modified;
8566 this.editing = false;
8568 this.store.afterCommit(this);
8573 hasError : function(){
8574 return this.error != null;
8578 clearError : function(){
8583 * Creates a copy of this record.
8584 * @param {String} id (optional) A new record id if you don't want to use this record's id
8587 copy : function(newId) {
8588 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8592 * Ext JS Library 1.1.1
8593 * Copyright(c) 2006-2007, Ext JS, LLC.
8595 * Originally Released Under LGPL - original licence link has changed is not relivant.
8598 * <script type="text/javascript">
8604 * @class Roo.data.Store
8605 * @extends Roo.util.Observable
8606 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8607 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8609 * 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
8610 * has no knowledge of the format of the data returned by the Proxy.<br>
8612 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8613 * instances from the data object. These records are cached and made available through accessor functions.
8615 * Creates a new Store.
8616 * @param {Object} config A config object containing the objects needed for the Store to access data,
8617 * and read the data into Records.
8619 Roo.data.Store = function(config){
8620 this.data = new Roo.util.MixedCollection(false);
8621 this.data.getKey = function(o){
8624 this.baseParams = {};
8631 "multisort" : "_multisort"
8634 if(config && config.data){
8635 this.inlineData = config.data;
8639 Roo.apply(this, config);
8641 if(this.reader){ // reader passed
8642 this.reader = Roo.factory(this.reader, Roo.data);
8643 this.reader.xmodule = this.xmodule || false;
8644 if(!this.recordType){
8645 this.recordType = this.reader.recordType;
8647 if(this.reader.onMetaChange){
8648 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8652 if(this.recordType){
8653 this.fields = this.recordType.prototype.fields;
8659 * @event datachanged
8660 * Fires when the data cache has changed, and a widget which is using this Store
8661 * as a Record cache should refresh its view.
8662 * @param {Store} this
8667 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8668 * @param {Store} this
8669 * @param {Object} meta The JSON metadata
8674 * Fires when Records have been added to the Store
8675 * @param {Store} this
8676 * @param {Roo.data.Record[]} records The array of Records added
8677 * @param {Number} index The index at which the record(s) were added
8682 * Fires when a Record has been removed from the Store
8683 * @param {Store} this
8684 * @param {Roo.data.Record} record The Record that was removed
8685 * @param {Number} index The index at which the record was removed
8690 * Fires when a Record has been updated
8691 * @param {Store} this
8692 * @param {Roo.data.Record} record The Record that was updated
8693 * @param {String} operation The update operation being performed. Value may be one of:
8695 Roo.data.Record.EDIT
8696 Roo.data.Record.REJECT
8697 Roo.data.Record.COMMIT
8703 * Fires when the data cache has been cleared.
8704 * @param {Store} this
8709 * Fires before a request is made for a new data object. If the beforeload handler returns false
8710 * the load action will be canceled.
8711 * @param {Store} this
8712 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8716 * @event beforeloadadd
8717 * Fires after a new set of Records has been loaded.
8718 * @param {Store} this
8719 * @param {Roo.data.Record[]} records The Records that were loaded
8720 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8722 beforeloadadd : true,
8725 * Fires after a new set of Records has been loaded, before they are added to the store.
8726 * @param {Store} this
8727 * @param {Roo.data.Record[]} records The Records that were loaded
8728 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8729 * @params {Object} return from reader
8733 * @event loadexception
8734 * Fires if an exception occurs in the Proxy during loading.
8735 * Called with the signature of the Proxy's "loadexception" event.
8736 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8739 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8740 * @param {Object} load options
8741 * @param {Object} jsonData from your request (normally this contains the Exception)
8743 loadexception : true
8747 this.proxy = Roo.factory(this.proxy, Roo.data);
8748 this.proxy.xmodule = this.xmodule || false;
8749 this.relayEvents(this.proxy, ["loadexception"]);
8751 this.sortToggle = {};
8752 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8754 Roo.data.Store.superclass.constructor.call(this);
8756 if(this.inlineData){
8757 this.loadData(this.inlineData);
8758 delete this.inlineData;
8762 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8764 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8765 * without a remote query - used by combo/forms at present.
8769 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8772 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8775 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8776 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8779 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8780 * on any HTTP request
8783 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8786 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8790 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8791 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8796 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8797 * loaded or when a record is removed. (defaults to false).
8799 pruneModifiedRecords : false,
8805 * Add Records to the Store and fires the add event.
8806 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8808 add : function(records){
8809 records = [].concat(records);
8810 for(var i = 0, len = records.length; i < len; i++){
8811 records[i].join(this);
8813 var index = this.data.length;
8814 this.data.addAll(records);
8815 this.fireEvent("add", this, records, index);
8819 * Remove a Record from the Store and fires the remove event.
8820 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8822 remove : function(record){
8823 var index = this.data.indexOf(record);
8824 this.data.removeAt(index);
8825 if(this.pruneModifiedRecords){
8826 this.modified.remove(record);
8828 this.fireEvent("remove", this, record, index);
8832 * Remove all Records from the Store and fires the clear event.
8834 removeAll : function(){
8836 if(this.pruneModifiedRecords){
8839 this.fireEvent("clear", this);
8843 * Inserts Records to the Store at the given index and fires the add event.
8844 * @param {Number} index The start index at which to insert the passed Records.
8845 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8847 insert : function(index, records){
8848 records = [].concat(records);
8849 for(var i = 0, len = records.length; i < len; i++){
8850 this.data.insert(index, records[i]);
8851 records[i].join(this);
8853 this.fireEvent("add", this, records, index);
8857 * Get the index within the cache of the passed Record.
8858 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8859 * @return {Number} The index of the passed Record. Returns -1 if not found.
8861 indexOf : function(record){
8862 return this.data.indexOf(record);
8866 * Get the index within the cache of the Record with the passed id.
8867 * @param {String} id The id of the Record to find.
8868 * @return {Number} The index of the Record. Returns -1 if not found.
8870 indexOfId : function(id){
8871 return this.data.indexOfKey(id);
8875 * Get the Record with the specified id.
8876 * @param {String} id The id of the Record to find.
8877 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8879 getById : function(id){
8880 return this.data.key(id);
8884 * Get the Record at the specified index.
8885 * @param {Number} index The index of the Record to find.
8886 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8888 getAt : function(index){
8889 return this.data.itemAt(index);
8893 * Returns a range of Records between specified indices.
8894 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8895 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8896 * @return {Roo.data.Record[]} An array of Records
8898 getRange : function(start, end){
8899 return this.data.getRange(start, end);
8903 storeOptions : function(o){
8904 o = Roo.apply({}, o);
8907 this.lastOptions = o;
8911 * Loads the Record cache from the configured Proxy using the configured Reader.
8913 * If using remote paging, then the first load call must specify the <em>start</em>
8914 * and <em>limit</em> properties in the options.params property to establish the initial
8915 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8917 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8918 * and this call will return before the new data has been loaded. Perform any post-processing
8919 * in a callback function, or in a "load" event handler.</strong>
8921 * @param {Object} options An object containing properties which control loading options:<ul>
8922 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8923 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8924 * passed the following arguments:<ul>
8925 * <li>r : Roo.data.Record[]</li>
8926 * <li>options: Options object from the load call</li>
8927 * <li>success: Boolean success indicator</li></ul></li>
8928 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8929 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8932 load : function(options){
8933 options = options || {};
8934 if(this.fireEvent("beforeload", this, options) !== false){
8935 this.storeOptions(options);
8936 var p = Roo.apply(options.params || {}, this.baseParams);
8937 // if meta was not loaded from remote source.. try requesting it.
8938 if (!this.reader.metaFromRemote) {
8941 if(this.sortInfo && this.remoteSort){
8942 var pn = this.paramNames;
8943 p[pn["sort"]] = this.sortInfo.field;
8944 p[pn["dir"]] = this.sortInfo.direction;
8946 if (this.multiSort) {
8947 var pn = this.paramNames;
8948 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8951 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8956 * Reloads the Record cache from the configured Proxy using the configured Reader and
8957 * the options from the last load operation performed.
8958 * @param {Object} options (optional) An object containing properties which may override the options
8959 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8960 * the most recently used options are reused).
8962 reload : function(options){
8963 this.load(Roo.applyIf(options||{}, this.lastOptions));
8967 // Called as a callback by the Reader during a load operation.
8968 loadRecords : function(o, options, success){
8969 if(!o || success === false){
8970 if(success !== false){
8971 this.fireEvent("load", this, [], options, o);
8973 if(options.callback){
8974 options.callback.call(options.scope || this, [], options, false);
8978 // if data returned failure - throw an exception.
8979 if (o.success === false) {
8980 // show a message if no listener is registered.
8981 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8982 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8984 // loadmask wil be hooked into this..
8985 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8988 var r = o.records, t = o.totalRecords || r.length;
8990 this.fireEvent("beforeloadadd", this, r, options, o);
8992 if(!options || options.add !== true){
8993 if(this.pruneModifiedRecords){
8996 for(var i = 0, len = r.length; i < len; i++){
9000 this.data = this.snapshot;
9001 delete this.snapshot;
9004 this.data.addAll(r);
9005 this.totalLength = t;
9007 this.fireEvent("datachanged", this);
9009 this.totalLength = Math.max(t, this.data.length+r.length);
9012 this.fireEvent("load", this, r, options, o);
9013 if(options.callback){
9014 options.callback.call(options.scope || this, r, options, true);
9020 * Loads data from a passed data block. A Reader which understands the format of the data
9021 * must have been configured in the constructor.
9022 * @param {Object} data The data block from which to read the Records. The format of the data expected
9023 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9024 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9026 loadData : function(o, append){
9027 var r = this.reader.readRecords(o);
9028 this.loadRecords(r, {add: append}, true);
9032 * Gets the number of cached records.
9034 * <em>If using paging, this may not be the total size of the dataset. If the data object
9035 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9036 * the data set size</em>
9038 getCount : function(){
9039 return this.data.length || 0;
9043 * Gets the total number of records in the dataset as returned by the server.
9045 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9046 * the dataset size</em>
9048 getTotalCount : function(){
9049 return this.totalLength || 0;
9053 * Returns the sort state of the Store as an object with two properties:
9055 field {String} The name of the field by which the Records are sorted
9056 direction {String} The sort order, "ASC" or "DESC"
9059 getSortState : function(){
9060 return this.sortInfo;
9064 applySort : function(){
9065 if(this.sortInfo && !this.remoteSort){
9066 var s = this.sortInfo, f = s.field;
9067 var st = this.fields.get(f).sortType;
9068 var fn = function(r1, r2){
9069 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9070 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9072 this.data.sort(s.direction, fn);
9073 if(this.snapshot && this.snapshot != this.data){
9074 this.snapshot.sort(s.direction, fn);
9080 * Sets the default sort column and order to be used by the next load operation.
9081 * @param {String} fieldName The name of the field to sort by.
9082 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9084 setDefaultSort : function(field, dir){
9085 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9090 * If remote sorting is used, the sort is performed on the server, and the cache is
9091 * reloaded. If local sorting is used, the cache is sorted internally.
9092 * @param {String} fieldName The name of the field to sort by.
9093 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9095 sort : function(fieldName, dir){
9096 var f = this.fields.get(fieldName);
9098 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9100 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9101 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9106 this.sortToggle[f.name] = dir;
9107 this.sortInfo = {field: f.name, direction: dir};
9108 if(!this.remoteSort){
9110 this.fireEvent("datachanged", this);
9112 this.load(this.lastOptions);
9117 * Calls the specified function for each of the Records in the cache.
9118 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9119 * Returning <em>false</em> aborts and exits the iteration.
9120 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9122 each : function(fn, scope){
9123 this.data.each(fn, scope);
9127 * Gets all records modified since the last commit. Modified records are persisted across load operations
9128 * (e.g., during paging).
9129 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9131 getModifiedRecords : function(){
9132 return this.modified;
9136 createFilterFn : function(property, value, anyMatch){
9137 if(!value.exec){ // not a regex
9138 value = String(value);
9139 if(value.length == 0){
9142 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9145 return value.test(r.data[property]);
9150 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9151 * @param {String} property A field on your records
9152 * @param {Number} start The record index to start at (defaults to 0)
9153 * @param {Number} end The last record index to include (defaults to length - 1)
9154 * @return {Number} The sum
9156 sum : function(property, start, end){
9157 var rs = this.data.items, v = 0;
9159 end = (end || end === 0) ? end : rs.length-1;
9161 for(var i = start; i <= end; i++){
9162 v += (rs[i].data[property] || 0);
9168 * Filter the records by a specified property.
9169 * @param {String} field A field on your records
9170 * @param {String/RegExp} value Either a string that the field
9171 * should start with or a RegExp to test against the field
9172 * @param {Boolean} anyMatch True to match any part not just the beginning
9174 filter : function(property, value, anyMatch){
9175 var fn = this.createFilterFn(property, value, anyMatch);
9176 return fn ? this.filterBy(fn) : this.clearFilter();
9180 * Filter by a function. The specified function will be called with each
9181 * record in this data source. If the function returns true the record is included,
9182 * otherwise it is filtered.
9183 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9184 * @param {Object} scope (optional) The scope of the function (defaults to this)
9186 filterBy : function(fn, scope){
9187 this.snapshot = this.snapshot || this.data;
9188 this.data = this.queryBy(fn, scope||this);
9189 this.fireEvent("datachanged", this);
9193 * Query the records by a specified property.
9194 * @param {String} field A field on your records
9195 * @param {String/RegExp} value Either a string that the field
9196 * should start with or a RegExp to test against the field
9197 * @param {Boolean} anyMatch True to match any part not just the beginning
9198 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9200 query : function(property, value, anyMatch){
9201 var fn = this.createFilterFn(property, value, anyMatch);
9202 return fn ? this.queryBy(fn) : this.data.clone();
9206 * Query by a function. The specified function will be called with each
9207 * record in this data source. If the function returns true the record is included
9209 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9210 * @param {Object} scope (optional) The scope of the function (defaults to this)
9211 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9213 queryBy : function(fn, scope){
9214 var data = this.snapshot || this.data;
9215 return data.filterBy(fn, scope||this);
9219 * Collects unique values for a particular dataIndex from this store.
9220 * @param {String} dataIndex The property to collect
9221 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9222 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9223 * @return {Array} An array of the unique values
9225 collect : function(dataIndex, allowNull, bypassFilter){
9226 var d = (bypassFilter === true && this.snapshot) ?
9227 this.snapshot.items : this.data.items;
9228 var v, sv, r = [], l = {};
9229 for(var i = 0, len = d.length; i < len; i++){
9230 v = d[i].data[dataIndex];
9232 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9241 * Revert to a view of the Record cache with no filtering applied.
9242 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9244 clearFilter : function(suppressEvent){
9245 if(this.snapshot && this.snapshot != this.data){
9246 this.data = this.snapshot;
9247 delete this.snapshot;
9248 if(suppressEvent !== true){
9249 this.fireEvent("datachanged", this);
9255 afterEdit : function(record){
9256 if(this.modified.indexOf(record) == -1){
9257 this.modified.push(record);
9259 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9263 afterReject : function(record){
9264 this.modified.remove(record);
9265 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9269 afterCommit : function(record){
9270 this.modified.remove(record);
9271 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9275 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9276 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9278 commitChanges : function(){
9279 var m = this.modified.slice(0);
9281 for(var i = 0, len = m.length; i < len; i++){
9287 * Cancel outstanding changes on all changed records.
9289 rejectChanges : function(){
9290 var m = this.modified.slice(0);
9292 for(var i = 0, len = m.length; i < len; i++){
9297 onMetaChange : function(meta, rtype, o){
9298 this.recordType = rtype;
9299 this.fields = rtype.prototype.fields;
9300 delete this.snapshot;
9301 this.sortInfo = meta.sortInfo || this.sortInfo;
9303 this.fireEvent('metachange', this, this.reader.meta);
9306 moveIndex : function(data, type)
9308 var index = this.indexOf(data);
9310 var newIndex = index + type;
9314 this.insert(newIndex, data);
9319 * Ext JS Library 1.1.1
9320 * Copyright(c) 2006-2007, Ext JS, LLC.
9322 * Originally Released Under LGPL - original licence link has changed is not relivant.
9325 * <script type="text/javascript">
9329 * @class Roo.data.SimpleStore
9330 * @extends Roo.data.Store
9331 * Small helper class to make creating Stores from Array data easier.
9332 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9333 * @cfg {Array} fields An array of field definition objects, or field name strings.
9334 * @cfg {Array} data The multi-dimensional array of data
9336 * @param {Object} config
9338 Roo.data.SimpleStore = function(config){
9339 Roo.data.SimpleStore.superclass.constructor.call(this, {
9341 reader: new Roo.data.ArrayReader({
9344 Roo.data.Record.create(config.fields)
9346 proxy : new Roo.data.MemoryProxy(config.data)
9350 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9352 * Ext JS Library 1.1.1
9353 * Copyright(c) 2006-2007, Ext JS, LLC.
9355 * Originally Released Under LGPL - original licence link has changed is not relivant.
9358 * <script type="text/javascript">
9363 * @extends Roo.data.Store
9364 * @class Roo.data.JsonStore
9365 * Small helper class to make creating Stores for JSON data easier. <br/>
9367 var store = new Roo.data.JsonStore({
9368 url: 'get-images.php',
9370 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9373 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9374 * JsonReader and HttpProxy (unless inline data is provided).</b>
9375 * @cfg {Array} fields An array of field definition objects, or field name strings.
9377 * @param {Object} config
9379 Roo.data.JsonStore = function(c){
9380 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9381 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9382 reader: new Roo.data.JsonReader(c, c.fields)
9385 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9387 * Ext JS Library 1.1.1
9388 * Copyright(c) 2006-2007, Ext JS, LLC.
9390 * Originally Released Under LGPL - original licence link has changed is not relivant.
9393 * <script type="text/javascript">
9397 Roo.data.Field = function(config){
9398 if(typeof config == "string"){
9399 config = {name: config};
9401 Roo.apply(this, config);
9407 var st = Roo.data.SortTypes;
9408 // named sortTypes are supported, here we look them up
9409 if(typeof this.sortType == "string"){
9410 this.sortType = st[this.sortType];
9413 // set default sortType for strings and dates
9417 this.sortType = st.asUCString;
9420 this.sortType = st.asDate;
9423 this.sortType = st.none;
9428 var stripRe = /[\$,%]/g;
9430 // prebuilt conversion function for this field, instead of
9431 // switching every time we're reading a value
9433 var cv, dateFormat = this.dateFormat;
9438 cv = function(v){ return v; };
9441 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9445 return v !== undefined && v !== null && v !== '' ?
9446 parseInt(String(v).replace(stripRe, ""), 10) : '';
9451 return v !== undefined && v !== null && v !== '' ?
9452 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9457 cv = function(v){ return v === true || v === "true" || v == 1; };
9464 if(v instanceof Date){
9468 if(dateFormat == "timestamp"){
9469 return new Date(v*1000);
9471 return Date.parseDate(v, dateFormat);
9473 var parsed = Date.parse(v);
9474 return parsed ? new Date(parsed) : null;
9483 Roo.data.Field.prototype = {
9491 * Ext JS Library 1.1.1
9492 * Copyright(c) 2006-2007, Ext JS, LLC.
9494 * Originally Released Under LGPL - original licence link has changed is not relivant.
9497 * <script type="text/javascript">
9500 // Base class for reading structured data from a data source. This class is intended to be
9501 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9504 * @class Roo.data.DataReader
9505 * Base class for reading structured data from a data source. This class is intended to be
9506 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9509 Roo.data.DataReader = function(meta, recordType){
9513 this.recordType = recordType instanceof Array ?
9514 Roo.data.Record.create(recordType) : recordType;
9517 Roo.data.DataReader.prototype = {
9519 * Create an empty record
9520 * @param {Object} data (optional) - overlay some values
9521 * @return {Roo.data.Record} record created.
9523 newRow : function(d) {
9525 this.recordType.prototype.fields.each(function(c) {
9527 case 'int' : da[c.name] = 0; break;
9528 case 'date' : da[c.name] = new Date(); break;
9529 case 'float' : da[c.name] = 0.0; break;
9530 case 'boolean' : da[c.name] = false; break;
9531 default : da[c.name] = ""; break;
9535 return new this.recordType(Roo.apply(da, d));
9540 * Ext JS Library 1.1.1
9541 * Copyright(c) 2006-2007, Ext JS, LLC.
9543 * Originally Released Under LGPL - original licence link has changed is not relivant.
9546 * <script type="text/javascript">
9550 * @class Roo.data.DataProxy
9551 * @extends Roo.data.Observable
9552 * This class is an abstract base class for implementations which provide retrieval of
9553 * unformatted data objects.<br>
9555 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9556 * (of the appropriate type which knows how to parse the data object) to provide a block of
9557 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9559 * Custom implementations must implement the load method as described in
9560 * {@link Roo.data.HttpProxy#load}.
9562 Roo.data.DataProxy = function(){
9566 * Fires before a network request is made to retrieve a data object.
9567 * @param {Object} This DataProxy object.
9568 * @param {Object} params The params parameter to the load function.
9573 * Fires before the load method's callback is called.
9574 * @param {Object} This DataProxy object.
9575 * @param {Object} o The data object.
9576 * @param {Object} arg The callback argument object passed to the load function.
9580 * @event loadexception
9581 * Fires if an Exception occurs during data retrieval.
9582 * @param {Object} This DataProxy object.
9583 * @param {Object} o The data object.
9584 * @param {Object} arg The callback argument object passed to the load function.
9585 * @param {Object} e The Exception.
9587 loadexception : true
9589 Roo.data.DataProxy.superclass.constructor.call(this);
9592 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9595 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9599 * Ext JS Library 1.1.1
9600 * Copyright(c) 2006-2007, Ext JS, LLC.
9602 * Originally Released Under LGPL - original licence link has changed is not relivant.
9605 * <script type="text/javascript">
9608 * @class Roo.data.MemoryProxy
9609 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9610 * to the Reader when its load method is called.
9612 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9614 Roo.data.MemoryProxy = function(data){
9618 Roo.data.MemoryProxy.superclass.constructor.call(this);
9622 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9624 * Load data from the requested source (in this case an in-memory
9625 * data object passed to the constructor), read the data object into
9626 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9627 * process that block using the passed callback.
9628 * @param {Object} params This parameter is not used by the MemoryProxy class.
9629 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9630 * object into a block of Roo.data.Records.
9631 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9632 * The function must be passed <ul>
9633 * <li>The Record block object</li>
9634 * <li>The "arg" argument from the load function</li>
9635 * <li>A boolean success indicator</li>
9637 * @param {Object} scope The scope in which to call the callback
9638 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9640 load : function(params, reader, callback, scope, arg){
9641 params = params || {};
9644 result = reader.readRecords(this.data);
9646 this.fireEvent("loadexception", this, arg, null, e);
9647 callback.call(scope, null, arg, false);
9650 callback.call(scope, result, arg, true);
9654 update : function(params, records){
9659 * Ext JS Library 1.1.1
9660 * Copyright(c) 2006-2007, Ext JS, LLC.
9662 * Originally Released Under LGPL - original licence link has changed is not relivant.
9665 * <script type="text/javascript">
9668 * @class Roo.data.HttpProxy
9669 * @extends Roo.data.DataProxy
9670 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9671 * configured to reference a certain URL.<br><br>
9673 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9674 * from which the running page was served.<br><br>
9676 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9678 * Be aware that to enable the browser to parse an XML document, the server must set
9679 * the Content-Type header in the HTTP response to "text/xml".
9681 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9682 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9683 * will be used to make the request.
9685 Roo.data.HttpProxy = function(conn){
9686 Roo.data.HttpProxy.superclass.constructor.call(this);
9687 // is conn a conn config or a real conn?
9689 this.useAjax = !conn || !conn.events;
9693 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9694 // thse are take from connection...
9697 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9700 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9701 * extra parameters to each request made by this object. (defaults to undefined)
9704 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9705 * to each request made by this object. (defaults to undefined)
9708 * @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)
9711 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9714 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9720 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9724 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9725 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9726 * a finer-grained basis than the DataProxy events.
9728 getConnection : function(){
9729 return this.useAjax ? Roo.Ajax : this.conn;
9733 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9734 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9735 * process that block using the passed callback.
9736 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9737 * for the request to the remote server.
9738 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9739 * object into a block of Roo.data.Records.
9740 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9741 * The function must be passed <ul>
9742 * <li>The Record block object</li>
9743 * <li>The "arg" argument from the load function</li>
9744 * <li>A boolean success indicator</li>
9746 * @param {Object} scope The scope in which to call the callback
9747 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9749 load : function(params, reader, callback, scope, arg){
9750 if(this.fireEvent("beforeload", this, params) !== false){
9752 params : params || {},
9754 callback : callback,
9759 callback : this.loadResponse,
9763 Roo.applyIf(o, this.conn);
9764 if(this.activeRequest){
9765 Roo.Ajax.abort(this.activeRequest);
9767 this.activeRequest = Roo.Ajax.request(o);
9769 this.conn.request(o);
9772 callback.call(scope||this, null, arg, false);
9777 loadResponse : function(o, success, response){
9778 delete this.activeRequest;
9780 this.fireEvent("loadexception", this, o, response);
9781 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9786 result = o.reader.read(response);
9788 this.fireEvent("loadexception", this, o, response, e);
9789 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9793 this.fireEvent("load", this, o, o.request.arg);
9794 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9798 update : function(dataSet){
9803 updateResponse : function(dataSet){
9808 * Ext JS Library 1.1.1
9809 * Copyright(c) 2006-2007, Ext JS, LLC.
9811 * Originally Released Under LGPL - original licence link has changed is not relivant.
9814 * <script type="text/javascript">
9818 * @class Roo.data.ScriptTagProxy
9819 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9820 * other than the originating domain of the running page.<br><br>
9822 * <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
9823 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9825 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9826 * source code that is used as the source inside a <script> tag.<br><br>
9828 * In order for the browser to process the returned data, the server must wrap the data object
9829 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9830 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9831 * depending on whether the callback name was passed:
9834 boolean scriptTag = false;
9835 String cb = request.getParameter("callback");
9838 response.setContentType("text/javascript");
9840 response.setContentType("application/x-json");
9842 Writer out = response.getWriter();
9844 out.write(cb + "(");
9846 out.print(dataBlock.toJsonString());
9853 * @param {Object} config A configuration object.
9855 Roo.data.ScriptTagProxy = function(config){
9856 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9857 Roo.apply(this, config);
9858 this.head = document.getElementsByTagName("head")[0];
9861 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9863 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9865 * @cfg {String} url The URL from which to request the data object.
9868 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9872 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9873 * the server the name of the callback function set up by the load call to process the returned data object.
9874 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9875 * javascript output which calls this named function passing the data object as its only parameter.
9877 callbackParam : "callback",
9879 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9880 * name to the request.
9885 * Load data from the configured URL, read the data object into
9886 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9887 * process that block using the passed callback.
9888 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9889 * for the request to the remote server.
9890 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9891 * object into a block of Roo.data.Records.
9892 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9893 * The function must be passed <ul>
9894 * <li>The Record block object</li>
9895 * <li>The "arg" argument from the load function</li>
9896 * <li>A boolean success indicator</li>
9898 * @param {Object} scope The scope in which to call the callback
9899 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9901 load : function(params, reader, callback, scope, arg){
9902 if(this.fireEvent("beforeload", this, params) !== false){
9904 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9907 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9909 url += "&_dc=" + (new Date().getTime());
9911 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9914 cb : "stcCallback"+transId,
9915 scriptId : "stcScript"+transId,
9919 callback : callback,
9925 window[trans.cb] = function(o){
9926 conn.handleResponse(o, trans);
9929 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9931 if(this.autoAbort !== false){
9935 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9937 var script = document.createElement("script");
9938 script.setAttribute("src", url);
9939 script.setAttribute("type", "text/javascript");
9940 script.setAttribute("id", trans.scriptId);
9941 this.head.appendChild(script);
9945 callback.call(scope||this, null, arg, false);
9950 isLoading : function(){
9951 return this.trans ? true : false;
9955 * Abort the current server request.
9958 if(this.isLoading()){
9959 this.destroyTrans(this.trans);
9964 destroyTrans : function(trans, isLoaded){
9965 this.head.removeChild(document.getElementById(trans.scriptId));
9966 clearTimeout(trans.timeoutId);
9968 window[trans.cb] = undefined;
9970 delete window[trans.cb];
9973 // if hasn't been loaded, wait for load to remove it to prevent script error
9974 window[trans.cb] = function(){
9975 window[trans.cb] = undefined;
9977 delete window[trans.cb];
9984 handleResponse : function(o, trans){
9986 this.destroyTrans(trans, true);
9989 result = trans.reader.readRecords(o);
9991 this.fireEvent("loadexception", this, o, trans.arg, e);
9992 trans.callback.call(trans.scope||window, null, trans.arg, false);
9995 this.fireEvent("load", this, o, trans.arg);
9996 trans.callback.call(trans.scope||window, result, trans.arg, true);
10000 handleFailure : function(trans){
10001 this.trans = false;
10002 this.destroyTrans(trans, false);
10003 this.fireEvent("loadexception", this, null, trans.arg);
10004 trans.callback.call(trans.scope||window, null, trans.arg, false);
10008 * Ext JS Library 1.1.1
10009 * Copyright(c) 2006-2007, Ext JS, LLC.
10011 * Originally Released Under LGPL - original licence link has changed is not relivant.
10014 * <script type="text/javascript">
10018 * @class Roo.data.JsonReader
10019 * @extends Roo.data.DataReader
10020 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10021 * based on mappings in a provided Roo.data.Record constructor.
10023 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10024 * in the reply previously.
10029 var RecordDef = Roo.data.Record.create([
10030 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10031 {name: 'occupation'} // This field will use "occupation" as the mapping.
10033 var myReader = new Roo.data.JsonReader({
10034 totalProperty: "results", // The property which contains the total dataset size (optional)
10035 root: "rows", // The property which contains an Array of row objects
10036 id: "id" // The property within each row object that provides an ID for the record (optional)
10040 * This would consume a JSON file like this:
10042 { 'results': 2, 'rows': [
10043 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10044 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10047 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10048 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10049 * paged from the remote server.
10050 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10051 * @cfg {String} root name of the property which contains the Array of row objects.
10052 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10054 * Create a new JsonReader
10055 * @param {Object} meta Metadata configuration options
10056 * @param {Object} recordType Either an Array of field definition objects,
10057 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10059 Roo.data.JsonReader = function(meta, recordType){
10062 // set some defaults:
10063 Roo.applyIf(meta, {
10064 totalProperty: 'total',
10065 successProperty : 'success',
10070 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10072 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10075 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10076 * Used by Store query builder to append _requestMeta to params.
10079 metaFromRemote : false,
10081 * This method is only used by a DataProxy which has retrieved data from a remote server.
10082 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10083 * @return {Object} data A data block which is used by an Roo.data.Store object as
10084 * a cache of Roo.data.Records.
10086 read : function(response){
10087 var json = response.responseText;
10089 var o = /* eval:var:o */ eval("("+json+")");
10091 throw {message: "JsonReader.read: Json object not found"};
10097 this.metaFromRemote = true;
10098 this.meta = o.metaData;
10099 this.recordType = Roo.data.Record.create(o.metaData.fields);
10100 this.onMetaChange(this.meta, this.recordType, o);
10102 return this.readRecords(o);
10105 // private function a store will implement
10106 onMetaChange : function(meta, recordType, o){
10113 simpleAccess: function(obj, subsc) {
10120 getJsonAccessor: function(){
10122 return function(expr) {
10124 return(re.test(expr))
10125 ? new Function("obj", "return obj." + expr)
10130 return Roo.emptyFn;
10135 * Create a data block containing Roo.data.Records from an XML document.
10136 * @param {Object} o An object which contains an Array of row objects in the property specified
10137 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10138 * which contains the total size of the dataset.
10139 * @return {Object} data A data block which is used by an Roo.data.Store object as
10140 * a cache of Roo.data.Records.
10142 readRecords : function(o){
10144 * After any data loads, the raw JSON data is available for further custom processing.
10148 var s = this.meta, Record = this.recordType,
10149 f = Record.prototype.fields, fi = f.items, fl = f.length;
10151 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10153 if(s.totalProperty) {
10154 this.getTotal = this.getJsonAccessor(s.totalProperty);
10156 if(s.successProperty) {
10157 this.getSuccess = this.getJsonAccessor(s.successProperty);
10159 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10161 var g = this.getJsonAccessor(s.id);
10162 this.getId = function(rec) {
10164 return (r === undefined || r === "") ? null : r;
10167 this.getId = function(){return null;};
10170 for(var jj = 0; jj < fl; jj++){
10172 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10173 this.ef[jj] = this.getJsonAccessor(map);
10177 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10178 if(s.totalProperty){
10179 var vt = parseInt(this.getTotal(o), 10);
10184 if(s.successProperty){
10185 var vs = this.getSuccess(o);
10186 if(vs === false || vs === 'false'){
10191 for(var i = 0; i < c; i++){
10194 var id = this.getId(n);
10195 for(var j = 0; j < fl; j++){
10197 var v = this.ef[j](n);
10199 Roo.log('missing convert for ' + f.name);
10203 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10205 var record = new Record(values, id);
10207 records[i] = record;
10213 totalRecords : totalRecords
10218 * Ext JS Library 1.1.1
10219 * Copyright(c) 2006-2007, Ext JS, LLC.
10221 * Originally Released Under LGPL - original licence link has changed is not relivant.
10224 * <script type="text/javascript">
10228 * @class Roo.data.ArrayReader
10229 * @extends Roo.data.DataReader
10230 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10231 * Each element of that Array represents a row of data fields. The
10232 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10233 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10237 var RecordDef = Roo.data.Record.create([
10238 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10239 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10241 var myReader = new Roo.data.ArrayReader({
10242 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10246 * This would consume an Array like this:
10248 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10250 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10252 * Create a new JsonReader
10253 * @param {Object} meta Metadata configuration options.
10254 * @param {Object} recordType Either an Array of field definition objects
10255 * as specified to {@link Roo.data.Record#create},
10256 * or an {@link Roo.data.Record} object
10257 * created using {@link Roo.data.Record#create}.
10259 Roo.data.ArrayReader = function(meta, recordType){
10260 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10263 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10265 * Create a data block containing Roo.data.Records from an XML document.
10266 * @param {Object} o An Array of row objects which represents the dataset.
10267 * @return {Object} data A data block which is used by an Roo.data.Store object as
10268 * a cache of Roo.data.Records.
10270 readRecords : function(o){
10271 var sid = this.meta ? this.meta.id : null;
10272 var recordType = this.recordType, fields = recordType.prototype.fields;
10275 for(var i = 0; i < root.length; i++){
10278 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10279 for(var j = 0, jlen = fields.length; j < jlen; j++){
10280 var f = fields.items[j];
10281 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10282 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10284 values[f.name] = v;
10286 var record = new recordType(values, id);
10288 records[records.length] = record;
10292 totalRecords : records.length
10301 * @class Roo.bootstrap.ComboBox
10302 * @extends Roo.bootstrap.TriggerField
10303 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10304 * @cfg {Boolean} append (true|false) default false
10305 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10306 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10307 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10308 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10309 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10311 * Create a new ComboBox.
10312 * @param {Object} config Configuration options
10314 Roo.bootstrap.ComboBox = function(config){
10315 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10319 * Fires when the dropdown list is expanded
10320 * @param {Roo.bootstrap.ComboBox} combo This combo box
10325 * Fires when the dropdown list is collapsed
10326 * @param {Roo.bootstrap.ComboBox} combo This combo box
10330 * @event beforeselect
10331 * Fires before a list item is selected. Return false to cancel the selection.
10332 * @param {Roo.bootstrap.ComboBox} combo This combo box
10333 * @param {Roo.data.Record} record The data record returned from the underlying store
10334 * @param {Number} index The index of the selected item in the dropdown list
10336 'beforeselect' : true,
10339 * Fires when a list item is selected
10340 * @param {Roo.bootstrap.ComboBox} combo This combo box
10341 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10342 * @param {Number} index The index of the selected item in the dropdown list
10346 * @event beforequery
10347 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10348 * The event object passed has these properties:
10349 * @param {Roo.bootstrap.ComboBox} combo This combo box
10350 * @param {String} query The query
10351 * @param {Boolean} forceAll true to force "all" query
10352 * @param {Boolean} cancel true to cancel the query
10353 * @param {Object} e The query event object
10355 'beforequery': true,
10358 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10359 * @param {Roo.bootstrap.ComboBox} combo This combo box
10364 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10365 * @param {Roo.bootstrap.ComboBox} combo This combo box
10366 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10371 * Fires when the remove value from the combobox array
10372 * @param {Roo.bootstrap.ComboBox} combo This combo box
10379 this.tickItems = [];
10381 this.selectedIndex = -1;
10382 if(this.mode == 'local'){
10383 if(config.queryDelay === undefined){
10384 this.queryDelay = 10;
10386 if(config.minChars === undefined){
10392 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10395 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10396 * rendering into an Roo.Editor, defaults to false)
10399 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10400 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10403 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10406 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10407 * the dropdown list (defaults to undefined, with no header element)
10411 * @cfg {String/Roo.Template} tpl The template to use to render the output
10415 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10417 listWidth: undefined,
10419 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10420 * mode = 'remote' or 'text' if mode = 'local')
10422 displayField: undefined,
10424 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10425 * mode = 'remote' or 'value' if mode = 'local').
10426 * Note: use of a valueField requires the user make a selection
10427 * in order for a value to be mapped.
10429 valueField: undefined,
10433 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10434 * field's data value (defaults to the underlying DOM element's name)
10436 hiddenName: undefined,
10438 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10442 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10444 selectedClass: 'active',
10447 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10451 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10452 * anchor positions (defaults to 'tl-bl')
10454 listAlign: 'tl-bl?',
10456 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10460 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10461 * query specified by the allQuery config option (defaults to 'query')
10463 triggerAction: 'query',
10465 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10466 * (defaults to 4, does not apply if editable = false)
10470 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10471 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10475 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10476 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10480 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10481 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10485 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10486 * when editable = true (defaults to false)
10488 selectOnFocus:false,
10490 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10492 queryParam: 'query',
10494 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10495 * when mode = 'remote' (defaults to 'Loading...')
10497 loadingText: 'Loading...',
10499 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10503 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10507 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10508 * traditional select (defaults to true)
10512 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10516 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10520 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10521 * listWidth has a higher value)
10525 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10526 * allow the user to set arbitrary text into the field (defaults to false)
10528 forceSelection:false,
10530 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10531 * if typeAhead = true (defaults to 250)
10533 typeAheadDelay : 250,
10535 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10536 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10538 valueNotFoundText : undefined,
10540 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10542 blockFocus : false,
10545 * @cfg {Boolean} disableClear Disable showing of clear button.
10547 disableClear : false,
10549 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10551 alwaysQuery : false,
10554 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10568 btnPosition : 'right',
10569 triggerList : true,
10570 showToggleBtn : true,
10571 // element that contains real text value.. (when hidden is used..)
10573 getAutoCreate : function()
10580 if(!this.tickable){
10581 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10586 * ComboBox with tickable selections
10589 var align = this.labelAlign || this.parentLabelAlign();
10592 cls : 'form-group roo-combobox-tickable' //input-group
10598 cls : 'tickable-buttons',
10603 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10610 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10617 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10624 Roo.each(buttons.cn, function(c){
10626 c.cls += ' btn-' + _this.size;
10629 if (_this.disabled) {
10640 cls: 'form-hidden-field'
10644 cls: 'select2-choices',
10648 cls: 'select2-search-field',
10660 cls: 'select2-container input-group select2-container-multi',
10665 // cls: 'typeahead typeahead-long dropdown-menu',
10666 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10671 if (align ==='left' && this.fieldLabel.length) {
10673 Roo.log("left and has label");
10679 cls : 'control-label col-sm-' + this.labelWidth,
10680 html : this.fieldLabel
10684 cls : "col-sm-" + (12 - this.labelWidth),
10691 } else if ( this.fieldLabel.length) {
10697 //cls : 'input-group-addon',
10698 html : this.fieldLabel
10708 Roo.log(" no label && no align");
10715 ['xs','sm','md','lg'].map(function(size){
10716 if (settings[size]) {
10717 cfg.cls += ' col-' + size + '-' + settings[size];
10726 initEvents: function()
10730 throw "can not find store for combo";
10732 this.store = Roo.factory(this.store, Roo.data);
10735 this.initTickableEvents();
10739 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10741 if(this.hiddenName){
10743 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10745 this.hiddenField.dom.value =
10746 this.hiddenValue !== undefined ? this.hiddenValue :
10747 this.value !== undefined ? this.value : '';
10749 // prevent input submission
10750 this.el.dom.removeAttribute('name');
10751 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10756 // this.el.dom.setAttribute('autocomplete', 'off');
10759 var cls = 'x-combo-list';
10761 //this.list = new Roo.Layer({
10762 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10768 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10769 _this.list.setWidth(lw);
10772 this.list.on('mouseover', this.onViewOver, this);
10773 this.list.on('mousemove', this.onViewMove, this);
10775 this.list.on('scroll', this.onViewScroll, this);
10778 this.list.swallowEvent('mousewheel');
10779 this.assetHeight = 0;
10782 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10783 this.assetHeight += this.header.getHeight();
10786 this.innerList = this.list.createChild({cls:cls+'-inner'});
10787 this.innerList.on('mouseover', this.onViewOver, this);
10788 this.innerList.on('mousemove', this.onViewMove, this);
10789 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10791 if(this.allowBlank && !this.pageSize && !this.disableClear){
10792 this.footer = this.list.createChild({cls:cls+'-ft'});
10793 this.pageTb = new Roo.Toolbar(this.footer);
10797 this.footer = this.list.createChild({cls:cls+'-ft'});
10798 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10799 {pageSize: this.pageSize});
10803 if (this.pageTb && this.allowBlank && !this.disableClear) {
10805 this.pageTb.add(new Roo.Toolbar.Fill(), {
10806 cls: 'x-btn-icon x-btn-clear',
10808 handler: function()
10811 _this.clearValue();
10812 _this.onSelect(false, -1);
10817 this.assetHeight += this.footer.getHeight();
10822 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10825 this.view = new Roo.View(this.list, this.tpl, {
10826 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10828 //this.view.wrapEl.setDisplayed(false);
10829 this.view.on('click', this.onViewClick, this);
10833 this.store.on('beforeload', this.onBeforeLoad, this);
10834 this.store.on('load', this.onLoad, this);
10835 this.store.on('loadexception', this.onLoadException, this);
10837 if(this.resizable){
10838 this.resizer = new Roo.Resizable(this.list, {
10839 pinned:true, handles:'se'
10841 this.resizer.on('resize', function(r, w, h){
10842 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10843 this.listWidth = w;
10844 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10845 this.restrictHeight();
10847 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10850 if(!this.editable){
10851 this.editable = true;
10852 this.setEditable(false);
10857 if (typeof(this.events.add.listeners) != 'undefined') {
10859 this.addicon = this.wrap.createChild(
10860 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10862 this.addicon.on('click', function(e) {
10863 this.fireEvent('add', this);
10866 if (typeof(this.events.edit.listeners) != 'undefined') {
10868 this.editicon = this.wrap.createChild(
10869 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10870 if (this.addicon) {
10871 this.editicon.setStyle('margin-left', '40px');
10873 this.editicon.on('click', function(e) {
10875 // we fire even if inothing is selected..
10876 this.fireEvent('edit', this, this.lastData );
10882 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10883 "up" : function(e){
10884 this.inKeyMode = true;
10888 "down" : function(e){
10889 if(!this.isExpanded()){
10890 this.onTriggerClick();
10892 this.inKeyMode = true;
10897 "enter" : function(e){
10898 // this.onViewClick();
10902 if(this.fireEvent("specialkey", this, e)){
10903 this.onViewClick(false);
10909 "esc" : function(e){
10913 "tab" : function(e){
10916 if(this.fireEvent("specialkey", this, e)){
10917 this.onViewClick(false);
10925 doRelay : function(foo, bar, hname){
10926 if(hname == 'down' || this.scope.isExpanded()){
10927 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10936 this.queryDelay = Math.max(this.queryDelay || 10,
10937 this.mode == 'local' ? 10 : 250);
10940 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10942 if(this.typeAhead){
10943 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10945 if(this.editable !== false){
10946 this.inputEl().on("keyup", this.onKeyUp, this);
10948 if(this.forceSelection){
10949 this.inputEl().on('blur', this.doForce, this);
10953 this.choices = this.el.select('ul.select2-choices', true).first();
10954 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10958 initTickableEvents: function()
10962 if(this.hiddenName){
10964 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10966 this.hiddenField.dom.value =
10967 this.hiddenValue !== undefined ? this.hiddenValue :
10968 this.value !== undefined ? this.value : '';
10970 // prevent input submission
10971 this.el.dom.removeAttribute('name');
10972 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10977 // this.list = this.el.select('ul.dropdown-menu',true).first();
10979 this.choices = this.el.select('ul.select2-choices', true).first();
10980 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10981 if(this.triggerList){
10982 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10985 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10986 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10988 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10989 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10991 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10992 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10994 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10995 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10996 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10999 this.cancelBtn.hide();
11004 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11005 _this.list.setWidth(lw);
11008 this.list.on('mouseover', this.onViewOver, this);
11009 this.list.on('mousemove', this.onViewMove, this);
11011 this.list.on('scroll', this.onViewScroll, this);
11014 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>';
11017 this.view = new Roo.View(this.list, this.tpl, {
11018 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11021 //this.view.wrapEl.setDisplayed(false);
11022 this.view.on('click', this.onViewClick, this);
11026 this.store.on('beforeload', this.onBeforeLoad, this);
11027 this.store.on('load', this.onLoad, this);
11028 this.store.on('loadexception', this.onLoadException, this);
11030 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11031 // "up" : function(e){
11032 // this.inKeyMode = true;
11033 // this.selectPrev();
11036 // "down" : function(e){
11037 // if(!this.isExpanded()){
11038 // this.onTriggerClick();
11040 // this.inKeyMode = true;
11041 // this.selectNext();
11045 // "enter" : function(e){
11046 //// this.onViewClick();
11048 // this.collapse();
11050 // if(this.fireEvent("specialkey", this, e)){
11051 // this.onViewClick(false);
11057 // "esc" : function(e){
11058 // this.collapse();
11061 // "tab" : function(e){
11062 // this.collapse();
11064 // if(this.fireEvent("specialkey", this, e)){
11065 // this.onViewClick(false);
11073 // doRelay : function(foo, bar, hname){
11074 // if(hname == 'down' || this.scope.isExpanded()){
11075 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11080 // forceKeyDown: true
11084 this.queryDelay = Math.max(this.queryDelay || 10,
11085 this.mode == 'local' ? 10 : 250);
11088 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11090 if(this.typeAhead){
11091 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11095 onDestroy : function(){
11097 this.view.setStore(null);
11098 this.view.el.removeAllListeners();
11099 this.view.el.remove();
11100 this.view.purgeListeners();
11103 this.list.dom.innerHTML = '';
11107 this.store.un('beforeload', this.onBeforeLoad, this);
11108 this.store.un('load', this.onLoad, this);
11109 this.store.un('loadexception', this.onLoadException, this);
11111 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11115 fireKey : function(e){
11116 if(e.isNavKeyPress() && !this.list.isVisible()){
11117 this.fireEvent("specialkey", this, e);
11122 onResize: function(w, h){
11123 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11125 // if(typeof w != 'number'){
11126 // // we do not handle it!?!?
11129 // var tw = this.trigger.getWidth();
11130 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11131 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11133 // this.inputEl().setWidth( this.adjustWidth('input', x));
11135 // //this.trigger.setStyle('left', x+'px');
11137 // if(this.list && this.listWidth === undefined){
11138 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11139 // this.list.setWidth(lw);
11140 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11148 * Allow or prevent the user from directly editing the field text. If false is passed,
11149 * the user will only be able to select from the items defined in the dropdown list. This method
11150 * is the runtime equivalent of setting the 'editable' config option at config time.
11151 * @param {Boolean} value True to allow the user to directly edit the field text
11153 setEditable : function(value){
11154 if(value == this.editable){
11157 this.editable = value;
11159 this.inputEl().dom.setAttribute('readOnly', true);
11160 this.inputEl().on('mousedown', this.onTriggerClick, this);
11161 this.inputEl().addClass('x-combo-noedit');
11163 this.inputEl().dom.setAttribute('readOnly', false);
11164 this.inputEl().un('mousedown', this.onTriggerClick, this);
11165 this.inputEl().removeClass('x-combo-noedit');
11171 onBeforeLoad : function(combo,opts){
11172 if(!this.hasFocus){
11176 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11178 this.restrictHeight();
11179 this.selectedIndex = -1;
11183 onLoad : function(){
11185 this.hasQuery = false;
11187 if(!this.hasFocus){
11191 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11192 this.loading.hide();
11195 if(this.store.getCount() > 0){
11197 // this.restrictHeight();
11198 if(this.lastQuery == this.allQuery){
11199 if(this.editable && !this.tickable){
11200 this.inputEl().dom.select();
11204 !this.selectByValue(this.value, true) &&
11205 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11206 this.store.lastOptions.add != true)
11208 this.select(0, true);
11211 if(this.autoFocus){
11214 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11215 this.taTask.delay(this.typeAheadDelay);
11219 this.onEmptyResults();
11225 onLoadException : function()
11227 this.hasQuery = false;
11229 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11230 this.loading.hide();
11234 Roo.log(this.store.reader.jsonData);
11235 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11237 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11243 onTypeAhead : function(){
11244 if(this.store.getCount() > 0){
11245 var r = this.store.getAt(0);
11246 var newValue = r.data[this.displayField];
11247 var len = newValue.length;
11248 var selStart = this.getRawValue().length;
11250 if(selStart != len){
11251 this.setRawValue(newValue);
11252 this.selectText(selStart, newValue.length);
11258 onSelect : function(record, index){
11260 if(this.fireEvent('beforeselect', this, record, index) !== false){
11262 this.setFromData(index > -1 ? record.data : false);
11265 this.fireEvent('select', this, record, index);
11270 * Returns the currently selected field value or empty string if no value is set.
11271 * @return {String} value The selected value
11273 getValue : function(){
11276 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11279 if(this.valueField){
11280 return typeof this.value != 'undefined' ? this.value : '';
11282 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11287 * Clears any text/value currently set in the field
11289 clearValue : function(){
11290 if(this.hiddenField){
11291 this.hiddenField.dom.value = '';
11294 this.setRawValue('');
11295 this.lastSelectionText = '';
11300 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11301 * will be displayed in the field. If the value does not match the data value of an existing item,
11302 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11303 * Otherwise the field will be blank (although the value will still be set).
11304 * @param {String} value The value to match
11306 setValue : function(v){
11313 if(this.valueField){
11314 var r = this.findRecord(this.valueField, v);
11316 text = r.data[this.displayField];
11317 }else if(this.valueNotFoundText !== undefined){
11318 text = this.valueNotFoundText;
11321 this.lastSelectionText = text;
11322 if(this.hiddenField){
11323 this.hiddenField.dom.value = v;
11325 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11329 * @property {Object} the last set data for the element
11334 * Sets the value of the field based on a object which is related to the record format for the store.
11335 * @param {Object} value the value to set as. or false on reset?
11337 setFromData : function(o){
11344 var dv = ''; // display value
11345 var vv = ''; // value value..
11347 if (this.displayField) {
11348 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11350 // this is an error condition!!!
11351 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11354 if(this.valueField){
11355 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11358 if(this.hiddenField){
11359 this.hiddenField.dom.value = vv;
11361 this.lastSelectionText = dv;
11362 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11366 // no hidden field.. - we store the value in 'value', but still display
11367 // display field!!!!
11368 this.lastSelectionText = dv;
11369 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11375 reset : function(){
11376 // overridden so that last data is reset..
11377 this.setValue(this.originalValue);
11378 this.clearInvalid();
11379 this.lastData = false;
11381 this.view.clearSelections();
11385 findRecord : function(prop, value){
11387 if(this.store.getCount() > 0){
11388 this.store.each(function(r){
11389 if(r.data[prop] == value){
11399 getName: function()
11401 // returns hidden if it's set..
11402 if (!this.rendered) {return ''};
11403 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11407 onViewMove : function(e, t){
11408 this.inKeyMode = false;
11412 onViewOver : function(e, t){
11413 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11416 var item = this.view.findItemFromChild(t);
11419 var index = this.view.indexOf(item);
11420 this.select(index, false);
11425 onViewClick : function(view, doFocus, el, e)
11427 var index = this.view.getSelectedIndexes()[0];
11429 var r = this.store.getAt(index);
11433 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11440 Roo.each(this.tickItems, function(v,k){
11442 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11443 _this.tickItems.splice(k, 1);
11453 this.tickItems.push(r.data);
11458 this.onSelect(r, index);
11460 if(doFocus !== false && !this.blockFocus){
11461 this.inputEl().focus();
11466 restrictHeight : function(){
11467 //this.innerList.dom.style.height = '';
11468 //var inner = this.innerList.dom;
11469 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11470 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11471 //this.list.beginUpdate();
11472 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11473 this.list.alignTo(this.inputEl(), this.listAlign);
11474 this.list.alignTo(this.inputEl(), this.listAlign);
11475 //this.list.endUpdate();
11479 onEmptyResults : function(){
11484 * Returns true if the dropdown list is expanded, else false.
11486 isExpanded : function(){
11487 return this.list.isVisible();
11491 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11492 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11493 * @param {String} value The data value of the item to select
11494 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11495 * selected item if it is not currently in view (defaults to true)
11496 * @return {Boolean} True if the value matched an item in the list, else false
11498 selectByValue : function(v, scrollIntoView){
11499 if(v !== undefined && v !== null){
11500 var r = this.findRecord(this.valueField || this.displayField, v);
11502 this.select(this.store.indexOf(r), scrollIntoView);
11510 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11511 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11512 * @param {Number} index The zero-based index of the list item to select
11513 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11514 * selected item if it is not currently in view (defaults to true)
11516 select : function(index, scrollIntoView){
11517 this.selectedIndex = index;
11518 this.view.select(index);
11519 if(scrollIntoView !== false){
11520 var el = this.view.getNode(index);
11521 if(el && !this.multiple && !this.tickable){
11522 this.list.scrollChildIntoView(el, false);
11528 selectNext : function(){
11529 var ct = this.store.getCount();
11531 if(this.selectedIndex == -1){
11533 }else if(this.selectedIndex < ct-1){
11534 this.select(this.selectedIndex+1);
11540 selectPrev : function(){
11541 var ct = this.store.getCount();
11543 if(this.selectedIndex == -1){
11545 }else if(this.selectedIndex != 0){
11546 this.select(this.selectedIndex-1);
11552 onKeyUp : function(e){
11553 if(this.editable !== false && !e.isSpecialKey()){
11554 this.lastKey = e.getKey();
11555 this.dqTask.delay(this.queryDelay);
11560 validateBlur : function(){
11561 return !this.list || !this.list.isVisible();
11565 initQuery : function(){
11566 this.doQuery(this.getRawValue());
11570 doForce : function(){
11571 if(this.inputEl().dom.value.length > 0){
11572 this.inputEl().dom.value =
11573 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11579 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11580 * query allowing the query action to be canceled if needed.
11581 * @param {String} query The SQL query to execute
11582 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11583 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11584 * saved in the current store (defaults to false)
11586 doQuery : function(q, forceAll){
11588 if(q === undefined || q === null){
11593 forceAll: forceAll,
11597 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11602 forceAll = qe.forceAll;
11603 if(forceAll === true || (q.length >= this.minChars)){
11605 this.hasQuery = true;
11607 if(this.lastQuery != q || this.alwaysQuery){
11608 this.lastQuery = q;
11609 if(this.mode == 'local'){
11610 this.selectedIndex = -1;
11612 this.store.clearFilter();
11614 this.store.filter(this.displayField, q);
11618 this.store.baseParams[this.queryParam] = q;
11620 var options = {params : this.getParams(q)};
11623 options.add = true;
11624 options.params.start = this.page * this.pageSize;
11627 this.store.load(options);
11629 * this code will make the page width larger, at the beginning, the list not align correctly,
11630 * we should expand the list on onLoad
11631 * so command out it
11636 this.selectedIndex = -1;
11641 this.loadNext = false;
11645 getParams : function(q){
11647 //p[this.queryParam] = q;
11651 p.limit = this.pageSize;
11657 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11659 collapse : function(){
11660 if(!this.isExpanded()){
11668 this.cancelBtn.hide();
11669 this.trigger.show();
11672 Roo.get(document).un('mousedown', this.collapseIf, this);
11673 Roo.get(document).un('mousewheel', this.collapseIf, this);
11674 if (!this.editable) {
11675 Roo.get(document).un('keydown', this.listKeyPress, this);
11677 this.fireEvent('collapse', this);
11681 collapseIf : function(e){
11682 var in_combo = e.within(this.el);
11683 var in_list = e.within(this.list);
11684 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11686 if (in_combo || in_list || is_list) {
11687 //e.stopPropagation();
11692 this.onTickableFooterButtonClick(e, false, false);
11700 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11702 expand : function(){
11704 if(this.isExpanded() || !this.hasFocus){
11708 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11709 this.list.setWidth(lw);
11716 this.restrictHeight();
11720 this.tickItems = Roo.apply([], this.item);
11723 this.cancelBtn.show();
11724 this.trigger.hide();
11728 Roo.get(document).on('mousedown', this.collapseIf, this);
11729 Roo.get(document).on('mousewheel', this.collapseIf, this);
11730 if (!this.editable) {
11731 Roo.get(document).on('keydown', this.listKeyPress, this);
11734 this.fireEvent('expand', this);
11738 // Implements the default empty TriggerField.onTriggerClick function
11739 onTriggerClick : function(e)
11741 Roo.log('trigger click');
11743 if(this.disabled || !this.triggerList){
11748 this.loadNext = false;
11750 if(this.isExpanded()){
11752 if (!this.blockFocus) {
11753 this.inputEl().focus();
11757 this.hasFocus = true;
11758 if(this.triggerAction == 'all') {
11759 this.doQuery(this.allQuery, true);
11761 this.doQuery(this.getRawValue());
11763 if (!this.blockFocus) {
11764 this.inputEl().focus();
11769 onTickableTriggerClick : function(e)
11776 this.loadNext = false;
11777 this.hasFocus = true;
11779 if(this.triggerAction == 'all') {
11780 this.doQuery(this.allQuery, true);
11782 this.doQuery(this.getRawValue());
11786 onSearchFieldClick : function(e)
11788 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11793 this.loadNext = false;
11794 this.hasFocus = true;
11796 if(this.triggerAction == 'all') {
11797 this.doQuery(this.allQuery, true);
11799 this.doQuery(this.getRawValue());
11803 listKeyPress : function(e)
11805 //Roo.log('listkeypress');
11806 // scroll to first matching element based on key pres..
11807 if (e.isSpecialKey()) {
11810 var k = String.fromCharCode(e.getKey()).toUpperCase();
11813 var csel = this.view.getSelectedNodes();
11814 var cselitem = false;
11816 var ix = this.view.indexOf(csel[0]);
11817 cselitem = this.store.getAt(ix);
11818 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11824 this.store.each(function(v) {
11826 // start at existing selection.
11827 if (cselitem.id == v.id) {
11833 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11834 match = this.store.indexOf(v);
11840 if (match === false) {
11841 return true; // no more action?
11844 this.view.select(match);
11845 var sn = Roo.get(this.view.getSelectedNodes()[0])
11846 //sn.scrollIntoView(sn.dom.parentNode, false);
11849 onViewScroll : function(e, t){
11851 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){
11855 this.hasQuery = true;
11857 this.loading = this.list.select('.loading', true).first();
11859 if(this.loading === null){
11860 this.list.createChild({
11862 cls: 'loading select2-more-results select2-active',
11863 html: 'Loading more results...'
11866 this.loading = this.list.select('.loading', true).first();
11868 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11870 this.loading.hide();
11873 this.loading.show();
11878 this.loadNext = true;
11880 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11885 addItem : function(o)
11887 var dv = ''; // display value
11889 if (this.displayField) {
11890 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11892 // this is an error condition!!!
11893 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11900 var choice = this.choices.createChild({
11902 cls: 'select2-search-choice',
11911 cls: 'select2-search-choice-close',
11916 }, this.searchField);
11918 var close = choice.select('a.select2-search-choice-close', true).first()
11920 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11928 this.inputEl().dom.value = '';
11932 onRemoveItem : function(e, _self, o)
11934 e.preventDefault();
11935 var index = this.item.indexOf(o.data) * 1;
11938 Roo.log('not this item?!');
11942 this.item.splice(index, 1);
11947 this.fireEvent('remove', this, e);
11951 syncValue : function()
11953 if(!this.item.length){
11960 Roo.each(this.item, function(i){
11961 if(_this.valueField){
11962 value.push(i[_this.valueField]);
11969 this.value = value.join(',');
11971 if(this.hiddenField){
11972 this.hiddenField.dom.value = this.value;
11976 clearItem : function()
11978 if(!this.multiple){
11984 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11991 inputEl: function ()
11994 return this.searchField;
11996 return this.el.select('input.form-control',true).first();
12000 onTickableFooterButtonClick : function(e, btn, el)
12002 e.preventDefault();
12004 if(btn && btn.name == 'cancel'){
12005 this.tickItems = Roo.apply([], this.item);
12014 Roo.each(this.tickItems, function(o){
12025 * @cfg {Boolean} grow
12029 * @cfg {Number} growMin
12033 * @cfg {Number} growMax
12043 * Ext JS Library 1.1.1
12044 * Copyright(c) 2006-2007, Ext JS, LLC.
12046 * Originally Released Under LGPL - original licence link has changed is not relivant.
12049 * <script type="text/javascript">
12054 * @extends Roo.util.Observable
12055 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12056 * This class also supports single and multi selection modes. <br>
12057 * Create a data model bound view:
12059 var store = new Roo.data.Store(...);
12061 var view = new Roo.View({
12063 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12065 singleSelect: true,
12066 selectedClass: "ydataview-selected",
12070 // listen for node click?
12071 view.on("click", function(vw, index, node, e){
12072 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12076 dataModel.load("foobar.xml");
12078 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12080 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12081 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12083 * Note: old style constructor is still suported (container, template, config)
12086 * Create a new View
12087 * @param {Object} config The config object
12090 Roo.View = function(config, depreciated_tpl, depreciated_config){
12092 this.parent = false;
12094 if (typeof(depreciated_tpl) == 'undefined') {
12095 // new way.. - universal constructor.
12096 Roo.apply(this, config);
12097 this.el = Roo.get(this.el);
12100 this.el = Roo.get(config);
12101 this.tpl = depreciated_tpl;
12102 Roo.apply(this, depreciated_config);
12104 this.wrapEl = this.el.wrap().wrap();
12105 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12108 if(typeof(this.tpl) == "string"){
12109 this.tpl = new Roo.Template(this.tpl);
12111 // support xtype ctors..
12112 this.tpl = new Roo.factory(this.tpl, Roo);
12116 this.tpl.compile();
12121 * @event beforeclick
12122 * Fires before a click is processed. Returns false to cancel the default action.
12123 * @param {Roo.View} this
12124 * @param {Number} index The index of the target node
12125 * @param {HTMLElement} node The target node
12126 * @param {Roo.EventObject} e The raw event object
12128 "beforeclick" : true,
12131 * Fires when a template node is clicked.
12132 * @param {Roo.View} this
12133 * @param {Number} index The index of the target node
12134 * @param {HTMLElement} node The target node
12135 * @param {Roo.EventObject} e The raw event object
12140 * Fires when a template node is double clicked.
12141 * @param {Roo.View} this
12142 * @param {Number} index The index of the target node
12143 * @param {HTMLElement} node The target node
12144 * @param {Roo.EventObject} e The raw event object
12148 * @event contextmenu
12149 * Fires when a template node is right clicked.
12150 * @param {Roo.View} this
12151 * @param {Number} index The index of the target node
12152 * @param {HTMLElement} node The target node
12153 * @param {Roo.EventObject} e The raw event object
12155 "contextmenu" : true,
12157 * @event selectionchange
12158 * Fires when the selected nodes change.
12159 * @param {Roo.View} this
12160 * @param {Array} selections Array of the selected nodes
12162 "selectionchange" : true,
12165 * @event beforeselect
12166 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12167 * @param {Roo.View} this
12168 * @param {HTMLElement} node The node to be selected
12169 * @param {Array} selections Array of currently selected nodes
12171 "beforeselect" : true,
12173 * @event preparedata
12174 * Fires on every row to render, to allow you to change the data.
12175 * @param {Roo.View} this
12176 * @param {Object} data to be rendered (change this)
12178 "preparedata" : true
12186 "click": this.onClick,
12187 "dblclick": this.onDblClick,
12188 "contextmenu": this.onContextMenu,
12192 this.selections = [];
12194 this.cmp = new Roo.CompositeElementLite([]);
12196 this.store = Roo.factory(this.store, Roo.data);
12197 this.setStore(this.store, true);
12200 if ( this.footer && this.footer.xtype) {
12202 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12204 this.footer.dataSource = this.store
12205 this.footer.container = fctr;
12206 this.footer = Roo.factory(this.footer, Roo);
12207 fctr.insertFirst(this.el);
12209 // this is a bit insane - as the paging toolbar seems to detach the el..
12210 // dom.parentNode.parentNode.parentNode
12211 // they get detached?
12215 Roo.View.superclass.constructor.call(this);
12220 Roo.extend(Roo.View, Roo.util.Observable, {
12223 * @cfg {Roo.data.Store} store Data store to load data from.
12228 * @cfg {String|Roo.Element} el The container element.
12233 * @cfg {String|Roo.Template} tpl The template used by this View
12237 * @cfg {String} dataName the named area of the template to use as the data area
12238 * Works with domtemplates roo-name="name"
12242 * @cfg {String} selectedClass The css class to add to selected nodes
12244 selectedClass : "x-view-selected",
12246 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12251 * @cfg {String} text to display on mask (default Loading)
12255 * @cfg {Boolean} multiSelect Allow multiple selection
12257 multiSelect : false,
12259 * @cfg {Boolean} singleSelect Allow single selection
12261 singleSelect: false,
12264 * @cfg {Boolean} toggleSelect - selecting
12266 toggleSelect : false,
12269 * @cfg {Boolean} tickable - selecting
12274 * Returns the element this view is bound to.
12275 * @return {Roo.Element}
12277 getEl : function(){
12278 return this.wrapEl;
12284 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12286 refresh : function(){
12287 Roo.log('refresh');
12290 // if we are using something like 'domtemplate', then
12291 // the what gets used is:
12292 // t.applySubtemplate(NAME, data, wrapping data..)
12293 // the outer template then get' applied with
12294 // the store 'extra data'
12295 // and the body get's added to the
12296 // roo-name="data" node?
12297 // <span class='roo-tpl-{name}'></span> ?????
12301 this.clearSelections();
12302 this.el.update("");
12304 var records = this.store.getRange();
12305 if(records.length < 1) {
12307 // is this valid?? = should it render a template??
12309 this.el.update(this.emptyText);
12313 if (this.dataName) {
12314 this.el.update(t.apply(this.store.meta)); //????
12315 el = this.el.child('.roo-tpl-' + this.dataName);
12318 for(var i = 0, len = records.length; i < len; i++){
12319 var data = this.prepareData(records[i].data, i, records[i]);
12320 this.fireEvent("preparedata", this, data, i, records[i]);
12322 var d = Roo.apply({}, data);
12325 Roo.apply(d, {'roo-id' : Roo.id()});
12329 Roo.each(this.parent.item, function(item){
12330 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12333 Roo.apply(d, {'roo-data-checked' : 'checked'});
12337 html[html.length] = Roo.util.Format.trim(
12339 t.applySubtemplate(this.dataName, d, this.store.meta) :
12346 el.update(html.join(""));
12347 this.nodes = el.dom.childNodes;
12348 this.updateIndexes(0);
12353 * Function to override to reformat the data that is sent to
12354 * the template for each node.
12355 * DEPRICATED - use the preparedata event handler.
12356 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12357 * a JSON object for an UpdateManager bound view).
12359 prepareData : function(data, index, record)
12361 this.fireEvent("preparedata", this, data, index, record);
12365 onUpdate : function(ds, record){
12366 Roo.log('on update');
12367 this.clearSelections();
12368 var index = this.store.indexOf(record);
12369 var n = this.nodes[index];
12370 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12371 n.parentNode.removeChild(n);
12372 this.updateIndexes(index, index);
12378 onAdd : function(ds, records, index)
12380 Roo.log(['on Add', ds, records, index] );
12381 this.clearSelections();
12382 if(this.nodes.length == 0){
12386 var n = this.nodes[index];
12387 for(var i = 0, len = records.length; i < len; i++){
12388 var d = this.prepareData(records[i].data, i, records[i]);
12390 this.tpl.insertBefore(n, d);
12393 this.tpl.append(this.el, d);
12396 this.updateIndexes(index);
12399 onRemove : function(ds, record, index){
12400 Roo.log('onRemove');
12401 this.clearSelections();
12402 var el = this.dataName ?
12403 this.el.child('.roo-tpl-' + this.dataName) :
12406 el.dom.removeChild(this.nodes[index]);
12407 this.updateIndexes(index);
12411 * Refresh an individual node.
12412 * @param {Number} index
12414 refreshNode : function(index){
12415 this.onUpdate(this.store, this.store.getAt(index));
12418 updateIndexes : function(startIndex, endIndex){
12419 var ns = this.nodes;
12420 startIndex = startIndex || 0;
12421 endIndex = endIndex || ns.length - 1;
12422 for(var i = startIndex; i <= endIndex; i++){
12423 ns[i].nodeIndex = i;
12428 * Changes the data store this view uses and refresh the view.
12429 * @param {Store} store
12431 setStore : function(store, initial){
12432 if(!initial && this.store){
12433 this.store.un("datachanged", this.refresh);
12434 this.store.un("add", this.onAdd);
12435 this.store.un("remove", this.onRemove);
12436 this.store.un("update", this.onUpdate);
12437 this.store.un("clear", this.refresh);
12438 this.store.un("beforeload", this.onBeforeLoad);
12439 this.store.un("load", this.onLoad);
12440 this.store.un("loadexception", this.onLoad);
12444 store.on("datachanged", this.refresh, this);
12445 store.on("add", this.onAdd, this);
12446 store.on("remove", this.onRemove, this);
12447 store.on("update", this.onUpdate, this);
12448 store.on("clear", this.refresh, this);
12449 store.on("beforeload", this.onBeforeLoad, this);
12450 store.on("load", this.onLoad, this);
12451 store.on("loadexception", this.onLoad, this);
12459 * onbeforeLoad - masks the loading area.
12462 onBeforeLoad : function(store,opts)
12464 Roo.log('onBeforeLoad');
12466 this.el.update("");
12468 this.el.mask(this.mask ? this.mask : "Loading" );
12470 onLoad : function ()
12477 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12478 * @param {HTMLElement} node
12479 * @return {HTMLElement} The template node
12481 findItemFromChild : function(node){
12482 var el = this.dataName ?
12483 this.el.child('.roo-tpl-' + this.dataName,true) :
12486 if(!node || node.parentNode == el){
12489 var p = node.parentNode;
12490 while(p && p != el){
12491 if(p.parentNode == el){
12500 onClick : function(e){
12501 var item = this.findItemFromChild(e.getTarget());
12503 var index = this.indexOf(item);
12504 if(this.onItemClick(item, index, e) !== false){
12505 this.fireEvent("click", this, index, item, e);
12508 this.clearSelections();
12513 onContextMenu : function(e){
12514 var item = this.findItemFromChild(e.getTarget());
12516 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12521 onDblClick : function(e){
12522 var item = this.findItemFromChild(e.getTarget());
12524 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12528 onItemClick : function(item, index, e)
12530 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12533 if (this.toggleSelect) {
12534 var m = this.isSelected(item) ? 'unselect' : 'select';
12537 _t[m](item, true, false);
12540 if(this.multiSelect || this.singleSelect){
12541 if(this.multiSelect && e.shiftKey && this.lastSelection){
12542 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12544 this.select(item, this.multiSelect && e.ctrlKey);
12545 this.lastSelection = item;
12548 if(!this.tickable){
12549 e.preventDefault();
12557 * Get the number of selected nodes.
12560 getSelectionCount : function(){
12561 return this.selections.length;
12565 * Get the currently selected nodes.
12566 * @return {Array} An array of HTMLElements
12568 getSelectedNodes : function(){
12569 return this.selections;
12573 * Get the indexes of the selected nodes.
12576 getSelectedIndexes : function(){
12577 var indexes = [], s = this.selections;
12578 for(var i = 0, len = s.length; i < len; i++){
12579 indexes.push(s[i].nodeIndex);
12585 * Clear all selections
12586 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12588 clearSelections : function(suppressEvent){
12589 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12590 this.cmp.elements = this.selections;
12591 this.cmp.removeClass(this.selectedClass);
12592 this.selections = [];
12593 if(!suppressEvent){
12594 this.fireEvent("selectionchange", this, this.selections);
12600 * Returns true if the passed node is selected
12601 * @param {HTMLElement/Number} node The node or node index
12602 * @return {Boolean}
12604 isSelected : function(node){
12605 var s = this.selections;
12609 node = this.getNode(node);
12610 return s.indexOf(node) !== -1;
12615 * @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
12616 * @param {Boolean} keepExisting (optional) true to keep existing selections
12617 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12619 select : function(nodeInfo, keepExisting, suppressEvent){
12620 Roo.log('running Roo.View select!!!!!!!!!!!!!!!!!!!!!!1');
12621 if(nodeInfo instanceof Array){
12623 this.clearSelections(true);
12625 for(var i = 0, len = nodeInfo.length; i < len; i++){
12626 this.select(nodeInfo[i], true, true);
12630 var node = this.getNode(nodeInfo);
12631 if(!node || this.isSelected(node)){
12632 return; // already selected.
12635 this.clearSelections(true);
12638 Roo.log(this.parent);
12639 // var el = this.view.getNode(index);
12640 // if(el && !this.multiple && !this.tickable){
12641 // this.list.scrollChildIntoView(el, false);
12644 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12645 Roo.fly(node).addClass(this.selectedClass);
12646 this.selections.push(node);
12647 if(!suppressEvent){
12648 this.fireEvent("selectionchange", this, this.selections);
12656 * @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
12657 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12658 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12660 unselect : function(nodeInfo, keepExisting, suppressEvent)
12662 if(nodeInfo instanceof Array){
12663 Roo.each(this.selections, function(s) {
12664 this.unselect(s, nodeInfo);
12668 var node = this.getNode(nodeInfo);
12669 if(!node || !this.isSelected(node)){
12670 Roo.log("not selected");
12671 return; // not selected.
12675 Roo.each(this.selections, function(s) {
12677 Roo.fly(node).removeClass(this.selectedClass);
12684 this.selections= ns;
12685 this.fireEvent("selectionchange", this, this.selections);
12689 * Gets a template node.
12690 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12691 * @return {HTMLElement} The node or null if it wasn't found
12693 getNode : function(nodeInfo){
12694 if(typeof nodeInfo == "string"){
12695 return document.getElementById(nodeInfo);
12696 }else if(typeof nodeInfo == "number"){
12697 return this.nodes[nodeInfo];
12703 * Gets a range template nodes.
12704 * @param {Number} startIndex
12705 * @param {Number} endIndex
12706 * @return {Array} An array of nodes
12708 getNodes : function(start, end){
12709 var ns = this.nodes;
12710 start = start || 0;
12711 end = typeof end == "undefined" ? ns.length - 1 : end;
12714 for(var i = start; i <= end; i++){
12718 for(var i = start; i >= end; i--){
12726 * Finds the index of the passed node
12727 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12728 * @return {Number} The index of the node or -1
12730 indexOf : function(node){
12731 node = this.getNode(node);
12732 if(typeof node.nodeIndex == "number"){
12733 return node.nodeIndex;
12735 var ns = this.nodes;
12736 for(var i = 0, len = ns.length; i < len; i++){
12747 * based on jquery fullcalendar
12751 Roo.bootstrap = Roo.bootstrap || {};
12753 * @class Roo.bootstrap.Calendar
12754 * @extends Roo.bootstrap.Component
12755 * Bootstrap Calendar class
12756 * @cfg {Boolean} loadMask (true|false) default false
12757 * @cfg {Object} header generate the user specific header of the calendar, default false
12760 * Create a new Container
12761 * @param {Object} config The config object
12766 Roo.bootstrap.Calendar = function(config){
12767 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12771 * Fires when a date is selected
12772 * @param {DatePicker} this
12773 * @param {Date} date The selected date
12777 * @event monthchange
12778 * Fires when the displayed month changes
12779 * @param {DatePicker} this
12780 * @param {Date} date The selected month
12782 'monthchange': true,
12784 * @event evententer
12785 * Fires when mouse over an event
12786 * @param {Calendar} this
12787 * @param {event} Event
12789 'evententer': true,
12791 * @event eventleave
12792 * Fires when the mouse leaves an
12793 * @param {Calendar} this
12796 'eventleave': true,
12798 * @event eventclick
12799 * Fires when the mouse click an
12800 * @param {Calendar} this
12809 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12812 * @cfg {Number} startDay
12813 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12821 getAutoCreate : function(){
12824 var fc_button = function(name, corner, style, content ) {
12825 return Roo.apply({},{
12827 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12829 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12832 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12843 style : 'width:100%',
12850 cls : 'fc-header-left',
12852 fc_button('prev', 'left', 'arrow', '‹' ),
12853 fc_button('next', 'right', 'arrow', '›' ),
12854 { tag: 'span', cls: 'fc-header-space' },
12855 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12863 cls : 'fc-header-center',
12867 cls: 'fc-header-title',
12870 html : 'month / year'
12878 cls : 'fc-header-right',
12880 /* fc_button('month', 'left', '', 'month' ),
12881 fc_button('week', '', '', 'week' ),
12882 fc_button('day', 'right', '', 'day' )
12894 header = this.header;
12897 var cal_heads = function() {
12899 // fixme - handle this.
12901 for (var i =0; i < Date.dayNames.length; i++) {
12902 var d = Date.dayNames[i];
12905 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12906 html : d.substring(0,3)
12910 ret[0].cls += ' fc-first';
12911 ret[6].cls += ' fc-last';
12914 var cal_cell = function(n) {
12917 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12922 cls: 'fc-day-number',
12926 cls: 'fc-day-content',
12930 style: 'position: relative;' // height: 17px;
12942 var cal_rows = function() {
12945 for (var r = 0; r < 6; r++) {
12952 for (var i =0; i < Date.dayNames.length; i++) {
12953 var d = Date.dayNames[i];
12954 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12957 row.cn[0].cls+=' fc-first';
12958 row.cn[0].cn[0].style = 'min-height:90px';
12959 row.cn[6].cls+=' fc-last';
12963 ret[0].cls += ' fc-first';
12964 ret[4].cls += ' fc-prev-last';
12965 ret[5].cls += ' fc-last';
12972 cls: 'fc-border-separate',
12973 style : 'width:100%',
12981 cls : 'fc-first fc-last',
12999 cls : 'fc-content',
13000 style : "position: relative;",
13003 cls : 'fc-view fc-view-month fc-grid',
13004 style : 'position: relative',
13005 unselectable : 'on',
13008 cls : 'fc-event-container',
13009 style : 'position:absolute;z-index:8;top:0;left:0;'
13027 initEvents : function()
13030 throw "can not find store for calendar";
13036 style: "text-align:center",
13040 style: "background-color:white;width:50%;margin:250 auto",
13044 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13055 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13057 var size = this.el.select('.fc-content', true).first().getSize();
13058 this.maskEl.setSize(size.width, size.height);
13059 this.maskEl.enableDisplayMode("block");
13060 if(!this.loadMask){
13061 this.maskEl.hide();
13064 this.store = Roo.factory(this.store, Roo.data);
13065 this.store.on('load', this.onLoad, this);
13066 this.store.on('beforeload', this.onBeforeLoad, this);
13070 this.cells = this.el.select('.fc-day',true);
13071 //Roo.log(this.cells);
13072 this.textNodes = this.el.query('.fc-day-number');
13073 this.cells.addClassOnOver('fc-state-hover');
13075 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13076 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13077 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13078 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13080 this.on('monthchange', this.onMonthChange, this);
13082 this.update(new Date().clearTime());
13085 resize : function() {
13086 var sz = this.el.getSize();
13088 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13089 this.el.select('.fc-day-content div',true).setHeight(34);
13094 showPrevMonth : function(e){
13095 this.update(this.activeDate.add("mo", -1));
13097 showToday : function(e){
13098 this.update(new Date().clearTime());
13101 showNextMonth : function(e){
13102 this.update(this.activeDate.add("mo", 1));
13106 showPrevYear : function(){
13107 this.update(this.activeDate.add("y", -1));
13111 showNextYear : function(){
13112 this.update(this.activeDate.add("y", 1));
13117 update : function(date)
13119 var vd = this.activeDate;
13120 this.activeDate = date;
13121 // if(vd && this.el){
13122 // var t = date.getTime();
13123 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13124 // Roo.log('using add remove');
13126 // this.fireEvent('monthchange', this, date);
13128 // this.cells.removeClass("fc-state-highlight");
13129 // this.cells.each(function(c){
13130 // if(c.dateValue == t){
13131 // c.addClass("fc-state-highlight");
13132 // setTimeout(function(){
13133 // try{c.dom.firstChild.focus();}catch(e){}
13143 var days = date.getDaysInMonth();
13145 var firstOfMonth = date.getFirstDateOfMonth();
13146 var startingPos = firstOfMonth.getDay()-this.startDay;
13148 if(startingPos < this.startDay){
13152 var pm = date.add(Date.MONTH, -1);
13153 var prevStart = pm.getDaysInMonth()-startingPos;
13155 this.cells = this.el.select('.fc-day',true);
13156 this.textNodes = this.el.query('.fc-day-number');
13157 this.cells.addClassOnOver('fc-state-hover');
13159 var cells = this.cells.elements;
13160 var textEls = this.textNodes;
13162 Roo.each(cells, function(cell){
13163 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13166 days += startingPos;
13168 // convert everything to numbers so it's fast
13169 var day = 86400000;
13170 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13173 //Roo.log(prevStart);
13175 var today = new Date().clearTime().getTime();
13176 var sel = date.clearTime().getTime();
13177 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13178 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13179 var ddMatch = this.disabledDatesRE;
13180 var ddText = this.disabledDatesText;
13181 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13182 var ddaysText = this.disabledDaysText;
13183 var format = this.format;
13185 var setCellClass = function(cal, cell){
13189 //Roo.log('set Cell Class');
13191 var t = d.getTime();
13195 cell.dateValue = t;
13197 cell.className += " fc-today";
13198 cell.className += " fc-state-highlight";
13199 cell.title = cal.todayText;
13202 // disable highlight in other month..
13203 //cell.className += " fc-state-highlight";
13208 cell.className = " fc-state-disabled";
13209 cell.title = cal.minText;
13213 cell.className = " fc-state-disabled";
13214 cell.title = cal.maxText;
13218 if(ddays.indexOf(d.getDay()) != -1){
13219 cell.title = ddaysText;
13220 cell.className = " fc-state-disabled";
13223 if(ddMatch && format){
13224 var fvalue = d.dateFormat(format);
13225 if(ddMatch.test(fvalue)){
13226 cell.title = ddText.replace("%0", fvalue);
13227 cell.className = " fc-state-disabled";
13231 if (!cell.initialClassName) {
13232 cell.initialClassName = cell.dom.className;
13235 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13240 for(; i < startingPos; i++) {
13241 textEls[i].innerHTML = (++prevStart);
13242 d.setDate(d.getDate()+1);
13244 cells[i].className = "fc-past fc-other-month";
13245 setCellClass(this, cells[i]);
13250 for(; i < days; i++){
13251 intDay = i - startingPos + 1;
13252 textEls[i].innerHTML = (intDay);
13253 d.setDate(d.getDate()+1);
13255 cells[i].className = ''; // "x-date-active";
13256 setCellClass(this, cells[i]);
13260 for(; i < 42; i++) {
13261 textEls[i].innerHTML = (++extraDays);
13262 d.setDate(d.getDate()+1);
13264 cells[i].className = "fc-future fc-other-month";
13265 setCellClass(this, cells[i]);
13268 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13270 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13272 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13273 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13275 if(totalRows != 6){
13276 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13277 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13280 this.fireEvent('monthchange', this, date);
13284 if(!this.internalRender){
13285 var main = this.el.dom.firstChild;
13286 var w = main.offsetWidth;
13287 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13288 Roo.fly(main).setWidth(w);
13289 this.internalRender = true;
13290 // opera does not respect the auto grow header center column
13291 // then, after it gets a width opera refuses to recalculate
13292 // without a second pass
13293 if(Roo.isOpera && !this.secondPass){
13294 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13295 this.secondPass = true;
13296 this.update.defer(10, this, [date]);
13303 findCell : function(dt) {
13304 dt = dt.clearTime().getTime();
13306 this.cells.each(function(c){
13307 //Roo.log("check " +c.dateValue + '?=' + dt);
13308 if(c.dateValue == dt){
13318 findCells : function(ev) {
13319 var s = ev.start.clone().clearTime().getTime();
13321 var e= ev.end.clone().clearTime().getTime();
13324 this.cells.each(function(c){
13325 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13327 if(c.dateValue > e){
13330 if(c.dateValue < s){
13339 // findBestRow: function(cells)
13343 // for (var i =0 ; i < cells.length;i++) {
13344 // ret = Math.max(cells[i].rows || 0,ret);
13351 addItem : function(ev)
13353 // look for vertical location slot in
13354 var cells = this.findCells(ev);
13356 // ev.row = this.findBestRow(cells);
13358 // work out the location.
13362 for(var i =0; i < cells.length; i++) {
13364 cells[i].row = cells[0].row;
13367 cells[i].row = cells[i].row + 1;
13377 if (crow.start.getY() == cells[i].getY()) {
13379 crow.end = cells[i];
13396 cells[0].events.push(ev);
13398 this.calevents.push(ev);
13401 clearEvents: function() {
13403 if(!this.calevents){
13407 Roo.each(this.cells.elements, function(c){
13413 Roo.each(this.calevents, function(e) {
13414 Roo.each(e.els, function(el) {
13415 el.un('mouseenter' ,this.onEventEnter, this);
13416 el.un('mouseleave' ,this.onEventLeave, this);
13421 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13427 renderEvents: function()
13431 this.cells.each(function(c) {
13440 if(c.row != c.events.length){
13441 r = 4 - (4 - (c.row - c.events.length));
13444 c.events = ev.slice(0, r);
13445 c.more = ev.slice(r);
13447 if(c.more.length && c.more.length == 1){
13448 c.events.push(c.more.pop());
13451 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13455 this.cells.each(function(c) {
13457 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13460 for (var e = 0; e < c.events.length; e++){
13461 var ev = c.events[e];
13462 var rows = ev.rows;
13464 for(var i = 0; i < rows.length; i++) {
13466 // how many rows should it span..
13469 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13470 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13472 unselectable : "on",
13475 cls: 'fc-event-inner',
13479 // cls: 'fc-event-time',
13480 // html : cells.length > 1 ? '' : ev.time
13484 cls: 'fc-event-title',
13485 html : String.format('{0}', ev.title)
13492 cls: 'ui-resizable-handle ui-resizable-e',
13493 html : '  '
13500 cfg.cls += ' fc-event-start';
13502 if ((i+1) == rows.length) {
13503 cfg.cls += ' fc-event-end';
13506 var ctr = _this.el.select('.fc-event-container',true).first();
13507 var cg = ctr.createChild(cfg);
13509 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13510 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13512 var r = (c.more.length) ? 1 : 0;
13513 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13514 cg.setWidth(ebox.right - sbox.x -2);
13516 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13517 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13518 cg.on('click', _this.onEventClick, _this, ev);
13529 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13530 style : 'position: absolute',
13531 unselectable : "on",
13534 cls: 'fc-event-inner',
13538 cls: 'fc-event-title',
13546 cls: 'ui-resizable-handle ui-resizable-e',
13547 html : '  '
13553 var ctr = _this.el.select('.fc-event-container',true).first();
13554 var cg = ctr.createChild(cfg);
13556 var sbox = c.select('.fc-day-content',true).first().getBox();
13557 var ebox = c.select('.fc-day-content',true).first().getBox();
13559 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13560 cg.setWidth(ebox.right - sbox.x -2);
13562 cg.on('click', _this.onMoreEventClick, _this, c.more);
13572 onEventEnter: function (e, el,event,d) {
13573 this.fireEvent('evententer', this, el, event);
13576 onEventLeave: function (e, el,event,d) {
13577 this.fireEvent('eventleave', this, el, event);
13580 onEventClick: function (e, el,event,d) {
13581 this.fireEvent('eventclick', this, el, event);
13584 onMonthChange: function () {
13588 onMoreEventClick: function(e, el, more)
13592 this.calpopover.placement = 'right';
13593 this.calpopover.setTitle('More');
13595 this.calpopover.setContent('');
13597 var ctr = this.calpopover.el.select('.popover-content', true).first();
13599 Roo.each(more, function(m){
13601 cls : 'fc-event-hori fc-event-draggable',
13604 var cg = ctr.createChild(cfg);
13606 cg.on('click', _this.onEventClick, _this, m);
13609 this.calpopover.show(el);
13614 onLoad: function ()
13616 this.calevents = [];
13619 if(this.store.getCount() > 0){
13620 this.store.data.each(function(d){
13623 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13624 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13625 time : d.data.start_time,
13626 title : d.data.title,
13627 description : d.data.description,
13628 venue : d.data.venue
13633 this.renderEvents();
13635 if(this.calevents.length && this.loadMask){
13636 this.maskEl.hide();
13640 onBeforeLoad: function()
13642 this.clearEvents();
13644 this.maskEl.show();
13658 * @class Roo.bootstrap.Popover
13659 * @extends Roo.bootstrap.Component
13660 * Bootstrap Popover class
13661 * @cfg {String} html contents of the popover (or false to use children..)
13662 * @cfg {String} title of popover (or false to hide)
13663 * @cfg {String} placement how it is placed
13664 * @cfg {String} trigger click || hover (or false to trigger manually)
13665 * @cfg {String} over what (parent or false to trigger manually.)
13666 * @cfg {Number} delay - delay before showing
13669 * Create a new Popover
13670 * @param {Object} config The config object
13673 Roo.bootstrap.Popover = function(config){
13674 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13677 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13679 title: 'Fill in a title',
13682 placement : 'right',
13683 trigger : 'hover', // hover
13689 can_build_overlaid : false,
13691 getChildContainer : function()
13693 return this.el.select('.popover-content',true).first();
13696 getAutoCreate : function(){
13697 Roo.log('make popover?');
13699 cls : 'popover roo-dynamic',
13700 style: 'display:block',
13706 cls : 'popover-inner',
13710 cls: 'popover-title',
13714 cls : 'popover-content',
13725 setTitle: function(str)
13727 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13729 setContent: function(str)
13731 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13733 // as it get's added to the bottom of the page.
13734 onRender : function(ct, position)
13736 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13738 var cfg = Roo.apply({}, this.getAutoCreate());
13742 cfg.cls += ' ' + this.cls;
13745 cfg.style = this.style;
13747 Roo.log("adding to ")
13748 this.el = Roo.get(document.body).createChild(cfg, position);
13754 initEvents : function()
13756 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13757 this.el.enableDisplayMode('block');
13759 if (this.over === false) {
13762 if (this.triggers === false) {
13765 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13766 var triggers = this.trigger ? this.trigger.split(' ') : [];
13767 Roo.each(triggers, function(trigger) {
13769 if (trigger == 'click') {
13770 on_el.on('click', this.toggle, this);
13771 } else if (trigger != 'manual') {
13772 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13773 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13775 on_el.on(eventIn ,this.enter, this);
13776 on_el.on(eventOut, this.leave, this);
13787 toggle : function () {
13788 this.hoverState == 'in' ? this.leave() : this.enter();
13791 enter : function () {
13794 clearTimeout(this.timeout);
13796 this.hoverState = 'in'
13798 if (!this.delay || !this.delay.show) {
13803 this.timeout = setTimeout(function () {
13804 if (_t.hoverState == 'in') {
13807 }, this.delay.show)
13809 leave : function() {
13810 clearTimeout(this.timeout);
13812 this.hoverState = 'out'
13814 if (!this.delay || !this.delay.hide) {
13819 this.timeout = setTimeout(function () {
13820 if (_t.hoverState == 'out') {
13823 }, this.delay.hide)
13826 show : function (on_el)
13829 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13832 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13833 if (this.html !== false) {
13834 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13836 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13837 if (!this.title.length) {
13838 this.el.select('.popover-title',true).hide();
13841 var placement = typeof this.placement == 'function' ?
13842 this.placement.call(this, this.el, on_el) :
13845 var autoToken = /\s?auto?\s?/i;
13846 var autoPlace = autoToken.test(placement);
13848 placement = placement.replace(autoToken, '') || 'top';
13852 //this.el.setXY([0,0]);
13854 this.el.dom.style.display='block';
13855 this.el.addClass(placement);
13857 //this.el.appendTo(on_el);
13859 var p = this.getPosition();
13860 var box = this.el.getBox();
13865 var align = Roo.bootstrap.Popover.alignment[placement]
13866 this.el.alignTo(on_el, align[0],align[1]);
13867 //var arrow = this.el.select('.arrow',true).first();
13868 //arrow.set(align[2],
13870 this.el.addClass('in');
13871 this.hoverState = null;
13873 if (this.el.hasClass('fade')) {
13880 this.el.setXY([0,0]);
13881 this.el.removeClass('in');
13888 Roo.bootstrap.Popover.alignment = {
13889 'left' : ['r-l', [-10,0], 'right'],
13890 'right' : ['l-r', [10,0], 'left'],
13891 'bottom' : ['t-b', [0,10], 'top'],
13892 'top' : [ 'b-t', [0,-10], 'bottom']
13903 * @class Roo.bootstrap.Progress
13904 * @extends Roo.bootstrap.Component
13905 * Bootstrap Progress class
13906 * @cfg {Boolean} striped striped of the progress bar
13907 * @cfg {Boolean} active animated of the progress bar
13911 * Create a new Progress
13912 * @param {Object} config The config object
13915 Roo.bootstrap.Progress = function(config){
13916 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13919 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13924 getAutoCreate : function(){
13932 cfg.cls += ' progress-striped';
13936 cfg.cls += ' active';
13955 * @class Roo.bootstrap.ProgressBar
13956 * @extends Roo.bootstrap.Component
13957 * Bootstrap ProgressBar class
13958 * @cfg {Number} aria_valuenow aria-value now
13959 * @cfg {Number} aria_valuemin aria-value min
13960 * @cfg {Number} aria_valuemax aria-value max
13961 * @cfg {String} label label for the progress bar
13962 * @cfg {String} panel (success | info | warning | danger )
13963 * @cfg {String} role role of the progress bar
13964 * @cfg {String} sr_only text
13968 * Create a new ProgressBar
13969 * @param {Object} config The config object
13972 Roo.bootstrap.ProgressBar = function(config){
13973 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13976 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13980 aria_valuemax : 100,
13986 getAutoCreate : function()
13991 cls: 'progress-bar',
13992 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14004 cfg.role = this.role;
14007 if(this.aria_valuenow){
14008 cfg['aria-valuenow'] = this.aria_valuenow;
14011 if(this.aria_valuemin){
14012 cfg['aria-valuemin'] = this.aria_valuemin;
14015 if(this.aria_valuemax){
14016 cfg['aria-valuemax'] = this.aria_valuemax;
14019 if(this.label && !this.sr_only){
14020 cfg.html = this.label;
14024 cfg.cls += ' progress-bar-' + this.panel;
14030 update : function(aria_valuenow)
14032 this.aria_valuenow = aria_valuenow;
14034 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14049 * @class Roo.bootstrap.TabGroup
14050 * @extends Roo.bootstrap.Column
14051 * Bootstrap Column class
14052 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14053 * @cfg {Boolean} carousel true to make the group behave like a carousel
14056 * Create a new TabGroup
14057 * @param {Object} config The config object
14060 Roo.bootstrap.TabGroup = function(config){
14061 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14063 this.navId = Roo.id();
14066 Roo.bootstrap.TabGroup.register(this);
14070 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14073 transition : false,
14075 getAutoCreate : function()
14077 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14079 cfg.cls += ' tab-content';
14081 if (this.carousel) {
14082 cfg.cls += ' carousel slide';
14084 cls : 'carousel-inner'
14091 getChildContainer : function()
14093 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14097 * register a Navigation item
14098 * @param {Roo.bootstrap.NavItem} the navitem to add
14100 register : function(item)
14102 this.tabs.push( item);
14103 item.navId = this.navId; // not really needed..
14107 getActivePanel : function()
14110 Roo.each(this.tabs, function(t) {
14120 getPanelByName : function(n)
14123 Roo.each(this.tabs, function(t) {
14124 if (t.tabId == n) {
14132 indexOfPanel : function(p)
14135 Roo.each(this.tabs, function(t,i) {
14136 if (t.tabId == p.tabId) {
14145 * show a specific panel
14146 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14147 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14149 showPanel : function (pan)
14152 if (typeof(pan) == 'number') {
14153 pan = this.tabs[pan];
14155 if (typeof(pan) == 'string') {
14156 pan = this.getPanelByName(pan);
14158 if (pan.tabId == this.getActivePanel().tabId) {
14161 var cur = this.getActivePanel();
14163 if (false === cur.fireEvent('beforedeactivate')) {
14167 if (this.carousel) {
14168 this.transition = true;
14169 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14170 var lr = dir == 'next' ? 'left' : 'right';
14171 pan.el.addClass(dir); // or prev
14172 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14173 cur.el.addClass(lr); // or right
14174 pan.el.addClass(lr);
14177 cur.el.on('transitionend', function() {
14178 Roo.log("trans end?");
14180 pan.el.removeClass([lr,dir]);
14181 pan.setActive(true);
14183 cur.el.removeClass([lr]);
14184 cur.setActive(false);
14186 _this.transition = false;
14188 }, this, { single: true } );
14192 cur.setActive(false);
14193 pan.setActive(true);
14197 showPanelNext : function()
14199 var i = this.indexOfPanel(this.getActivePanel());
14200 if (i > this.tabs.length) {
14203 this.showPanel(this.tabs[i+1]);
14205 showPanelPrev : function()
14207 var i = this.indexOfPanel(this.getActivePanel());
14211 this.showPanel(this.tabs[i-1]);
14222 Roo.apply(Roo.bootstrap.TabGroup, {
14226 * register a Navigation Group
14227 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14229 register : function(navgrp)
14231 this.groups[navgrp.navId] = navgrp;
14235 * fetch a Navigation Group based on the navigation ID
14236 * if one does not exist , it will get created.
14237 * @param {string} the navgroup to add
14238 * @returns {Roo.bootstrap.NavGroup} the navgroup
14240 get: function(navId) {
14241 if (typeof(this.groups[navId]) == 'undefined') {
14242 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14244 return this.groups[navId] ;
14259 * @class Roo.bootstrap.TabPanel
14260 * @extends Roo.bootstrap.Component
14261 * Bootstrap TabPanel class
14262 * @cfg {Boolean} active panel active
14263 * @cfg {String} html panel content
14264 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14265 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14269 * Create a new TabPanel
14270 * @param {Object} config The config object
14273 Roo.bootstrap.TabPanel = function(config){
14274 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14278 * Fires when the active status changes
14279 * @param {Roo.bootstrap.TabPanel} this
14280 * @param {Boolean} state the new state
14285 * @event beforedeactivate
14286 * Fires before a tab is de-activated - can be used to do validation on a form.
14287 * @param {Roo.bootstrap.TabPanel} this
14288 * @return {Boolean} false if there is an error
14291 'beforedeactivate': true
14294 this.tabId = this.tabId || Roo.id();
14298 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14305 getAutoCreate : function(){
14308 // item is needed for carousel - not sure if it has any effect otherwise
14309 cls: 'tab-pane item',
14310 html: this.html || ''
14314 cfg.cls += ' active';
14318 cfg.tabId = this.tabId;
14325 initEvents: function()
14327 Roo.log('-------- init events on tab panel ---------');
14329 var p = this.parent();
14330 this.navId = this.navId || p.navId;
14332 if (typeof(this.navId) != 'undefined') {
14333 // not really needed.. but just in case.. parent should be a NavGroup.
14334 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14335 Roo.log(['register', tg, this]);
14341 onRender : function(ct, position)
14343 // Roo.log("Call onRender: " + this.xtype);
14345 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14353 setActive: function(state)
14355 Roo.log("panel - set active " + this.tabId + "=" + state);
14357 this.active = state;
14359 this.el.removeClass('active');
14361 } else if (!this.el.hasClass('active')) {
14362 this.el.addClass('active');
14364 this.fireEvent('changed', this, state);
14381 * @class Roo.bootstrap.DateField
14382 * @extends Roo.bootstrap.Input
14383 * Bootstrap DateField class
14384 * @cfg {Number} weekStart default 0
14385 * @cfg {Number} weekStart default 0
14386 * @cfg {Number} viewMode default empty, (months|years)
14387 * @cfg {Number} minViewMode default empty, (months|years)
14388 * @cfg {Number} startDate default -Infinity
14389 * @cfg {Number} endDate default Infinity
14390 * @cfg {Boolean} todayHighlight default false
14391 * @cfg {Boolean} todayBtn default false
14392 * @cfg {Boolean} calendarWeeks default false
14393 * @cfg {Object} daysOfWeekDisabled default empty
14395 * @cfg {Boolean} keyboardNavigation default true
14396 * @cfg {String} language default en
14399 * Create a new DateField
14400 * @param {Object} config The config object
14403 Roo.bootstrap.DateField = function(config){
14404 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14408 * Fires when this field show.
14409 * @param {Roo.bootstrap.DateField} this
14410 * @param {Mixed} date The date value
14415 * Fires when this field hide.
14416 * @param {Roo.bootstrap.DateField} this
14417 * @param {Mixed} date The date value
14422 * Fires when select a date.
14423 * @param {Roo.bootstrap.DateField} this
14424 * @param {Mixed} date The date value
14430 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14433 * @cfg {String} format
14434 * The default date format string which can be overriden for localization support. The format must be
14435 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14439 * @cfg {String} altFormats
14440 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14441 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14443 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14451 todayHighlight : false,
14457 keyboardNavigation: true,
14459 calendarWeeks: false,
14461 startDate: -Infinity,
14465 daysOfWeekDisabled: [],
14469 UTCDate: function()
14471 return new Date(Date.UTC.apply(Date, arguments));
14474 UTCToday: function()
14476 var today = new Date();
14477 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14480 getDate: function() {
14481 var d = this.getUTCDate();
14482 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14485 getUTCDate: function() {
14489 setDate: function(d) {
14490 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14493 setUTCDate: function(d) {
14495 this.setValue(this.formatDate(this.date));
14498 onRender: function(ct, position)
14501 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14503 this.language = this.language || 'en';
14504 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14505 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14507 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14508 this.format = this.format || 'm/d/y';
14509 this.isInline = false;
14510 this.isInput = true;
14511 this.component = this.el.select('.add-on', true).first() || false;
14512 this.component = (this.component && this.component.length === 0) ? false : this.component;
14513 this.hasInput = this.component && this.inputEL().length;
14515 if (typeof(this.minViewMode === 'string')) {
14516 switch (this.minViewMode) {
14518 this.minViewMode = 1;
14521 this.minViewMode = 2;
14524 this.minViewMode = 0;
14529 if (typeof(this.viewMode === 'string')) {
14530 switch (this.viewMode) {
14543 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14545 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14547 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14549 this.picker().on('mousedown', this.onMousedown, this);
14550 this.picker().on('click', this.onClick, this);
14552 this.picker().addClass('datepicker-dropdown');
14554 this.startViewMode = this.viewMode;
14557 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14558 if(!this.calendarWeeks){
14563 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14564 v.attr('colspan', function(i, val){
14565 return parseInt(val) + 1;
14570 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14572 this.setStartDate(this.startDate);
14573 this.setEndDate(this.endDate);
14575 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14582 if(this.isInline) {
14587 picker : function()
14589 return this.pickerEl;
14590 // return this.el.select('.datepicker', true).first();
14593 fillDow: function()
14595 var dowCnt = this.weekStart;
14604 if(this.calendarWeeks){
14612 while (dowCnt < this.weekStart + 7) {
14616 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14620 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14623 fillMonths: function()
14626 var months = this.picker().select('>.datepicker-months td', true).first();
14628 months.dom.innerHTML = '';
14634 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14637 months.createChild(month);
14644 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;
14646 if (this.date < this.startDate) {
14647 this.viewDate = new Date(this.startDate);
14648 } else if (this.date > this.endDate) {
14649 this.viewDate = new Date(this.endDate);
14651 this.viewDate = new Date(this.date);
14659 var d = new Date(this.viewDate),
14660 year = d.getUTCFullYear(),
14661 month = d.getUTCMonth(),
14662 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14663 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14664 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14665 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14666 currentDate = this.date && this.date.valueOf(),
14667 today = this.UTCToday();
14669 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14671 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14673 // this.picker.select('>tfoot th.today').
14674 // .text(dates[this.language].today)
14675 // .toggle(this.todayBtn !== false);
14677 this.updateNavArrows();
14680 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14682 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14684 prevMonth.setUTCDate(day);
14686 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14688 var nextMonth = new Date(prevMonth);
14690 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14692 nextMonth = nextMonth.valueOf();
14694 var fillMonths = false;
14696 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14698 while(prevMonth.valueOf() < nextMonth) {
14701 if (prevMonth.getUTCDay() === this.weekStart) {
14703 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14711 if(this.calendarWeeks){
14712 // ISO 8601: First week contains first thursday.
14713 // ISO also states week starts on Monday, but we can be more abstract here.
14715 // Start of current week: based on weekstart/current date
14716 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14717 // Thursday of this week
14718 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14719 // First Thursday of year, year from thursday
14720 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14721 // Calendar week: ms between thursdays, div ms per day, div 7 days
14722 calWeek = (th - yth) / 864e5 / 7 + 1;
14724 fillMonths.cn.push({
14732 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14734 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14737 if (this.todayHighlight &&
14738 prevMonth.getUTCFullYear() == today.getFullYear() &&
14739 prevMonth.getUTCMonth() == today.getMonth() &&
14740 prevMonth.getUTCDate() == today.getDate()) {
14741 clsName += ' today';
14744 if (currentDate && prevMonth.valueOf() === currentDate) {
14745 clsName += ' active';
14748 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14749 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14750 clsName += ' disabled';
14753 fillMonths.cn.push({
14755 cls: 'day ' + clsName,
14756 html: prevMonth.getDate()
14759 prevMonth.setDate(prevMonth.getDate()+1);
14762 var currentYear = this.date && this.date.getUTCFullYear();
14763 var currentMonth = this.date && this.date.getUTCMonth();
14765 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14767 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14768 v.removeClass('active');
14770 if(currentYear === year && k === currentMonth){
14771 v.addClass('active');
14774 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14775 v.addClass('disabled');
14781 year = parseInt(year/10, 10) * 10;
14783 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14785 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14788 for (var i = -1; i < 11; i++) {
14789 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14791 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14799 showMode: function(dir)
14802 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14804 Roo.each(this.picker().select('>div',true).elements, function(v){
14805 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14808 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14813 if(this.isInline) return;
14815 this.picker().removeClass(['bottom', 'top']);
14817 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14819 * place to the top of element!
14823 this.picker().addClass('top');
14824 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14829 this.picker().addClass('bottom');
14831 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14834 parseDate : function(value)
14836 if(!value || value instanceof Date){
14839 var v = Date.parseDate(value, this.format);
14840 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
14841 v = Date.parseDate(value, 'Y-m-d');
14843 if(!v && this.altFormats){
14844 if(!this.altFormatsArray){
14845 this.altFormatsArray = this.altFormats.split("|");
14847 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14848 v = Date.parseDate(value, this.altFormatsArray[i]);
14854 formatDate : function(date, fmt)
14856 return (!date || !(date instanceof Date)) ?
14857 date : date.dateFormat(fmt || this.format);
14860 onFocus : function()
14862 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14866 onBlur : function()
14868 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14870 var d = this.inputEl().getValue();
14879 this.picker().show();
14883 this.fireEvent('show', this, this.date);
14888 if(this.isInline) return;
14889 this.picker().hide();
14890 this.viewMode = this.startViewMode;
14893 this.fireEvent('hide', this, this.date);
14897 onMousedown: function(e)
14899 e.stopPropagation();
14900 e.preventDefault();
14905 Roo.bootstrap.DateField.superclass.keyup.call(this);
14909 setValue: function(v)
14912 // v can be a string or a date..
14915 var d = new Date(this.parseDate(v) ).clearTime();
14919 if(isNaN(d.getTime())){
14920 this.date = this.viewDate = '';
14921 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14925 v = this.formatDate(d);
14927 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14929 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14933 this.fireEvent('select', this, this.date);
14937 getValue: function()
14939 return this.formatDate(this.date);
14942 fireKey: function(e)
14944 if (!this.picker().isVisible()){
14945 if (e.keyCode == 27) // allow escape to hide and re-show picker
14950 var dateChanged = false,
14952 newDate, newViewDate;
14957 e.preventDefault();
14961 if (!this.keyboardNavigation) break;
14962 dir = e.keyCode == 37 ? -1 : 1;
14965 newDate = this.moveYear(this.date, dir);
14966 newViewDate = this.moveYear(this.viewDate, dir);
14967 } else if (e.shiftKey){
14968 newDate = this.moveMonth(this.date, dir);
14969 newViewDate = this.moveMonth(this.viewDate, dir);
14971 newDate = new Date(this.date);
14972 newDate.setUTCDate(this.date.getUTCDate() + dir);
14973 newViewDate = new Date(this.viewDate);
14974 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14976 if (this.dateWithinRange(newDate)){
14977 this.date = newDate;
14978 this.viewDate = newViewDate;
14979 this.setValue(this.formatDate(this.date));
14981 e.preventDefault();
14982 dateChanged = true;
14987 if (!this.keyboardNavigation) break;
14988 dir = e.keyCode == 38 ? -1 : 1;
14990 newDate = this.moveYear(this.date, dir);
14991 newViewDate = this.moveYear(this.viewDate, dir);
14992 } else if (e.shiftKey){
14993 newDate = this.moveMonth(this.date, dir);
14994 newViewDate = this.moveMonth(this.viewDate, dir);
14996 newDate = new Date(this.date);
14997 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14998 newViewDate = new Date(this.viewDate);
14999 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15001 if (this.dateWithinRange(newDate)){
15002 this.date = newDate;
15003 this.viewDate = newViewDate;
15004 this.setValue(this.formatDate(this.date));
15006 e.preventDefault();
15007 dateChanged = true;
15011 this.setValue(this.formatDate(this.date));
15013 e.preventDefault();
15016 this.setValue(this.formatDate(this.date));
15030 onClick: function(e)
15032 e.stopPropagation();
15033 e.preventDefault();
15035 var target = e.getTarget();
15037 if(target.nodeName.toLowerCase() === 'i'){
15038 target = Roo.get(target).dom.parentNode;
15041 var nodeName = target.nodeName;
15042 var className = target.className;
15043 var html = target.innerHTML;
15044 //Roo.log(nodeName);
15046 switch(nodeName.toLowerCase()) {
15048 switch(className) {
15054 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15055 switch(this.viewMode){
15057 this.viewDate = this.moveMonth(this.viewDate, dir);
15061 this.viewDate = this.moveYear(this.viewDate, dir);
15067 var date = new Date();
15068 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15070 this.setValue(this.formatDate(this.date));
15077 if (className.indexOf('disabled') < 0) {
15078 this.viewDate.setUTCDate(1);
15079 if (className.indexOf('month') > -1) {
15080 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15082 var year = parseInt(html, 10) || 0;
15083 this.viewDate.setUTCFullYear(year);
15092 //Roo.log(className);
15093 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15094 var day = parseInt(html, 10) || 1;
15095 var year = this.viewDate.getUTCFullYear(),
15096 month = this.viewDate.getUTCMonth();
15098 if (className.indexOf('old') > -1) {
15105 } else if (className.indexOf('new') > -1) {
15113 //Roo.log([year,month,day]);
15114 this.date = this.UTCDate(year, month, day,0,0,0,0);
15115 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15117 //Roo.log(this.formatDate(this.date));
15118 this.setValue(this.formatDate(this.date));
15125 setStartDate: function(startDate)
15127 this.startDate = startDate || -Infinity;
15128 if (this.startDate !== -Infinity) {
15129 this.startDate = this.parseDate(this.startDate);
15132 this.updateNavArrows();
15135 setEndDate: function(endDate)
15137 this.endDate = endDate || Infinity;
15138 if (this.endDate !== Infinity) {
15139 this.endDate = this.parseDate(this.endDate);
15142 this.updateNavArrows();
15145 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15147 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15148 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15149 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15151 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15152 return parseInt(d, 10);
15155 this.updateNavArrows();
15158 updateNavArrows: function()
15160 var d = new Date(this.viewDate),
15161 year = d.getUTCFullYear(),
15162 month = d.getUTCMonth();
15164 Roo.each(this.picker().select('.prev', true).elements, function(v){
15166 switch (this.viewMode) {
15169 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15175 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15182 Roo.each(this.picker().select('.next', true).elements, function(v){
15184 switch (this.viewMode) {
15187 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15193 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15201 moveMonth: function(date, dir)
15203 if (!dir) return date;
15204 var new_date = new Date(date.valueOf()),
15205 day = new_date.getUTCDate(),
15206 month = new_date.getUTCMonth(),
15207 mag = Math.abs(dir),
15209 dir = dir > 0 ? 1 : -1;
15212 // If going back one month, make sure month is not current month
15213 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15215 return new_date.getUTCMonth() == month;
15217 // If going forward one month, make sure month is as expected
15218 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15220 return new_date.getUTCMonth() != new_month;
15222 new_month = month + dir;
15223 new_date.setUTCMonth(new_month);
15224 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15225 if (new_month < 0 || new_month > 11)
15226 new_month = (new_month + 12) % 12;
15228 // For magnitudes >1, move one month at a time...
15229 for (var i=0; i<mag; i++)
15230 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15231 new_date = this.moveMonth(new_date, dir);
15232 // ...then reset the day, keeping it in the new month
15233 new_month = new_date.getUTCMonth();
15234 new_date.setUTCDate(day);
15236 return new_month != new_date.getUTCMonth();
15239 // Common date-resetting loop -- if date is beyond end of month, make it
15242 new_date.setUTCDate(--day);
15243 new_date.setUTCMonth(new_month);
15248 moveYear: function(date, dir)
15250 return this.moveMonth(date, dir*12);
15253 dateWithinRange: function(date)
15255 return date >= this.startDate && date <= this.endDate;
15261 this.picker().remove();
15266 Roo.apply(Roo.bootstrap.DateField, {
15277 html: '<i class="fa fa-arrow-left"/>'
15287 html: '<i class="fa fa-arrow-right"/>'
15329 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15330 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15331 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15332 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15333 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15346 navFnc: 'FullYear',
15351 navFnc: 'FullYear',
15356 Roo.apply(Roo.bootstrap.DateField, {
15360 cls: 'datepicker dropdown-menu',
15364 cls: 'datepicker-days',
15368 cls: 'table-condensed',
15370 Roo.bootstrap.DateField.head,
15374 Roo.bootstrap.DateField.footer
15381 cls: 'datepicker-months',
15385 cls: 'table-condensed',
15387 Roo.bootstrap.DateField.head,
15388 Roo.bootstrap.DateField.content,
15389 Roo.bootstrap.DateField.footer
15396 cls: 'datepicker-years',
15400 cls: 'table-condensed',
15402 Roo.bootstrap.DateField.head,
15403 Roo.bootstrap.DateField.content,
15404 Roo.bootstrap.DateField.footer
15423 * @class Roo.bootstrap.TimeField
15424 * @extends Roo.bootstrap.Input
15425 * Bootstrap DateField class
15429 * Create a new TimeField
15430 * @param {Object} config The config object
15433 Roo.bootstrap.TimeField = function(config){
15434 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15438 * Fires when this field show.
15439 * @param {Roo.bootstrap.DateField} this
15440 * @param {Mixed} date The date value
15445 * Fires when this field hide.
15446 * @param {Roo.bootstrap.DateField} this
15447 * @param {Mixed} date The date value
15452 * Fires when select a date.
15453 * @param {Roo.bootstrap.DateField} this
15454 * @param {Mixed} date The date value
15460 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15463 * @cfg {String} format
15464 * The default time format string which can be overriden for localization support. The format must be
15465 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15469 onRender: function(ct, position)
15472 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15474 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15476 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15478 this.pop = this.picker().select('>.datepicker-time',true).first();
15479 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15481 this.picker().on('mousedown', this.onMousedown, this);
15482 this.picker().on('click', this.onClick, this);
15484 this.picker().addClass('datepicker-dropdown');
15489 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15490 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15491 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15492 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15493 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15494 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15498 fireKey: function(e){
15499 if (!this.picker().isVisible()){
15500 if (e.keyCode == 27) // allow escape to hide and re-show picker
15505 e.preventDefault();
15513 this.onTogglePeriod();
15516 this.onIncrementMinutes();
15519 this.onDecrementMinutes();
15528 onClick: function(e) {
15529 e.stopPropagation();
15530 e.preventDefault();
15533 picker : function()
15535 return this.el.select('.datepicker', true).first();
15538 fillTime: function()
15540 var time = this.pop.select('tbody', true).first();
15542 time.dom.innerHTML = '';
15557 cls: 'hours-up glyphicon glyphicon-chevron-up'
15577 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15598 cls: 'timepicker-hour',
15613 cls: 'timepicker-minute',
15628 cls: 'btn btn-primary period',
15650 cls: 'hours-down glyphicon glyphicon-chevron-down'
15670 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15688 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15695 var hours = this.time.getHours();
15696 var minutes = this.time.getMinutes();
15709 hours = hours - 12;
15713 hours = '0' + hours;
15717 minutes = '0' + minutes;
15720 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15721 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15722 this.pop.select('button', true).first().dom.innerHTML = period;
15728 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15730 var cls = ['bottom'];
15732 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15739 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15744 this.picker().addClass(cls.join('-'));
15748 Roo.each(cls, function(c){
15750 _this.picker().setTop(_this.inputEl().getHeight());
15754 _this.picker().setTop(0 - _this.picker().getHeight());
15759 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15763 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15770 onFocus : function()
15772 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15776 onBlur : function()
15778 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15784 this.picker().show();
15789 this.fireEvent('show', this, this.date);
15794 this.picker().hide();
15797 this.fireEvent('hide', this, this.date);
15800 setTime : function()
15803 this.setValue(this.time.format(this.format));
15805 this.fireEvent('select', this, this.date);
15810 onMousedown: function(e){
15811 e.stopPropagation();
15812 e.preventDefault();
15815 onIncrementHours: function()
15817 Roo.log('onIncrementHours');
15818 this.time = this.time.add(Date.HOUR, 1);
15823 onDecrementHours: function()
15825 Roo.log('onDecrementHours');
15826 this.time = this.time.add(Date.HOUR, -1);
15830 onIncrementMinutes: function()
15832 Roo.log('onIncrementMinutes');
15833 this.time = this.time.add(Date.MINUTE, 1);
15837 onDecrementMinutes: function()
15839 Roo.log('onDecrementMinutes');
15840 this.time = this.time.add(Date.MINUTE, -1);
15844 onTogglePeriod: function()
15846 Roo.log('onTogglePeriod');
15847 this.time = this.time.add(Date.HOUR, 12);
15854 Roo.apply(Roo.bootstrap.TimeField, {
15884 cls: 'btn btn-info ok',
15896 Roo.apply(Roo.bootstrap.TimeField, {
15900 cls: 'datepicker dropdown-menu',
15904 cls: 'datepicker-time',
15908 cls: 'table-condensed',
15910 Roo.bootstrap.TimeField.content,
15911 Roo.bootstrap.TimeField.footer
15930 * @class Roo.bootstrap.CheckBox
15931 * @extends Roo.bootstrap.Input
15932 * Bootstrap CheckBox class
15934 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15935 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15936 * @cfg {String} boxLabel The text that appears beside the checkbox
15937 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15938 * @cfg {Boolean} checked initnal the element
15942 * Create a new CheckBox
15943 * @param {Object} config The config object
15946 Roo.bootstrap.CheckBox = function(config){
15947 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15952 * Fires when the element is checked or unchecked.
15953 * @param {Roo.bootstrap.CheckBox} this This input
15954 * @param {Boolean} checked The new checked value
15960 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15962 inputType: 'checkbox',
15969 getAutoCreate : function()
15971 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15977 cfg.cls = 'form-group checkbox' //input-group
15985 type : this.inputType,
15986 value : (!this.checked) ? this.valueOff : this.inputValue,
15987 cls : 'roo-checkbox', //'form-box',
15988 placeholder : this.placeholder || ''
15992 if (this.weight) { // Validity check?
15993 cfg.cls += " checkbox-" + this.weight;
15996 if (this.disabled) {
15997 input.disabled=true;
16001 input.checked = this.checked;
16005 input.name = this.name;
16009 input.cls += ' input-' + this.size;
16013 ['xs','sm','md','lg'].map(function(size){
16014 if (settings[size]) {
16015 cfg.cls += ' col-' + size + '-' + settings[size];
16021 var inputblock = input;
16026 if (this.before || this.after) {
16029 cls : 'input-group',
16033 inputblock.cn.push({
16035 cls : 'input-group-addon',
16039 inputblock.cn.push(input);
16041 inputblock.cn.push({
16043 cls : 'input-group-addon',
16050 if (align ==='left' && this.fieldLabel.length) {
16051 Roo.log("left and has label");
16057 cls : 'control-label col-md-' + this.labelWidth,
16058 html : this.fieldLabel
16062 cls : "col-md-" + (12 - this.labelWidth),
16069 } else if ( this.fieldLabel.length) {
16074 tag: this.boxLabel ? 'span' : 'label',
16076 cls: 'control-label box-input-label',
16077 //cls : 'input-group-addon',
16078 html : this.fieldLabel
16088 Roo.log(" no label && no align");
16089 cfg.cn = [ inputblock ] ;
16098 html: this.boxLabel
16110 * return the real input element.
16112 inputEl: function ()
16114 return this.el.select('input.roo-checkbox',true).first();
16119 return this.el.select('label.control-label',true).first();
16122 initEvents : function()
16124 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16126 this.inputEl().on('click', this.onClick, this);
16130 onClick : function()
16132 this.setChecked(!this.checked);
16135 setChecked : function(state,suppressEvent)
16137 this.checked = state;
16139 this.inputEl().dom.checked = state;
16141 if(suppressEvent !== true){
16142 this.fireEvent('check', this, state);
16145 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16149 setValue : function(v,suppressEvent)
16151 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16165 * @class Roo.bootstrap.Radio
16166 * @extends Roo.bootstrap.CheckBox
16167 * Bootstrap Radio class
16170 * Create a new Radio
16171 * @param {Object} config The config object
16174 Roo.bootstrap.Radio = function(config){
16175 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16179 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16181 inputType: 'radio',
16185 getAutoCreate : function()
16187 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16193 cfg.cls = 'form-group radio' //input-group
16198 type : this.inputType,
16199 value : (!this.checked) ? this.valueOff : this.inputValue,
16201 placeholder : this.placeholder || ''
16204 if (this.weight) { // Validity check?
16205 cfg.cls += " radio-" + this.weight;
16207 if (this.disabled) {
16208 input.disabled=true;
16212 input.checked = this.checked;
16216 input.name = this.name;
16220 input.cls += ' input-' + this.size;
16224 ['xs','sm','md','lg'].map(function(size){
16225 if (settings[size]) {
16226 cfg.cls += ' col-' + size + '-' + settings[size];
16230 var inputblock = input;
16232 if (this.before || this.after) {
16235 cls : 'input-group',
16239 inputblock.cn.push({
16241 cls : 'input-group-addon',
16245 inputblock.cn.push(input);
16247 inputblock.cn.push({
16249 cls : 'input-group-addon',
16256 if (align ==='left' && this.fieldLabel.length) {
16257 Roo.log("left and has label");
16263 cls : 'control-label col-md-' + this.labelWidth,
16264 html : this.fieldLabel
16268 cls : "col-md-" + (12 - this.labelWidth),
16275 } else if ( this.fieldLabel.length) {
16282 cls: 'control-label box-input-label',
16283 //cls : 'input-group-addon',
16284 html : this.fieldLabel
16294 Roo.log(" no label && no align");
16309 html: this.boxLabel
16316 inputEl: function ()
16318 return this.el.select('input.roo-radio',true).first();
16320 onClick : function()
16322 this.setChecked(true);
16325 setChecked : function(state,suppressEvent)
16328 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16329 v.dom.checked = false;
16333 this.checked = state;
16334 this.inputEl().dom.checked = state;
16336 if(suppressEvent !== true){
16337 this.fireEvent('check', this, state);
16340 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16344 getGroupValue : function()
16347 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16348 if(v.dom.checked == true){
16349 value = v.dom.value;
16357 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16358 * @return {Mixed} value The field value
16360 getValue : function(){
16361 return this.getGroupValue();
16367 //<script type="text/javascript">
16370 * Based Ext JS Library 1.1.1
16371 * Copyright(c) 2006-2007, Ext JS, LLC.
16377 * @class Roo.HtmlEditorCore
16378 * @extends Roo.Component
16379 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16381 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16384 Roo.HtmlEditorCore = function(config){
16387 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16392 * @event initialize
16393 * Fires when the editor is fully initialized (including the iframe)
16394 * @param {Roo.HtmlEditorCore} this
16399 * Fires when the editor is first receives the focus. Any insertion must wait
16400 * until after this event.
16401 * @param {Roo.HtmlEditorCore} this
16405 * @event beforesync
16406 * Fires before the textarea is updated with content from the editor iframe. Return false
16407 * to cancel the sync.
16408 * @param {Roo.HtmlEditorCore} this
16409 * @param {String} html
16413 * @event beforepush
16414 * Fires before the iframe editor is updated with content from the textarea. Return false
16415 * to cancel the push.
16416 * @param {Roo.HtmlEditorCore} this
16417 * @param {String} html
16422 * Fires when the textarea is updated with content from the editor iframe.
16423 * @param {Roo.HtmlEditorCore} this
16424 * @param {String} html
16429 * Fires when the iframe editor is updated with content from the textarea.
16430 * @param {Roo.HtmlEditorCore} this
16431 * @param {String} html
16436 * @event editorevent
16437 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16438 * @param {Roo.HtmlEditorCore} this
16443 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16445 // defaults : white / black...
16446 this.applyBlacklists();
16453 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16457 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16463 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16468 * @cfg {Number} height (in pixels)
16472 * @cfg {Number} width (in pixels)
16477 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16480 stylesheets: false,
16485 // private properties
16486 validationEvent : false,
16488 initialized : false,
16490 sourceEditMode : false,
16491 onFocus : Roo.emptyFn,
16493 hideMode:'offsets',
16497 // blacklist + whitelisted elements..
16504 * Protected method that will not generally be called directly. It
16505 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16506 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16508 getDocMarkup : function(){
16511 Roo.log(this.stylesheets);
16513 // inherit styels from page...??
16514 if (this.stylesheets === false) {
16516 Roo.get(document.head).select('style').each(function(node) {
16517 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16520 Roo.get(document.head).select('link').each(function(node) {
16521 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16524 } else if (!this.stylesheets.length) {
16526 st = '<style type="text/css">' +
16527 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16530 Roo.each(this.stylesheets, function(s) {
16531 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16536 st += '<style type="text/css">' +
16537 'IMG { cursor: pointer } ' +
16541 return '<html><head>' + st +
16542 //<style type="text/css">' +
16543 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16545 ' </head><body class="roo-htmleditor-body"></body></html>';
16549 onRender : function(ct, position)
16552 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16553 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16556 this.el.dom.style.border = '0 none';
16557 this.el.dom.setAttribute('tabIndex', -1);
16558 this.el.addClass('x-hidden hide');
16562 if(Roo.isIE){ // fix IE 1px bogus margin
16563 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16567 this.frameId = Roo.id();
16571 var iframe = this.owner.wrap.createChild({
16573 cls: 'form-control', // bootstrap..
16575 name: this.frameId,
16576 frameBorder : 'no',
16577 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16582 this.iframe = iframe.dom;
16584 this.assignDocWin();
16586 this.doc.designMode = 'on';
16589 this.doc.write(this.getDocMarkup());
16593 var task = { // must defer to wait for browser to be ready
16595 //console.log("run task?" + this.doc.readyState);
16596 this.assignDocWin();
16597 if(this.doc.body || this.doc.readyState == 'complete'){
16599 this.doc.designMode="on";
16603 Roo.TaskMgr.stop(task);
16604 this.initEditor.defer(10, this);
16611 Roo.TaskMgr.start(task);
16618 onResize : function(w, h)
16620 Roo.log('resize: ' +w + ',' + h );
16621 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16625 if(typeof w == 'number'){
16627 this.iframe.style.width = w + 'px';
16629 if(typeof h == 'number'){
16631 this.iframe.style.height = h + 'px';
16633 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16640 * Toggles the editor between standard and source edit mode.
16641 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16643 toggleSourceEdit : function(sourceEditMode){
16645 this.sourceEditMode = sourceEditMode === true;
16647 if(this.sourceEditMode){
16649 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16652 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16653 //this.iframe.className = '';
16656 //this.setSize(this.owner.wrap.getSize());
16657 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16664 * Protected method that will not generally be called directly. If you need/want
16665 * custom HTML cleanup, this is the method you should override.
16666 * @param {String} html The HTML to be cleaned
16667 * return {String} The cleaned HTML
16669 cleanHtml : function(html){
16670 html = String(html);
16671 if(html.length > 5){
16672 if(Roo.isSafari){ // strip safari nonsense
16673 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16676 if(html == ' '){
16683 * HTML Editor -> Textarea
16684 * Protected method that will not generally be called directly. Syncs the contents
16685 * of the editor iframe with the textarea.
16687 syncValue : function(){
16688 if(this.initialized){
16689 var bd = (this.doc.body || this.doc.documentElement);
16690 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16691 var html = bd.innerHTML;
16693 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16694 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16696 html = '<div style="'+m[0]+'">' + html + '</div>';
16699 html = this.cleanHtml(html);
16700 // fix up the special chars.. normaly like back quotes in word...
16701 // however we do not want to do this with chinese..
16702 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16703 var cc = b.charCodeAt();
16705 (cc >= 0x4E00 && cc < 0xA000 ) ||
16706 (cc >= 0x3400 && cc < 0x4E00 ) ||
16707 (cc >= 0xf900 && cc < 0xfb00 )
16713 if(this.owner.fireEvent('beforesync', this, html) !== false){
16714 this.el.dom.value = html;
16715 this.owner.fireEvent('sync', this, html);
16721 * Protected method that will not generally be called directly. Pushes the value of the textarea
16722 * into the iframe editor.
16724 pushValue : function(){
16725 if(this.initialized){
16726 var v = this.el.dom.value.trim();
16728 // if(v.length < 1){
16732 if(this.owner.fireEvent('beforepush', this, v) !== false){
16733 var d = (this.doc.body || this.doc.documentElement);
16735 this.cleanUpPaste();
16736 this.el.dom.value = d.innerHTML;
16737 this.owner.fireEvent('push', this, v);
16743 deferFocus : function(){
16744 this.focus.defer(10, this);
16748 focus : function(){
16749 if(this.win && !this.sourceEditMode){
16756 assignDocWin: function()
16758 var iframe = this.iframe;
16761 this.doc = iframe.contentWindow.document;
16762 this.win = iframe.contentWindow;
16764 // if (!Roo.get(this.frameId)) {
16767 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16768 // this.win = Roo.get(this.frameId).dom.contentWindow;
16770 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16774 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16775 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16780 initEditor : function(){
16781 //console.log("INIT EDITOR");
16782 this.assignDocWin();
16786 this.doc.designMode="on";
16788 this.doc.write(this.getDocMarkup());
16791 var dbody = (this.doc.body || this.doc.documentElement);
16792 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16793 // this copies styles from the containing element into thsi one..
16794 // not sure why we need all of this..
16795 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16797 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16798 //ss['background-attachment'] = 'fixed'; // w3c
16799 dbody.bgProperties = 'fixed'; // ie
16800 //Roo.DomHelper.applyStyles(dbody, ss);
16801 Roo.EventManager.on(this.doc, {
16802 //'mousedown': this.onEditorEvent,
16803 'mouseup': this.onEditorEvent,
16804 'dblclick': this.onEditorEvent,
16805 'click': this.onEditorEvent,
16806 'keyup': this.onEditorEvent,
16811 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16813 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16814 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16816 this.initialized = true;
16818 this.owner.fireEvent('initialize', this);
16823 onDestroy : function(){
16829 //for (var i =0; i < this.toolbars.length;i++) {
16830 // // fixme - ask toolbars for heights?
16831 // this.toolbars[i].onDestroy();
16834 //this.wrap.dom.innerHTML = '';
16835 //this.wrap.remove();
16840 onFirstFocus : function(){
16842 this.assignDocWin();
16845 this.activated = true;
16848 if(Roo.isGecko){ // prevent silly gecko errors
16850 var s = this.win.getSelection();
16851 if(!s.focusNode || s.focusNode.nodeType != 3){
16852 var r = s.getRangeAt(0);
16853 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16858 this.execCmd('useCSS', true);
16859 this.execCmd('styleWithCSS', false);
16862 this.owner.fireEvent('activate', this);
16866 adjustFont: function(btn){
16867 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16868 //if(Roo.isSafari){ // safari
16871 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16872 if(Roo.isSafari){ // safari
16873 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16874 v = (v < 10) ? 10 : v;
16875 v = (v > 48) ? 48 : v;
16876 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16881 v = Math.max(1, v+adjust);
16883 this.execCmd('FontSize', v );
16886 onEditorEvent : function(e){
16887 this.owner.fireEvent('editorevent', this, e);
16888 // this.updateToolbar();
16889 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16892 insertTag : function(tg)
16894 // could be a bit smarter... -> wrap the current selected tRoo..
16895 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16897 range = this.createRange(this.getSelection());
16898 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16899 wrappingNode.appendChild(range.extractContents());
16900 range.insertNode(wrappingNode);
16907 this.execCmd("formatblock", tg);
16911 insertText : function(txt)
16915 var range = this.createRange();
16916 range.deleteContents();
16917 //alert(Sender.getAttribute('label'));
16919 range.insertNode(this.doc.createTextNode(txt));
16925 * Executes a Midas editor command on the editor document and performs necessary focus and
16926 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16927 * @param {String} cmd The Midas command
16928 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16930 relayCmd : function(cmd, value){
16932 this.execCmd(cmd, value);
16933 this.owner.fireEvent('editorevent', this);
16934 //this.updateToolbar();
16935 this.owner.deferFocus();
16939 * Executes a Midas editor command directly on the editor document.
16940 * For visual commands, you should use {@link #relayCmd} instead.
16941 * <b>This should only be called after the editor is initialized.</b>
16942 * @param {String} cmd The Midas command
16943 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16945 execCmd : function(cmd, value){
16946 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16953 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16955 * @param {String} text | dom node..
16957 insertAtCursor : function(text)
16962 if(!this.activated){
16968 var r = this.doc.selection.createRange();
16979 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16983 // from jquery ui (MIT licenced)
16985 var win = this.win;
16987 if (win.getSelection && win.getSelection().getRangeAt) {
16988 range = win.getSelection().getRangeAt(0);
16989 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16990 range.insertNode(node);
16991 } else if (win.document.selection && win.document.selection.createRange) {
16992 // no firefox support
16993 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16994 win.document.selection.createRange().pasteHTML(txt);
16996 // no firefox support
16997 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16998 this.execCmd('InsertHTML', txt);
17007 mozKeyPress : function(e){
17009 var c = e.getCharCode(), cmd;
17012 c = String.fromCharCode(c).toLowerCase();
17026 this.cleanUpPaste.defer(100, this);
17034 e.preventDefault();
17042 fixKeys : function(){ // load time branching for fastest keydown performance
17044 return function(e){
17045 var k = e.getKey(), r;
17048 r = this.doc.selection.createRange();
17051 r.pasteHTML('    ');
17058 r = this.doc.selection.createRange();
17060 var target = r.parentElement();
17061 if(!target || target.tagName.toLowerCase() != 'li'){
17063 r.pasteHTML('<br />');
17069 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17070 this.cleanUpPaste.defer(100, this);
17076 }else if(Roo.isOpera){
17077 return function(e){
17078 var k = e.getKey();
17082 this.execCmd('InsertHTML','    ');
17085 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17086 this.cleanUpPaste.defer(100, this);
17091 }else if(Roo.isSafari){
17092 return function(e){
17093 var k = e.getKey();
17097 this.execCmd('InsertText','\t');
17101 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17102 this.cleanUpPaste.defer(100, this);
17110 getAllAncestors: function()
17112 var p = this.getSelectedNode();
17115 a.push(p); // push blank onto stack..
17116 p = this.getParentElement();
17120 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17124 a.push(this.doc.body);
17128 lastSelNode : false,
17131 getSelection : function()
17133 this.assignDocWin();
17134 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17137 getSelectedNode: function()
17139 // this may only work on Gecko!!!
17141 // should we cache this!!!!
17146 var range = this.createRange(this.getSelection()).cloneRange();
17149 var parent = range.parentElement();
17151 var testRange = range.duplicate();
17152 testRange.moveToElementText(parent);
17153 if (testRange.inRange(range)) {
17156 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17159 parent = parent.parentElement;
17164 // is ancestor a text element.
17165 var ac = range.commonAncestorContainer;
17166 if (ac.nodeType == 3) {
17167 ac = ac.parentNode;
17170 var ar = ac.childNodes;
17173 var other_nodes = [];
17174 var has_other_nodes = false;
17175 for (var i=0;i<ar.length;i++) {
17176 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17179 // fullly contained node.
17181 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17186 // probably selected..
17187 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17188 other_nodes.push(ar[i]);
17192 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17197 has_other_nodes = true;
17199 if (!nodes.length && other_nodes.length) {
17200 nodes= other_nodes;
17202 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17208 createRange: function(sel)
17210 // this has strange effects when using with
17211 // top toolbar - not sure if it's a great idea.
17212 //this.editor.contentWindow.focus();
17213 if (typeof sel != "undefined") {
17215 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17217 return this.doc.createRange();
17220 return this.doc.createRange();
17223 getParentElement: function()
17226 this.assignDocWin();
17227 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17229 var range = this.createRange(sel);
17232 var p = range.commonAncestorContainer;
17233 while (p.nodeType == 3) { // text node
17244 * Range intersection.. the hard stuff...
17248 * [ -- selected range --- ]
17252 * if end is before start or hits it. fail.
17253 * if start is after end or hits it fail.
17255 * if either hits (but other is outside. - then it's not
17261 // @see http://www.thismuchiknow.co.uk/?p=64.
17262 rangeIntersectsNode : function(range, node)
17264 var nodeRange = node.ownerDocument.createRange();
17266 nodeRange.selectNode(node);
17268 nodeRange.selectNodeContents(node);
17271 var rangeStartRange = range.cloneRange();
17272 rangeStartRange.collapse(true);
17274 var rangeEndRange = range.cloneRange();
17275 rangeEndRange.collapse(false);
17277 var nodeStartRange = nodeRange.cloneRange();
17278 nodeStartRange.collapse(true);
17280 var nodeEndRange = nodeRange.cloneRange();
17281 nodeEndRange.collapse(false);
17283 return rangeStartRange.compareBoundaryPoints(
17284 Range.START_TO_START, nodeEndRange) == -1 &&
17285 rangeEndRange.compareBoundaryPoints(
17286 Range.START_TO_START, nodeStartRange) == 1;
17290 rangeCompareNode : function(range, node)
17292 var nodeRange = node.ownerDocument.createRange();
17294 nodeRange.selectNode(node);
17296 nodeRange.selectNodeContents(node);
17300 range.collapse(true);
17302 nodeRange.collapse(true);
17304 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17305 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17307 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17309 var nodeIsBefore = ss == 1;
17310 var nodeIsAfter = ee == -1;
17312 if (nodeIsBefore && nodeIsAfter)
17314 if (!nodeIsBefore && nodeIsAfter)
17315 return 1; //right trailed.
17317 if (nodeIsBefore && !nodeIsAfter)
17318 return 2; // left trailed.
17323 // private? - in a new class?
17324 cleanUpPaste : function()
17326 // cleans up the whole document..
17327 Roo.log('cleanuppaste');
17329 this.cleanUpChildren(this.doc.body);
17330 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17331 if (clean != this.doc.body.innerHTML) {
17332 this.doc.body.innerHTML = clean;
17337 cleanWordChars : function(input) {// change the chars to hex code
17338 var he = Roo.HtmlEditorCore;
17340 var output = input;
17341 Roo.each(he.swapCodes, function(sw) {
17342 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17344 output = output.replace(swapper, sw[1]);
17351 cleanUpChildren : function (n)
17353 if (!n.childNodes.length) {
17356 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17357 this.cleanUpChild(n.childNodes[i]);
17364 cleanUpChild : function (node)
17367 //console.log(node);
17368 if (node.nodeName == "#text") {
17369 // clean up silly Windows -- stuff?
17372 if (node.nodeName == "#comment") {
17373 node.parentNode.removeChild(node);
17374 // clean up silly Windows -- stuff?
17377 var lcname = node.tagName.toLowerCase();
17378 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17379 // whitelist of tags..
17381 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17383 node.parentNode.removeChild(node);
17388 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17390 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17391 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17393 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17394 // remove_keep_children = true;
17397 if (remove_keep_children) {
17398 this.cleanUpChildren(node);
17399 // inserts everything just before this node...
17400 while (node.childNodes.length) {
17401 var cn = node.childNodes[0];
17402 node.removeChild(cn);
17403 node.parentNode.insertBefore(cn, node);
17405 node.parentNode.removeChild(node);
17409 if (!node.attributes || !node.attributes.length) {
17410 this.cleanUpChildren(node);
17414 function cleanAttr(n,v)
17417 if (v.match(/^\./) || v.match(/^\//)) {
17420 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17423 if (v.match(/^#/)) {
17426 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17427 node.removeAttribute(n);
17431 var cwhite = this.cwhite;
17432 var cblack = this.cblack;
17434 function cleanStyle(n,v)
17436 if (v.match(/expression/)) { //XSS?? should we even bother..
17437 node.removeAttribute(n);
17441 var parts = v.split(/;/);
17444 Roo.each(parts, function(p) {
17445 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17449 var l = p.split(':').shift().replace(/\s+/g,'');
17450 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17452 if ( cwhite.length && cblack.indexOf(l) > -1) {
17453 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17454 //node.removeAttribute(n);
17458 // only allow 'c whitelisted system attributes'
17459 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17460 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17461 //node.removeAttribute(n);
17471 if (clean.length) {
17472 node.setAttribute(n, clean.join(';'));
17474 node.removeAttribute(n);
17480 for (var i = node.attributes.length-1; i > -1 ; i--) {
17481 var a = node.attributes[i];
17484 if (a.name.toLowerCase().substr(0,2)=='on') {
17485 node.removeAttribute(a.name);
17488 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17489 node.removeAttribute(a.name);
17492 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17493 cleanAttr(a.name,a.value); // fixme..
17496 if (a.name == 'style') {
17497 cleanStyle(a.name,a.value);
17500 /// clean up MS crap..
17501 // tecnically this should be a list of valid class'es..
17504 if (a.name == 'class') {
17505 if (a.value.match(/^Mso/)) {
17506 node.className = '';
17509 if (a.value.match(/body/)) {
17510 node.className = '';
17521 this.cleanUpChildren(node);
17526 * Clean up MS wordisms...
17528 cleanWord : function(node)
17531 var cleanWordChildren = function()
17533 if (!node.childNodes.length) {
17536 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17537 _t.cleanWord(node.childNodes[i]);
17543 this.cleanWord(this.doc.body);
17546 if (node.nodeName == "#text") {
17547 // clean up silly Windows -- stuff?
17550 if (node.nodeName == "#comment") {
17551 node.parentNode.removeChild(node);
17552 // clean up silly Windows -- stuff?
17556 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17557 node.parentNode.removeChild(node);
17561 // remove - but keep children..
17562 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17563 while (node.childNodes.length) {
17564 var cn = node.childNodes[0];
17565 node.removeChild(cn);
17566 node.parentNode.insertBefore(cn, node);
17568 node.parentNode.removeChild(node);
17569 cleanWordChildren();
17573 if (node.className.length) {
17575 var cn = node.className.split(/\W+/);
17577 Roo.each(cn, function(cls) {
17578 if (cls.match(/Mso[a-zA-Z]+/)) {
17583 node.className = cna.length ? cna.join(' ') : '';
17585 node.removeAttribute("class");
17589 if (node.hasAttribute("lang")) {
17590 node.removeAttribute("lang");
17593 if (node.hasAttribute("style")) {
17595 var styles = node.getAttribute("style").split(";");
17597 Roo.each(styles, function(s) {
17598 if (!s.match(/:/)) {
17601 var kv = s.split(":");
17602 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17605 // what ever is left... we allow.
17608 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17609 if (!nstyle.length) {
17610 node.removeAttribute('style');
17614 cleanWordChildren();
17618 domToHTML : function(currentElement, depth, nopadtext) {
17620 depth = depth || 0;
17621 nopadtext = nopadtext || false;
17623 if (!currentElement) {
17624 return this.domToHTML(this.doc.body);
17627 //Roo.log(currentElement);
17629 var allText = false;
17630 var nodeName = currentElement.nodeName;
17631 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17633 if (nodeName == '#text') {
17634 return currentElement.nodeValue;
17639 if (nodeName != 'BODY') {
17642 // Prints the node tagName, such as <A>, <IMG>, etc
17645 for(i = 0; i < currentElement.attributes.length;i++) {
17647 var aname = currentElement.attributes.item(i).name;
17648 if (!currentElement.attributes.item(i).value.length) {
17651 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17654 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17663 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17666 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17671 // Traverse the tree
17673 var currentElementChild = currentElement.childNodes.item(i);
17674 var allText = true;
17675 var innerHTML = '';
17677 while (currentElementChild) {
17678 // Formatting code (indent the tree so it looks nice on the screen)
17679 var nopad = nopadtext;
17680 if (lastnode == 'SPAN') {
17684 if (currentElementChild.nodeName == '#text') {
17685 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17686 if (!nopad && toadd.length > 80) {
17687 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17689 innerHTML += toadd;
17692 currentElementChild = currentElement.childNodes.item(i);
17698 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17700 // Recursively traverse the tree structure of the child node
17701 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17702 lastnode = currentElementChild.nodeName;
17704 currentElementChild=currentElement.childNodes.item(i);
17710 // The remaining code is mostly for formatting the tree
17711 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17716 ret+= "</"+tagName+">";
17722 applyBlacklists : function()
17724 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17725 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17729 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17730 if (b.indexOf(tag) > -1) {
17733 this.white.push(tag);
17737 Roo.each(w, function(tag) {
17738 if (b.indexOf(tag) > -1) {
17741 if (this.white.indexOf(tag) > -1) {
17744 this.white.push(tag);
17749 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17750 if (w.indexOf(tag) > -1) {
17753 this.black.push(tag);
17757 Roo.each(b, function(tag) {
17758 if (w.indexOf(tag) > -1) {
17761 if (this.black.indexOf(tag) > -1) {
17764 this.black.push(tag);
17769 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
17770 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
17774 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17775 if (b.indexOf(tag) > -1) {
17778 this.cwhite.push(tag);
17782 Roo.each(w, function(tag) {
17783 if (b.indexOf(tag) > -1) {
17786 if (this.cwhite.indexOf(tag) > -1) {
17789 this.cwhite.push(tag);
17794 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
17795 if (w.indexOf(tag) > -1) {
17798 this.cblack.push(tag);
17802 Roo.each(b, function(tag) {
17803 if (w.indexOf(tag) > -1) {
17806 if (this.cblack.indexOf(tag) > -1) {
17809 this.cblack.push(tag);
17814 // hide stuff that is not compatible
17828 * @event specialkey
17832 * @cfg {String} fieldClass @hide
17835 * @cfg {String} focusClass @hide
17838 * @cfg {String} autoCreate @hide
17841 * @cfg {String} inputType @hide
17844 * @cfg {String} invalidClass @hide
17847 * @cfg {String} invalidText @hide
17850 * @cfg {String} msgFx @hide
17853 * @cfg {String} validateOnBlur @hide
17857 Roo.HtmlEditorCore.white = [
17858 'area', 'br', 'img', 'input', 'hr', 'wbr',
17860 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17861 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17862 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17863 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17864 'table', 'ul', 'xmp',
17866 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17869 'dir', 'menu', 'ol', 'ul', 'dl',
17875 Roo.HtmlEditorCore.black = [
17876 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17878 'base', 'basefont', 'bgsound', 'blink', 'body',
17879 'frame', 'frameset', 'head', 'html', 'ilayer',
17880 'iframe', 'layer', 'link', 'meta', 'object',
17881 'script', 'style' ,'title', 'xml' // clean later..
17883 Roo.HtmlEditorCore.clean = [
17884 'script', 'style', 'title', 'xml'
17886 Roo.HtmlEditorCore.remove = [
17891 Roo.HtmlEditorCore.ablack = [
17895 Roo.HtmlEditorCore.aclean = [
17896 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17900 Roo.HtmlEditorCore.pwhite= [
17901 'http', 'https', 'mailto'
17904 // white listed style attributes.
17905 Roo.HtmlEditorCore.cwhite= [
17906 // 'text-align', /// default is to allow most things..
17912 // black listed style attributes.
17913 Roo.HtmlEditorCore.cblack= [
17914 // 'font-size' -- this can be set by the project
17918 Roo.HtmlEditorCore.swapCodes =[
17937 * @class Roo.bootstrap.HtmlEditor
17938 * @extends Roo.bootstrap.TextArea
17939 * Bootstrap HtmlEditor class
17942 * Create a new HtmlEditor
17943 * @param {Object} config The config object
17946 Roo.bootstrap.HtmlEditor = function(config){
17947 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17948 if (!this.toolbars) {
17949 this.toolbars = [];
17951 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17954 * @event initialize
17955 * Fires when the editor is fully initialized (including the iframe)
17956 * @param {HtmlEditor} this
17961 * Fires when the editor is first receives the focus. Any insertion must wait
17962 * until after this event.
17963 * @param {HtmlEditor} this
17967 * @event beforesync
17968 * Fires before the textarea is updated with content from the editor iframe. Return false
17969 * to cancel the sync.
17970 * @param {HtmlEditor} this
17971 * @param {String} html
17975 * @event beforepush
17976 * Fires before the iframe editor is updated with content from the textarea. Return false
17977 * to cancel the push.
17978 * @param {HtmlEditor} this
17979 * @param {String} html
17984 * Fires when the textarea is updated with content from the editor iframe.
17985 * @param {HtmlEditor} this
17986 * @param {String} html
17991 * Fires when the iframe editor is updated with content from the textarea.
17992 * @param {HtmlEditor} this
17993 * @param {String} html
17997 * @event editmodechange
17998 * Fires when the editor switches edit modes
17999 * @param {HtmlEditor} this
18000 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18002 editmodechange: true,
18004 * @event editorevent
18005 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18006 * @param {HtmlEditor} this
18010 * @event firstfocus
18011 * Fires when on first focus - needed by toolbars..
18012 * @param {HtmlEditor} this
18017 * Auto save the htmlEditor value as a file into Events
18018 * @param {HtmlEditor} this
18022 * @event savedpreview
18023 * preview the saved version of htmlEditor
18024 * @param {HtmlEditor} this
18031 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18035 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18040 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18045 * @cfg {Number} height (in pixels)
18049 * @cfg {Number} width (in pixels)
18054 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18057 stylesheets: false,
18062 // private properties
18063 validationEvent : false,
18065 initialized : false,
18068 onFocus : Roo.emptyFn,
18070 hideMode:'offsets',
18073 tbContainer : false,
18075 toolbarContainer :function() {
18076 return this.wrap.select('.x-html-editor-tb',true).first();
18080 * Protected method that will not generally be called directly. It
18081 * is called when the editor creates its toolbar. Override this method if you need to
18082 * add custom toolbar buttons.
18083 * @param {HtmlEditor} editor
18085 createToolbar : function(){
18087 Roo.log("create toolbars");
18089 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18090 this.toolbars[0].render(this.toolbarContainer());
18094 // if (!editor.toolbars || !editor.toolbars.length) {
18095 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18098 // for (var i =0 ; i < editor.toolbars.length;i++) {
18099 // editor.toolbars[i] = Roo.factory(
18100 // typeof(editor.toolbars[i]) == 'string' ?
18101 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18102 // Roo.bootstrap.HtmlEditor);
18103 // editor.toolbars[i].init(editor);
18109 onRender : function(ct, position)
18111 // Roo.log("Call onRender: " + this.xtype);
18113 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18115 this.wrap = this.inputEl().wrap({
18116 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18119 this.editorcore.onRender(ct, position);
18121 if (this.resizable) {
18122 this.resizeEl = new Roo.Resizable(this.wrap, {
18126 minHeight : this.height,
18127 height: this.height,
18128 handles : this.resizable,
18131 resize : function(r, w, h) {
18132 _t.onResize(w,h); // -something
18138 this.createToolbar(this);
18141 if(!this.width && this.resizable){
18142 this.setSize(this.wrap.getSize());
18144 if (this.resizeEl) {
18145 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18146 // should trigger onReize..
18152 onResize : function(w, h)
18154 Roo.log('resize: ' +w + ',' + h );
18155 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18159 if(this.inputEl() ){
18160 if(typeof w == 'number'){
18161 var aw = w - this.wrap.getFrameWidth('lr');
18162 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18165 if(typeof h == 'number'){
18166 var tbh = -11; // fixme it needs to tool bar size!
18167 for (var i =0; i < this.toolbars.length;i++) {
18168 // fixme - ask toolbars for heights?
18169 tbh += this.toolbars[i].el.getHeight();
18170 //if (this.toolbars[i].footer) {
18171 // tbh += this.toolbars[i].footer.el.getHeight();
18179 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18180 ah -= 5; // knock a few pixes off for look..
18181 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18185 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18186 this.editorcore.onResize(ew,eh);
18191 * Toggles the editor between standard and source edit mode.
18192 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18194 toggleSourceEdit : function(sourceEditMode)
18196 this.editorcore.toggleSourceEdit(sourceEditMode);
18198 if(this.editorcore.sourceEditMode){
18199 Roo.log('editor - showing textarea');
18202 // Roo.log(this.syncValue());
18204 this.inputEl().removeClass(['hide', 'x-hidden']);
18205 this.inputEl().dom.removeAttribute('tabIndex');
18206 this.inputEl().focus();
18208 Roo.log('editor - hiding textarea');
18210 // Roo.log(this.pushValue());
18213 this.inputEl().addClass(['hide', 'x-hidden']);
18214 this.inputEl().dom.setAttribute('tabIndex', -1);
18215 //this.deferFocus();
18218 if(this.resizable){
18219 this.setSize(this.wrap.getSize());
18222 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18225 // private (for BoxComponent)
18226 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18228 // private (for BoxComponent)
18229 getResizeEl : function(){
18233 // private (for BoxComponent)
18234 getPositionEl : function(){
18239 initEvents : function(){
18240 this.originalValue = this.getValue();
18244 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18247 // markInvalid : Roo.emptyFn,
18249 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18252 // clearInvalid : Roo.emptyFn,
18254 setValue : function(v){
18255 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18256 this.editorcore.pushValue();
18261 deferFocus : function(){
18262 this.focus.defer(10, this);
18266 focus : function(){
18267 this.editorcore.focus();
18273 onDestroy : function(){
18279 for (var i =0; i < this.toolbars.length;i++) {
18280 // fixme - ask toolbars for heights?
18281 this.toolbars[i].onDestroy();
18284 this.wrap.dom.innerHTML = '';
18285 this.wrap.remove();
18290 onFirstFocus : function(){
18291 //Roo.log("onFirstFocus");
18292 this.editorcore.onFirstFocus();
18293 for (var i =0; i < this.toolbars.length;i++) {
18294 this.toolbars[i].onFirstFocus();
18300 syncValue : function()
18302 this.editorcore.syncValue();
18305 pushValue : function()
18307 this.editorcore.pushValue();
18311 // hide stuff that is not compatible
18325 * @event specialkey
18329 * @cfg {String} fieldClass @hide
18332 * @cfg {String} focusClass @hide
18335 * @cfg {String} autoCreate @hide
18338 * @cfg {String} inputType @hide
18341 * @cfg {String} invalidClass @hide
18344 * @cfg {String} invalidText @hide
18347 * @cfg {String} msgFx @hide
18350 * @cfg {String} validateOnBlur @hide
18359 Roo.namespace('Roo.bootstrap.htmleditor');
18361 * @class Roo.bootstrap.HtmlEditorToolbar1
18366 new Roo.bootstrap.HtmlEditor({
18369 new Roo.bootstrap.HtmlEditorToolbar1({
18370 disable : { fonts: 1 , format: 1, ..., ... , ...],
18376 * @cfg {Object} disable List of elements to disable..
18377 * @cfg {Array} btns List of additional buttons.
18381 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18384 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18387 Roo.apply(this, config);
18389 // default disabled, based on 'good practice'..
18390 this.disable = this.disable || {};
18391 Roo.applyIf(this.disable, {
18394 specialElements : true
18396 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18398 this.editor = config.editor;
18399 this.editorcore = config.editor.editorcore;
18401 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18403 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18404 // dont call parent... till later.
18406 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18411 editorcore : false,
18416 "h1","h2","h3","h4","h5","h6",
18418 "abbr", "acronym", "address", "cite", "samp", "var",
18422 onRender : function(ct, position)
18424 // Roo.log("Call onRender: " + this.xtype);
18426 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18428 this.el.dom.style.marginBottom = '0';
18430 var editorcore = this.editorcore;
18431 var editor= this.editor;
18434 var btn = function(id,cmd , toggle, handler){
18436 var event = toggle ? 'toggle' : 'click';
18441 xns: Roo.bootstrap,
18444 enableToggle:toggle !== false,
18446 pressed : toggle ? false : null,
18449 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18450 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18459 xns: Roo.bootstrap,
18460 glyphicon : 'font',
18464 xns: Roo.bootstrap,
18468 Roo.each(this.formats, function(f) {
18469 style.menu.items.push({
18471 xns: Roo.bootstrap,
18472 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18477 editorcore.insertTag(this.tagname);
18484 children.push(style);
18487 btn('bold',false,true);
18488 btn('italic',false,true);
18489 btn('align-left', 'justifyleft',true);
18490 btn('align-center', 'justifycenter',true);
18491 btn('align-right' , 'justifyright',true);
18492 btn('link', false, false, function(btn) {
18493 //Roo.log("create link?");
18494 var url = prompt(this.createLinkText, this.defaultLinkValue);
18495 if(url && url != 'http:/'+'/'){
18496 this.editorcore.relayCmd('createlink', url);
18499 btn('list','insertunorderedlist',true);
18500 btn('pencil', false,true, function(btn){
18503 this.toggleSourceEdit(btn.pressed);
18509 xns: Roo.bootstrap,
18514 xns: Roo.bootstrap,
18519 cog.menu.items.push({
18521 xns: Roo.bootstrap,
18522 html : Clean styles,
18527 editorcore.insertTag(this.tagname);
18536 this.xtype = 'NavSimplebar';
18538 for(var i=0;i< children.length;i++) {
18540 this.buttons.add(this.addxtypeChild(children[i]));
18544 editor.on('editorevent', this.updateToolbar, this);
18546 onBtnClick : function(id)
18548 this.editorcore.relayCmd(id);
18549 this.editorcore.focus();
18553 * Protected method that will not generally be called directly. It triggers
18554 * a toolbar update by reading the markup state of the current selection in the editor.
18556 updateToolbar: function(){
18558 if(!this.editorcore.activated){
18559 this.editor.onFirstFocus(); // is this neeed?
18563 var btns = this.buttons;
18564 var doc = this.editorcore.doc;
18565 btns.get('bold').setActive(doc.queryCommandState('bold'));
18566 btns.get('italic').setActive(doc.queryCommandState('italic'));
18567 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18569 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18570 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18571 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18573 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18574 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18577 var ans = this.editorcore.getAllAncestors();
18578 if (this.formatCombo) {
18581 var store = this.formatCombo.store;
18582 this.formatCombo.setValue("");
18583 for (var i =0; i < ans.length;i++) {
18584 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18586 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18594 // hides menus... - so this cant be on a menu...
18595 Roo.bootstrap.MenuMgr.hideAll();
18597 Roo.bootstrap.MenuMgr.hideAll();
18598 //this.editorsyncValue();
18600 onFirstFocus: function() {
18601 this.buttons.each(function(item){
18605 toggleSourceEdit : function(sourceEditMode){
18608 if(sourceEditMode){
18609 Roo.log("disabling buttons");
18610 this.buttons.each( function(item){
18611 if(item.cmd != 'pencil'){
18617 Roo.log("enabling buttons");
18618 if(this.editorcore.initialized){
18619 this.buttons.each( function(item){
18625 Roo.log("calling toggole on editor");
18626 // tell the editor that it's been pressed..
18627 this.editor.toggleSourceEdit(sourceEditMode);
18637 * @class Roo.bootstrap.Table.AbstractSelectionModel
18638 * @extends Roo.util.Observable
18639 * Abstract base class for grid SelectionModels. It provides the interface that should be
18640 * implemented by descendant classes. This class should not be directly instantiated.
18643 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18644 this.locked = false;
18645 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18649 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18650 /** @ignore Called by the grid automatically. Do not call directly. */
18651 init : function(grid){
18657 * Locks the selections.
18660 this.locked = true;
18664 * Unlocks the selections.
18666 unlock : function(){
18667 this.locked = false;
18671 * Returns true if the selections are locked.
18672 * @return {Boolean}
18674 isLocked : function(){
18675 return this.locked;
18679 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18680 * @class Roo.bootstrap.Table.RowSelectionModel
18681 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18682 * It supports multiple selections and keyboard selection/navigation.
18684 * @param {Object} config
18687 Roo.bootstrap.Table.RowSelectionModel = function(config){
18688 Roo.apply(this, config);
18689 this.selections = new Roo.util.MixedCollection(false, function(o){
18694 this.lastActive = false;
18698 * @event selectionchange
18699 * Fires when the selection changes
18700 * @param {SelectionModel} this
18702 "selectionchange" : true,
18704 * @event afterselectionchange
18705 * Fires after the selection changes (eg. by key press or clicking)
18706 * @param {SelectionModel} this
18708 "afterselectionchange" : true,
18710 * @event beforerowselect
18711 * Fires when a row is selected being selected, return false to cancel.
18712 * @param {SelectionModel} this
18713 * @param {Number} rowIndex The selected index
18714 * @param {Boolean} keepExisting False if other selections will be cleared
18716 "beforerowselect" : true,
18719 * Fires when a row is selected.
18720 * @param {SelectionModel} this
18721 * @param {Number} rowIndex The selected index
18722 * @param {Roo.data.Record} r The record
18724 "rowselect" : true,
18726 * @event rowdeselect
18727 * Fires when a row is deselected.
18728 * @param {SelectionModel} this
18729 * @param {Number} rowIndex The selected index
18731 "rowdeselect" : true
18733 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18734 this.locked = false;
18737 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18739 * @cfg {Boolean} singleSelect
18740 * True to allow selection of only one row at a time (defaults to false)
18742 singleSelect : false,
18745 initEvents : function(){
18747 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18748 this.grid.on("mousedown", this.handleMouseDown, this);
18749 }else{ // allow click to work like normal
18750 this.grid.on("rowclick", this.handleDragableRowClick, this);
18753 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18754 "up" : function(e){
18756 this.selectPrevious(e.shiftKey);
18757 }else if(this.last !== false && this.lastActive !== false){
18758 var last = this.last;
18759 this.selectRange(this.last, this.lastActive-1);
18760 this.grid.getView().focusRow(this.lastActive);
18761 if(last !== false){
18765 this.selectFirstRow();
18767 this.fireEvent("afterselectionchange", this);
18769 "down" : function(e){
18771 this.selectNext(e.shiftKey);
18772 }else if(this.last !== false && this.lastActive !== false){
18773 var last = this.last;
18774 this.selectRange(this.last, this.lastActive+1);
18775 this.grid.getView().focusRow(this.lastActive);
18776 if(last !== false){
18780 this.selectFirstRow();
18782 this.fireEvent("afterselectionchange", this);
18787 var view = this.grid.view;
18788 view.on("refresh", this.onRefresh, this);
18789 view.on("rowupdated", this.onRowUpdated, this);
18790 view.on("rowremoved", this.onRemove, this);
18794 onRefresh : function(){
18795 var ds = this.grid.dataSource, i, v = this.grid.view;
18796 var s = this.selections;
18797 s.each(function(r){
18798 if((i = ds.indexOfId(r.id)) != -1){
18807 onRemove : function(v, index, r){
18808 this.selections.remove(r);
18812 onRowUpdated : function(v, index, r){
18813 if(this.isSelected(r)){
18814 v.onRowSelect(index);
18820 * @param {Array} records The records to select
18821 * @param {Boolean} keepExisting (optional) True to keep existing selections
18823 selectRecords : function(records, keepExisting){
18825 this.clearSelections();
18827 var ds = this.grid.dataSource;
18828 for(var i = 0, len = records.length; i < len; i++){
18829 this.selectRow(ds.indexOf(records[i]), true);
18834 * Gets the number of selected rows.
18837 getCount : function(){
18838 return this.selections.length;
18842 * Selects the first row in the grid.
18844 selectFirstRow : function(){
18849 * Select the last row.
18850 * @param {Boolean} keepExisting (optional) True to keep existing selections
18852 selectLastRow : function(keepExisting){
18853 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18857 * Selects the row immediately following the last selected row.
18858 * @param {Boolean} keepExisting (optional) True to keep existing selections
18860 selectNext : function(keepExisting){
18861 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18862 this.selectRow(this.last+1, keepExisting);
18863 this.grid.getView().focusRow(this.last);
18868 * Selects the row that precedes the last selected row.
18869 * @param {Boolean} keepExisting (optional) True to keep existing selections
18871 selectPrevious : function(keepExisting){
18873 this.selectRow(this.last-1, keepExisting);
18874 this.grid.getView().focusRow(this.last);
18879 * Returns the selected records
18880 * @return {Array} Array of selected records
18882 getSelections : function(){
18883 return [].concat(this.selections.items);
18887 * Returns the first selected record.
18890 getSelected : function(){
18891 return this.selections.itemAt(0);
18896 * Clears all selections.
18898 clearSelections : function(fast){
18899 if(this.locked) return;
18901 var ds = this.grid.dataSource;
18902 var s = this.selections;
18903 s.each(function(r){
18904 this.deselectRow(ds.indexOfId(r.id));
18908 this.selections.clear();
18915 * Selects all rows.
18917 selectAll : function(){
18918 if(this.locked) return;
18919 this.selections.clear();
18920 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18921 this.selectRow(i, true);
18926 * Returns True if there is a selection.
18927 * @return {Boolean}
18929 hasSelection : function(){
18930 return this.selections.length > 0;
18934 * Returns True if the specified row is selected.
18935 * @param {Number/Record} record The record or index of the record to check
18936 * @return {Boolean}
18938 isSelected : function(index){
18939 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18940 return (r && this.selections.key(r.id) ? true : false);
18944 * Returns True if the specified record id is selected.
18945 * @param {String} id The id of record to check
18946 * @return {Boolean}
18948 isIdSelected : function(id){
18949 return (this.selections.key(id) ? true : false);
18953 handleMouseDown : function(e, t){
18954 var view = this.grid.getView(), rowIndex;
18955 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18958 if(e.shiftKey && this.last !== false){
18959 var last = this.last;
18960 this.selectRange(last, rowIndex, e.ctrlKey);
18961 this.last = last; // reset the last
18962 view.focusRow(rowIndex);
18964 var isSelected = this.isSelected(rowIndex);
18965 if(e.button !== 0 && isSelected){
18966 view.focusRow(rowIndex);
18967 }else if(e.ctrlKey && isSelected){
18968 this.deselectRow(rowIndex);
18969 }else if(!isSelected){
18970 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18971 view.focusRow(rowIndex);
18974 this.fireEvent("afterselectionchange", this);
18977 handleDragableRowClick : function(grid, rowIndex, e)
18979 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18980 this.selectRow(rowIndex, false);
18981 grid.view.focusRow(rowIndex);
18982 this.fireEvent("afterselectionchange", this);
18987 * Selects multiple rows.
18988 * @param {Array} rows Array of the indexes of the row to select
18989 * @param {Boolean} keepExisting (optional) True to keep existing selections
18991 selectRows : function(rows, keepExisting){
18993 this.clearSelections();
18995 for(var i = 0, len = rows.length; i < len; i++){
18996 this.selectRow(rows[i], true);
19001 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19002 * @param {Number} startRow The index of the first row in the range
19003 * @param {Number} endRow The index of the last row in the range
19004 * @param {Boolean} keepExisting (optional) True to retain existing selections
19006 selectRange : function(startRow, endRow, keepExisting){
19007 if(this.locked) return;
19009 this.clearSelections();
19011 if(startRow <= endRow){
19012 for(var i = startRow; i <= endRow; i++){
19013 this.selectRow(i, true);
19016 for(var i = startRow; i >= endRow; i--){
19017 this.selectRow(i, true);
19023 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19024 * @param {Number} startRow The index of the first row in the range
19025 * @param {Number} endRow The index of the last row in the range
19027 deselectRange : function(startRow, endRow, preventViewNotify){
19028 if(this.locked) return;
19029 for(var i = startRow; i <= endRow; i++){
19030 this.deselectRow(i, preventViewNotify);
19036 * @param {Number} row The index of the row to select
19037 * @param {Boolean} keepExisting (optional) True to keep existing selections
19039 selectRow : function(index, keepExisting, preventViewNotify){
19040 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19041 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19042 if(!keepExisting || this.singleSelect){
19043 this.clearSelections();
19045 var r = this.grid.dataSource.getAt(index);
19046 this.selections.add(r);
19047 this.last = this.lastActive = index;
19048 if(!preventViewNotify){
19049 this.grid.getView().onRowSelect(index);
19051 this.fireEvent("rowselect", this, index, r);
19052 this.fireEvent("selectionchange", this);
19058 * @param {Number} row The index of the row to deselect
19060 deselectRow : function(index, preventViewNotify){
19061 if(this.locked) return;
19062 if(this.last == index){
19065 if(this.lastActive == index){
19066 this.lastActive = false;
19068 var r = this.grid.dataSource.getAt(index);
19069 this.selections.remove(r);
19070 if(!preventViewNotify){
19071 this.grid.getView().onRowDeselect(index);
19073 this.fireEvent("rowdeselect", this, index);
19074 this.fireEvent("selectionchange", this);
19078 restoreLast : function(){
19080 this.last = this._last;
19085 acceptsNav : function(row, col, cm){
19086 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19090 onEditorKey : function(field, e){
19091 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19096 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19098 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19100 }else if(k == e.ENTER && !e.ctrlKey){
19104 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19106 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19108 }else if(k == e.ESC){
19112 g.startEditing(newCell[0], newCell[1]);
19117 * Ext JS Library 1.1.1
19118 * Copyright(c) 2006-2007, Ext JS, LLC.
19120 * Originally Released Under LGPL - original licence link has changed is not relivant.
19123 * <script type="text/javascript">
19127 * @class Roo.bootstrap.PagingToolbar
19129 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19131 * Create a new PagingToolbar
19132 * @param {Object} config The config object
19134 Roo.bootstrap.PagingToolbar = function(config)
19136 // old args format still supported... - xtype is prefered..
19137 // created from xtype...
19138 var ds = config.dataSource;
19139 this.toolbarItems = [];
19140 if (config.items) {
19141 this.toolbarItems = config.items;
19142 // config.items = [];
19145 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19152 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19156 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19158 * @cfg {Roo.data.Store} dataSource
19159 * The underlying data store providing the paged data
19162 * @cfg {String/HTMLElement/Element} container
19163 * container The id or element that will contain the toolbar
19166 * @cfg {Boolean} displayInfo
19167 * True to display the displayMsg (defaults to false)
19170 * @cfg {Number} pageSize
19171 * The number of records to display per page (defaults to 20)
19175 * @cfg {String} displayMsg
19176 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19178 displayMsg : 'Displaying {0} - {1} of {2}',
19180 * @cfg {String} emptyMsg
19181 * The message to display when no records are found (defaults to "No data to display")
19183 emptyMsg : 'No data to display',
19185 * Customizable piece of the default paging text (defaults to "Page")
19188 beforePageText : "Page",
19190 * Customizable piece of the default paging text (defaults to "of %0")
19193 afterPageText : "of {0}",
19195 * Customizable piece of the default paging text (defaults to "First Page")
19198 firstText : "First Page",
19200 * Customizable piece of the default paging text (defaults to "Previous Page")
19203 prevText : "Previous Page",
19205 * Customizable piece of the default paging text (defaults to "Next Page")
19208 nextText : "Next Page",
19210 * Customizable piece of the default paging text (defaults to "Last Page")
19213 lastText : "Last Page",
19215 * Customizable piece of the default paging text (defaults to "Refresh")
19218 refreshText : "Refresh",
19222 onRender : function(ct, position)
19224 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19225 this.navgroup.parentId = this.id;
19226 this.navgroup.onRender(this.el, null);
19227 // add the buttons to the navgroup
19229 if(this.displayInfo){
19230 Roo.log(this.el.select('ul.navbar-nav',true).first());
19231 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19232 this.displayEl = this.el.select('.x-paging-info', true).first();
19233 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19234 // this.displayEl = navel.el.select('span',true).first();
19240 Roo.each(_this.buttons, function(e){
19241 Roo.factory(e).onRender(_this.el, null);
19245 Roo.each(_this.toolbarItems, function(e) {
19246 _this.navgroup.addItem(e);
19249 this.first = this.navgroup.addItem({
19250 tooltip: this.firstText,
19252 icon : 'fa fa-backward',
19254 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19257 this.prev = this.navgroup.addItem({
19258 tooltip: this.prevText,
19260 icon : 'fa fa-step-backward',
19262 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19264 //this.addSeparator();
19267 var field = this.navgroup.addItem( {
19269 cls : 'x-paging-position',
19271 html : this.beforePageText +
19272 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19273 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19276 this.field = field.el.select('input', true).first();
19277 this.field.on("keydown", this.onPagingKeydown, this);
19278 this.field.on("focus", function(){this.dom.select();});
19281 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19282 //this.field.setHeight(18);
19283 //this.addSeparator();
19284 this.next = this.navgroup.addItem({
19285 tooltip: this.nextText,
19287 html : ' <i class="fa fa-step-forward">',
19289 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19291 this.last = this.navgroup.addItem({
19292 tooltip: this.lastText,
19293 icon : 'fa fa-forward',
19296 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19298 //this.addSeparator();
19299 this.loading = this.navgroup.addItem({
19300 tooltip: this.refreshText,
19301 icon: 'fa fa-refresh',
19303 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19309 updateInfo : function(){
19310 if(this.displayEl){
19311 var count = this.ds.getCount();
19312 var msg = count == 0 ?
19316 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19318 this.displayEl.update(msg);
19323 onLoad : function(ds, r, o){
19324 this.cursor = o.params ? o.params.start : 0;
19325 var d = this.getPageData(),
19329 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19330 this.field.dom.value = ap;
19331 this.first.setDisabled(ap == 1);
19332 this.prev.setDisabled(ap == 1);
19333 this.next.setDisabled(ap == ps);
19334 this.last.setDisabled(ap == ps);
19335 this.loading.enable();
19340 getPageData : function(){
19341 var total = this.ds.getTotalCount();
19344 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19345 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19350 onLoadError : function(){
19351 this.loading.enable();
19355 onPagingKeydown : function(e){
19356 var k = e.getKey();
19357 var d = this.getPageData();
19359 var v = this.field.dom.value, pageNum;
19360 if(!v || isNaN(pageNum = parseInt(v, 10))){
19361 this.field.dom.value = d.activePage;
19364 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19365 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19368 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))
19370 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19371 this.field.dom.value = pageNum;
19372 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19375 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19377 var v = this.field.dom.value, pageNum;
19378 var increment = (e.shiftKey) ? 10 : 1;
19379 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19381 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19382 this.field.dom.value = d.activePage;
19385 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19387 this.field.dom.value = parseInt(v, 10) + increment;
19388 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19389 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19396 beforeLoad : function(){
19398 this.loading.disable();
19403 onClick : function(which){
19410 ds.load({params:{start: 0, limit: this.pageSize}});
19413 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19416 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19419 var total = ds.getTotalCount();
19420 var extra = total % this.pageSize;
19421 var lastStart = extra ? (total - extra) : total-this.pageSize;
19422 ds.load({params:{start: lastStart, limit: this.pageSize}});
19425 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19431 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19432 * @param {Roo.data.Store} store The data store to unbind
19434 unbind : function(ds){
19435 ds.un("beforeload", this.beforeLoad, this);
19436 ds.un("load", this.onLoad, this);
19437 ds.un("loadexception", this.onLoadError, this);
19438 ds.un("remove", this.updateInfo, this);
19439 ds.un("add", this.updateInfo, this);
19440 this.ds = undefined;
19444 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19445 * @param {Roo.data.Store} store The data store to bind
19447 bind : function(ds){
19448 ds.on("beforeload", this.beforeLoad, this);
19449 ds.on("load", this.onLoad, this);
19450 ds.on("loadexception", this.onLoadError, this);
19451 ds.on("remove", this.updateInfo, this);
19452 ds.on("add", this.updateInfo, this);
19463 * @class Roo.bootstrap.MessageBar
19464 * @extends Roo.bootstrap.Component
19465 * Bootstrap MessageBar class
19466 * @cfg {String} html contents of the MessageBar
19467 * @cfg {String} weight (info | success | warning | danger) default info
19468 * @cfg {String} beforeClass insert the bar before the given class
19469 * @cfg {Boolean} closable (true | false) default false
19470 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19473 * Create a new Element
19474 * @param {Object} config The config object
19477 Roo.bootstrap.MessageBar = function(config){
19478 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19481 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19487 beforeClass: 'bootstrap-sticky-wrap',
19489 getAutoCreate : function(){
19493 cls: 'alert alert-dismissable alert-' + this.weight,
19498 html: this.html || ''
19504 cfg.cls += ' alert-messages-fixed';
19518 onRender : function(ct, position)
19520 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19523 var cfg = Roo.apply({}, this.getAutoCreate());
19527 cfg.cls += ' ' + this.cls;
19530 cfg.style = this.style;
19532 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19534 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19537 this.el.select('>button.close').on('click', this.hide, this);
19543 if (!this.rendered) {
19549 this.fireEvent('show', this);
19555 if (!this.rendered) {
19561 this.fireEvent('hide', this);
19564 update : function()
19566 // var e = this.el.dom.firstChild;
19568 // if(this.closable){
19569 // e = e.nextSibling;
19572 // e.data = this.html || '';
19574 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19590 * @class Roo.bootstrap.Graph
19591 * @extends Roo.bootstrap.Component
19592 * Bootstrap Graph class
19596 @cfg {String} graphtype bar | vbar | pie
19597 @cfg {number} g_x coodinator | centre x (pie)
19598 @cfg {number} g_y coodinator | centre y (pie)
19599 @cfg {number} g_r radius (pie)
19600 @cfg {number} g_height height of the chart (respected by all elements in the set)
19601 @cfg {number} g_width width of the chart (respected by all elements in the set)
19602 @cfg {Object} title The title of the chart
19605 -opts (object) options for the chart
19607 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19608 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19610 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.
19611 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19613 o stretch (boolean)
19615 -opts (object) options for the pie
19618 o startAngle (number)
19619 o endAngle (number)
19623 * Create a new Input
19624 * @param {Object} config The config object
19627 Roo.bootstrap.Graph = function(config){
19628 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19634 * The img click event for the img.
19635 * @param {Roo.EventObject} e
19641 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19652 //g_colors: this.colors,
19659 getAutoCreate : function(){
19670 onRender : function(ct,position){
19671 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19672 this.raphael = Raphael(this.el.dom);
19674 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19675 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19676 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19677 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19679 r.text(160, 10, "Single Series Chart").attr(txtattr);
19680 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19681 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19682 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19684 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19685 r.barchart(330, 10, 300, 220, data1);
19686 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19687 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19690 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19691 // r.barchart(30, 30, 560, 250, xdata, {
19692 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19693 // axis : "0 0 1 1",
19694 // axisxlabels : xdata
19695 // //yvalues : cols,
19698 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19700 // this.load(null,xdata,{
19701 // axis : "0 0 1 1",
19702 // axisxlabels : xdata
19707 load : function(graphtype,xdata,opts){
19708 this.raphael.clear();
19710 graphtype = this.graphtype;
19715 var r = this.raphael,
19716 fin = function () {
19717 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19719 fout = function () {
19720 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19722 pfin = function() {
19723 this.sector.stop();
19724 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19727 this.label[0].stop();
19728 this.label[0].attr({ r: 7.5 });
19729 this.label[1].attr({ "font-weight": 800 });
19732 pfout = function() {
19733 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19736 this.label[0].animate({ r: 5 }, 500, "bounce");
19737 this.label[1].attr({ "font-weight": 400 });
19743 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19746 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19749 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19750 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19752 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19759 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19764 setTitle: function(o)
19769 initEvents: function() {
19772 this.el.on('click', this.onClick, this);
19776 onClick : function(e)
19778 Roo.log('img onclick');
19779 this.fireEvent('click', this, e);
19791 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19794 * @class Roo.bootstrap.dash.NumberBox
19795 * @extends Roo.bootstrap.Component
19796 * Bootstrap NumberBox class
19797 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19798 * @cfg {String} headline Box headline
19799 * @cfg {String} content Box content
19800 * @cfg {String} icon Box icon
19801 * @cfg {String} footer Footer text
19802 * @cfg {String} fhref Footer href
19805 * Create a new NumberBox
19806 * @param {Object} config The config object
19810 Roo.bootstrap.dash.NumberBox = function(config){
19811 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19815 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19825 getAutoCreate : function(){
19829 cls : 'small-box bg-' + this.bgcolor,
19837 cls : 'roo-headline',
19838 html : this.headline
19842 cls : 'roo-content',
19843 html : this.content
19857 cls : 'ion ' + this.icon
19866 cls : 'small-box-footer',
19867 href : this.fhref || '#',
19871 cfg.cn.push(footer);
19878 onRender : function(ct,position){
19879 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19886 setHeadline: function (value)
19888 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19891 setFooter: function (value, href)
19893 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19896 this.el.select('a.small-box-footer',true).first().attr('href', href);
19901 setContent: function (value)
19903 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19906 initEvents: function()
19920 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19923 * @class Roo.bootstrap.dash.TabBox
19924 * @extends Roo.bootstrap.Component
19925 * Bootstrap TabBox class
19926 * @cfg {String} title Title of the TabBox
19927 * @cfg {String} icon Icon of the TabBox
19928 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19929 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
19932 * Create a new TabBox
19933 * @param {Object} config The config object
19937 Roo.bootstrap.dash.TabBox = function(config){
19938 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19943 * When a pane is added
19944 * @param {Roo.bootstrap.dash.TabPane} pane
19948 * @event activatepane
19949 * When a pane is activated
19950 * @param {Roo.bootstrap.dash.TabPane} pane
19952 "activatepane" : true
19960 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19965 tabScrollable : false,
19967 getChildContainer : function()
19969 return this.el.select('.tab-content', true).first();
19972 getAutoCreate : function(){
19976 cls: 'pull-left header',
19984 cls: 'fa ' + this.icon
19990 cls: 'nav nav-tabs pull-right',
19996 if(this.tabScrollable){
20003 cls: 'nav nav-tabs pull-right',
20014 cls: 'nav-tabs-custom',
20019 cls: 'tab-content no-padding',
20027 initEvents : function()
20029 //Roo.log('add add pane handler');
20030 this.on('addpane', this.onAddPane, this);
20033 * Updates the box title
20034 * @param {String} html to set the title to.
20036 setTitle : function(value)
20038 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20040 onAddPane : function(pane)
20042 this.panes.push(pane);
20043 //Roo.log('addpane');
20045 // tabs are rendere left to right..
20046 if(!this.showtabs){
20050 var ctr = this.el.select('.nav-tabs', true).first();
20053 var existing = ctr.select('.nav-tab',true);
20054 var qty = existing.getCount();;
20057 var tab = ctr.createChild({
20059 cls : 'nav-tab' + (qty ? '' : ' active'),
20067 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20070 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20072 pane.el.addClass('active');
20077 onTabClick : function(ev,un,ob,pane)
20079 //Roo.log('tab - prev default');
20080 ev.preventDefault();
20083 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20084 pane.tab.addClass('active');
20085 //Roo.log(pane.title);
20086 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20087 // technically we should have a deactivate event.. but maybe add later.
20088 // and it should not de-activate the selected tab...
20089 this.fireEvent('activatepane', pane);
20090 pane.el.addClass('active');
20091 pane.fireEvent('activate');
20096 getActivePane : function()
20099 Roo.each(this.panes, function(p) {
20100 if(p.el.hasClass('active')){
20121 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20123 * @class Roo.bootstrap.TabPane
20124 * @extends Roo.bootstrap.Component
20125 * Bootstrap TabPane class
20126 * @cfg {Boolean} active (false | true) Default false
20127 * @cfg {String} title title of panel
20131 * Create a new TabPane
20132 * @param {Object} config The config object
20135 Roo.bootstrap.dash.TabPane = function(config){
20136 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20142 * When a pane is activated
20143 * @param {Roo.bootstrap.dash.TabPane} pane
20150 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20155 // the tabBox that this is attached to.
20158 getAutoCreate : function()
20166 cfg.cls += ' active';
20171 initEvents : function()
20173 //Roo.log('trigger add pane handler');
20174 this.parent().fireEvent('addpane', this)
20178 * Updates the tab title
20179 * @param {String} html to set the title to.
20181 setTitle: function(str)
20187 this.tab.select('a', true).first().dom.innerHTML = str;
20204 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20207 * @class Roo.bootstrap.menu.Menu
20208 * @extends Roo.bootstrap.Component
20209 * Bootstrap Menu class - container for Menu
20210 * @cfg {String} html Text of the menu
20211 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20212 * @cfg {String} icon Font awesome icon
20213 * @cfg {String} pos Menu align to (top | bottom) default bottom
20217 * Create a new Menu
20218 * @param {Object} config The config object
20222 Roo.bootstrap.menu.Menu = function(config){
20223 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20227 * @event beforeshow
20228 * Fires before this menu is displayed
20229 * @param {Roo.bootstrap.menu.Menu} this
20233 * @event beforehide
20234 * Fires before this menu is hidden
20235 * @param {Roo.bootstrap.menu.Menu} this
20240 * Fires after this menu is displayed
20241 * @param {Roo.bootstrap.menu.Menu} this
20246 * Fires after this menu is hidden
20247 * @param {Roo.bootstrap.menu.Menu} this
20252 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20253 * @param {Roo.bootstrap.menu.Menu} this
20254 * @param {Roo.EventObject} e
20261 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20265 weight : 'default',
20270 getChildContainer : function() {
20271 if(this.isSubMenu){
20275 return this.el.select('ul.dropdown-menu', true).first();
20278 getAutoCreate : function()
20283 cls : 'roo-menu-text',
20291 cls : 'fa ' + this.icon
20302 cls : 'dropdown-button btn btn-' + this.weight,
20307 cls : 'dropdown-toggle btn btn-' + this.weight,
20317 cls : 'dropdown-menu'
20323 if(this.pos == 'top'){
20324 cfg.cls += ' dropup';
20327 if(this.isSubMenu){
20330 cls : 'dropdown-menu'
20337 onRender : function(ct, position)
20339 this.isSubMenu = ct.hasClass('dropdown-submenu');
20341 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20344 initEvents : function()
20346 if(this.isSubMenu){
20350 this.hidden = true;
20352 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20353 this.triggerEl.on('click', this.onTriggerPress, this);
20355 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20356 this.buttonEl.on('click', this.onClick, this);
20362 if(this.isSubMenu){
20366 return this.el.select('ul.dropdown-menu', true).first();
20369 onClick : function(e)
20371 this.fireEvent("click", this, e);
20374 onTriggerPress : function(e)
20376 if (this.isVisible()) {
20383 isVisible : function(){
20384 return !this.hidden;
20389 this.fireEvent("beforeshow", this);
20391 this.hidden = false;
20392 this.el.addClass('open');
20394 Roo.get(document).on("mouseup", this.onMouseUp, this);
20396 this.fireEvent("show", this);
20403 this.fireEvent("beforehide", this);
20405 this.hidden = true;
20406 this.el.removeClass('open');
20408 Roo.get(document).un("mouseup", this.onMouseUp);
20410 this.fireEvent("hide", this);
20413 onMouseUp : function()
20427 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20430 * @class Roo.bootstrap.menu.Item
20431 * @extends Roo.bootstrap.Component
20432 * Bootstrap MenuItem class
20433 * @cfg {Boolean} submenu (true | false) default false
20434 * @cfg {String} html text of the item
20435 * @cfg {String} href the link
20436 * @cfg {Boolean} disable (true | false) default false
20437 * @cfg {Boolean} preventDefault (true | false) default true
20438 * @cfg {String} icon Font awesome icon
20439 * @cfg {String} pos Submenu align to (left | right) default right
20443 * Create a new Item
20444 * @param {Object} config The config object
20448 Roo.bootstrap.menu.Item = function(config){
20449 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20453 * Fires when the mouse is hovering over this menu
20454 * @param {Roo.bootstrap.menu.Item} this
20455 * @param {Roo.EventObject} e
20460 * Fires when the mouse exits this menu
20461 * @param {Roo.bootstrap.menu.Item} this
20462 * @param {Roo.EventObject} e
20468 * The raw click event for the entire grid.
20469 * @param {Roo.EventObject} e
20475 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20480 preventDefault: true,
20485 getAutoCreate : function()
20490 cls : 'roo-menu-item-text',
20498 cls : 'fa ' + this.icon
20507 href : this.href || '#',
20514 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20518 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20520 if(this.pos == 'left'){
20521 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20528 initEvents : function()
20530 this.el.on('mouseover', this.onMouseOver, this);
20531 this.el.on('mouseout', this.onMouseOut, this);
20533 this.el.select('a', true).first().on('click', this.onClick, this);
20537 onClick : function(e)
20539 if(this.preventDefault){
20540 e.preventDefault();
20543 this.fireEvent("click", this, e);
20546 onMouseOver : function(e)
20548 if(this.submenu && this.pos == 'left'){
20549 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20552 this.fireEvent("mouseover", this, e);
20555 onMouseOut : function(e)
20557 this.fireEvent("mouseout", this, e);
20569 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20572 * @class Roo.bootstrap.menu.Separator
20573 * @extends Roo.bootstrap.Component
20574 * Bootstrap Separator class
20577 * Create a new Separator
20578 * @param {Object} config The config object
20582 Roo.bootstrap.menu.Separator = function(config){
20583 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20586 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20588 getAutoCreate : function(){
20609 * @class Roo.bootstrap.Tooltip
20610 * Bootstrap Tooltip class
20611 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20612 * to determine which dom element triggers the tooltip.
20614 * It needs to add support for additional attributes like tooltip-position
20617 * Create a new Toolti
20618 * @param {Object} config The config object
20621 Roo.bootstrap.Tooltip = function(config){
20622 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20625 Roo.apply(Roo.bootstrap.Tooltip, {
20627 * @function init initialize tooltip monitoring.
20631 currentTip : false,
20632 currentRegion : false,
20638 Roo.get(document).on('mouseover', this.enter ,this);
20639 Roo.get(document).on('mouseout', this.leave, this);
20642 this.currentTip = new Roo.bootstrap.Tooltip();
20645 enter : function(ev)
20647 var dom = ev.getTarget();
20648 //Roo.log(['enter',dom]);
20649 var el = Roo.fly(dom);
20650 if (this.currentEl) {
20652 //Roo.log(this.currentEl);
20653 //Roo.log(this.currentEl.contains(dom));
20654 if (this.currentEl == el) {
20657 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20665 if (this.currentTip) {
20666 this.currentTip.hide();
20669 if (!el.attr('tooltip')) { // parents who have tip?
20672 this.currentEl = el;
20673 this.currentTip.bind(el);
20674 this.currentRegion = Roo.lib.Region.getRegion(dom);
20675 this.currentTip.enter();
20678 leave : function(ev)
20680 var dom = ev.getTarget();
20681 //Roo.log(['leave',dom]);
20682 if (!this.currentEl) {
20687 if (dom != this.currentEl.dom) {
20690 var xy = ev.getXY();
20691 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
20694 // only activate leave if mouse cursor is outside... bounding box..
20699 if (this.currentTip) {
20700 this.currentTip.leave();
20702 //Roo.log('clear currentEl');
20703 this.currentEl = false;
20708 'left' : ['r-l', [-2,0], 'right'],
20709 'right' : ['l-r', [2,0], 'left'],
20710 'bottom' : ['t-b', [0,2], 'top'],
20711 'top' : [ 'b-t', [0,-2], 'bottom']
20717 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
20722 delay : null, // can be { show : 300 , hide: 500}
20726 hoverState : null, //???
20728 placement : 'bottom',
20730 getAutoCreate : function(){
20737 cls : 'tooltip-arrow'
20740 cls : 'tooltip-inner',
20747 bind : function(el)
20753 enter : function () {
20755 if (this.timeout != null) {
20756 clearTimeout(this.timeout);
20759 this.hoverState = 'in'
20760 //Roo.log("enter - show");
20761 if (!this.delay || !this.delay.show) {
20766 this.timeout = setTimeout(function () {
20767 if (_t.hoverState == 'in') {
20770 }, this.delay.show)
20774 clearTimeout(this.timeout);
20776 this.hoverState = 'out'
20777 if (!this.delay || !this.delay.hide) {
20783 this.timeout = setTimeout(function () {
20784 //Roo.log("leave - timeout");
20786 if (_t.hoverState == 'out') {
20788 Roo.bootstrap.Tooltip.currentEl = false;
20796 this.render(document.body);
20799 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
20800 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
20802 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
20804 var placement = typeof this.placement == 'function' ?
20805 this.placement.call(this, this.el, on_el) :
20808 var autoToken = /\s?auto?\s?/i;
20809 var autoPlace = autoToken.test(placement);
20811 placement = placement.replace(autoToken, '') || 'top';
20815 //this.el.setXY([0,0]);
20817 //this.el.dom.style.display='block';
20818 this.el.addClass(placement);
20820 //this.el.appendTo(on_el);
20822 var p = this.getPosition();
20823 var box = this.el.getBox();
20828 var align = Roo.bootstrap.Tooltip.alignment[placement]
20829 this.el.alignTo(this.bindEl, align[0],align[1]);
20830 //var arrow = this.el.select('.arrow',true).first();
20831 //arrow.set(align[2],
20833 this.el.addClass('in fade');
20834 this.hoverState = null;
20836 if (this.el.hasClass('fade')) {
20847 //this.el.setXY([0,0]);
20848 this.el.removeClass('in');