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
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
33 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
36 allowDomMove : false, // to stop relocations in parent onRender...
46 * Initialize Events for the element
48 initEvents : function() { },
54 can_build_overlaid : true,
56 container_method : false,
63 // returns the parent component..
64 return Roo.ComponentMgr.get(this.parentId)
70 onRender : function(ct, position)
72 // Roo.log("Call onRender: " + this.xtype);
74 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
77 if (this.el.attr('xtype')) {
78 this.el.attr('xtypex', this.el.attr('xtype'));
79 this.el.dom.removeAttribute('xtype');
89 var cfg = Roo.apply({}, this.getAutoCreate());
92 // fill in the extra attributes
93 if (this.xattr && typeof(this.xattr) =='object') {
94 for (var i in this.xattr) {
95 cfg[i] = this.xattr[i];
100 cfg.dataId = this.dataId;
104 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
107 if (this.style) { // fixme needs to support more complex style data.
108 cfg.style = this.style;
112 cfg.name = this.name;
117 this.el = ct.createChild(cfg, position);
120 this.tooltipEl().attr('tooltip', this.tooltip);
123 if(this.tabIndex !== undefined){
124 this.el.dom.setAttribute('tabIndex', this.tabIndex);
131 * Fetch the element to add children to
132 * @return {Roo.Element} defaults to this.el
134 getChildContainer : function()
139 * Fetch the element to display the tooltip on.
140 * @return {Roo.Element} defaults to this.el
142 tooltipEl : function()
147 addxtype : function(tree,cntr)
151 cn = Roo.factory(tree);
153 cn.parentType = this.xtype; //??
154 cn.parentId = this.id;
156 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
157 if (typeof(cn.container_method) == 'string') {
158 cntr = cn.container_method;
162 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
164 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
166 var build_from_html = Roo.XComponent.build_from_html;
168 var is_body = (tree.xtype == 'Body') ;
170 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
172 var self_cntr_el = Roo.get(this[cntr](false));
174 // do not try and build conditional elements
175 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
179 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
180 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
181 return this.addxtypeChild(tree,cntr);
184 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
187 return this.addxtypeChild(Roo.apply({}, tree),cntr);
190 Roo.log('skipping render');
198 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
204 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
208 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
213 addxtypeChild : function (tree, cntr)
215 Roo.debug && Roo.log('addxtypeChild:' + cntr);
217 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
220 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
221 (typeof(tree['flexy:foreach']) != 'undefined');
225 skip_children = false;
226 // render the element if it's not BODY.
227 if (tree.xtype != 'Body') {
229 cn = Roo.factory(tree);
231 cn.parentType = this.xtype; //??
232 cn.parentId = this.id;
234 var build_from_html = Roo.XComponent.build_from_html;
237 // does the container contain child eleemnts with 'xtype' attributes.
238 // that match this xtype..
239 // note - when we render we create these as well..
240 // so we should check to see if body has xtype set.
241 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
243 var self_cntr_el = Roo.get(this[cntr](false));
244 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
247 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
248 // and are not displayed -this causes this to use up the wrong element when matching.
249 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
252 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
253 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
259 //echild.dom.removeAttribute('xtype');
261 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
262 Roo.debug && Roo.log(self_cntr_el);
263 Roo.debug && Roo.log(echild);
264 Roo.debug && Roo.log(cn);
270 // if object has flexy:if - then it may or may not be rendered.
271 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
272 // skip a flexy if element.
273 Roo.debug && Roo.log('skipping render');
274 Roo.debug && Roo.log(tree);
276 Roo.debug && Roo.log('skipping all children');
277 skip_children = true;
282 // actually if flexy:foreach is found, we really want to create
283 // multiple copies here...
285 //Roo.log(this[cntr]());
286 cn.render(this[cntr](true));
288 // then add the element..
296 if (typeof (tree.menu) != 'undefined') {
297 tree.menu.parentType = cn.xtype;
298 tree.menu.triggerEl = cn.el;
299 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
303 if (!tree.items || !tree.items.length) {
307 var items = tree.items;
310 //Roo.log(items.length);
312 if (!skip_children) {
313 for(var i =0;i < items.length;i++) {
314 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
336 * @class Roo.bootstrap.Body
337 * @extends Roo.bootstrap.Component
338 * Bootstrap Body class
342 * @param {Object} config The config object
345 Roo.bootstrap.Body = function(config){
346 Roo.bootstrap.Body.superclass.constructor.call(this, config);
347 this.el = Roo.get(document.body);
348 if (this.cls && this.cls.length) {
349 Roo.get(document.body).addClass(this.cls);
353 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
358 onRender : function(ct, position)
360 /* Roo.log("Roo.bootstrap.Body - onRender");
361 if (this.cls && this.cls.length) {
362 Roo.get(document.body).addClass(this.cls);
382 * @class Roo.bootstrap.ButtonGroup
383 * @extends Roo.bootstrap.Component
384 * Bootstrap ButtonGroup class
385 * @cfg {String} size lg | sm | xs (default empty normal)
386 * @cfg {String} align vertical | justified (default none)
387 * @cfg {String} direction up | down (default down)
388 * @cfg {Boolean} toolbar false | true
389 * @cfg {Boolean} btn true | false
394 * @param {Object} config The config object
397 Roo.bootstrap.ButtonGroup = function(config){
398 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
401 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
409 getAutoCreate : function(){
415 cfg.html = this.html || cfg.html;
426 if (['vertical','justified'].indexOf(this.align)!==-1) {
427 cfg.cls = 'btn-group-' + this.align;
429 if (this.align == 'justified') {
430 console.log(this.items);
434 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
435 cfg.cls += ' btn-group-' + this.size;
438 if (this.direction == 'up') {
439 cfg.cls += ' dropup' ;
455 * @class Roo.bootstrap.Button
456 * @extends Roo.bootstrap.Component
457 * Bootstrap Button class
458 * @cfg {String} html The button content
459 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
460 * @cfg {String} size ( lg | sm | xs)
461 * @cfg {String} tag ( a | input | submit)
462 * @cfg {String} href empty or href
463 * @cfg {Boolean} disabled default false;
464 * @cfg {Boolean} isClose default false;
465 * @cfg {String} glyphicon (| 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)
466 * @cfg {String} badge text for badge
467 * @cfg {String} theme default
468 * @cfg {Boolean} inverse
469 * @cfg {Boolean} toggle
470 * @cfg {String} ontext text for on toggle state
471 * @cfg {String} offtext text for off toggle state
472 * @cfg {Boolean} defaulton
473 * @cfg {Boolean} preventDefault default true
474 * @cfg {Boolean} removeClass remove the standard class..
475 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
478 * Create a new button
479 * @param {Object} config The config object
483 Roo.bootstrap.Button = function(config){
484 Roo.bootstrap.Button.superclass.constructor.call(this, config);
489 * When a butotn is pressed
490 * @param {Roo.EventObject} e
495 * After the button has been toggles
496 * @param {Roo.EventObject} e
497 * @param {boolean} pressed (also available as button.pressed)
503 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
521 preventDefault: true,
530 getAutoCreate : function(){
538 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
539 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
544 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
546 if (this.toggle == true) {
549 cls: 'slider-frame roo-button',
554 'data-off-text':'OFF',
555 cls: 'slider-button',
561 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
562 cfg.cls += ' '+this.weight;
571 cfg["aria-hidden"] = true;
573 cfg.html = "×";
579 if (this.theme==='default') {
580 cfg.cls = 'btn roo-button';
582 //if (this.parentType != 'Navbar') {
583 this.weight = this.weight.length ? this.weight : 'default';
585 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
587 cfg.cls += ' btn-' + this.weight;
589 } else if (this.theme==='glow') {
592 cfg.cls = 'btn-glow roo-button';
594 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
596 cfg.cls += ' ' + this.weight;
602 this.cls += ' inverse';
607 cfg.cls += ' active';
611 cfg.disabled = 'disabled';
615 Roo.log('changing to ul' );
617 this.glyphicon = 'caret';
620 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
622 //gsRoo.log(this.parentType);
623 if (this.parentType === 'Navbar' && !this.parent().bar) {
624 Roo.log('changing to li?');
633 href : this.href || '#'
636 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
637 cfg.cls += ' dropdown';
644 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
646 if (this.glyphicon) {
647 cfg.html = ' ' + cfg.html;
652 cls: 'glyphicon glyphicon-' + this.glyphicon
662 // cfg.cls='btn roo-button';
666 var value = cfg.html;
671 cls: 'glyphicon glyphicon-' + this.glyphicon,
690 cfg.cls += ' dropdown';
691 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
694 if (cfg.tag !== 'a' && this.href !== '') {
695 throw "Tag must be a to set href.";
696 } else if (this.href.length > 0) {
697 cfg.href = this.href;
700 if(this.removeClass){
705 cfg.target = this.target;
710 initEvents: function() {
711 // Roo.log('init events?');
712 // Roo.log(this.el.dom);
715 if (typeof (this.menu) != 'undefined') {
716 this.menu.parentType = this.xtype;
717 this.menu.triggerEl = this.el;
718 this.addxtype(Roo.apply({}, this.menu));
722 if (this.el.hasClass('roo-button')) {
723 this.el.on('click', this.onClick, this);
725 this.el.select('.roo-button').on('click', this.onClick, this);
728 if(this.removeClass){
729 this.el.on('click', this.onClick, this);
732 this.el.enableDisplayMode();
735 onClick : function(e)
742 Roo.log('button on click ');
743 if(this.preventDefault){
746 if (this.pressed === true || this.pressed === false) {
747 this.pressed = !this.pressed;
748 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
749 this.fireEvent('toggle', this, e, this.pressed);
753 this.fireEvent('click', this, e);
757 * Enables this button
761 this.disabled = false;
762 this.el.removeClass('disabled');
766 * Disable this button
770 this.disabled = true;
771 this.el.addClass('disabled');
774 * sets the active state on/off,
775 * @param {Boolean} state (optional) Force a particular state
777 setActive : function(v) {
779 this.el[v ? 'addClass' : 'removeClass']('active');
782 * toggles the current active state
784 toggleActive : function()
786 var active = this.el.hasClass('active');
787 this.setActive(!active);
791 setText : function(str)
793 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
797 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
820 * @class Roo.bootstrap.Column
821 * @extends Roo.bootstrap.Component
822 * Bootstrap Column class
823 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
824 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
825 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
826 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
827 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
828 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
829 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
830 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
833 * @cfg {Boolean} hidden (true|false) hide the element
834 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
835 * @cfg {String} fa (ban|check|...) font awesome icon
836 * @cfg {Number} fasize (1|2|....) font awsome size
838 * @cfg {String} icon (info-sign|check|...) glyphicon name
840 * @cfg {String} html content of column.
843 * Create a new Column
844 * @param {Object} config The config object
847 Roo.bootstrap.Column = function(config){
848 Roo.bootstrap.Column.superclass.constructor.call(this, config);
851 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
869 getAutoCreate : function(){
870 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
878 ['xs','sm','md','lg'].map(function(size){
879 //Roo.log( size + ':' + settings[size]);
881 if (settings[size+'off'] !== false) {
882 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
885 if (settings[size] === false) {
888 Roo.log(settings[size]);
889 if (!settings[size]) { // 0 = hidden
890 cfg.cls += ' hidden-' + size;
893 cfg.cls += ' col-' + size + '-' + settings[size];
898 cfg.cls += ' hidden';
901 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
902 cfg.cls +=' alert alert-' + this.alert;
906 if (this.html.length) {
907 cfg.html = this.html;
911 if (this.fasize > 1) {
912 fasize = ' fa-' + this.fasize + 'x';
914 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
919 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
938 * @class Roo.bootstrap.Container
939 * @extends Roo.bootstrap.Component
940 * Bootstrap Container class
941 * @cfg {Boolean} jumbotron is it a jumbotron element
942 * @cfg {String} html content of element
943 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
944 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
945 * @cfg {String} header content of header (for panel)
946 * @cfg {String} footer content of footer (for panel)
947 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
948 * @cfg {String} tag (header|aside|section) type of HTML tag.
949 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
950 * @cfg {String} fa (ban|check|...) font awesome icon
951 * @cfg {String} icon (info-sign|check|...) glyphicon name
952 * @cfg {Boolean} hidden (true|false) hide the element
956 * Create a new Container
957 * @param {Object} config The config object
960 Roo.bootstrap.Container = function(config){
961 Roo.bootstrap.Container.superclass.constructor.call(this, config);
964 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
978 getChildContainer : function() {
984 if (this.panel.length) {
985 return this.el.select('.panel-body',true).first();
992 getAutoCreate : function(){
995 tag : this.tag || 'div',
999 if (this.jumbotron) {
1000 cfg.cls = 'jumbotron';
1005 // - this is applied by the parent..
1007 // cfg.cls = this.cls + '';
1010 if (this.sticky.length) {
1012 var bd = Roo.get(document.body);
1013 if (!bd.hasClass('bootstrap-sticky')) {
1014 bd.addClass('bootstrap-sticky');
1015 Roo.select('html',true).setStyle('height', '100%');
1018 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1022 if (this.well.length) {
1023 switch (this.well) {
1026 cfg.cls +=' well well-' +this.well;
1035 cfg.cls += ' hidden';
1039 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1040 cfg.cls +=' alert alert-' + this.alert;
1045 if (this.panel.length) {
1046 cfg.cls += ' panel panel-' + this.panel;
1048 if (this.header.length) {
1051 cls : 'panel-heading',
1054 cls : 'panel-title',
1067 if (this.footer.length) {
1069 cls : 'panel-footer',
1078 body.html = this.html || cfg.html;
1079 // prefix with the icons..
1081 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1084 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1089 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1090 cfg.cls = 'container';
1096 titleEl : function()
1098 if(!this.el || !this.panel.length || !this.header.length){
1102 return this.el.select('.panel-title',true).first();
1105 setTitle : function(v)
1107 var titleEl = this.titleEl();
1113 titleEl.dom.innerHTML = v;
1116 getTitle : function()
1119 var titleEl = this.titleEl();
1125 return titleEl.dom.innerHTML;
1129 this.el.removeClass('hidden');
1132 if (!this.el.hasClass('hidden')) {
1133 this.el.addClass('hidden');
1149 * @class Roo.bootstrap.Img
1150 * @extends Roo.bootstrap.Component
1151 * Bootstrap Img class
1152 * @cfg {Boolean} imgResponsive false | true
1153 * @cfg {String} border rounded | circle | thumbnail
1154 * @cfg {String} src image source
1155 * @cfg {String} alt image alternative text
1156 * @cfg {String} href a tag href
1157 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1160 * Create a new Input
1161 * @param {Object} config The config object
1164 Roo.bootstrap.Img = function(config){
1165 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1171 * The img click event for the img.
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1180 imgResponsive: true,
1186 getAutoCreate : function(){
1190 cls: (this.imgResponsive) ? 'img-responsive' : '',
1194 cfg.html = this.html || cfg.html;
1196 cfg.src = this.src || cfg.src;
1198 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1199 cfg.cls += ' img-' + this.border;
1216 a.target = this.target;
1222 return (this.href) ? a : cfg;
1225 initEvents: function() {
1228 this.el.on('click', this.onClick, this);
1232 onClick : function(e)
1234 Roo.log('img onclick');
1235 this.fireEvent('click', this, e);
1249 * @class Roo.bootstrap.Link
1250 * @extends Roo.bootstrap.Component
1251 * Bootstrap Link Class
1252 * @cfg {String} alt image alternative text
1253 * @cfg {String} href a tag href
1254 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1255 * @cfg {String} html the content of the link.
1256 * @cfg {String} anchor name for the anchor link
1258 * @cfg {Boolean} preventDefault (true | false) default false
1262 * Create a new Input
1263 * @param {Object} config The config object
1266 Roo.bootstrap.Link = function(config){
1267 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1273 * The img click event for the img.
1274 * @param {Roo.EventObject} e
1280 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1284 preventDefault: false,
1288 getAutoCreate : function()
1294 // anchor's do not require html/href...
1295 if (this.anchor === false) {
1296 cfg.html = this.html || 'html-missing';
1297 cfg.href = this.href || '#';
1299 cfg.name = this.anchor;
1300 if (this.html !== false) {
1301 cfg.html = this.html;
1303 if (this.href !== false) {
1304 cfg.href = this.href;
1308 if(this.alt !== false){
1313 if(this.target !== false) {
1314 cfg.target = this.target;
1320 initEvents: function() {
1322 if(!this.href || this.preventDefault){
1323 this.el.on('click', this.onClick, this);
1327 onClick : function(e)
1329 if(this.preventDefault){
1332 //Roo.log('img onclick');
1333 this.fireEvent('click', this, e);
1346 * @class Roo.bootstrap.Header
1347 * @extends Roo.bootstrap.Component
1348 * Bootstrap Header class
1349 * @cfg {String} html content of header
1350 * @cfg {Number} level (1|2|3|4|5|6) default 1
1353 * Create a new Header
1354 * @param {Object} config The config object
1358 Roo.bootstrap.Header = function(config){
1359 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1362 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1370 getAutoCreate : function(){
1373 tag: 'h' + (1 *this.level),
1374 html: this.html || 'fill in html'
1386 * Ext JS Library 1.1.1
1387 * Copyright(c) 2006-2007, Ext JS, LLC.
1389 * Originally Released Under LGPL - original licence link has changed is not relivant.
1392 * <script type="text/javascript">
1396 * @class Roo.bootstrap.MenuMgr
1397 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1400 Roo.bootstrap.MenuMgr = function(){
1401 var menus, active, groups = {}, attached = false, lastShow = new Date();
1403 // private - called when first menu is created
1406 active = new Roo.util.MixedCollection();
1407 Roo.get(document).addKeyListener(27, function(){
1408 if(active.length > 0){
1416 if(active && active.length > 0){
1417 var c = active.clone();
1427 if(active.length < 1){
1428 Roo.get(document).un("mouseup", onMouseDown);
1436 var last = active.last();
1437 lastShow = new Date();
1440 Roo.get(document).on("mouseup", onMouseDown);
1445 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1446 m.parentMenu.activeChild = m;
1447 }else if(last && last.isVisible()){
1448 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1453 function onBeforeHide(m){
1455 m.activeChild.hide();
1457 if(m.autoHideTimer){
1458 clearTimeout(m.autoHideTimer);
1459 delete m.autoHideTimer;
1464 function onBeforeShow(m){
1465 var pm = m.parentMenu;
1466 if(!pm && !m.allowOtherMenus){
1468 }else if(pm && pm.activeChild && active != m){
1469 pm.activeChild.hide();
1474 function onMouseDown(e){
1475 Roo.log("on MouseDown");
1476 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1484 function onBeforeCheck(mi, state){
1486 var g = groups[mi.group];
1487 for(var i = 0, l = g.length; i < l; i++){
1489 g[i].setChecked(false);
1498 * Hides all menus that are currently visible
1500 hideAll : function(){
1505 register : function(menu){
1509 menus[menu.id] = menu;
1510 menu.on("beforehide", onBeforeHide);
1511 menu.on("hide", onHide);
1512 menu.on("beforeshow", onBeforeShow);
1513 menu.on("show", onShow);
1515 if(g && menu.events["checkchange"]){
1519 groups[g].push(menu);
1520 menu.on("checkchange", onCheck);
1525 * Returns a {@link Roo.menu.Menu} object
1526 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1527 * be used to generate and return a new Menu instance.
1529 get : function(menu){
1530 if(typeof menu == "string"){ // menu id
1532 }else if(menu.events){ // menu instance
1535 /*else if(typeof menu.length == 'number'){ // array of menu items?
1536 return new Roo.bootstrap.Menu({items:menu});
1537 }else{ // otherwise, must be a config
1538 return new Roo.bootstrap.Menu(menu);
1545 unregister : function(menu){
1546 delete menus[menu.id];
1547 menu.un("beforehide", onBeforeHide);
1548 menu.un("hide", onHide);
1549 menu.un("beforeshow", onBeforeShow);
1550 menu.un("show", onShow);
1552 if(g && menu.events["checkchange"]){
1553 groups[g].remove(menu);
1554 menu.un("checkchange", onCheck);
1559 registerCheckable : function(menuItem){
1560 var g = menuItem.group;
1565 groups[g].push(menuItem);
1566 menuItem.on("beforecheckchange", onBeforeCheck);
1571 unregisterCheckable : function(menuItem){
1572 var g = menuItem.group;
1574 groups[g].remove(menuItem);
1575 menuItem.un("beforecheckchange", onBeforeCheck);
1587 * @class Roo.bootstrap.Menu
1588 * @extends Roo.bootstrap.Component
1589 * Bootstrap Menu class - container for MenuItems
1590 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1594 * @param {Object} config The config object
1598 Roo.bootstrap.Menu = function(config){
1599 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1600 if (this.registerMenu) {
1601 Roo.bootstrap.MenuMgr.register(this);
1606 * Fires before this menu is displayed
1607 * @param {Roo.menu.Menu} this
1612 * Fires before this menu is hidden
1613 * @param {Roo.menu.Menu} this
1618 * Fires after this menu is displayed
1619 * @param {Roo.menu.Menu} this
1624 * Fires after this menu is hidden
1625 * @param {Roo.menu.Menu} this
1630 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1631 * @param {Roo.menu.Menu} this
1632 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1633 * @param {Roo.EventObject} e
1638 * Fires when the mouse is hovering over this menu
1639 * @param {Roo.menu.Menu} this
1640 * @param {Roo.EventObject} e
1641 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1646 * Fires when the mouse exits this menu
1647 * @param {Roo.menu.Menu} this
1648 * @param {Roo.EventObject} e
1649 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1654 * Fires when a menu item contained in this menu is clicked
1655 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1656 * @param {Roo.EventObject} e
1660 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1663 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1667 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1670 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1672 registerMenu : true,
1674 menuItems :false, // stores the menu items..
1680 getChildContainer : function() {
1684 getAutoCreate : function(){
1686 //if (['right'].indexOf(this.align)!==-1) {
1687 // cfg.cn[1].cls += ' pull-right'
1693 cls : 'dropdown-menu' ,
1694 style : 'z-index:1000'
1698 if (this.type === 'submenu') {
1699 cfg.cls = 'submenu active';
1701 if (this.type === 'treeview') {
1702 cfg.cls = 'treeview-menu';
1707 initEvents : function() {
1709 // Roo.log("ADD event");
1710 // Roo.log(this.triggerEl.dom);
1711 this.triggerEl.on('click', this.onTriggerPress, this);
1712 this.triggerEl.addClass('dropdown-toggle');
1713 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1715 this.el.on("mouseover", this.onMouseOver, this);
1716 this.el.on("mouseout", this.onMouseOut, this);
1720 findTargetItem : function(e){
1721 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1725 //Roo.log(t); Roo.log(t.id);
1727 //Roo.log(this.menuitems);
1728 return this.menuitems.get(t.id);
1730 //return this.items.get(t.menuItemId);
1735 onClick : function(e){
1736 Roo.log("menu.onClick");
1737 var t = this.findTargetItem(e);
1738 if(!t || t.isContainer){
1743 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1744 if(t == this.activeItem && t.shouldDeactivate(e)){
1745 this.activeItem.deactivate();
1746 delete this.activeItem;
1750 this.setActiveItem(t, true);
1758 Roo.log('pass click event');
1762 this.fireEvent("click", this, t, e);
1766 onMouseOver : function(e){
1767 var t = this.findTargetItem(e);
1770 // if(t.canActivate && !t.disabled){
1771 // this.setActiveItem(t, true);
1775 this.fireEvent("mouseover", this, e, t);
1777 isVisible : function(){
1778 return !this.hidden;
1780 onMouseOut : function(e){
1781 var t = this.findTargetItem(e);
1784 // if(t == this.activeItem && t.shouldDeactivate(e)){
1785 // this.activeItem.deactivate();
1786 // delete this.activeItem;
1789 this.fireEvent("mouseout", this, e, t);
1794 * Displays this menu relative to another element
1795 * @param {String/HTMLElement/Roo.Element} element The element to align to
1796 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1797 * the element (defaults to this.defaultAlign)
1798 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1800 show : function(el, pos, parentMenu){
1801 this.parentMenu = parentMenu;
1805 this.fireEvent("beforeshow", this);
1806 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1809 * Displays this menu at a specific xy position
1810 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1811 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1813 showAt : function(xy, parentMenu, /* private: */_e){
1814 this.parentMenu = parentMenu;
1819 this.fireEvent("beforeshow", this);
1821 //xy = this.el.adjustForConstraints(xy);
1823 //this.el.setXY(xy);
1825 this.hideMenuItems();
1826 this.hidden = false;
1827 this.triggerEl.addClass('open');
1829 this.fireEvent("show", this);
1835 this.doFocus.defer(50, this);
1839 doFocus : function(){
1841 this.focusEl.focus();
1846 * Hides this menu and optionally all parent menus
1847 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1849 hide : function(deep){
1851 this.hideMenuItems();
1852 if(this.el && this.isVisible()){
1853 this.fireEvent("beforehide", this);
1854 if(this.activeItem){
1855 this.activeItem.deactivate();
1856 this.activeItem = null;
1858 this.triggerEl.removeClass('open');;
1860 this.fireEvent("hide", this);
1862 if(deep === true && this.parentMenu){
1863 this.parentMenu.hide(true);
1867 onTriggerPress : function(e)
1870 Roo.log('trigger press');
1871 //Roo.log(e.getTarget());
1872 // Roo.log(this.triggerEl.dom);
1873 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1876 if (this.isVisible()) {
1880 this.show(this.triggerEl, false, false);
1889 hideMenuItems : function()
1891 //$(backdrop).remove()
1892 Roo.select('.open',true).each(function(aa) {
1894 aa.removeClass('open');
1895 //var parent = getParent($(this))
1896 //var relatedTarget = { relatedTarget: this }
1898 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1899 //if (e.isDefaultPrevented()) return
1900 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1903 addxtypeChild : function (tree, cntr) {
1904 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1906 this.menuitems.add(comp);
1927 * @class Roo.bootstrap.MenuItem
1928 * @extends Roo.bootstrap.Component
1929 * Bootstrap MenuItem class
1930 * @cfg {String} html the menu label
1931 * @cfg {String} href the link
1932 * @cfg {Boolean} preventDefault (true | false) default true
1933 * @cfg {Boolean} isContainer (true | false) default false
1937 * Create a new MenuItem
1938 * @param {Object} config The config object
1942 Roo.bootstrap.MenuItem = function(config){
1943 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1948 * The raw click event for the entire grid.
1949 * @param {Roo.EventObject} e
1955 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1959 preventDefault: true,
1960 isContainer : false,
1962 getAutoCreate : function(){
1964 if(this.isContainer){
1967 cls: 'dropdown-menu-item'
1973 cls: 'dropdown-menu-item',
1982 if (this.parent().type == 'treeview') {
1983 cfg.cls = 'treeview-menu';
1986 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1987 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1991 initEvents: function() {
1993 //this.el.select('a').on('click', this.onClick, this);
1996 onClick : function(e)
1998 Roo.log('item on click ');
1999 //if(this.preventDefault){
2000 // e.preventDefault();
2002 //this.parent().hideMenuItems();
2004 this.fireEvent('click', this, e);
2023 * @class Roo.bootstrap.MenuSeparator
2024 * @extends Roo.bootstrap.Component
2025 * Bootstrap MenuSeparator class
2028 * Create a new MenuItem
2029 * @param {Object} config The config object
2033 Roo.bootstrap.MenuSeparator = function(config){
2034 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2037 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2039 getAutoCreate : function(){
2054 <div class="modal fade">
2055 <div class="modal-dialog">
2056 <div class="modal-content">
2057 <div class="modal-header">
2058 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
2059 <h4 class="modal-title">Modal title</h4>
2061 <div class="modal-body">
2062 <p>One fine body…</p>
2064 <div class="modal-footer">
2065 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2066 <button type="button" class="btn btn-primary">Save changes</button>
2068 </div><!-- /.modal-content -->
2069 </div><!-- /.modal-dialog -->
2070 </div><!-- /.modal -->
2080 * @class Roo.bootstrap.Modal
2081 * @extends Roo.bootstrap.Component
2082 * Bootstrap Modal class
2083 * @cfg {String} title Title of dialog
2084 * @cfg {Boolean} specificTitle default false
2085 * @cfg {Array} buttons Array of buttons or standard button set..
2086 * @cfg {String} buttonPosition (left|right|center) default right
2087 * @cfg {Boolean} animate default true
2088 * @cfg {Boolean} allow_close default true
2091 * Create a new Modal Dialog
2092 * @param {Object} config The config object
2095 Roo.bootstrap.Modal = function(config){
2096 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2101 * The raw btnclick event for the button
2102 * @param {Roo.EventObject} e
2106 this.buttons = this.buttons || [];
2109 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2111 title : 'test dialog',
2118 specificTitle: false,
2120 buttonPosition: 'right',
2126 onRender : function(ct, position)
2128 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2131 var cfg = Roo.apply({}, this.getAutoCreate());
2134 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2136 //if (!cfg.name.length) {
2140 cfg.cls += ' ' + this.cls;
2143 cfg.style = this.style;
2145 this.el = Roo.get(document.body).createChild(cfg, position);
2147 //var type = this.el.dom.type;
2149 if(this.tabIndex !== undefined){
2150 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2155 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2156 this.maskEl.enableDisplayMode("block");
2158 //this.el.addClass("x-dlg-modal");
2160 if (this.buttons.length) {
2161 Roo.each(this.buttons, function(bb) {
2162 b = Roo.apply({}, bb);
2163 b.xns = b.xns || Roo.bootstrap;
2164 b.xtype = b.xtype || 'Button';
2165 if (typeof(b.listeners) == 'undefined') {
2166 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2169 var btn = Roo.factory(b);
2171 btn.onRender(this.el.select('.modal-footer div').first());
2175 // render the children.
2178 if(typeof(this.items) != 'undefined'){
2179 var items = this.items;
2182 for(var i =0;i < items.length;i++) {
2183 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2187 this.items = nitems;
2189 this.body = this.el.select('.modal-body',true).first();
2190 this.close = this.el.select('.modal-header .close', true).first();
2191 this.footer = this.el.select('.modal-footer',true).first();
2193 //this.el.addClass([this.fieldClass, this.cls]);
2196 getAutoCreate : function(){
2201 html : this.html || ''
2206 cls : 'modal-title',
2210 if(this.specificTitle){
2216 if (this.allow_close) {
2227 style : 'display: none',
2230 cls: "modal-dialog",
2233 cls : "modal-content",
2236 cls : 'modal-header',
2241 cls : 'modal-footer',
2245 cls: 'btn-' + this.buttonPosition
2262 modal.cls += ' fade';
2268 getChildContainer : function() {
2270 return this.el.select('.modal-body',true).first();
2273 getButtonContainer : function() {
2274 return this.el.select('.modal-footer div',true).first();
2277 initEvents : function()
2279 this.el.select('.modal-header .close').on('click', this.hide, this);
2281 // this.addxtype(this);
2285 if (!this.rendered) {
2289 this.el.setStyle('display', 'block');
2293 (function(){ _this.el.addClass('in'); }).defer(50);
2295 this.el.addClass('in');
2298 Roo.get(document.body).addClass("x-body-masked");
2299 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2301 this.el.setStyle('zIndex', '10001');
2303 this.fireEvent('show', this);
2310 Roo.get(document.body).removeClass("x-body-masked");
2311 this.el.removeClass('in');
2315 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2317 this.el.setStyle('display', 'none');
2320 this.fireEvent('hide', this);
2323 addButton : function(str, cb)
2327 var b = Roo.apply({}, { html : str } );
2328 b.xns = b.xns || Roo.bootstrap;
2329 b.xtype = b.xtype || 'Button';
2330 if (typeof(b.listeners) == 'undefined') {
2331 b.listeners = { click : cb.createDelegate(this) };
2334 var btn = Roo.factory(b);
2336 btn.onRender(this.el.select('.modal-footer div').first());
2342 setDefaultButton : function(btn)
2344 //this.el.select('.modal-footer').()
2346 resizeTo: function(w,h)
2350 setContentSize : function(w, h)
2354 onButtonClick: function(btn,e)
2357 this.fireEvent('btnclick', btn.name, e);
2359 setTitle: function(str) {
2360 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2366 Roo.apply(Roo.bootstrap.Modal, {
2368 * Button config that displays a single OK button
2377 * Button config that displays Yes and No buttons
2393 * Button config that displays OK and Cancel buttons
2408 * Button config that displays Yes, No and Cancel buttons
2430 * messagebox - can be used as a replace
2434 * @class Roo.MessageBox
2435 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2439 Roo.Msg.alert('Status', 'Changes saved successfully.');
2441 // Prompt for user data:
2442 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2444 // process text value...
2448 // Show a dialog using config options:
2450 title:'Save Changes?',
2451 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2452 buttons: Roo.Msg.YESNOCANCEL,
2459 Roo.bootstrap.MessageBox = function(){
2460 var dlg, opt, mask, waitTimer;
2461 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2462 var buttons, activeTextEl, bwidth;
2466 var handleButton = function(button){
2468 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2472 var handleHide = function(){
2474 dlg.el.removeClass(opt.cls);
2477 // Roo.TaskMgr.stop(waitTimer);
2478 // waitTimer = null;
2483 var updateButtons = function(b){
2486 buttons["ok"].hide();
2487 buttons["cancel"].hide();
2488 buttons["yes"].hide();
2489 buttons["no"].hide();
2490 //dlg.footer.dom.style.display = 'none';
2493 dlg.footer.dom.style.display = '';
2494 for(var k in buttons){
2495 if(typeof buttons[k] != "function"){
2498 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2499 width += buttons[k].el.getWidth()+15;
2509 var handleEsc = function(d, k, e){
2510 if(opt && opt.closable !== false){
2520 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2521 * @return {Roo.BasicDialog} The BasicDialog element
2523 getDialog : function(){
2525 dlg = new Roo.bootstrap.Modal( {
2528 //constraintoviewport:false,
2530 //collapsible : false,
2535 //buttonAlign:"center",
2536 closeClick : function(){
2537 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2540 handleButton("cancel");
2545 dlg.on("hide", handleHide);
2547 //dlg.addKeyListener(27, handleEsc);
2549 this.buttons = buttons;
2550 var bt = this.buttonText;
2551 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2552 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2553 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2554 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2556 bodyEl = dlg.body.createChild({
2558 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2559 '<textarea class="roo-mb-textarea"></textarea>' +
2560 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2562 msgEl = bodyEl.dom.firstChild;
2563 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2564 textboxEl.enableDisplayMode();
2565 textboxEl.addKeyListener([10,13], function(){
2566 if(dlg.isVisible() && opt && opt.buttons){
2569 }else if(opt.buttons.yes){
2570 handleButton("yes");
2574 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2575 textareaEl.enableDisplayMode();
2576 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2577 progressEl.enableDisplayMode();
2578 var pf = progressEl.dom.firstChild;
2580 pp = Roo.get(pf.firstChild);
2581 pp.setHeight(pf.offsetHeight);
2589 * Updates the message box body text
2590 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2591 * the XHTML-compliant non-breaking space character '&#160;')
2592 * @return {Roo.MessageBox} This message box
2594 updateText : function(text){
2595 if(!dlg.isVisible() && !opt.width){
2596 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2598 msgEl.innerHTML = text || ' ';
2600 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2601 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2603 Math.min(opt.width || cw , this.maxWidth),
2604 Math.max(opt.minWidth || this.minWidth, bwidth)
2607 activeTextEl.setWidth(w);
2609 if(dlg.isVisible()){
2610 dlg.fixedcenter = false;
2612 // to big, make it scroll. = But as usual stupid IE does not support
2615 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2616 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2617 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2619 bodyEl.dom.style.height = '';
2620 bodyEl.dom.style.overflowY = '';
2623 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2625 bodyEl.dom.style.overflowX = '';
2628 dlg.setContentSize(w, bodyEl.getHeight());
2629 if(dlg.isVisible()){
2630 dlg.fixedcenter = true;
2636 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2637 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2638 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2639 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2640 * @return {Roo.MessageBox} This message box
2642 updateProgress : function(value, text){
2644 this.updateText(text);
2646 if (pp) { // weird bug on my firefox - for some reason this is not defined
2647 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2653 * Returns true if the message box is currently displayed
2654 * @return {Boolean} True if the message box is visible, else false
2656 isVisible : function(){
2657 return dlg && dlg.isVisible();
2661 * Hides the message box if it is displayed
2664 if(this.isVisible()){
2670 * Displays a new message box, or reinitializes an existing message box, based on the config options
2671 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2672 * The following config object properties are supported:
2674 Property Type Description
2675 ---------- --------------- ------------------------------------------------------------------------------------
2676 animEl String/Element An id or Element from which the message box should animate as it opens and
2677 closes (defaults to undefined)
2678 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2679 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2680 closable Boolean False to hide the top-right close button (defaults to true). Note that
2681 progress and wait dialogs will ignore this property and always hide the
2682 close button as they can only be closed programmatically.
2683 cls String A custom CSS class to apply to the message box element
2684 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2685 displayed (defaults to 75)
2686 fn Function A callback function to execute after closing the dialog. The arguments to the
2687 function will be btn (the name of the button that was clicked, if applicable,
2688 e.g. "ok"), and text (the value of the active text field, if applicable).
2689 Progress and wait dialogs will ignore this option since they do not respond to
2690 user actions and can only be closed programmatically, so any required function
2691 should be called by the same code after it closes the dialog.
2692 icon String A CSS class that provides a background image to be used as an icon for
2693 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2694 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2695 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2696 modal Boolean False to allow user interaction with the page while the message box is
2697 displayed (defaults to true)
2698 msg String A string that will replace the existing message box body text (defaults
2699 to the XHTML-compliant non-breaking space character ' ')
2700 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2701 progress Boolean True to display a progress bar (defaults to false)
2702 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2703 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2704 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2705 title String The title text
2706 value String The string value to set into the active textbox element if displayed
2707 wait Boolean True to display a progress bar (defaults to false)
2708 width Number The width of the dialog in pixels
2715 msg: 'Please enter your address:',
2717 buttons: Roo.MessageBox.OKCANCEL,
2720 animEl: 'addAddressBtn'
2723 * @param {Object} config Configuration options
2724 * @return {Roo.MessageBox} This message box
2726 show : function(options)
2729 // this causes nightmares if you show one dialog after another
2730 // especially on callbacks..
2732 if(this.isVisible()){
2735 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2736 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2737 Roo.log("New Dialog Message:" + options.msg )
2738 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2739 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2742 var d = this.getDialog();
2744 d.setTitle(opt.title || " ");
2745 d.close.setDisplayed(opt.closable !== false);
2746 activeTextEl = textboxEl;
2747 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2752 textareaEl.setHeight(typeof opt.multiline == "number" ?
2753 opt.multiline : this.defaultTextHeight);
2754 activeTextEl = textareaEl;
2763 progressEl.setDisplayed(opt.progress === true);
2764 this.updateProgress(0);
2765 activeTextEl.dom.value = opt.value || "";
2767 dlg.setDefaultButton(activeTextEl);
2769 var bs = opt.buttons;
2773 }else if(bs && bs.yes){
2774 db = buttons["yes"];
2776 dlg.setDefaultButton(db);
2778 bwidth = updateButtons(opt.buttons);
2779 this.updateText(opt.msg);
2781 d.el.addClass(opt.cls);
2783 d.proxyDrag = opt.proxyDrag === true;
2784 d.modal = opt.modal !== false;
2785 d.mask = opt.modal !== false ? mask : false;
2787 // force it to the end of the z-index stack so it gets a cursor in FF
2788 document.body.appendChild(dlg.el.dom);
2789 d.animateTarget = null;
2790 d.show(options.animEl);
2796 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2797 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2798 * and closing the message box when the process is complete.
2799 * @param {String} title The title bar text
2800 * @param {String} msg The message box body text
2801 * @return {Roo.MessageBox} This message box
2803 progress : function(title, msg){
2810 minWidth: this.minProgressWidth,
2817 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2818 * If a callback function is passed it will be called after the user clicks the button, and the
2819 * id of the button that was clicked will be passed as the only parameter to the callback
2820 * (could also be the top-right close button).
2821 * @param {String} title The title bar text
2822 * @param {String} msg The message box body text
2823 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2824 * @param {Object} scope (optional) The scope of the callback function
2825 * @return {Roo.MessageBox} This message box
2827 alert : function(title, msg, fn, scope){
2840 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2841 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2842 * You are responsible for closing the message box when the process is complete.
2843 * @param {String} msg The message box body text
2844 * @param {String} title (optional) The title bar text
2845 * @return {Roo.MessageBox} This message box
2847 wait : function(msg, title){
2858 waitTimer = Roo.TaskMgr.start({
2860 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2868 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2869 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2870 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2871 * @param {String} title The title bar text
2872 * @param {String} msg The message box body text
2873 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2874 * @param {Object} scope (optional) The scope of the callback function
2875 * @return {Roo.MessageBox} This message box
2877 confirm : function(title, msg, fn, scope){
2881 buttons: this.YESNO,
2890 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2891 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2892 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2893 * (could also be the top-right close button) and the text that was entered will be passed as the two
2894 * parameters to the callback.
2895 * @param {String} title The title bar text
2896 * @param {String} msg The message box body text
2897 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2898 * @param {Object} scope (optional) The scope of the callback function
2899 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2900 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2901 * @return {Roo.MessageBox} This message box
2903 prompt : function(title, msg, fn, scope, multiline){
2907 buttons: this.OKCANCEL,
2912 multiline: multiline,
2919 * Button config that displays a single OK button
2924 * Button config that displays Yes and No buttons
2927 YESNO : {yes:true, no:true},
2929 * Button config that displays OK and Cancel buttons
2932 OKCANCEL : {ok:true, cancel:true},
2934 * Button config that displays Yes, No and Cancel buttons
2937 YESNOCANCEL : {yes:true, no:true, cancel:true},
2940 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2943 defaultTextHeight : 75,
2945 * The maximum width in pixels of the message box (defaults to 600)
2950 * The minimum width in pixels of the message box (defaults to 100)
2955 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2956 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2959 minProgressWidth : 250,
2961 * An object containing the default button text strings that can be overriden for localized language support.
2962 * Supported properties are: ok, cancel, yes and no.
2963 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2976 * Shorthand for {@link Roo.MessageBox}
2978 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
2979 Roo.Msg = Roo.Msg || Roo.MessageBox;
2988 * @class Roo.bootstrap.Navbar
2989 * @extends Roo.bootstrap.Component
2990 * Bootstrap Navbar class
2993 * Create a new Navbar
2994 * @param {Object} config The config object
2998 Roo.bootstrap.Navbar = function(config){
2999 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3003 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3012 getAutoCreate : function(){
3015 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3019 initEvents :function ()
3021 //Roo.log(this.el.select('.navbar-toggle',true));
3022 this.el.select('.navbar-toggle',true).on('click', function() {
3023 // Roo.log('click');
3024 this.el.select('.navbar-collapse',true).toggleClass('in');
3032 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3034 var size = this.el.getSize();
3035 this.maskEl.setSize(size.width, size.height);
3036 this.maskEl.enableDisplayMode("block");
3045 getChildContainer : function()
3047 if (this.el.select('.collapse').getCount()) {
3048 return this.el.select('.collapse',true).first();
3081 * @class Roo.bootstrap.NavSimplebar
3082 * @extends Roo.bootstrap.Navbar
3083 * Bootstrap Sidebar class
3085 * @cfg {Boolean} inverse is inverted color
3087 * @cfg {String} type (nav | pills | tabs)
3088 * @cfg {Boolean} arrangement stacked | justified
3089 * @cfg {String} align (left | right) alignment
3091 * @cfg {Boolean} main (true|false) main nav bar? default false
3092 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3094 * @cfg {String} tag (header|footer|nav|div) default is nav
3100 * Create a new Sidebar
3101 * @param {Object} config The config object
3105 Roo.bootstrap.NavSimplebar = function(config){
3106 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3109 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3125 getAutoCreate : function(){
3129 tag : this.tag || 'div',
3142 this.type = this.type || 'nav';
3143 if (['tabs','pills'].indexOf(this.type)!==-1) {
3144 cfg.cn[0].cls += ' nav-' + this.type
3148 if (this.type!=='nav') {
3149 Roo.log('nav type must be nav/tabs/pills')
3151 cfg.cn[0].cls += ' navbar-nav'
3157 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3158 cfg.cn[0].cls += ' nav-' + this.arrangement;
3162 if (this.align === 'right') {
3163 cfg.cn[0].cls += ' navbar-right';
3167 cfg.cls += ' navbar-inverse';
3194 * @class Roo.bootstrap.NavHeaderbar
3195 * @extends Roo.bootstrap.NavSimplebar
3196 * Bootstrap Sidebar class
3198 * @cfg {String} brand what is brand
3199 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3200 * @cfg {String} brand_href href of the brand
3201 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3202 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3203 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3204 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3207 * Create a new Sidebar
3208 * @param {Object} config The config object
3212 Roo.bootstrap.NavHeaderbar = function(config){
3213 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3217 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3224 desktopCenter : false,
3227 getAutoCreate : function(){
3230 tag: this.nav || 'nav',
3237 if (this.desktopCenter) {
3238 cn.push({cls : 'container', cn : []});
3245 cls: 'navbar-header',
3250 cls: 'navbar-toggle',
3251 'data-toggle': 'collapse',
3256 html: 'Toggle navigation'
3278 cls: 'collapse navbar-collapse',
3282 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3284 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3285 cfg.cls += ' navbar-' + this.position;
3287 // tag can override this..
3289 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3292 if (this.brand !== '') {
3295 href: this.brand_href ? this.brand_href : '#',
3296 cls: 'navbar-brand',
3304 cfg.cls += ' main-nav';
3312 getHeaderChildContainer : function()
3314 if (this.el.select('.navbar-header').getCount()) {
3315 return this.el.select('.navbar-header',true).first();
3318 return this.getChildContainer();
3322 initEvents : function()
3324 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3326 if (this.autohide) {
3331 Roo.get(document).on('scroll',function(e) {
3332 var ns = Roo.get(document).getScroll().top;
3333 var os = prevScroll;
3337 ft.removeClass('slideDown');
3338 ft.addClass('slideUp');
3341 ft.removeClass('slideUp');
3342 ft.addClass('slideDown');
3366 * @class Roo.bootstrap.NavSidebar
3367 * @extends Roo.bootstrap.Navbar
3368 * Bootstrap Sidebar class
3371 * Create a new Sidebar
3372 * @param {Object} config The config object
3376 Roo.bootstrap.NavSidebar = function(config){
3377 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3380 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3382 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3384 getAutoCreate : function(){
3389 cls: 'sidebar sidebar-nav'
3411 * @class Roo.bootstrap.NavGroup
3412 * @extends Roo.bootstrap.Component
3413 * Bootstrap NavGroup class
3414 * @cfg {String} align left | right
3415 * @cfg {Boolean} inverse false | true
3416 * @cfg {String} type (nav|pills|tab) default nav
3417 * @cfg {String} navId - reference Id for navbar.
3421 * Create a new nav group
3422 * @param {Object} config The config object
3425 Roo.bootstrap.NavGroup = function(config){
3426 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3429 Roo.bootstrap.NavGroup.register(this);
3433 * Fires when the active item changes
3434 * @param {Roo.bootstrap.NavGroup} this
3435 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3436 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3443 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3454 getAutoCreate : function()
3456 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3463 if (['tabs','pills'].indexOf(this.type)!==-1) {
3464 cfg.cls += ' nav-' + this.type
3466 if (this.type!=='nav') {
3467 Roo.log('nav type must be nav/tabs/pills')
3469 cfg.cls += ' navbar-nav'
3472 if (this.parent().sidebar) {
3475 cls: 'dashboard-menu sidebar-menu'
3481 if (this.form === true) {
3487 if (this.align === 'right') {
3488 cfg.cls += ' navbar-right';
3490 cfg.cls += ' navbar-left';
3494 if (this.align === 'right') {
3495 cfg.cls += ' navbar-right';
3499 cfg.cls += ' navbar-inverse';
3507 * sets the active Navigation item
3508 * @param {Roo.bootstrap.NavItem} the new current navitem
3510 setActiveItem : function(item)
3513 Roo.each(this.navItems, function(v){
3518 v.setActive(false, true);
3525 item.setActive(true, true);
3526 this.fireEvent('changed', this, item, prev);
3531 * gets the active Navigation item
3532 * @return {Roo.bootstrap.NavItem} the current navitem
3534 getActive : function()
3538 Roo.each(this.navItems, function(v){
3549 indexOfNav : function()
3553 Roo.each(this.navItems, function(v,i){
3564 * adds a Navigation item
3565 * @param {Roo.bootstrap.NavItem} the navitem to add
3567 addItem : function(cfg)
3569 var cn = new Roo.bootstrap.NavItem(cfg);
3571 cn.parentId = this.id;
3572 cn.onRender(this.el, null);
3576 * register a Navigation item
3577 * @param {Roo.bootstrap.NavItem} the navitem to add
3579 register : function(item)
3581 this.navItems.push( item);
3582 item.navId = this.navId;
3587 * clear all the Navigation item
3590 clearAll : function()
3593 this.el.dom.innerHTML = '';
3596 getNavItem: function(tabId)
3599 Roo.each(this.navItems, function(e) {
3600 if (e.tabId == tabId) {
3610 setActiveNext : function()
3612 var i = this.indexOfNav(this.getActive());
3613 if (i > this.navItems.length) {
3616 this.setActiveItem(this.navItems[i+1]);
3618 setActivePrev : function()
3620 var i = this.indexOfNav(this.getActive());
3624 this.setActiveItem(this.navItems[i-1]);
3626 clearWasActive : function(except) {
3627 Roo.each(this.navItems, function(e) {
3628 if (e.tabId != except.tabId && e.was_active) {
3629 e.was_active = false;
3636 getWasActive : function ()
3639 Roo.each(this.navItems, function(e) {
3654 Roo.apply(Roo.bootstrap.NavGroup, {
3658 * register a Navigation Group
3659 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3661 register : function(navgrp)
3663 this.groups[navgrp.navId] = navgrp;
3667 * fetch a Navigation Group based on the navigation ID
3668 * @param {string} the navgroup to add
3669 * @returns {Roo.bootstrap.NavGroup} the navgroup
3671 get: function(navId) {
3672 if (typeof(this.groups[navId]) == 'undefined') {
3674 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3676 return this.groups[navId] ;
3691 * @class Roo.bootstrap.NavItem
3692 * @extends Roo.bootstrap.Component
3693 * Bootstrap Navbar.NavItem class
3694 * @cfg {String} href link to
3695 * @cfg {String} html content of button
3696 * @cfg {String} badge text inside badge
3697 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3698 * @cfg {String} glyphicon name of glyphicon
3699 * @cfg {String} icon name of font awesome icon
3700 * @cfg {Boolean} active Is item active
3701 * @cfg {Boolean} disabled Is item disabled
3703 * @cfg {Boolean} preventDefault (true | false) default false
3704 * @cfg {String} tabId the tab that this item activates.
3705 * @cfg {String} tagtype (a|span) render as a href or span?
3708 * Create a new Navbar Item
3709 * @param {Object} config The config object
3711 Roo.bootstrap.NavItem = function(config){
3712 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3717 * The raw click event for the entire grid.
3718 * @param {Roo.EventObject} e
3723 * Fires when the active item active state changes
3724 * @param {Roo.bootstrap.NavItem} this
3725 * @param {boolean} state the new state
3733 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3741 preventDefault : false,
3748 getAutoCreate : function(){
3756 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3758 if (this.disabled) {
3759 cfg.cls += ' disabled';
3762 if (this.href || this.html || this.glyphicon || this.icon) {
3766 href : this.href || "#",
3767 html: this.html || ''
3772 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3775 if(this.glyphicon) {
3776 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3781 cfg.cn[0].html += " <span class='caret'></span>";
3785 if (this.badge !== '') {
3787 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3795 initEvents: function()
3797 if (typeof (this.menu) != 'undefined') {
3798 this.menu.parentType = this.xtype;
3799 this.menu.triggerEl = this.el;
3800 this.menu = this.addxtype(Roo.apply({}, this.menu));
3803 this.el.select('a',true).on('click', this.onClick, this);
3805 if(this.tagtype == 'span'){
3806 this.el.select('span',true).on('click', this.onClick, this);
3809 // at this point parent should be available..
3810 this.parent().register(this);
3813 onClick : function(e)
3815 if(this.preventDefault || this.href == '#'){
3819 if (this.disabled) {
3823 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3824 if (tg && tg.transition) {
3825 Roo.log("waiting for the transitionend");
3829 Roo.log("fire event clicked");
3830 if(this.fireEvent('click', this, e) === false){
3834 if(this.tagtype == 'span'){
3838 var p = this.parent();
3839 if (['tabs','pills'].indexOf(p.type)!==-1) {
3840 if (typeof(p.setActiveItem) !== 'undefined') {
3841 p.setActiveItem(this);
3844 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3845 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3846 // remove the collapsed menu expand...
3847 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3852 isActive: function () {
3855 setActive : function(state, fire, is_was_active)
3857 if (this.active && !state & this.navId) {
3858 this.was_active = true;
3859 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3861 nv.clearWasActive(this);
3865 this.active = state;
3868 this.el.removeClass('active');
3869 } else if (!this.el.hasClass('active')) {
3870 this.el.addClass('active');
3873 this.fireEvent('changed', this, state);
3876 // show a panel if it's registered and related..
3878 if (!this.navId || !this.tabId || !state || is_was_active) {
3882 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3886 var pan = tg.getPanelByName(this.tabId);
3890 // if we can not flip to new panel - go back to old nav highlight..
3891 if (false == tg.showPanel(pan)) {
3892 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3894 var onav = nv.getWasActive();
3896 onav.setActive(true, false, true);
3905 // this should not be here...
3906 setDisabled : function(state)
3908 this.disabled = state;
3910 this.el.removeClass('disabled');
3911 } else if (!this.el.hasClass('disabled')) {
3912 this.el.addClass('disabled');
3918 * Fetch the element to display the tooltip on.
3919 * @return {Roo.Element} defaults to this.el
3921 tooltipEl : function()
3923 return this.el.select('' + this.tagtype + '', true).first();
3934 * <span> icon </span>
3935 * <span> text </span>
3936 * <span>badge </span>
3940 * @class Roo.bootstrap.NavSidebarItem
3941 * @extends Roo.bootstrap.NavItem
3942 * Bootstrap Navbar.NavSidebarItem class
3944 * Create a new Navbar Button
3945 * @param {Object} config The config object
3947 Roo.bootstrap.NavSidebarItem = function(config){
3948 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3953 * The raw click event for the entire grid.
3954 * @param {Roo.EventObject} e
3959 * Fires when the active item active state changes
3960 * @param {Roo.bootstrap.NavSidebarItem} this
3961 * @param {boolean} state the new state
3969 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3972 getAutoCreate : function(){
3977 href : this.href || '#',
3989 html : this.html || ''
3994 cfg.cls += ' active';
3998 if (this.glyphicon || this.icon) {
3999 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4000 a.cn.push({ tag : 'i', cls : c }) ;
4005 if (this.badge !== '') {
4006 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4010 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4011 a.cls += 'dropdown-toggle treeview' ;
4035 * @class Roo.bootstrap.Row
4036 * @extends Roo.bootstrap.Component
4037 * Bootstrap Row class (contains columns...)
4041 * @param {Object} config The config object
4044 Roo.bootstrap.Row = function(config){
4045 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4048 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4050 getAutoCreate : function(){
4069 * @class Roo.bootstrap.Element
4070 * @extends Roo.bootstrap.Component
4071 * Bootstrap Element class
4072 * @cfg {String} html contents of the element
4073 * @cfg {String} tag tag of the element
4074 * @cfg {String} cls class of the element
4077 * Create a new Element
4078 * @param {Object} config The config object
4081 Roo.bootstrap.Element = function(config){
4082 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4085 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4092 getAutoCreate : function(){
4117 * @class Roo.bootstrap.Pagination
4118 * @extends Roo.bootstrap.Component
4119 * Bootstrap Pagination class
4120 * @cfg {String} size xs | sm | md | lg
4121 * @cfg {Boolean} inverse false | true
4124 * Create a new Pagination
4125 * @param {Object} config The config object
4128 Roo.bootstrap.Pagination = function(config){
4129 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4132 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4138 getAutoCreate : function(){
4144 cfg.cls += ' inverse';
4150 cfg.cls += " " + this.cls;
4168 * @class Roo.bootstrap.PaginationItem
4169 * @extends Roo.bootstrap.Component
4170 * Bootstrap PaginationItem class
4171 * @cfg {String} html text
4172 * @cfg {String} href the link
4173 * @cfg {Boolean} preventDefault (true | false) default true
4174 * @cfg {Boolean} active (true | false) default false
4175 * @cfg {Boolean} disabled default false
4179 * Create a new PaginationItem
4180 * @param {Object} config The config object
4184 Roo.bootstrap.PaginationItem = function(config){
4185 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4190 * The raw click event for the entire grid.
4191 * @param {Roo.EventObject} e
4197 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4201 preventDefault: true,
4206 getAutoCreate : function(){
4212 href : this.href ? this.href : '#',
4213 html : this.html ? this.html : ''
4223 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4227 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4233 initEvents: function() {
4235 this.el.on('click', this.onClick, this);
4238 onClick : function(e)
4240 Roo.log('PaginationItem on click ');
4241 if(this.preventDefault){
4249 this.fireEvent('click', this, e);
4265 * @class Roo.bootstrap.Slider
4266 * @extends Roo.bootstrap.Component
4267 * Bootstrap Slider class
4270 * Create a new Slider
4271 * @param {Object} config The config object
4274 Roo.bootstrap.Slider = function(config){
4275 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4278 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4280 getAutoCreate : function(){
4284 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4288 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4300 * Ext JS Library 1.1.1
4301 * Copyright(c) 2006-2007, Ext JS, LLC.
4303 * Originally Released Under LGPL - original licence link has changed is not relivant.
4306 * <script type="text/javascript">
4311 * @class Roo.grid.ColumnModel
4312 * @extends Roo.util.Observable
4313 * This is the default implementation of a ColumnModel used by the Grid. It defines
4314 * the columns in the grid.
4317 var colModel = new Roo.grid.ColumnModel([
4318 {header: "Ticker", width: 60, sortable: true, locked: true},
4319 {header: "Company Name", width: 150, sortable: true},
4320 {header: "Market Cap.", width: 100, sortable: true},
4321 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4322 {header: "Employees", width: 100, sortable: true, resizable: false}
4327 * The config options listed for this class are options which may appear in each
4328 * individual column definition.
4329 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4331 * @param {Object} config An Array of column config objects. See this class's
4332 * config objects for details.
4334 Roo.grid.ColumnModel = function(config){
4336 * The config passed into the constructor
4338 this.config = config;
4341 // if no id, create one
4342 // if the column does not have a dataIndex mapping,
4343 // map it to the order it is in the config
4344 for(var i = 0, len = config.length; i < len; i++){
4346 if(typeof c.dataIndex == "undefined"){
4349 if(typeof c.renderer == "string"){
4350 c.renderer = Roo.util.Format[c.renderer];
4352 if(typeof c.id == "undefined"){
4355 if(c.editor && c.editor.xtype){
4356 c.editor = Roo.factory(c.editor, Roo.grid);
4358 if(c.editor && c.editor.isFormField){
4359 c.editor = new Roo.grid.GridEditor(c.editor);
4361 this.lookup[c.id] = c;
4365 * The width of columns which have no width specified (defaults to 100)
4368 this.defaultWidth = 100;
4371 * Default sortable of columns which have no sortable specified (defaults to false)
4374 this.defaultSortable = false;
4378 * @event widthchange
4379 * Fires when the width of a column changes.
4380 * @param {ColumnModel} this
4381 * @param {Number} columnIndex The column index
4382 * @param {Number} newWidth The new width
4384 "widthchange": true,
4386 * @event headerchange
4387 * Fires when the text of a header changes.
4388 * @param {ColumnModel} this
4389 * @param {Number} columnIndex The column index
4390 * @param {Number} newText The new header text
4392 "headerchange": true,
4394 * @event hiddenchange
4395 * Fires when a column is hidden or "unhidden".
4396 * @param {ColumnModel} this
4397 * @param {Number} columnIndex The column index
4398 * @param {Boolean} hidden true if hidden, false otherwise
4400 "hiddenchange": true,
4402 * @event columnmoved
4403 * Fires when a column is moved.
4404 * @param {ColumnModel} this
4405 * @param {Number} oldIndex
4406 * @param {Number} newIndex
4408 "columnmoved" : true,
4410 * @event columlockchange
4411 * Fires when a column's locked state is changed
4412 * @param {ColumnModel} this
4413 * @param {Number} colIndex
4414 * @param {Boolean} locked true if locked
4416 "columnlockchange" : true
4418 Roo.grid.ColumnModel.superclass.constructor.call(this);
4420 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4422 * @cfg {String} header The header text to display in the Grid view.
4425 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4426 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4427 * specified, the column's index is used as an index into the Record's data Array.
4430 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4431 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4434 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4435 * Defaults to the value of the {@link #defaultSortable} property.
4436 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4439 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4442 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4445 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4448 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4451 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4452 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4453 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4454 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4457 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4460 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4463 * @cfg {String} cursor (Optional)
4466 * @cfg {String} tooltip (Optional)
4469 * Returns the id of the column at the specified index.
4470 * @param {Number} index The column index
4471 * @return {String} the id
4473 getColumnId : function(index){
4474 return this.config[index].id;
4478 * Returns the column for a specified id.
4479 * @param {String} id The column id
4480 * @return {Object} the column
4482 getColumnById : function(id){
4483 return this.lookup[id];
4488 * Returns the column for a specified dataIndex.
4489 * @param {String} dataIndex The column dataIndex
4490 * @return {Object|Boolean} the column or false if not found
4492 getColumnByDataIndex: function(dataIndex){
4493 var index = this.findColumnIndex(dataIndex);
4494 return index > -1 ? this.config[index] : false;
4498 * Returns the index for a specified column id.
4499 * @param {String} id The column id
4500 * @return {Number} the index, or -1 if not found
4502 getIndexById : function(id){
4503 for(var i = 0, len = this.config.length; i < len; i++){
4504 if(this.config[i].id == id){
4512 * Returns the index for a specified column dataIndex.
4513 * @param {String} dataIndex The column dataIndex
4514 * @return {Number} the index, or -1 if not found
4517 findColumnIndex : function(dataIndex){
4518 for(var i = 0, len = this.config.length; i < len; i++){
4519 if(this.config[i].dataIndex == dataIndex){
4527 moveColumn : function(oldIndex, newIndex){
4528 var c = this.config[oldIndex];
4529 this.config.splice(oldIndex, 1);
4530 this.config.splice(newIndex, 0, c);
4531 this.dataMap = null;
4532 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4535 isLocked : function(colIndex){
4536 return this.config[colIndex].locked === true;
4539 setLocked : function(colIndex, value, suppressEvent){
4540 if(this.isLocked(colIndex) == value){
4543 this.config[colIndex].locked = value;
4545 this.fireEvent("columnlockchange", this, colIndex, value);
4549 getTotalLockedWidth : function(){
4551 for(var i = 0; i < this.config.length; i++){
4552 if(this.isLocked(i) && !this.isHidden(i)){
4553 this.totalWidth += this.getColumnWidth(i);
4559 getLockedCount : function(){
4560 for(var i = 0, len = this.config.length; i < len; i++){
4561 if(!this.isLocked(i)){
4568 * Returns the number of columns.
4571 getColumnCount : function(visibleOnly){
4572 if(visibleOnly === true){
4574 for(var i = 0, len = this.config.length; i < len; i++){
4575 if(!this.isHidden(i)){
4581 return this.config.length;
4585 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4586 * @param {Function} fn
4587 * @param {Object} scope (optional)
4588 * @return {Array} result
4590 getColumnsBy : function(fn, scope){
4592 for(var i = 0, len = this.config.length; i < len; i++){
4593 var c = this.config[i];
4594 if(fn.call(scope||this, c, i) === true){
4602 * Returns true if the specified column is sortable.
4603 * @param {Number} col The column index
4606 isSortable : function(col){
4607 if(typeof this.config[col].sortable == "undefined"){
4608 return this.defaultSortable;
4610 return this.config[col].sortable;
4614 * Returns the rendering (formatting) function defined for the column.
4615 * @param {Number} col The column index.
4616 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4618 getRenderer : function(col){
4619 if(!this.config[col].renderer){
4620 return Roo.grid.ColumnModel.defaultRenderer;
4622 return this.config[col].renderer;
4626 * Sets the rendering (formatting) function for a column.
4627 * @param {Number} col The column index
4628 * @param {Function} fn The function to use to process the cell's raw data
4629 * to return HTML markup for the grid view. The render function is called with
4630 * the following parameters:<ul>
4631 * <li>Data value.</li>
4632 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4633 * <li>css A CSS style string to apply to the table cell.</li>
4634 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4635 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4636 * <li>Row index</li>
4637 * <li>Column index</li>
4638 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4640 setRenderer : function(col, fn){
4641 this.config[col].renderer = fn;
4645 * Returns the width for the specified column.
4646 * @param {Number} col The column index
4649 getColumnWidth : function(col){
4650 return this.config[col].width * 1 || this.defaultWidth;
4654 * Sets the width for a column.
4655 * @param {Number} col The column index
4656 * @param {Number} width The new width
4658 setColumnWidth : function(col, width, suppressEvent){
4659 this.config[col].width = width;
4660 this.totalWidth = null;
4662 this.fireEvent("widthchange", this, col, width);
4667 * Returns the total width of all columns.
4668 * @param {Boolean} includeHidden True to include hidden column widths
4671 getTotalWidth : function(includeHidden){
4672 if(!this.totalWidth){
4673 this.totalWidth = 0;
4674 for(var i = 0, len = this.config.length; i < len; i++){
4675 if(includeHidden || !this.isHidden(i)){
4676 this.totalWidth += this.getColumnWidth(i);
4680 return this.totalWidth;
4684 * Returns the header for the specified column.
4685 * @param {Number} col The column index
4688 getColumnHeader : function(col){
4689 return this.config[col].header;
4693 * Sets the header for a column.
4694 * @param {Number} col The column index
4695 * @param {String} header The new header
4697 setColumnHeader : function(col, header){
4698 this.config[col].header = header;
4699 this.fireEvent("headerchange", this, col, header);
4703 * Returns the tooltip for the specified column.
4704 * @param {Number} col The column index
4707 getColumnTooltip : function(col){
4708 return this.config[col].tooltip;
4711 * Sets the tooltip for a column.
4712 * @param {Number} col The column index
4713 * @param {String} tooltip The new tooltip
4715 setColumnTooltip : function(col, tooltip){
4716 this.config[col].tooltip = tooltip;
4720 * Returns the dataIndex for the specified column.
4721 * @param {Number} col The column index
4724 getDataIndex : function(col){
4725 return this.config[col].dataIndex;
4729 * Sets the dataIndex for a column.
4730 * @param {Number} col The column index
4731 * @param {Number} dataIndex The new dataIndex
4733 setDataIndex : function(col, dataIndex){
4734 this.config[col].dataIndex = dataIndex;
4740 * Returns true if the cell is editable.
4741 * @param {Number} colIndex The column index
4742 * @param {Number} rowIndex The row index
4745 isCellEditable : function(colIndex, rowIndex){
4746 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4750 * Returns the editor defined for the cell/column.
4751 * return false or null to disable editing.
4752 * @param {Number} colIndex The column index
4753 * @param {Number} rowIndex The row index
4756 getCellEditor : function(colIndex, rowIndex){
4757 return this.config[colIndex].editor;
4761 * Sets if a column is editable.
4762 * @param {Number} col The column index
4763 * @param {Boolean} editable True if the column is editable
4765 setEditable : function(col, editable){
4766 this.config[col].editable = editable;
4771 * Returns true if the column is hidden.
4772 * @param {Number} colIndex The column index
4775 isHidden : function(colIndex){
4776 return this.config[colIndex].hidden;
4781 * Returns true if the column width cannot be changed
4783 isFixed : function(colIndex){
4784 return this.config[colIndex].fixed;
4788 * Returns true if the column can be resized
4791 isResizable : function(colIndex){
4792 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4795 * Sets if a column is hidden.
4796 * @param {Number} colIndex The column index
4797 * @param {Boolean} hidden True if the column is hidden
4799 setHidden : function(colIndex, hidden){
4800 this.config[colIndex].hidden = hidden;
4801 this.totalWidth = null;
4802 this.fireEvent("hiddenchange", this, colIndex, hidden);
4806 * Sets the editor for a column.
4807 * @param {Number} col The column index
4808 * @param {Object} editor The editor object
4810 setEditor : function(col, editor){
4811 this.config[col].editor = editor;
4815 Roo.grid.ColumnModel.defaultRenderer = function(value){
4816 if(typeof value == "string" && value.length < 1){
4822 // Alias for backwards compatibility
4823 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4826 * Ext JS Library 1.1.1
4827 * Copyright(c) 2006-2007, Ext JS, LLC.
4829 * Originally Released Under LGPL - original licence link has changed is not relivant.
4832 * <script type="text/javascript">
4836 * @class Roo.LoadMask
4837 * A simple utility class for generically masking elements while loading data. If the element being masked has
4838 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4839 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4840 * element's UpdateManager load indicator and will be destroyed after the initial load.
4842 * Create a new LoadMask
4843 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4844 * @param {Object} config The config object
4846 Roo.LoadMask = function(el, config){
4847 this.el = Roo.get(el);
4848 Roo.apply(this, config);
4850 this.store.on('beforeload', this.onBeforeLoad, this);
4851 this.store.on('load', this.onLoad, this);
4852 this.store.on('loadexception', this.onLoadException, this);
4853 this.removeMask = false;
4855 var um = this.el.getUpdateManager();
4856 um.showLoadIndicator = false; // disable the default indicator
4857 um.on('beforeupdate', this.onBeforeLoad, this);
4858 um.on('update', this.onLoad, this);
4859 um.on('failure', this.onLoad, this);
4860 this.removeMask = true;
4864 Roo.LoadMask.prototype = {
4866 * @cfg {Boolean} removeMask
4867 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4868 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4872 * The text to display in a centered loading message box (defaults to 'Loading...')
4876 * @cfg {String} msgCls
4877 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4879 msgCls : 'x-mask-loading',
4882 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4888 * Disables the mask to prevent it from being displayed
4890 disable : function(){
4891 this.disabled = true;
4895 * Enables the mask so that it can be displayed
4897 enable : function(){
4898 this.disabled = false;
4901 onLoadException : function()
4905 if (typeof(arguments[3]) != 'undefined') {
4906 Roo.MessageBox.alert("Error loading",arguments[3]);
4910 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4911 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4920 this.el.unmask(this.removeMask);
4925 this.el.unmask(this.removeMask);
4929 onBeforeLoad : function(){
4931 this.el.mask(this.msg, this.msgCls);
4936 destroy : function(){
4938 this.store.un('beforeload', this.onBeforeLoad, this);
4939 this.store.un('load', this.onLoad, this);
4940 this.store.un('loadexception', this.onLoadException, this);
4942 var um = this.el.getUpdateManager();
4943 um.un('beforeupdate', this.onBeforeLoad, this);
4944 um.un('update', this.onLoad, this);
4945 um.un('failure', this.onLoad, this);
4956 * @class Roo.bootstrap.Table
4957 * @extends Roo.bootstrap.Component
4958 * Bootstrap Table class
4959 * @cfg {String} cls table class
4960 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4961 * @cfg {String} bgcolor Specifies the background color for a table
4962 * @cfg {Number} border Specifies whether the table cells should have borders or not
4963 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4964 * @cfg {Number} cellspacing Specifies the space between cells
4965 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4966 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4967 * @cfg {String} sortable Specifies that the table should be sortable
4968 * @cfg {String} summary Specifies a summary of the content of a table
4969 * @cfg {Number} width Specifies the width of a table
4970 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4972 * @cfg {boolean} striped Should the rows be alternative striped
4973 * @cfg {boolean} bordered Add borders to the table
4974 * @cfg {boolean} hover Add hover highlighting
4975 * @cfg {boolean} condensed Format condensed
4976 * @cfg {boolean} responsive Format condensed
4977 * @cfg {Boolean} loadMask (true|false) default false
4978 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4979 * @cfg {Boolean} thead (true|false) generate thead, default true
4980 * @cfg {Boolean} RowSelection (true|false) default false
4981 * @cfg {Boolean} CellSelection (true|false) default false
4982 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4986 * Create a new Table
4987 * @param {Object} config The config object
4990 Roo.bootstrap.Table = function(config){
4991 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4994 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4995 this.sm = this.selModel;
4996 this.sm.xmodule = this.xmodule || false;
4998 if (this.cm && typeof(this.cm.config) == 'undefined') {
4999 this.colModel = new Roo.grid.ColumnModel(this.cm);
5000 this.cm = this.colModel;
5001 this.cm.xmodule = this.xmodule || false;
5004 this.store= Roo.factory(this.store, Roo.data);
5005 this.ds = this.store;
5006 this.ds.xmodule = this.xmodule || false;
5009 if (this.footer && this.store) {
5010 this.footer.dataSource = this.ds;
5011 this.footer = Roo.factory(this.footer);
5018 * Fires when a cell is clicked
5019 * @param {Roo.bootstrap.Table} this
5020 * @param {Roo.Element} el
5021 * @param {Number} rowIndex
5022 * @param {Number} columnIndex
5023 * @param {Roo.EventObject} e
5027 * @event celldblclick
5028 * Fires when a cell is double clicked
5029 * @param {Roo.bootstrap.Table} this
5030 * @param {Roo.Element} el
5031 * @param {Number} rowIndex
5032 * @param {Number} columnIndex
5033 * @param {Roo.EventObject} e
5035 "celldblclick" : true,
5038 * Fires when a row is clicked
5039 * @param {Roo.bootstrap.Table} this
5040 * @param {Roo.Element} el
5041 * @param {Number} rowIndex
5042 * @param {Roo.EventObject} e
5046 * @event rowdblclick
5047 * Fires when a row is double clicked
5048 * @param {Roo.bootstrap.Table} this
5049 * @param {Roo.Element} el
5050 * @param {Number} rowIndex
5051 * @param {Roo.EventObject} e
5053 "rowdblclick" : true,
5056 * Fires when a mouseover occur
5057 * @param {Roo.bootstrap.Table} this
5058 * @param {Roo.Element} el
5059 * @param {Number} rowIndex
5060 * @param {Number} columnIndex
5061 * @param {Roo.EventObject} e
5066 * Fires when a mouseout occur
5067 * @param {Roo.bootstrap.Table} this
5068 * @param {Roo.Element} el
5069 * @param {Number} rowIndex
5070 * @param {Number} columnIndex
5071 * @param {Roo.EventObject} e
5076 * Fires when a row is rendered, so you can change add a style to it.
5077 * @param {Roo.bootstrap.Table} this
5078 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5082 * @event rowsrendered
5083 * Fires when all the rows have been rendered
5084 * @param {Roo.bootstrap.Table} this
5086 'rowsrendered' : true
5091 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5115 RowSelection : false,
5116 CellSelection : false,
5119 // Roo.Element - the tbody
5122 getAutoCreate : function(){
5123 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5132 cfg.cls += ' table-striped';
5136 cfg.cls += ' table-hover';
5138 if (this.bordered) {
5139 cfg.cls += ' table-bordered';
5141 if (this.condensed) {
5142 cfg.cls += ' table-condensed';
5144 if (this.responsive) {
5145 cfg.cls += ' table-responsive';
5149 cfg.cls+= ' ' +this.cls;
5152 // this lot should be simplifed...
5155 cfg.align=this.align;
5158 cfg.bgcolor=this.bgcolor;
5161 cfg.border=this.border;
5163 if (this.cellpadding) {
5164 cfg.cellpadding=this.cellpadding;
5166 if (this.cellspacing) {
5167 cfg.cellspacing=this.cellspacing;
5170 cfg.frame=this.frame;
5173 cfg.rules=this.rules;
5175 if (this.sortable) {
5176 cfg.sortable=this.sortable;
5179 cfg.summary=this.summary;
5182 cfg.width=this.width;
5185 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5188 if(this.store || this.cm){
5190 cfg.cn.push(this.renderHeader());
5193 cfg.cn.push(this.renderBody());
5196 cfg.cn.push(this.renderFooter());
5199 cfg.cls+= ' TableGrid';
5202 return { cn : [ cfg ] };
5205 initEvents : function()
5207 if(!this.store || !this.cm){
5211 //Roo.log('initEvents with ds!!!!');
5213 this.mainBody = this.el.select('tbody', true).first();
5218 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5219 e.on('click', _this.sort, _this);
5222 this.el.on("click", this.onClick, this);
5223 this.el.on("dblclick", this.onDblClick, this);
5225 // why is this done????? = it breaks dialogs??
5226 //this.parent().el.setStyle('position', 'relative');
5230 this.footer.parentId = this.id;
5231 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5234 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5236 this.store.on('load', this.onLoad, this);
5237 this.store.on('beforeload', this.onBeforeLoad, this);
5238 this.store.on('update', this.onUpdate, this);
5239 this.store.on('add', this.onAdd, this);
5243 onMouseover : function(e, el)
5245 var cell = Roo.get(el);
5251 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5252 cell = cell.findParent('td', false, true);
5255 var row = cell.findParent('tr', false, true);
5256 var cellIndex = cell.dom.cellIndex;
5257 var rowIndex = row.dom.rowIndex - 1; // start from 0
5259 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5263 onMouseout : function(e, el)
5265 var cell = Roo.get(el);
5271 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5272 cell = cell.findParent('td', false, true);
5275 var row = cell.findParent('tr', false, true);
5276 var cellIndex = cell.dom.cellIndex;
5277 var rowIndex = row.dom.rowIndex - 1; // start from 0
5279 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5283 onClick : function(e, el)
5285 var cell = Roo.get(el);
5287 if(!cell || (!this.CellSelection && !this.RowSelection)){
5291 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5292 cell = cell.findParent('td', false, true);
5295 if(!cell || typeof(cell) == 'undefined'){
5299 var row = cell.findParent('tr', false, true);
5301 if(!row || typeof(row) == 'undefined'){
5305 var cellIndex = cell.dom.cellIndex;
5306 var rowIndex = this.getRowIndex(row);
5308 if(this.CellSelection){
5309 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5312 if(this.RowSelection){
5313 this.fireEvent('rowclick', this, row, rowIndex, e);
5319 onDblClick : function(e,el)
5321 var cell = Roo.get(el);
5323 if(!cell || (!this.CellSelection && !this.RowSelection)){
5327 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5328 cell = cell.findParent('td', false, true);
5331 if(!cell || typeof(cell) == 'undefined'){
5335 var row = cell.findParent('tr', false, true);
5337 if(!row || typeof(row) == 'undefined'){
5341 var cellIndex = cell.dom.cellIndex;
5342 var rowIndex = this.getRowIndex(row);
5344 if(this.CellSelection){
5345 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5348 if(this.RowSelection){
5349 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5353 sort : function(e,el)
5355 var col = Roo.get(el);
5357 if(!col.hasClass('sortable')){
5361 var sort = col.attr('sort');
5364 if(col.hasClass('glyphicon-arrow-up')){
5368 this.store.sortInfo = {field : sort, direction : dir};
5371 Roo.log("calling footer first");
5372 this.footer.onClick('first');
5375 this.store.load({ params : { start : 0 } });
5379 renderHeader : function()
5388 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5390 var config = cm.config[i];
5395 html: cm.getColumnHeader(i)
5398 if(typeof(config.tooltip) != 'undefined'){
5399 c.tooltip = config.tooltip;
5402 if(typeof(config.hidden) != 'undefined' && config.hidden){
5403 c.style += ' display:none;';
5406 if(typeof(config.dataIndex) != 'undefined'){
5407 c.sort = config.dataIndex;
5410 if(typeof(config.sortable) != 'undefined' && config.sortable){
5414 if(typeof(config.align) != 'undefined' && config.align.length){
5415 c.style += ' text-align:' + config.align + ';';
5418 if(typeof(config.width) != 'undefined'){
5419 c.style += ' width:' + config.width + 'px;';
5428 renderBody : function()
5438 colspan : this.cm.getColumnCount()
5448 renderFooter : function()
5458 colspan : this.cm.getColumnCount()
5472 Roo.log('ds onload');
5477 var ds = this.store;
5479 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5480 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5482 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5483 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5486 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5487 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5491 var tbody = this.mainBody;
5493 if(ds.getCount() > 0){
5494 ds.data.each(function(d,rowIndex){
5495 var row = this.renderRow(cm, ds, rowIndex);
5497 tbody.createChild(row);
5501 if(row.cellObjects.length){
5502 Roo.each(row.cellObjects, function(r){
5503 _this.renderCellObject(r);
5510 Roo.each(this.el.select('tbody td', true).elements, function(e){
5511 e.on('mouseover', _this.onMouseover, _this);
5514 Roo.each(this.el.select('tbody td', true).elements, function(e){
5515 e.on('mouseout', _this.onMouseout, _this);
5517 this.fireEvent('rowsrendered', this);
5518 //if(this.loadMask){
5519 // this.maskEl.hide();
5524 onUpdate : function(ds,record)
5526 this.refreshRow(record);
5529 onRemove : function(ds, record, index, isUpdate){
5530 if(isUpdate !== true){
5531 this.fireEvent("beforerowremoved", this, index, record);
5533 var bt = this.mainBody.dom;
5535 var rows = this.el.select('tbody > tr', true).elements;
5537 if(typeof(rows[index]) != 'undefined'){
5538 bt.removeChild(rows[index].dom);
5541 // if(bt.rows[index]){
5542 // bt.removeChild(bt.rows[index]);
5545 if(isUpdate !== true){
5546 //this.stripeRows(index);
5547 //this.syncRowHeights(index, index);
5549 this.fireEvent("rowremoved", this, index, record);
5553 onAdd : function(ds, records, rowIndex)
5555 //Roo.log('on Add called');
5556 // - note this does not handle multiple adding very well..
5557 var bt = this.mainBody.dom;
5558 for (var i =0 ; i < records.length;i++) {
5559 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5560 //Roo.log(records[i]);
5561 //Roo.log(this.store.getAt(rowIndex+i));
5562 this.insertRow(this.store, rowIndex + i, false);
5569 refreshRow : function(record){
5570 var ds = this.store, index;
5571 if(typeof record == 'number'){
5573 record = ds.getAt(index);
5575 index = ds.indexOf(record);
5577 this.insertRow(ds, index, true);
5578 this.onRemove(ds, record, index+1, true);
5579 //this.syncRowHeights(index, index);
5581 this.fireEvent("rowupdated", this, index, record);
5584 insertRow : function(dm, rowIndex, isUpdate){
5587 this.fireEvent("beforerowsinserted", this, rowIndex);
5589 //var s = this.getScrollState();
5590 var row = this.renderRow(this.cm, this.store, rowIndex);
5591 // insert before rowIndex..
5592 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5596 if(row.cellObjects.length){
5597 Roo.each(row.cellObjects, function(r){
5598 _this.renderCellObject(r);
5603 this.fireEvent("rowsinserted", this, rowIndex);
5604 //this.syncRowHeights(firstRow, lastRow);
5605 //this.stripeRows(firstRow);
5612 getRowDom : function(rowIndex)
5614 var rows = this.el.select('tbody > tr', true).elements;
5616 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5619 // returns the object tree for a tr..
5622 renderRow : function(cm, ds, rowIndex)
5625 var d = ds.getAt(rowIndex);
5632 var cellObjects = [];
5634 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5635 var config = cm.config[i];
5637 var renderer = cm.getRenderer(i);
5641 if(typeof(renderer) !== 'undefined'){
5642 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5644 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5645 // and are rendered into the cells after the row is rendered - using the id for the element.
5647 if(typeof(value) === 'object'){
5657 rowIndex : rowIndex,
5662 this.fireEvent('rowclass', this, rowcfg);
5666 cls : rowcfg.rowClass,
5668 html: (typeof(value) === 'object') ? '' : value
5675 if(typeof(config.hidden) != 'undefined' && config.hidden){
5676 td.style += ' display:none;';
5679 if(typeof(config.align) != 'undefined' && config.align.length){
5680 td.style += ' text-align:' + config.align + ';';
5683 if(typeof(config.width) != 'undefined'){
5684 td.style += ' width:' + config.width + 'px;';
5687 if(typeof(config.cursor) != 'undefined'){
5688 td.style += ' cursor:' + config.cursor + ';';
5695 row.cellObjects = cellObjects;
5703 onBeforeLoad : function()
5705 //Roo.log('ds onBeforeLoad');
5709 //if(this.loadMask){
5710 // this.maskEl.show();
5718 this.el.select('tbody', true).first().dom.innerHTML = '';
5721 * Show or hide a row.
5722 * @param {Number} rowIndex to show or hide
5723 * @param {Boolean} state hide
5725 setRowVisibility : function(rowIndex, state)
5727 var bt = this.mainBody.dom;
5729 var rows = this.el.select('tbody > tr', true).elements;
5731 if(typeof(rows[rowIndex]) == 'undefined'){
5734 rows[rowIndex].dom.style.display = state ? '' : 'none';
5738 getSelectionModel : function(){
5740 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5742 return this.selModel;
5745 * Render the Roo.bootstrap object from renderder
5747 renderCellObject : function(r)
5751 var t = r.cfg.render(r.container);
5754 Roo.each(r.cfg.cn, function(c){
5756 container: t.getChildContainer(),
5759 _this.renderCellObject(child);
5764 getRowIndex : function(row)
5768 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5791 * @class Roo.bootstrap.TableCell
5792 * @extends Roo.bootstrap.Component
5793 * Bootstrap TableCell class
5794 * @cfg {String} html cell contain text
5795 * @cfg {String} cls cell class
5796 * @cfg {String} tag cell tag (td|th) default td
5797 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5798 * @cfg {String} align Aligns the content in a cell
5799 * @cfg {String} axis Categorizes cells
5800 * @cfg {String} bgcolor Specifies the background color of a cell
5801 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5802 * @cfg {Number} colspan Specifies the number of columns a cell should span
5803 * @cfg {String} headers Specifies one or more header cells a cell is related to
5804 * @cfg {Number} height Sets the height of a cell
5805 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5806 * @cfg {Number} rowspan Sets the number of rows a cell should span
5807 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5808 * @cfg {String} valign Vertical aligns the content in a cell
5809 * @cfg {Number} width Specifies the width of a cell
5812 * Create a new TableCell
5813 * @param {Object} config The config object
5816 Roo.bootstrap.TableCell = function(config){
5817 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5820 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5840 getAutoCreate : function(){
5841 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5861 cfg.align=this.align
5867 cfg.bgcolor=this.bgcolor
5870 cfg.charoff=this.charoff
5873 cfg.colspan=this.colspan
5876 cfg.headers=this.headers
5879 cfg.height=this.height
5882 cfg.nowrap=this.nowrap
5885 cfg.rowspan=this.rowspan
5888 cfg.scope=this.scope
5891 cfg.valign=this.valign
5894 cfg.width=this.width
5913 * @class Roo.bootstrap.TableRow
5914 * @extends Roo.bootstrap.Component
5915 * Bootstrap TableRow class
5916 * @cfg {String} cls row class
5917 * @cfg {String} align Aligns the content in a table row
5918 * @cfg {String} bgcolor Specifies a background color for a table row
5919 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5920 * @cfg {String} valign Vertical aligns the content in a table row
5923 * Create a new TableRow
5924 * @param {Object} config The config object
5927 Roo.bootstrap.TableRow = function(config){
5928 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5931 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5939 getAutoCreate : function(){
5940 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5950 cfg.align = this.align;
5953 cfg.bgcolor = this.bgcolor;
5956 cfg.charoff = this.charoff;
5959 cfg.valign = this.valign;
5977 * @class Roo.bootstrap.TableBody
5978 * @extends Roo.bootstrap.Component
5979 * Bootstrap TableBody class
5980 * @cfg {String} cls element class
5981 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5982 * @cfg {String} align Aligns the content inside the element
5983 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5984 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5987 * Create a new TableBody
5988 * @param {Object} config The config object
5991 Roo.bootstrap.TableBody = function(config){
5992 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5995 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6003 getAutoCreate : function(){
6004 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6018 cfg.align = this.align;
6021 cfg.charoff = this.charoff;
6024 cfg.valign = this.valign;
6031 // initEvents : function()
6038 // this.store = Roo.factory(this.store, Roo.data);
6039 // this.store.on('load', this.onLoad, this);
6041 // this.store.load();
6045 // onLoad: function ()
6047 // this.fireEvent('load', this);
6057 * Ext JS Library 1.1.1
6058 * Copyright(c) 2006-2007, Ext JS, LLC.
6060 * Originally Released Under LGPL - original licence link has changed is not relivant.
6063 * <script type="text/javascript">
6066 // as we use this in bootstrap.
6067 Roo.namespace('Roo.form');
6069 * @class Roo.form.Action
6070 * Internal Class used to handle form actions
6072 * @param {Roo.form.BasicForm} el The form element or its id
6073 * @param {Object} config Configuration options
6078 // define the action interface
6079 Roo.form.Action = function(form, options){
6081 this.options = options || {};
6084 * Client Validation Failed
6087 Roo.form.Action.CLIENT_INVALID = 'client';
6089 * Server Validation Failed
6092 Roo.form.Action.SERVER_INVALID = 'server';
6094 * Connect to Server Failed
6097 Roo.form.Action.CONNECT_FAILURE = 'connect';
6099 * Reading Data from Server Failed
6102 Roo.form.Action.LOAD_FAILURE = 'load';
6104 Roo.form.Action.prototype = {
6106 failureType : undefined,
6107 response : undefined,
6111 run : function(options){
6116 success : function(response){
6121 handleResponse : function(response){
6125 // default connection failure
6126 failure : function(response){
6128 this.response = response;
6129 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6130 this.form.afterAction(this, false);
6133 processResponse : function(response){
6134 this.response = response;
6135 if(!response.responseText){
6138 this.result = this.handleResponse(response);
6142 // utility functions used internally
6143 getUrl : function(appendParams){
6144 var url = this.options.url || this.form.url || this.form.el.dom.action;
6146 var p = this.getParams();
6148 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6154 getMethod : function(){
6155 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6158 getParams : function(){
6159 var bp = this.form.baseParams;
6160 var p = this.options.params;
6162 if(typeof p == "object"){
6163 p = Roo.urlEncode(Roo.applyIf(p, bp));
6164 }else if(typeof p == 'string' && bp){
6165 p += '&' + Roo.urlEncode(bp);
6168 p = Roo.urlEncode(bp);
6173 createCallback : function(){
6175 success: this.success,
6176 failure: this.failure,
6178 timeout: (this.form.timeout*1000),
6179 upload: this.form.fileUpload ? this.success : undefined
6184 Roo.form.Action.Submit = function(form, options){
6185 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6188 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6191 haveProgress : false,
6192 uploadComplete : false,
6194 // uploadProgress indicator.
6195 uploadProgress : function()
6197 if (!this.form.progressUrl) {
6201 if (!this.haveProgress) {
6202 Roo.MessageBox.progress("Uploading", "Uploading");
6204 if (this.uploadComplete) {
6205 Roo.MessageBox.hide();
6209 this.haveProgress = true;
6211 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6213 var c = new Roo.data.Connection();
6215 url : this.form.progressUrl,
6220 success : function(req){
6221 //console.log(data);
6225 rdata = Roo.decode(req.responseText)
6227 Roo.log("Invalid data from server..");
6231 if (!rdata || !rdata.success) {
6233 Roo.MessageBox.alert(Roo.encode(rdata));
6236 var data = rdata.data;
6238 if (this.uploadComplete) {
6239 Roo.MessageBox.hide();
6244 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6245 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6248 this.uploadProgress.defer(2000,this);
6251 failure: function(data) {
6252 Roo.log('progress url failed ');
6263 // run get Values on the form, so it syncs any secondary forms.
6264 this.form.getValues();
6266 var o = this.options;
6267 var method = this.getMethod();
6268 var isPost = method == 'POST';
6269 if(o.clientValidation === false || this.form.isValid()){
6271 if (this.form.progressUrl) {
6272 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6273 (new Date() * 1) + '' + Math.random());
6278 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6279 form:this.form.el.dom,
6280 url:this.getUrl(!isPost),
6282 params:isPost ? this.getParams() : null,
6283 isUpload: this.form.fileUpload
6286 this.uploadProgress();
6288 }else if (o.clientValidation !== false){ // client validation failed
6289 this.failureType = Roo.form.Action.CLIENT_INVALID;
6290 this.form.afterAction(this, false);
6294 success : function(response)
6296 this.uploadComplete= true;
6297 if (this.haveProgress) {
6298 Roo.MessageBox.hide();
6302 var result = this.processResponse(response);
6303 if(result === true || result.success){
6304 this.form.afterAction(this, true);
6308 this.form.markInvalid(result.errors);
6309 this.failureType = Roo.form.Action.SERVER_INVALID;
6311 this.form.afterAction(this, false);
6313 failure : function(response)
6315 this.uploadComplete= true;
6316 if (this.haveProgress) {
6317 Roo.MessageBox.hide();
6320 this.response = response;
6321 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6322 this.form.afterAction(this, false);
6325 handleResponse : function(response){
6326 if(this.form.errorReader){
6327 var rs = this.form.errorReader.read(response);
6330 for(var i = 0, len = rs.records.length; i < len; i++) {
6331 var r = rs.records[i];
6335 if(errors.length < 1){
6339 success : rs.success,
6345 ret = Roo.decode(response.responseText);
6349 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6359 Roo.form.Action.Load = function(form, options){
6360 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6361 this.reader = this.form.reader;
6364 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6369 Roo.Ajax.request(Roo.apply(
6370 this.createCallback(), {
6371 method:this.getMethod(),
6372 url:this.getUrl(false),
6373 params:this.getParams()
6377 success : function(response){
6379 var result = this.processResponse(response);
6380 if(result === true || !result.success || !result.data){
6381 this.failureType = Roo.form.Action.LOAD_FAILURE;
6382 this.form.afterAction(this, false);
6385 this.form.clearInvalid();
6386 this.form.setValues(result.data);
6387 this.form.afterAction(this, true);
6390 handleResponse : function(response){
6391 if(this.form.reader){
6392 var rs = this.form.reader.read(response);
6393 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6395 success : rs.success,
6399 return Roo.decode(response.responseText);
6403 Roo.form.Action.ACTION_TYPES = {
6404 'load' : Roo.form.Action.Load,
6405 'submit' : Roo.form.Action.Submit
6414 * @class Roo.bootstrap.Form
6415 * @extends Roo.bootstrap.Component
6416 * Bootstrap Form class
6417 * @cfg {String} method GET | POST (default POST)
6418 * @cfg {String} labelAlign top | left (default top)
6419 * @cfg {String} align left | right - for navbars
6420 * @cfg {Boolean} loadMask load mask when submit (default true)
6425 * @param {Object} config The config object
6429 Roo.bootstrap.Form = function(config){
6430 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6433 * @event clientvalidation
6434 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6435 * @param {Form} this
6436 * @param {Boolean} valid true if the form has passed client-side validation
6438 clientvalidation: true,
6440 * @event beforeaction
6441 * Fires before any action is performed. Return false to cancel the action.
6442 * @param {Form} this
6443 * @param {Action} action The action to be performed
6447 * @event actionfailed
6448 * Fires when an action fails.
6449 * @param {Form} this
6450 * @param {Action} action The action that failed
6452 actionfailed : true,
6454 * @event actioncomplete
6455 * Fires when an action is completed.
6456 * @param {Form} this
6457 * @param {Action} action The action that completed
6459 actioncomplete : true
6464 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6467 * @cfg {String} method
6468 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6473 * The URL to use for form actions if one isn't supplied in the action options.
6476 * @cfg {Boolean} fileUpload
6477 * Set to true if this form is a file upload.
6481 * @cfg {Object} baseParams
6482 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6486 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6490 * @cfg {Sting} align (left|right) for navbar forms
6495 activeAction : null,
6498 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6499 * element by passing it or its id or mask the form itself by passing in true.
6502 waitMsgTarget : false,
6506 getAutoCreate : function(){
6510 method : this.method || 'POST',
6511 id : this.id || Roo.id(),
6514 if (this.parent().xtype.match(/^Nav/)) {
6515 cfg.cls = 'navbar-form navbar-' + this.align;
6519 if (this.labelAlign == 'left' ) {
6520 cfg.cls += ' form-horizontal';
6526 initEvents : function()
6528 this.el.on('submit', this.onSubmit, this);
6529 // this was added as random key presses on the form where triggering form submit.
6530 this.el.on('keypress', function(e) {
6531 if (e.getCharCode() != 13) {
6534 // we might need to allow it for textareas.. and some other items.
6535 // check e.getTarget().
6537 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6541 Roo.log("keypress blocked");
6549 onSubmit : function(e){
6554 * Returns true if client-side validation on the form is successful.
6557 isValid : function(){
6558 var items = this.getItems();
6560 items.each(function(f){
6569 * Returns true if any fields in this form have changed since their original load.
6572 isDirty : function(){
6574 var items = this.getItems();
6575 items.each(function(f){
6585 * Performs a predefined action (submit or load) or custom actions you define on this form.
6586 * @param {String} actionName The name of the action type
6587 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6588 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6589 * accept other config options):
6591 Property Type Description
6592 ---------------- --------------- ----------------------------------------------------------------------------------
6593 url String The url for the action (defaults to the form's url)
6594 method String The form method to use (defaults to the form's method, or POST if not defined)
6595 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6596 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6597 validate the form on the client (defaults to false)
6599 * @return {BasicForm} this
6601 doAction : function(action, options){
6602 if(typeof action == 'string'){
6603 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6605 if(this.fireEvent('beforeaction', this, action) !== false){
6606 this.beforeAction(action);
6607 action.run.defer(100, action);
6613 beforeAction : function(action){
6614 var o = action.options;
6617 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6619 // not really supported yet.. ??
6621 //if(this.waitMsgTarget === true){
6622 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6623 //}else if(this.waitMsgTarget){
6624 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6625 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6627 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6633 afterAction : function(action, success){
6634 this.activeAction = null;
6635 var o = action.options;
6637 //if(this.waitMsgTarget === true){
6639 //}else if(this.waitMsgTarget){
6640 // this.waitMsgTarget.unmask();
6642 // Roo.MessageBox.updateProgress(1);
6643 // Roo.MessageBox.hide();
6650 Roo.callback(o.success, o.scope, [this, action]);
6651 this.fireEvent('actioncomplete', this, action);
6655 // failure condition..
6656 // we have a scenario where updates need confirming.
6657 // eg. if a locking scenario exists..
6658 // we look for { errors : { needs_confirm : true }} in the response.
6660 (typeof(action.result) != 'undefined') &&
6661 (typeof(action.result.errors) != 'undefined') &&
6662 (typeof(action.result.errors.needs_confirm) != 'undefined')
6665 Roo.log("not supported yet");
6668 Roo.MessageBox.confirm(
6669 "Change requires confirmation",
6670 action.result.errorMsg,
6675 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6685 Roo.callback(o.failure, o.scope, [this, action]);
6686 // show an error message if no failed handler is set..
6687 if (!this.hasListener('actionfailed')) {
6688 Roo.log("need to add dialog support");
6690 Roo.MessageBox.alert("Error",
6691 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6692 action.result.errorMsg :
6693 "Saving Failed, please check your entries or try again"
6698 this.fireEvent('actionfailed', this, action);
6703 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6704 * @param {String} id The value to search for
6707 findField : function(id){
6708 var items = this.getItems();
6709 var field = items.get(id);
6711 items.each(function(f){
6712 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6719 return field || null;
6722 * Mark fields in this form invalid in bulk.
6723 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6724 * @return {BasicForm} this
6726 markInvalid : function(errors){
6727 if(errors instanceof Array){
6728 for(var i = 0, len = errors.length; i < len; i++){
6729 var fieldError = errors[i];
6730 var f = this.findField(fieldError.id);
6732 f.markInvalid(fieldError.msg);
6738 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6739 field.markInvalid(errors[id]);
6743 //Roo.each(this.childForms || [], function (f) {
6744 // f.markInvalid(errors);
6751 * Set values for fields in this form in bulk.
6752 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6753 * @return {BasicForm} this
6755 setValues : function(values){
6756 if(values instanceof Array){ // array of objects
6757 for(var i = 0, len = values.length; i < len; i++){
6759 var f = this.findField(v.id);
6761 f.setValue(v.value);
6762 if(this.trackResetOnLoad){
6763 f.originalValue = f.getValue();
6767 }else{ // object hash
6770 if(typeof values[id] != 'function' && (field = this.findField(id))){
6772 if (field.setFromData &&
6774 field.displayField &&
6775 // combos' with local stores can
6776 // be queried via setValue()
6777 // to set their value..
6778 (field.store && !field.store.isLocal)
6782 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6783 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6784 field.setFromData(sd);
6787 field.setValue(values[id]);
6791 if(this.trackResetOnLoad){
6792 field.originalValue = field.getValue();
6798 //Roo.each(this.childForms || [], function (f) {
6799 // f.setValues(values);
6806 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6807 * they are returned as an array.
6808 * @param {Boolean} asString
6811 getValues : function(asString){
6812 //if (this.childForms) {
6813 // copy values from the child forms
6814 // Roo.each(this.childForms, function (f) {
6815 // this.setValues(f.getValues());
6821 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6822 if(asString === true){
6825 return Roo.urlDecode(fs);
6829 * Returns the fields in this form as an object with key/value pairs.
6830 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6833 getFieldValues : function(with_hidden)
6835 var items = this.getItems();
6837 items.each(function(f){
6841 var v = f.getValue();
6842 if (f.inputType =='radio') {
6843 if (typeof(ret[f.getName()]) == 'undefined') {
6844 ret[f.getName()] = ''; // empty..
6847 if (!f.el.dom.checked) {
6855 // not sure if this supported any more..
6856 if ((typeof(v) == 'object') && f.getRawValue) {
6857 v = f.getRawValue() ; // dates..
6859 // combo boxes where name != hiddenName...
6860 if (f.name != f.getName()) {
6861 ret[f.name] = f.getRawValue();
6863 ret[f.getName()] = v;
6870 * Clears all invalid messages in this form.
6871 * @return {BasicForm} this
6873 clearInvalid : function(){
6874 var items = this.getItems();
6876 items.each(function(f){
6887 * @return {BasicForm} this
6890 var items = this.getItems();
6891 items.each(function(f){
6895 Roo.each(this.childForms || [], function (f) {
6902 getItems : function()
6904 var r=new Roo.util.MixedCollection(false, function(o){
6905 return o.id || (o.id = Roo.id());
6907 var iter = function(el) {
6914 Roo.each(el.items,function(e) {
6933 * Ext JS Library 1.1.1
6934 * Copyright(c) 2006-2007, Ext JS, LLC.
6936 * Originally Released Under LGPL - original licence link has changed is not relivant.
6939 * <script type="text/javascript">
6942 * @class Roo.form.VTypes
6943 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6946 Roo.form.VTypes = function(){
6947 // closure these in so they are only created once.
6948 var alpha = /^[a-zA-Z_]+$/;
6949 var alphanum = /^[a-zA-Z0-9_]+$/;
6950 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6951 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6953 // All these messages and functions are configurable
6956 * The function used to validate email addresses
6957 * @param {String} value The email address
6959 'email' : function(v){
6960 return email.test(v);
6963 * The error text to display when the email validation function returns false
6966 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6968 * The keystroke filter mask to be applied on email input
6971 'emailMask' : /[a-z0-9_\.\-@]/i,
6974 * The function used to validate URLs
6975 * @param {String} value The URL
6977 'url' : function(v){
6981 * The error text to display when the url validation function returns false
6984 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6987 * The function used to validate alpha values
6988 * @param {String} value The value
6990 'alpha' : function(v){
6991 return alpha.test(v);
6994 * The error text to display when the alpha validation function returns false
6997 'alphaText' : 'This field should only contain letters and _',
6999 * The keystroke filter mask to be applied on alpha input
7002 'alphaMask' : /[a-z_]/i,
7005 * The function used to validate alphanumeric values
7006 * @param {String} value The value
7008 'alphanum' : function(v){
7009 return alphanum.test(v);
7012 * The error text to display when the alphanumeric validation function returns false
7015 'alphanumText' : 'This field should only contain letters, numbers and _',
7017 * The keystroke filter mask to be applied on alphanumeric input
7020 'alphanumMask' : /[a-z0-9_]/i
7030 * @class Roo.bootstrap.Input
7031 * @extends Roo.bootstrap.Component
7032 * Bootstrap Input class
7033 * @cfg {Boolean} disabled is it disabled
7034 * @cfg {String} fieldLabel - the label associated
7035 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7036 * @cfg {String} name name of the input
7037 * @cfg {string} fieldLabel - the label associated
7038 * @cfg {string} inputType - input / file submit ...
7039 * @cfg {string} placeholder - placeholder to put in text.
7040 * @cfg {string} before - input group add on before
7041 * @cfg {string} after - input group add on after
7042 * @cfg {string} size - (lg|sm) or leave empty..
7043 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7044 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7045 * @cfg {Number} md colspan out of 12 for computer-sized screens
7046 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7047 * @cfg {string} value default value of the input
7048 * @cfg {Number} labelWidth set the width of label (0-12)
7049 * @cfg {String} labelAlign (top|left)
7050 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7051 * @cfg {String} align (left|center|right) Default left
7055 * Create a new Input
7056 * @param {Object} config The config object
7059 Roo.bootstrap.Input = function(config){
7060 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7065 * Fires when this field receives input focus.
7066 * @param {Roo.form.Field} this
7071 * Fires when this field loses input focus.
7072 * @param {Roo.form.Field} this
7077 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7078 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7079 * @param {Roo.form.Field} this
7080 * @param {Roo.EventObject} e The event object
7085 * Fires just before the field blurs if the field value has changed.
7086 * @param {Roo.form.Field} this
7087 * @param {Mixed} newValue The new value
7088 * @param {Mixed} oldValue The original value
7093 * Fires after the field has been marked as invalid.
7094 * @param {Roo.form.Field} this
7095 * @param {String} msg The validation message
7100 * Fires after the field has been validated with no errors.
7101 * @param {Roo.form.Field} this
7106 * Fires after the key up
7107 * @param {Roo.form.Field} this
7108 * @param {Roo.EventObject} e The event Object
7114 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7116 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7117 automatic validation (defaults to "keyup").
7119 validationEvent : "keyup",
7121 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7123 validateOnBlur : true,
7125 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7127 validationDelay : 250,
7129 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7131 focusClass : "x-form-focus", // not needed???
7135 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7137 invalidClass : "has-error",
7140 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7142 selectOnFocus : false,
7145 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7149 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7154 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7156 disableKeyFilter : false,
7159 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7163 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7167 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7169 blankText : "This field is required",
7172 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7176 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7178 maxLength : Number.MAX_VALUE,
7180 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7182 minLengthText : "The minimum length for this field is {0}",
7184 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7186 maxLengthText : "The maximum length for this field is {0}",
7190 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7191 * If available, this function will be called only after the basic validators all return true, and will be passed the
7192 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7196 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7197 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7198 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7202 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7225 formatedValue : false,
7227 parentLabelAlign : function()
7230 while (parent.parent()) {
7231 parent = parent.parent();
7232 if (typeof(parent.labelAlign) !='undefined') {
7233 return parent.labelAlign;
7240 getAutoCreate : function(){
7242 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7248 if(this.inputType != 'hidden'){
7249 cfg.cls = 'form-group' //input-group
7255 type : this.inputType,
7257 cls : 'form-control',
7258 placeholder : this.placeholder || ''
7263 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7266 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7267 input.maxLength = this.maxLength;
7270 if (this.disabled) {
7271 input.disabled=true;
7274 if (this.readOnly) {
7275 input.readonly=true;
7279 input.name = this.name;
7282 input.cls += ' input-' + this.size;
7285 ['xs','sm','md','lg'].map(function(size){
7286 if (settings[size]) {
7287 cfg.cls += ' col-' + size + '-' + settings[size];
7291 var inputblock = input;
7293 if (this.before || this.after) {
7296 cls : 'input-group',
7299 if (this.before && typeof(this.before) == 'string') {
7301 inputblock.cn.push({
7303 cls : 'roo-input-before input-group-addon',
7307 if (this.before && typeof(this.before) == 'object') {
7308 this.before = Roo.factory(this.before);
7309 Roo.log(this.before);
7310 inputblock.cn.push({
7312 cls : 'roo-input-before input-group-' +
7313 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7317 inputblock.cn.push(input);
7319 if (this.after && typeof(this.after) == 'string') {
7320 inputblock.cn.push({
7322 cls : 'roo-input-after input-group-addon',
7326 if (this.after && typeof(this.after) == 'object') {
7327 this.after = Roo.factory(this.after);
7328 Roo.log(this.after);
7329 inputblock.cn.push({
7331 cls : 'roo-input-after input-group-' +
7332 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7337 if (align ==='left' && this.fieldLabel.length) {
7338 Roo.log("left and has label");
7344 cls : 'control-label col-sm-' + this.labelWidth,
7345 html : this.fieldLabel
7349 cls : "col-sm-" + (12 - this.labelWidth),
7356 } else if ( this.fieldLabel.length) {
7362 //cls : 'input-group-addon',
7363 html : this.fieldLabel
7373 Roo.log(" no label && no align");
7382 Roo.log('input-parentType: ' + this.parentType);
7384 if (this.parentType === 'Navbar' && this.parent().bar) {
7385 cfg.cls += ' navbar-form';
7393 * return the real input element.
7395 inputEl: function ()
7397 return this.el.select('input.form-control',true).first();
7400 tooltipEl : function()
7402 return this.inputEl();
7405 setDisabled : function(v)
7407 var i = this.inputEl().dom;
7409 i.removeAttribute('disabled');
7413 i.setAttribute('disabled','true');
7415 initEvents : function()
7418 this.inputEl().on("keydown" , this.fireKey, this);
7419 this.inputEl().on("focus", this.onFocus, this);
7420 this.inputEl().on("blur", this.onBlur, this);
7422 this.inputEl().relayEvent('keyup', this);
7424 // reference to original value for reset
7425 this.originalValue = this.getValue();
7426 //Roo.form.TextField.superclass.initEvents.call(this);
7427 if(this.validationEvent == 'keyup'){
7428 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7429 this.inputEl().on('keyup', this.filterValidation, this);
7431 else if(this.validationEvent !== false){
7432 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7435 if(this.selectOnFocus){
7436 this.on("focus", this.preFocus, this);
7439 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7440 this.inputEl().on("keypress", this.filterKeys, this);
7443 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7444 this.el.on("click", this.autoSize, this);
7447 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7448 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7451 if (typeof(this.before) == 'object') {
7452 this.before.render(this.el.select('.roo-input-before',true).first());
7454 if (typeof(this.after) == 'object') {
7455 this.after.render(this.el.select('.roo-input-after',true).first());
7460 filterValidation : function(e){
7461 if(!e.isNavKeyPress()){
7462 this.validationTask.delay(this.validationDelay);
7466 * Validates the field value
7467 * @return {Boolean} True if the value is valid, else false
7469 validate : function(){
7470 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7471 if(this.disabled || this.validateValue(this.getRawValue())){
7472 this.clearInvalid();
7480 * Validates a value according to the field's validation rules and marks the field as invalid
7481 * if the validation fails
7482 * @param {Mixed} value The value to validate
7483 * @return {Boolean} True if the value is valid, else false
7485 validateValue : function(value){
7486 if(value.length < 1) { // if it's blank
7487 if(this.allowBlank){
7488 this.clearInvalid();
7491 this.markInvalid(this.blankText);
7495 if(value.length < this.minLength){
7496 this.markInvalid(String.format(this.minLengthText, this.minLength));
7499 if(value.length > this.maxLength){
7500 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7504 var vt = Roo.form.VTypes;
7505 if(!vt[this.vtype](value, this)){
7506 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7510 if(typeof this.validator == "function"){
7511 var msg = this.validator(value);
7513 this.markInvalid(msg);
7517 if(this.regex && !this.regex.test(value)){
7518 this.markInvalid(this.regexText);
7527 fireKey : function(e){
7528 //Roo.log('field ' + e.getKey());
7529 if(e.isNavKeyPress()){
7530 this.fireEvent("specialkey", this, e);
7533 focus : function (selectText){
7535 this.inputEl().focus();
7536 if(selectText === true){
7537 this.inputEl().dom.select();
7543 onFocus : function(){
7544 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7545 // this.el.addClass(this.focusClass);
7548 this.hasFocus = true;
7549 this.startValue = this.getValue();
7550 this.fireEvent("focus", this);
7554 beforeBlur : Roo.emptyFn,
7558 onBlur : function(){
7560 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7561 //this.el.removeClass(this.focusClass);
7563 this.hasFocus = false;
7564 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7567 var v = this.getValue();
7568 if(String(v) !== String(this.startValue)){
7569 this.fireEvent('change', this, v, this.startValue);
7571 this.fireEvent("blur", this);
7575 * Resets the current field value to the originally loaded value and clears any validation messages
7578 this.setValue(this.originalValue);
7579 this.clearInvalid();
7582 * Returns the name of the field
7583 * @return {Mixed} name The name field
7585 getName: function(){
7589 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7590 * @return {Mixed} value The field value
7592 getValue : function(){
7594 var v = this.inputEl().getValue();
7599 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7600 * @return {Mixed} value The field value
7602 getRawValue : function(){
7603 var v = this.inputEl().getValue();
7609 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7610 * @param {Mixed} value The value to set
7612 setRawValue : function(v){
7613 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7616 selectText : function(start, end){
7617 var v = this.getRawValue();
7619 start = start === undefined ? 0 : start;
7620 end = end === undefined ? v.length : end;
7621 var d = this.inputEl().dom;
7622 if(d.setSelectionRange){
7623 d.setSelectionRange(start, end);
7624 }else if(d.createTextRange){
7625 var range = d.createTextRange();
7626 range.moveStart("character", start);
7627 range.moveEnd("character", v.length-end);
7634 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7635 * @param {Mixed} value The value to set
7637 setValue : function(v){
7640 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7646 processValue : function(value){
7647 if(this.stripCharsRe){
7648 var newValue = value.replace(this.stripCharsRe, '');
7649 if(newValue !== value){
7650 this.setRawValue(newValue);
7657 preFocus : function(){
7659 if(this.selectOnFocus){
7660 this.inputEl().dom.select();
7663 filterKeys : function(e){
7665 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7668 var c = e.getCharCode(), cc = String.fromCharCode(c);
7669 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7672 if(!this.maskRe.test(cc)){
7677 * Clear any invalid styles/messages for this field
7679 clearInvalid : function(){
7681 if(!this.el || this.preventMark){ // not rendered
7684 this.el.removeClass(this.invalidClass);
7686 switch(this.msgTarget){
7688 this.el.dom.qtip = '';
7691 this.el.dom.title = '';
7695 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7700 this.errorIcon.dom.qtip = '';
7701 this.errorIcon.hide();
7702 this.un('resize', this.alignErrorIcon, this);
7706 var t = Roo.getDom(this.msgTarget);
7708 t.style.display = 'none';
7712 this.fireEvent('valid', this);
7715 * Mark this field as invalid
7716 * @param {String} msg The validation message
7718 markInvalid : function(msg){
7719 if(!this.el || this.preventMark){ // not rendered
7722 this.el.addClass(this.invalidClass);
7724 msg = msg || this.invalidText;
7725 switch(this.msgTarget){
7727 this.el.dom.qtip = msg;
7728 this.el.dom.qclass = 'x-form-invalid-tip';
7729 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7730 Roo.QuickTips.enable();
7734 this.el.dom.title = msg;
7738 var elp = this.el.findParent('.x-form-element', 5, true);
7739 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7740 this.errorEl.setWidth(elp.getWidth(true)-20);
7742 this.errorEl.update(msg);
7743 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7746 if(!this.errorIcon){
7747 var elp = this.el.findParent('.x-form-element', 5, true);
7748 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7750 this.alignErrorIcon();
7751 this.errorIcon.dom.qtip = msg;
7752 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7753 this.errorIcon.show();
7754 this.on('resize', this.alignErrorIcon, this);
7757 var t = Roo.getDom(this.msgTarget);
7759 t.style.display = this.msgDisplay;
7763 this.fireEvent('invalid', this, msg);
7766 SafariOnKeyDown : function(event)
7768 // this is a workaround for a password hang bug on chrome/ webkit.
7770 var isSelectAll = false;
7772 if(this.inputEl().dom.selectionEnd > 0){
7773 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7775 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7776 event.preventDefault();
7781 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7783 event.preventDefault();
7784 // this is very hacky as keydown always get's upper case.
7786 var cc = String.fromCharCode(event.getCharCode());
7787 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7791 adjustWidth : function(tag, w){
7792 tag = tag.toLowerCase();
7793 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7794 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7798 if(tag == 'textarea'){
7801 }else if(Roo.isOpera){
7805 if(tag == 'textarea'){
7824 * @class Roo.bootstrap.TextArea
7825 * @extends Roo.bootstrap.Input
7826 * Bootstrap TextArea class
7827 * @cfg {Number} cols Specifies the visible width of a text area
7828 * @cfg {Number} rows Specifies the visible number of lines in a text area
7829 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7830 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7831 * @cfg {string} html text
7834 * Create a new TextArea
7835 * @param {Object} config The config object
7838 Roo.bootstrap.TextArea = function(config){
7839 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7843 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7853 getAutoCreate : function(){
7855 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7866 value : this.value || '',
7867 html: this.html || '',
7868 cls : 'form-control',
7869 placeholder : this.placeholder || ''
7873 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7874 input.maxLength = this.maxLength;
7878 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7882 input.cols = this.cols;
7885 if (this.readOnly) {
7886 input.readonly = true;
7890 input.name = this.name;
7894 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7898 ['xs','sm','md','lg'].map(function(size){
7899 if (settings[size]) {
7900 cfg.cls += ' col-' + size + '-' + settings[size];
7904 var inputblock = input;
7906 if (this.before || this.after) {
7909 cls : 'input-group',
7913 inputblock.cn.push({
7915 cls : 'input-group-addon',
7919 inputblock.cn.push(input);
7921 inputblock.cn.push({
7923 cls : 'input-group-addon',
7930 if (align ==='left' && this.fieldLabel.length) {
7931 Roo.log("left and has label");
7937 cls : 'control-label col-sm-' + this.labelWidth,
7938 html : this.fieldLabel
7942 cls : "col-sm-" + (12 - this.labelWidth),
7949 } else if ( this.fieldLabel.length) {
7955 //cls : 'input-group-addon',
7956 html : this.fieldLabel
7966 Roo.log(" no label && no align");
7976 if (this.disabled) {
7977 input.disabled=true;
7984 * return the real textarea element.
7986 inputEl: function ()
7988 return this.el.select('textarea.form-control',true).first();
7996 * trigger field - base class for combo..
8001 * @class Roo.bootstrap.TriggerField
8002 * @extends Roo.bootstrap.Input
8003 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8004 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8005 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8006 * for which you can provide a custom implementation. For example:
8008 var trigger = new Roo.bootstrap.TriggerField();
8009 trigger.onTriggerClick = myTriggerFn;
8010 trigger.applyTo('my-field');
8013 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8014 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8015 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8016 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8017 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8020 * Create a new TriggerField.
8021 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8022 * to the base TextField)
8024 Roo.bootstrap.TriggerField = function(config){
8025 this.mimicing = false;
8026 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8029 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8031 * @cfg {String} triggerClass A CSS class to apply to the trigger
8034 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8038 /** @cfg {Boolean} grow @hide */
8039 /** @cfg {Number} growMin @hide */
8040 /** @cfg {Number} growMax @hide */
8046 autoSize: Roo.emptyFn,
8053 actionMode : 'wrap',
8058 getAutoCreate : function(){
8060 var align = this.labelAlign || this.parentLabelAlign();
8065 cls: 'form-group' //input-group
8072 type : this.inputType,
8073 cls : 'form-control',
8074 autocomplete: 'false',
8075 placeholder : this.placeholder || ''
8079 input.name = this.name;
8082 input.cls += ' input-' + this.size;
8085 if (this.disabled) {
8086 input.disabled=true;
8089 var inputblock = input;
8091 if (this.before || this.after) {
8094 cls : 'input-group',
8098 inputblock.cn.push({
8100 cls : 'input-group-addon',
8104 inputblock.cn.push(input);
8106 inputblock.cn.push({
8108 cls : 'input-group-addon',
8121 cls: 'form-hidden-field'
8129 Roo.log('multiple');
8137 cls: 'form-hidden-field'
8141 cls: 'select2-choices',
8145 cls: 'select2-search-field',
8158 cls: 'select2-container input-group',
8163 // cls: 'typeahead typeahead-long dropdown-menu',
8164 // style: 'display:none'
8169 if(!this.multiple && this.showToggleBtn){
8175 if (this.caret != false) {
8178 cls: 'fa fa-' + this.caret
8185 cls : 'input-group-addon btn dropdown-toggle',
8190 cls: 'combobox-clear',
8204 combobox.cls += ' select2-container-multi';
8207 if (align ==='left' && this.fieldLabel.length) {
8209 Roo.log("left and has label");
8215 cls : 'control-label col-sm-' + this.labelWidth,
8216 html : this.fieldLabel
8220 cls : "col-sm-" + (12 - this.labelWidth),
8227 } else if ( this.fieldLabel.length) {
8233 //cls : 'input-group-addon',
8234 html : this.fieldLabel
8244 Roo.log(" no label && no align");
8251 ['xs','sm','md','lg'].map(function(size){
8252 if (settings[size]) {
8253 cfg.cls += ' col-' + size + '-' + settings[size];
8264 onResize : function(w, h){
8265 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8266 // if(typeof w == 'number'){
8267 // var x = w - this.trigger.getWidth();
8268 // this.inputEl().setWidth(this.adjustWidth('input', x));
8269 // this.trigger.setStyle('left', x+'px');
8274 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8277 getResizeEl : function(){
8278 return this.inputEl();
8282 getPositionEl : function(){
8283 return this.inputEl();
8287 alignErrorIcon : function(){
8288 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8292 initEvents : function(){
8296 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8297 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8298 if(!this.multiple && this.showToggleBtn){
8299 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8300 if(this.hideTrigger){
8301 this.trigger.setDisplayed(false);
8303 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8307 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8310 //this.trigger.addClassOnOver('x-form-trigger-over');
8311 //this.trigger.addClassOnClick('x-form-trigger-click');
8314 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8318 createList : function()
8320 this.list = Roo.get(document.body).createChild({
8322 cls: 'typeahead typeahead-long dropdown-menu',
8323 style: 'display:none'
8326 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8331 initTrigger : function(){
8336 onDestroy : function(){
8338 this.trigger.removeAllListeners();
8339 // this.trigger.remove();
8342 // this.wrap.remove();
8344 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8348 onFocus : function(){
8349 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8352 this.wrap.addClass('x-trigger-wrap-focus');
8353 this.mimicing = true;
8354 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8355 if(this.monitorTab){
8356 this.el.on("keydown", this.checkTab, this);
8363 checkTab : function(e){
8364 if(e.getKey() == e.TAB){
8370 onBlur : function(){
8375 mimicBlur : function(e, t){
8377 if(!this.wrap.contains(t) && this.validateBlur()){
8384 triggerBlur : function(){
8385 this.mimicing = false;
8386 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8387 if(this.monitorTab){
8388 this.el.un("keydown", this.checkTab, this);
8390 //this.wrap.removeClass('x-trigger-wrap-focus');
8391 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8395 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8396 validateBlur : function(e, t){
8401 onDisable : function(){
8402 this.inputEl().dom.disabled = true;
8403 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8405 // this.wrap.addClass('x-item-disabled');
8410 onEnable : function(){
8411 this.inputEl().dom.disabled = false;
8412 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8414 // this.el.removeClass('x-item-disabled');
8419 onShow : function(){
8420 var ae = this.getActionEl();
8423 ae.dom.style.display = '';
8424 ae.dom.style.visibility = 'visible';
8430 onHide : function(){
8431 var ae = this.getActionEl();
8432 ae.dom.style.display = 'none';
8436 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8437 * by an implementing function.
8439 * @param {EventObject} e
8441 onTriggerClick : Roo.emptyFn
8445 * Ext JS Library 1.1.1
8446 * Copyright(c) 2006-2007, Ext JS, LLC.
8448 * Originally Released Under LGPL - original licence link has changed is not relivant.
8451 * <script type="text/javascript">
8456 * @class Roo.data.SortTypes
8458 * Defines the default sorting (casting?) comparison functions used when sorting data.
8460 Roo.data.SortTypes = {
8462 * Default sort that does nothing
8463 * @param {Mixed} s The value being converted
8464 * @return {Mixed} The comparison value
8471 * The regular expression used to strip tags
8475 stripTagsRE : /<\/?[^>]+>/gi,
8478 * Strips all HTML tags to sort on text only
8479 * @param {Mixed} s The value being converted
8480 * @return {String} The comparison value
8482 asText : function(s){
8483 return String(s).replace(this.stripTagsRE, "");
8487 * Strips all HTML tags to sort on text only - Case insensitive
8488 * @param {Mixed} s The value being converted
8489 * @return {String} The comparison value
8491 asUCText : function(s){
8492 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8496 * Case insensitive string
8497 * @param {Mixed} s The value being converted
8498 * @return {String} The comparison value
8500 asUCString : function(s) {
8501 return String(s).toUpperCase();
8506 * @param {Mixed} s The value being converted
8507 * @return {Number} The comparison value
8509 asDate : function(s) {
8513 if(s instanceof Date){
8516 return Date.parse(String(s));
8521 * @param {Mixed} s The value being converted
8522 * @return {Float} The comparison value
8524 asFloat : function(s) {
8525 var val = parseFloat(String(s).replace(/,/g, ""));
8526 if(isNaN(val)) val = 0;
8532 * @param {Mixed} s The value being converted
8533 * @return {Number} The comparison value
8535 asInt : function(s) {
8536 var val = parseInt(String(s).replace(/,/g, ""));
8537 if(isNaN(val)) val = 0;
8542 * Ext JS Library 1.1.1
8543 * Copyright(c) 2006-2007, Ext JS, LLC.
8545 * Originally Released Under LGPL - original licence link has changed is not relivant.
8548 * <script type="text/javascript">
8552 * @class Roo.data.Record
8553 * Instances of this class encapsulate both record <em>definition</em> information, and record
8554 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8555 * to access Records cached in an {@link Roo.data.Store} object.<br>
8557 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8558 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8561 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8563 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8564 * {@link #create}. The parameters are the same.
8565 * @param {Array} data An associative Array of data values keyed by the field name.
8566 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8567 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8568 * not specified an integer id is generated.
8570 Roo.data.Record = function(data, id){
8571 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8576 * Generate a constructor for a specific record layout.
8577 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8578 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8579 * Each field definition object may contain the following properties: <ul>
8580 * <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,
8581 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8582 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8583 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8584 * is being used, then this is a string containing the javascript expression to reference the data relative to
8585 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8586 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8587 * this may be omitted.</p></li>
8588 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8589 * <ul><li>auto (Default, implies no conversion)</li>
8594 * <li>date</li></ul></p></li>
8595 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8596 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8597 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8598 * by the Reader into an object that will be stored in the Record. It is passed the
8599 * following parameters:<ul>
8600 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8602 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8604 * <br>usage:<br><pre><code>
8605 var TopicRecord = Roo.data.Record.create(
8606 {name: 'title', mapping: 'topic_title'},
8607 {name: 'author', mapping: 'username'},
8608 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8609 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8610 {name: 'lastPoster', mapping: 'user2'},
8611 {name: 'excerpt', mapping: 'post_text'}
8614 var myNewRecord = new TopicRecord({
8615 title: 'Do my job please',
8618 lastPost: new Date(),
8619 lastPoster: 'Animal',
8620 excerpt: 'No way dude!'
8622 myStore.add(myNewRecord);
8627 Roo.data.Record.create = function(o){
8629 f.superclass.constructor.apply(this, arguments);
8631 Roo.extend(f, Roo.data.Record);
8632 var p = f.prototype;
8633 p.fields = new Roo.util.MixedCollection(false, function(field){
8636 for(var i = 0, len = o.length; i < len; i++){
8637 p.fields.add(new Roo.data.Field(o[i]));
8639 f.getField = function(name){
8640 return p.fields.get(name);
8645 Roo.data.Record.AUTO_ID = 1000;
8646 Roo.data.Record.EDIT = 'edit';
8647 Roo.data.Record.REJECT = 'reject';
8648 Roo.data.Record.COMMIT = 'commit';
8650 Roo.data.Record.prototype = {
8652 * Readonly flag - true if this record has been modified.
8661 join : function(store){
8666 * Set the named field to the specified value.
8667 * @param {String} name The name of the field to set.
8668 * @param {Object} value The value to set the field to.
8670 set : function(name, value){
8671 if(this.data[name] == value){
8678 if(typeof this.modified[name] == 'undefined'){
8679 this.modified[name] = this.data[name];
8681 this.data[name] = value;
8682 if(!this.editing && this.store){
8683 this.store.afterEdit(this);
8688 * Get the value of the named field.
8689 * @param {String} name The name of the field to get the value of.
8690 * @return {Object} The value of the field.
8692 get : function(name){
8693 return this.data[name];
8697 beginEdit : function(){
8698 this.editing = true;
8703 cancelEdit : function(){
8704 this.editing = false;
8705 delete this.modified;
8709 endEdit : function(){
8710 this.editing = false;
8711 if(this.dirty && this.store){
8712 this.store.afterEdit(this);
8717 * Usually called by the {@link Roo.data.Store} which owns the Record.
8718 * Rejects all changes made to the Record since either creation, or the last commit operation.
8719 * Modified fields are reverted to their original values.
8721 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8722 * of reject operations.
8724 reject : function(){
8725 var m = this.modified;
8727 if(typeof m[n] != "function"){
8728 this.data[n] = m[n];
8732 delete this.modified;
8733 this.editing = false;
8735 this.store.afterReject(this);
8740 * Usually called by the {@link Roo.data.Store} which owns the Record.
8741 * Commits all changes made to the Record since either creation, or the last commit operation.
8743 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8744 * of commit operations.
8746 commit : function(){
8748 delete this.modified;
8749 this.editing = false;
8751 this.store.afterCommit(this);
8756 hasError : function(){
8757 return this.error != null;
8761 clearError : function(){
8766 * Creates a copy of this record.
8767 * @param {String} id (optional) A new record id if you don't want to use this record's id
8770 copy : function(newId) {
8771 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8775 * Ext JS Library 1.1.1
8776 * Copyright(c) 2006-2007, Ext JS, LLC.
8778 * Originally Released Under LGPL - original licence link has changed is not relivant.
8781 * <script type="text/javascript">
8787 * @class Roo.data.Store
8788 * @extends Roo.util.Observable
8789 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8790 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8792 * 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
8793 * has no knowledge of the format of the data returned by the Proxy.<br>
8795 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8796 * instances from the data object. These records are cached and made available through accessor functions.
8798 * Creates a new Store.
8799 * @param {Object} config A config object containing the objects needed for the Store to access data,
8800 * and read the data into Records.
8802 Roo.data.Store = function(config){
8803 this.data = new Roo.util.MixedCollection(false);
8804 this.data.getKey = function(o){
8807 this.baseParams = {};
8814 "multisort" : "_multisort"
8817 if(config && config.data){
8818 this.inlineData = config.data;
8822 Roo.apply(this, config);
8824 if(this.reader){ // reader passed
8825 this.reader = Roo.factory(this.reader, Roo.data);
8826 this.reader.xmodule = this.xmodule || false;
8827 if(!this.recordType){
8828 this.recordType = this.reader.recordType;
8830 if(this.reader.onMetaChange){
8831 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8835 if(this.recordType){
8836 this.fields = this.recordType.prototype.fields;
8842 * @event datachanged
8843 * Fires when the data cache has changed, and a widget which is using this Store
8844 * as a Record cache should refresh its view.
8845 * @param {Store} this
8850 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8851 * @param {Store} this
8852 * @param {Object} meta The JSON metadata
8857 * Fires when Records have been added to the Store
8858 * @param {Store} this
8859 * @param {Roo.data.Record[]} records The array of Records added
8860 * @param {Number} index The index at which the record(s) were added
8865 * Fires when a Record has been removed from the Store
8866 * @param {Store} this
8867 * @param {Roo.data.Record} record The Record that was removed
8868 * @param {Number} index The index at which the record was removed
8873 * Fires when a Record has been updated
8874 * @param {Store} this
8875 * @param {Roo.data.Record} record The Record that was updated
8876 * @param {String} operation The update operation being performed. Value may be one of:
8878 Roo.data.Record.EDIT
8879 Roo.data.Record.REJECT
8880 Roo.data.Record.COMMIT
8886 * Fires when the data cache has been cleared.
8887 * @param {Store} this
8892 * Fires before a request is made for a new data object. If the beforeload handler returns false
8893 * the load action will be canceled.
8894 * @param {Store} this
8895 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8899 * @event beforeloadadd
8900 * Fires after a new set of Records has been loaded.
8901 * @param {Store} this
8902 * @param {Roo.data.Record[]} records The Records that were loaded
8903 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8905 beforeloadadd : true,
8908 * Fires after a new set of Records has been loaded, before they are added to the store.
8909 * @param {Store} this
8910 * @param {Roo.data.Record[]} records The Records that were loaded
8911 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8912 * @params {Object} return from reader
8916 * @event loadexception
8917 * Fires if an exception occurs in the Proxy during loading.
8918 * Called with the signature of the Proxy's "loadexception" event.
8919 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8922 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8923 * @param {Object} load options
8924 * @param {Object} jsonData from your request (normally this contains the Exception)
8926 loadexception : true
8930 this.proxy = Roo.factory(this.proxy, Roo.data);
8931 this.proxy.xmodule = this.xmodule || false;
8932 this.relayEvents(this.proxy, ["loadexception"]);
8934 this.sortToggle = {};
8935 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8937 Roo.data.Store.superclass.constructor.call(this);
8939 if(this.inlineData){
8940 this.loadData(this.inlineData);
8941 delete this.inlineData;
8945 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8947 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8948 * without a remote query - used by combo/forms at present.
8952 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8955 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8958 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8959 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8962 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8963 * on any HTTP request
8966 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8969 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8973 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8974 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8979 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8980 * loaded or when a record is removed. (defaults to false).
8982 pruneModifiedRecords : false,
8988 * Add Records to the Store and fires the add event.
8989 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8991 add : function(records){
8992 records = [].concat(records);
8993 for(var i = 0, len = records.length; i < len; i++){
8994 records[i].join(this);
8996 var index = this.data.length;
8997 this.data.addAll(records);
8998 this.fireEvent("add", this, records, index);
9002 * Remove a Record from the Store and fires the remove event.
9003 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9005 remove : function(record){
9006 var index = this.data.indexOf(record);
9007 this.data.removeAt(index);
9008 if(this.pruneModifiedRecords){
9009 this.modified.remove(record);
9011 this.fireEvent("remove", this, record, index);
9015 * Remove all Records from the Store and fires the clear event.
9017 removeAll : function(){
9019 if(this.pruneModifiedRecords){
9022 this.fireEvent("clear", this);
9026 * Inserts Records to the Store at the given index and fires the add event.
9027 * @param {Number} index The start index at which to insert the passed Records.
9028 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9030 insert : function(index, records){
9031 records = [].concat(records);
9032 for(var i = 0, len = records.length; i < len; i++){
9033 this.data.insert(index, records[i]);
9034 records[i].join(this);
9036 this.fireEvent("add", this, records, index);
9040 * Get the index within the cache of the passed Record.
9041 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9042 * @return {Number} The index of the passed Record. Returns -1 if not found.
9044 indexOf : function(record){
9045 return this.data.indexOf(record);
9049 * Get the index within the cache of the Record with the passed id.
9050 * @param {String} id The id of the Record to find.
9051 * @return {Number} The index of the Record. Returns -1 if not found.
9053 indexOfId : function(id){
9054 return this.data.indexOfKey(id);
9058 * Get the Record with the specified id.
9059 * @param {String} id The id of the Record to find.
9060 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9062 getById : function(id){
9063 return this.data.key(id);
9067 * Get the Record at the specified index.
9068 * @param {Number} index The index of the Record to find.
9069 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9071 getAt : function(index){
9072 return this.data.itemAt(index);
9076 * Returns a range of Records between specified indices.
9077 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9078 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9079 * @return {Roo.data.Record[]} An array of Records
9081 getRange : function(start, end){
9082 return this.data.getRange(start, end);
9086 storeOptions : function(o){
9087 o = Roo.apply({}, o);
9090 this.lastOptions = o;
9094 * Loads the Record cache from the configured Proxy using the configured Reader.
9096 * If using remote paging, then the first load call must specify the <em>start</em>
9097 * and <em>limit</em> properties in the options.params property to establish the initial
9098 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9100 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9101 * and this call will return before the new data has been loaded. Perform any post-processing
9102 * in a callback function, or in a "load" event handler.</strong>
9104 * @param {Object} options An object containing properties which control loading options:<ul>
9105 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9106 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9107 * passed the following arguments:<ul>
9108 * <li>r : Roo.data.Record[]</li>
9109 * <li>options: Options object from the load call</li>
9110 * <li>success: Boolean success indicator</li></ul></li>
9111 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9112 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9115 load : function(options){
9116 options = options || {};
9117 if(this.fireEvent("beforeload", this, options) !== false){
9118 this.storeOptions(options);
9119 var p = Roo.apply(options.params || {}, this.baseParams);
9120 // if meta was not loaded from remote source.. try requesting it.
9121 if (!this.reader.metaFromRemote) {
9124 if(this.sortInfo && this.remoteSort){
9125 var pn = this.paramNames;
9126 p[pn["sort"]] = this.sortInfo.field;
9127 p[pn["dir"]] = this.sortInfo.direction;
9129 if (this.multiSort) {
9130 var pn = this.paramNames;
9131 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9134 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9139 * Reloads the Record cache from the configured Proxy using the configured Reader and
9140 * the options from the last load operation performed.
9141 * @param {Object} options (optional) An object containing properties which may override the options
9142 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9143 * the most recently used options are reused).
9145 reload : function(options){
9146 this.load(Roo.applyIf(options||{}, this.lastOptions));
9150 // Called as a callback by the Reader during a load operation.
9151 loadRecords : function(o, options, success){
9152 if(!o || success === false){
9153 if(success !== false){
9154 this.fireEvent("load", this, [], options, o);
9156 if(options.callback){
9157 options.callback.call(options.scope || this, [], options, false);
9161 // if data returned failure - throw an exception.
9162 if (o.success === false) {
9163 // show a message if no listener is registered.
9164 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9165 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9167 // loadmask wil be hooked into this..
9168 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9171 var r = o.records, t = o.totalRecords || r.length;
9173 this.fireEvent("beforeloadadd", this, r, options, o);
9175 if(!options || options.add !== true){
9176 if(this.pruneModifiedRecords){
9179 for(var i = 0, len = r.length; i < len; i++){
9183 this.data = this.snapshot;
9184 delete this.snapshot;
9187 this.data.addAll(r);
9188 this.totalLength = t;
9190 this.fireEvent("datachanged", this);
9192 this.totalLength = Math.max(t, this.data.length+r.length);
9195 this.fireEvent("load", this, r, options, o);
9196 if(options.callback){
9197 options.callback.call(options.scope || this, r, options, true);
9203 * Loads data from a passed data block. A Reader which understands the format of the data
9204 * must have been configured in the constructor.
9205 * @param {Object} data The data block from which to read the Records. The format of the data expected
9206 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9207 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9209 loadData : function(o, append){
9210 var r = this.reader.readRecords(o);
9211 this.loadRecords(r, {add: append}, true);
9215 * Gets the number of cached records.
9217 * <em>If using paging, this may not be the total size of the dataset. If the data object
9218 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9219 * the data set size</em>
9221 getCount : function(){
9222 return this.data.length || 0;
9226 * Gets the total number of records in the dataset as returned by the server.
9228 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9229 * the dataset size</em>
9231 getTotalCount : function(){
9232 return this.totalLength || 0;
9236 * Returns the sort state of the Store as an object with two properties:
9238 field {String} The name of the field by which the Records are sorted
9239 direction {String} The sort order, "ASC" or "DESC"
9242 getSortState : function(){
9243 return this.sortInfo;
9247 applySort : function(){
9248 if(this.sortInfo && !this.remoteSort){
9249 var s = this.sortInfo, f = s.field;
9250 var st = this.fields.get(f).sortType;
9251 var fn = function(r1, r2){
9252 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9253 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9255 this.data.sort(s.direction, fn);
9256 if(this.snapshot && this.snapshot != this.data){
9257 this.snapshot.sort(s.direction, fn);
9263 * Sets the default sort column and order to be used by the next load operation.
9264 * @param {String} fieldName The name of the field to sort by.
9265 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9267 setDefaultSort : function(field, dir){
9268 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9273 * If remote sorting is used, the sort is performed on the server, and the cache is
9274 * reloaded. If local sorting is used, the cache is sorted internally.
9275 * @param {String} fieldName The name of the field to sort by.
9276 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9278 sort : function(fieldName, dir){
9279 var f = this.fields.get(fieldName);
9281 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9283 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9284 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9289 this.sortToggle[f.name] = dir;
9290 this.sortInfo = {field: f.name, direction: dir};
9291 if(!this.remoteSort){
9293 this.fireEvent("datachanged", this);
9295 this.load(this.lastOptions);
9300 * Calls the specified function for each of the Records in the cache.
9301 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9302 * Returning <em>false</em> aborts and exits the iteration.
9303 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9305 each : function(fn, scope){
9306 this.data.each(fn, scope);
9310 * Gets all records modified since the last commit. Modified records are persisted across load operations
9311 * (e.g., during paging).
9312 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9314 getModifiedRecords : function(){
9315 return this.modified;
9319 createFilterFn : function(property, value, anyMatch){
9320 if(!value.exec){ // not a regex
9321 value = String(value);
9322 if(value.length == 0){
9325 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9328 return value.test(r.data[property]);
9333 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9334 * @param {String} property A field on your records
9335 * @param {Number} start The record index to start at (defaults to 0)
9336 * @param {Number} end The last record index to include (defaults to length - 1)
9337 * @return {Number} The sum
9339 sum : function(property, start, end){
9340 var rs = this.data.items, v = 0;
9342 end = (end || end === 0) ? end : rs.length-1;
9344 for(var i = start; i <= end; i++){
9345 v += (rs[i].data[property] || 0);
9351 * Filter the records by a specified property.
9352 * @param {String} field A field on your records
9353 * @param {String/RegExp} value Either a string that the field
9354 * should start with or a RegExp to test against the field
9355 * @param {Boolean} anyMatch True to match any part not just the beginning
9357 filter : function(property, value, anyMatch){
9358 var fn = this.createFilterFn(property, value, anyMatch);
9359 return fn ? this.filterBy(fn) : this.clearFilter();
9363 * Filter by a function. The specified function will be called with each
9364 * record in this data source. If the function returns true the record is included,
9365 * otherwise it is filtered.
9366 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9367 * @param {Object} scope (optional) The scope of the function (defaults to this)
9369 filterBy : function(fn, scope){
9370 this.snapshot = this.snapshot || this.data;
9371 this.data = this.queryBy(fn, scope||this);
9372 this.fireEvent("datachanged", this);
9376 * Query the records by a specified property.
9377 * @param {String} field A field on your records
9378 * @param {String/RegExp} value Either a string that the field
9379 * should start with or a RegExp to test against the field
9380 * @param {Boolean} anyMatch True to match any part not just the beginning
9381 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9383 query : function(property, value, anyMatch){
9384 var fn = this.createFilterFn(property, value, anyMatch);
9385 return fn ? this.queryBy(fn) : this.data.clone();
9389 * Query by a function. The specified function will be called with each
9390 * record in this data source. If the function returns true the record is included
9392 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9393 * @param {Object} scope (optional) The scope of the function (defaults to this)
9394 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9396 queryBy : function(fn, scope){
9397 var data = this.snapshot || this.data;
9398 return data.filterBy(fn, scope||this);
9402 * Collects unique values for a particular dataIndex from this store.
9403 * @param {String} dataIndex The property to collect
9404 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9405 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9406 * @return {Array} An array of the unique values
9408 collect : function(dataIndex, allowNull, bypassFilter){
9409 var d = (bypassFilter === true && this.snapshot) ?
9410 this.snapshot.items : this.data.items;
9411 var v, sv, r = [], l = {};
9412 for(var i = 0, len = d.length; i < len; i++){
9413 v = d[i].data[dataIndex];
9415 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9424 * Revert to a view of the Record cache with no filtering applied.
9425 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9427 clearFilter : function(suppressEvent){
9428 if(this.snapshot && this.snapshot != this.data){
9429 this.data = this.snapshot;
9430 delete this.snapshot;
9431 if(suppressEvent !== true){
9432 this.fireEvent("datachanged", this);
9438 afterEdit : function(record){
9439 if(this.modified.indexOf(record) == -1){
9440 this.modified.push(record);
9442 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9446 afterReject : function(record){
9447 this.modified.remove(record);
9448 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9452 afterCommit : function(record){
9453 this.modified.remove(record);
9454 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9458 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9459 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9461 commitChanges : function(){
9462 var m = this.modified.slice(0);
9464 for(var i = 0, len = m.length; i < len; i++){
9470 * Cancel outstanding changes on all changed records.
9472 rejectChanges : function(){
9473 var m = this.modified.slice(0);
9475 for(var i = 0, len = m.length; i < len; i++){
9480 onMetaChange : function(meta, rtype, o){
9481 this.recordType = rtype;
9482 this.fields = rtype.prototype.fields;
9483 delete this.snapshot;
9484 this.sortInfo = meta.sortInfo || this.sortInfo;
9486 this.fireEvent('metachange', this, this.reader.meta);
9489 moveIndex : function(data, type)
9491 var index = this.indexOf(data);
9493 var newIndex = index + type;
9497 this.insert(newIndex, data);
9502 * Ext JS Library 1.1.1
9503 * Copyright(c) 2006-2007, Ext JS, LLC.
9505 * Originally Released Under LGPL - original licence link has changed is not relivant.
9508 * <script type="text/javascript">
9512 * @class Roo.data.SimpleStore
9513 * @extends Roo.data.Store
9514 * Small helper class to make creating Stores from Array data easier.
9515 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9516 * @cfg {Array} fields An array of field definition objects, or field name strings.
9517 * @cfg {Array} data The multi-dimensional array of data
9519 * @param {Object} config
9521 Roo.data.SimpleStore = function(config){
9522 Roo.data.SimpleStore.superclass.constructor.call(this, {
9524 reader: new Roo.data.ArrayReader({
9527 Roo.data.Record.create(config.fields)
9529 proxy : new Roo.data.MemoryProxy(config.data)
9533 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9535 * Ext JS Library 1.1.1
9536 * Copyright(c) 2006-2007, Ext JS, LLC.
9538 * Originally Released Under LGPL - original licence link has changed is not relivant.
9541 * <script type="text/javascript">
9546 * @extends Roo.data.Store
9547 * @class Roo.data.JsonStore
9548 * Small helper class to make creating Stores for JSON data easier. <br/>
9550 var store = new Roo.data.JsonStore({
9551 url: 'get-images.php',
9553 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9556 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9557 * JsonReader and HttpProxy (unless inline data is provided).</b>
9558 * @cfg {Array} fields An array of field definition objects, or field name strings.
9560 * @param {Object} config
9562 Roo.data.JsonStore = function(c){
9563 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9564 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9565 reader: new Roo.data.JsonReader(c, c.fields)
9568 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9570 * Ext JS Library 1.1.1
9571 * Copyright(c) 2006-2007, Ext JS, LLC.
9573 * Originally Released Under LGPL - original licence link has changed is not relivant.
9576 * <script type="text/javascript">
9580 Roo.data.Field = function(config){
9581 if(typeof config == "string"){
9582 config = {name: config};
9584 Roo.apply(this, config);
9590 var st = Roo.data.SortTypes;
9591 // named sortTypes are supported, here we look them up
9592 if(typeof this.sortType == "string"){
9593 this.sortType = st[this.sortType];
9596 // set default sortType for strings and dates
9600 this.sortType = st.asUCString;
9603 this.sortType = st.asDate;
9606 this.sortType = st.none;
9611 var stripRe = /[\$,%]/g;
9613 // prebuilt conversion function for this field, instead of
9614 // switching every time we're reading a value
9616 var cv, dateFormat = this.dateFormat;
9621 cv = function(v){ return v; };
9624 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9628 return v !== undefined && v !== null && v !== '' ?
9629 parseInt(String(v).replace(stripRe, ""), 10) : '';
9634 return v !== undefined && v !== null && v !== '' ?
9635 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9640 cv = function(v){ return v === true || v === "true" || v == 1; };
9647 if(v instanceof Date){
9651 if(dateFormat == "timestamp"){
9652 return new Date(v*1000);
9654 return Date.parseDate(v, dateFormat);
9656 var parsed = Date.parse(v);
9657 return parsed ? new Date(parsed) : null;
9666 Roo.data.Field.prototype = {
9674 * Ext JS Library 1.1.1
9675 * Copyright(c) 2006-2007, Ext JS, LLC.
9677 * Originally Released Under LGPL - original licence link has changed is not relivant.
9680 * <script type="text/javascript">
9683 // Base class for reading structured data from a data source. This class is intended to be
9684 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9687 * @class Roo.data.DataReader
9688 * Base class for reading structured data from a data source. This class is intended to be
9689 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9692 Roo.data.DataReader = function(meta, recordType){
9696 this.recordType = recordType instanceof Array ?
9697 Roo.data.Record.create(recordType) : recordType;
9700 Roo.data.DataReader.prototype = {
9702 * Create an empty record
9703 * @param {Object} data (optional) - overlay some values
9704 * @return {Roo.data.Record} record created.
9706 newRow : function(d) {
9708 this.recordType.prototype.fields.each(function(c) {
9710 case 'int' : da[c.name] = 0; break;
9711 case 'date' : da[c.name] = new Date(); break;
9712 case 'float' : da[c.name] = 0.0; break;
9713 case 'boolean' : da[c.name] = false; break;
9714 default : da[c.name] = ""; break;
9718 return new this.recordType(Roo.apply(da, d));
9723 * Ext JS Library 1.1.1
9724 * Copyright(c) 2006-2007, Ext JS, LLC.
9726 * Originally Released Under LGPL - original licence link has changed is not relivant.
9729 * <script type="text/javascript">
9733 * @class Roo.data.DataProxy
9734 * @extends Roo.data.Observable
9735 * This class is an abstract base class for implementations which provide retrieval of
9736 * unformatted data objects.<br>
9738 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9739 * (of the appropriate type which knows how to parse the data object) to provide a block of
9740 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9742 * Custom implementations must implement the load method as described in
9743 * {@link Roo.data.HttpProxy#load}.
9745 Roo.data.DataProxy = function(){
9749 * Fires before a network request is made to retrieve a data object.
9750 * @param {Object} This DataProxy object.
9751 * @param {Object} params The params parameter to the load function.
9756 * Fires before the load method's callback is called.
9757 * @param {Object} This DataProxy object.
9758 * @param {Object} o The data object.
9759 * @param {Object} arg The callback argument object passed to the load function.
9763 * @event loadexception
9764 * Fires if an Exception occurs during data retrieval.
9765 * @param {Object} This DataProxy object.
9766 * @param {Object} o The data object.
9767 * @param {Object} arg The callback argument object passed to the load function.
9768 * @param {Object} e The Exception.
9770 loadexception : true
9772 Roo.data.DataProxy.superclass.constructor.call(this);
9775 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9778 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9782 * Ext JS Library 1.1.1
9783 * Copyright(c) 2006-2007, Ext JS, LLC.
9785 * Originally Released Under LGPL - original licence link has changed is not relivant.
9788 * <script type="text/javascript">
9791 * @class Roo.data.MemoryProxy
9792 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9793 * to the Reader when its load method is called.
9795 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9797 Roo.data.MemoryProxy = function(data){
9801 Roo.data.MemoryProxy.superclass.constructor.call(this);
9805 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9807 * Load data from the requested source (in this case an in-memory
9808 * data object passed to the constructor), read the data object into
9809 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9810 * process that block using the passed callback.
9811 * @param {Object} params This parameter is not used by the MemoryProxy class.
9812 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9813 * object into a block of Roo.data.Records.
9814 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9815 * The function must be passed <ul>
9816 * <li>The Record block object</li>
9817 * <li>The "arg" argument from the load function</li>
9818 * <li>A boolean success indicator</li>
9820 * @param {Object} scope The scope in which to call the callback
9821 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9823 load : function(params, reader, callback, scope, arg){
9824 params = params || {};
9827 result = reader.readRecords(this.data);
9829 this.fireEvent("loadexception", this, arg, null, e);
9830 callback.call(scope, null, arg, false);
9833 callback.call(scope, result, arg, true);
9837 update : function(params, records){
9842 * Ext JS Library 1.1.1
9843 * Copyright(c) 2006-2007, Ext JS, LLC.
9845 * Originally Released Under LGPL - original licence link has changed is not relivant.
9848 * <script type="text/javascript">
9851 * @class Roo.data.HttpProxy
9852 * @extends Roo.data.DataProxy
9853 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9854 * configured to reference a certain URL.<br><br>
9856 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9857 * from which the running page was served.<br><br>
9859 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9861 * Be aware that to enable the browser to parse an XML document, the server must set
9862 * the Content-Type header in the HTTP response to "text/xml".
9864 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9865 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9866 * will be used to make the request.
9868 Roo.data.HttpProxy = function(conn){
9869 Roo.data.HttpProxy.superclass.constructor.call(this);
9870 // is conn a conn config or a real conn?
9872 this.useAjax = !conn || !conn.events;
9876 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9877 // thse are take from connection...
9880 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9883 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9884 * extra parameters to each request made by this object. (defaults to undefined)
9887 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9888 * to each request made by this object. (defaults to undefined)
9891 * @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)
9894 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9897 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9903 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9907 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9908 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9909 * a finer-grained basis than the DataProxy events.
9911 getConnection : function(){
9912 return this.useAjax ? Roo.Ajax : this.conn;
9916 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9917 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9918 * process that block using the passed callback.
9919 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9920 * for the request to the remote server.
9921 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9922 * object into a block of Roo.data.Records.
9923 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9924 * The function must be passed <ul>
9925 * <li>The Record block object</li>
9926 * <li>The "arg" argument from the load function</li>
9927 * <li>A boolean success indicator</li>
9929 * @param {Object} scope The scope in which to call the callback
9930 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9932 load : function(params, reader, callback, scope, arg){
9933 if(this.fireEvent("beforeload", this, params) !== false){
9935 params : params || {},
9937 callback : callback,
9942 callback : this.loadResponse,
9946 Roo.applyIf(o, this.conn);
9947 if(this.activeRequest){
9948 Roo.Ajax.abort(this.activeRequest);
9950 this.activeRequest = Roo.Ajax.request(o);
9952 this.conn.request(o);
9955 callback.call(scope||this, null, arg, false);
9960 loadResponse : function(o, success, response){
9961 delete this.activeRequest;
9963 this.fireEvent("loadexception", this, o, response);
9964 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9969 result = o.reader.read(response);
9971 this.fireEvent("loadexception", this, o, response, e);
9972 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9976 this.fireEvent("load", this, o, o.request.arg);
9977 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9981 update : function(dataSet){
9986 updateResponse : function(dataSet){
9991 * Ext JS Library 1.1.1
9992 * Copyright(c) 2006-2007, Ext JS, LLC.
9994 * Originally Released Under LGPL - original licence link has changed is not relivant.
9997 * <script type="text/javascript">
10001 * @class Roo.data.ScriptTagProxy
10002 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10003 * other than the originating domain of the running page.<br><br>
10005 * <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
10006 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10008 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10009 * source code that is used as the source inside a <script> tag.<br><br>
10011 * In order for the browser to process the returned data, the server must wrap the data object
10012 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10013 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10014 * depending on whether the callback name was passed:
10017 boolean scriptTag = false;
10018 String cb = request.getParameter("callback");
10021 response.setContentType("text/javascript");
10023 response.setContentType("application/x-json");
10025 Writer out = response.getWriter();
10027 out.write(cb + "(");
10029 out.print(dataBlock.toJsonString());
10036 * @param {Object} config A configuration object.
10038 Roo.data.ScriptTagProxy = function(config){
10039 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10040 Roo.apply(this, config);
10041 this.head = document.getElementsByTagName("head")[0];
10044 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10046 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10048 * @cfg {String} url The URL from which to request the data object.
10051 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10055 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10056 * the server the name of the callback function set up by the load call to process the returned data object.
10057 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10058 * javascript output which calls this named function passing the data object as its only parameter.
10060 callbackParam : "callback",
10062 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10063 * name to the request.
10068 * Load data from the configured URL, read the data object into
10069 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10070 * process that block using the passed callback.
10071 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10072 * for the request to the remote server.
10073 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10074 * object into a block of Roo.data.Records.
10075 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10076 * The function must be passed <ul>
10077 * <li>The Record block object</li>
10078 * <li>The "arg" argument from the load function</li>
10079 * <li>A boolean success indicator</li>
10081 * @param {Object} scope The scope in which to call the callback
10082 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10084 load : function(params, reader, callback, scope, arg){
10085 if(this.fireEvent("beforeload", this, params) !== false){
10087 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10089 var url = this.url;
10090 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10092 url += "&_dc=" + (new Date().getTime());
10094 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10097 cb : "stcCallback"+transId,
10098 scriptId : "stcScript"+transId,
10102 callback : callback,
10108 window[trans.cb] = function(o){
10109 conn.handleResponse(o, trans);
10112 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10114 if(this.autoAbort !== false){
10118 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10120 var script = document.createElement("script");
10121 script.setAttribute("src", url);
10122 script.setAttribute("type", "text/javascript");
10123 script.setAttribute("id", trans.scriptId);
10124 this.head.appendChild(script);
10126 this.trans = trans;
10128 callback.call(scope||this, null, arg, false);
10133 isLoading : function(){
10134 return this.trans ? true : false;
10138 * Abort the current server request.
10140 abort : function(){
10141 if(this.isLoading()){
10142 this.destroyTrans(this.trans);
10147 destroyTrans : function(trans, isLoaded){
10148 this.head.removeChild(document.getElementById(trans.scriptId));
10149 clearTimeout(trans.timeoutId);
10151 window[trans.cb] = undefined;
10153 delete window[trans.cb];
10156 // if hasn't been loaded, wait for load to remove it to prevent script error
10157 window[trans.cb] = function(){
10158 window[trans.cb] = undefined;
10160 delete window[trans.cb];
10167 handleResponse : function(o, trans){
10168 this.trans = false;
10169 this.destroyTrans(trans, true);
10172 result = trans.reader.readRecords(o);
10174 this.fireEvent("loadexception", this, o, trans.arg, e);
10175 trans.callback.call(trans.scope||window, null, trans.arg, false);
10178 this.fireEvent("load", this, o, trans.arg);
10179 trans.callback.call(trans.scope||window, result, trans.arg, true);
10183 handleFailure : function(trans){
10184 this.trans = false;
10185 this.destroyTrans(trans, false);
10186 this.fireEvent("loadexception", this, null, trans.arg);
10187 trans.callback.call(trans.scope||window, null, trans.arg, false);
10191 * Ext JS Library 1.1.1
10192 * Copyright(c) 2006-2007, Ext JS, LLC.
10194 * Originally Released Under LGPL - original licence link has changed is not relivant.
10197 * <script type="text/javascript">
10201 * @class Roo.data.JsonReader
10202 * @extends Roo.data.DataReader
10203 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10204 * based on mappings in a provided Roo.data.Record constructor.
10206 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10207 * in the reply previously.
10212 var RecordDef = Roo.data.Record.create([
10213 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10214 {name: 'occupation'} // This field will use "occupation" as the mapping.
10216 var myReader = new Roo.data.JsonReader({
10217 totalProperty: "results", // The property which contains the total dataset size (optional)
10218 root: "rows", // The property which contains an Array of row objects
10219 id: "id" // The property within each row object that provides an ID for the record (optional)
10223 * This would consume a JSON file like this:
10225 { 'results': 2, 'rows': [
10226 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10227 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10230 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10231 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10232 * paged from the remote server.
10233 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10234 * @cfg {String} root name of the property which contains the Array of row objects.
10235 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10237 * Create a new JsonReader
10238 * @param {Object} meta Metadata configuration options
10239 * @param {Object} recordType Either an Array of field definition objects,
10240 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10242 Roo.data.JsonReader = function(meta, recordType){
10245 // set some defaults:
10246 Roo.applyIf(meta, {
10247 totalProperty: 'total',
10248 successProperty : 'success',
10253 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10255 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10258 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10259 * Used by Store query builder to append _requestMeta to params.
10262 metaFromRemote : false,
10264 * This method is only used by a DataProxy which has retrieved data from a remote server.
10265 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10266 * @return {Object} data A data block which is used by an Roo.data.Store object as
10267 * a cache of Roo.data.Records.
10269 read : function(response){
10270 var json = response.responseText;
10272 var o = /* eval:var:o */ eval("("+json+")");
10274 throw {message: "JsonReader.read: Json object not found"};
10280 this.metaFromRemote = true;
10281 this.meta = o.metaData;
10282 this.recordType = Roo.data.Record.create(o.metaData.fields);
10283 this.onMetaChange(this.meta, this.recordType, o);
10285 return this.readRecords(o);
10288 // private function a store will implement
10289 onMetaChange : function(meta, recordType, o){
10296 simpleAccess: function(obj, subsc) {
10303 getJsonAccessor: function(){
10305 return function(expr) {
10307 return(re.test(expr))
10308 ? new Function("obj", "return obj." + expr)
10313 return Roo.emptyFn;
10318 * Create a data block containing Roo.data.Records from an XML document.
10319 * @param {Object} o An object which contains an Array of row objects in the property specified
10320 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10321 * which contains the total size of the dataset.
10322 * @return {Object} data A data block which is used by an Roo.data.Store object as
10323 * a cache of Roo.data.Records.
10325 readRecords : function(o){
10327 * After any data loads, the raw JSON data is available for further custom processing.
10331 var s = this.meta, Record = this.recordType,
10332 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10334 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10336 if(s.totalProperty) {
10337 this.getTotal = this.getJsonAccessor(s.totalProperty);
10339 if(s.successProperty) {
10340 this.getSuccess = this.getJsonAccessor(s.successProperty);
10342 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10344 var g = this.getJsonAccessor(s.id);
10345 this.getId = function(rec) {
10347 return (r === undefined || r === "") ? null : r;
10350 this.getId = function(){return null;};
10353 for(var jj = 0; jj < fl; jj++){
10355 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10356 this.ef[jj] = this.getJsonAccessor(map);
10360 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10361 if(s.totalProperty){
10362 var vt = parseInt(this.getTotal(o), 10);
10367 if(s.successProperty){
10368 var vs = this.getSuccess(o);
10369 if(vs === false || vs === 'false'){
10374 for(var i = 0; i < c; i++){
10377 var id = this.getId(n);
10378 for(var j = 0; j < fl; j++){
10380 var v = this.ef[j](n);
10382 Roo.log('missing convert for ' + f.name);
10386 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10388 var record = new Record(values, id);
10390 records[i] = record;
10396 totalRecords : totalRecords
10401 * Ext JS Library 1.1.1
10402 * Copyright(c) 2006-2007, Ext JS, LLC.
10404 * Originally Released Under LGPL - original licence link has changed is not relivant.
10407 * <script type="text/javascript">
10411 * @class Roo.data.ArrayReader
10412 * @extends Roo.data.DataReader
10413 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10414 * Each element of that Array represents a row of data fields. The
10415 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10416 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10420 var RecordDef = Roo.data.Record.create([
10421 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10422 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10424 var myReader = new Roo.data.ArrayReader({
10425 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10429 * This would consume an Array like this:
10431 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10433 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10435 * Create a new JsonReader
10436 * @param {Object} meta Metadata configuration options.
10437 * @param {Object} recordType Either an Array of field definition objects
10438 * as specified to {@link Roo.data.Record#create},
10439 * or an {@link Roo.data.Record} object
10440 * created using {@link Roo.data.Record#create}.
10442 Roo.data.ArrayReader = function(meta, recordType){
10443 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10446 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10448 * Create a data block containing Roo.data.Records from an XML document.
10449 * @param {Object} o An Array of row objects which represents the dataset.
10450 * @return {Object} data A data block which is used by an Roo.data.Store object as
10451 * a cache of Roo.data.Records.
10453 readRecords : function(o){
10454 var sid = this.meta ? this.meta.id : null;
10455 var recordType = this.recordType, fields = recordType.prototype.fields;
10458 for(var i = 0; i < root.length; i++){
10461 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10462 for(var j = 0, jlen = fields.length; j < jlen; j++){
10463 var f = fields.items[j];
10464 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10465 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10467 values[f.name] = v;
10469 var record = new recordType(values, id);
10471 records[records.length] = record;
10475 totalRecords : records.length
10484 * @class Roo.bootstrap.ComboBox
10485 * @extends Roo.bootstrap.TriggerField
10486 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10487 * @cfg {Boolean} append (true|false) default false
10488 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10489 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10490 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10491 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10492 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10494 * Create a new ComboBox.
10495 * @param {Object} config Configuration options
10497 Roo.bootstrap.ComboBox = function(config){
10498 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10502 * Fires when the dropdown list is expanded
10503 * @param {Roo.bootstrap.ComboBox} combo This combo box
10508 * Fires when the dropdown list is collapsed
10509 * @param {Roo.bootstrap.ComboBox} combo This combo box
10513 * @event beforeselect
10514 * Fires before a list item is selected. Return false to cancel the selection.
10515 * @param {Roo.bootstrap.ComboBox} combo This combo box
10516 * @param {Roo.data.Record} record The data record returned from the underlying store
10517 * @param {Number} index The index of the selected item in the dropdown list
10519 'beforeselect' : true,
10522 * Fires when a list item is selected
10523 * @param {Roo.bootstrap.ComboBox} combo This combo box
10524 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10525 * @param {Number} index The index of the selected item in the dropdown list
10529 * @event beforequery
10530 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10531 * The event object passed has these properties:
10532 * @param {Roo.bootstrap.ComboBox} combo This combo box
10533 * @param {String} query The query
10534 * @param {Boolean} forceAll true to force "all" query
10535 * @param {Boolean} cancel true to cancel the query
10536 * @param {Object} e The query event object
10538 'beforequery': true,
10541 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10542 * @param {Roo.bootstrap.ComboBox} combo This combo box
10547 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10548 * @param {Roo.bootstrap.ComboBox} combo This combo box
10549 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10554 * Fires when the remove value from the combobox array
10555 * @param {Roo.bootstrap.ComboBox} combo This combo box
10562 this.tickItems = [];
10564 this.selectedIndex = -1;
10565 if(this.mode == 'local'){
10566 if(config.queryDelay === undefined){
10567 this.queryDelay = 10;
10569 if(config.minChars === undefined){
10575 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10578 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10579 * rendering into an Roo.Editor, defaults to false)
10582 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10583 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10586 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10589 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10590 * the dropdown list (defaults to undefined, with no header element)
10594 * @cfg {String/Roo.Template} tpl The template to use to render the output
10598 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10600 listWidth: undefined,
10602 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10603 * mode = 'remote' or 'text' if mode = 'local')
10605 displayField: undefined,
10607 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10608 * mode = 'remote' or 'value' if mode = 'local').
10609 * Note: use of a valueField requires the user make a selection
10610 * in order for a value to be mapped.
10612 valueField: undefined,
10616 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10617 * field's data value (defaults to the underlying DOM element's name)
10619 hiddenName: undefined,
10621 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10625 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10627 selectedClass: 'active',
10630 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10634 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10635 * anchor positions (defaults to 'tl-bl')
10637 listAlign: 'tl-bl?',
10639 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10643 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10644 * query specified by the allQuery config option (defaults to 'query')
10646 triggerAction: 'query',
10648 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10649 * (defaults to 4, does not apply if editable = false)
10653 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10654 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10658 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10659 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10663 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10664 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10668 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10669 * when editable = true (defaults to false)
10671 selectOnFocus:false,
10673 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10675 queryParam: 'query',
10677 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10678 * when mode = 'remote' (defaults to 'Loading...')
10680 loadingText: 'Loading...',
10682 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10686 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10690 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10691 * traditional select (defaults to true)
10695 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10699 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10703 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10704 * listWidth has a higher value)
10708 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10709 * allow the user to set arbitrary text into the field (defaults to false)
10711 forceSelection:false,
10713 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10714 * if typeAhead = true (defaults to 250)
10716 typeAheadDelay : 250,
10718 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10719 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10721 valueNotFoundText : undefined,
10723 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10725 blockFocus : false,
10728 * @cfg {Boolean} disableClear Disable showing of clear button.
10730 disableClear : false,
10732 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10734 alwaysQuery : false,
10737 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10751 btnPosition : 'right',
10752 triggerList : true,
10753 showToggleBtn : true,
10754 // element that contains real text value.. (when hidden is used..)
10756 getAutoCreate : function()
10763 if(!this.tickable){
10764 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10769 * ComboBox with tickable selections
10772 var align = this.labelAlign || this.parentLabelAlign();
10775 cls : 'form-group roo-combobox-tickable' //input-group
10781 cls : 'tickable-buttons',
10786 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10793 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10800 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10807 Roo.each(buttons.cn, function(c){
10809 c.cls += ' btn-' + _this.size;
10812 if (_this.disabled) {
10823 cls: 'form-hidden-field'
10827 cls: 'select2-choices',
10831 cls: 'select2-search-field',
10843 cls: 'select2-container input-group select2-container-multi',
10848 // cls: 'typeahead typeahead-long dropdown-menu',
10849 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10854 if (align ==='left' && this.fieldLabel.length) {
10856 Roo.log("left and has label");
10862 cls : 'control-label col-sm-' + this.labelWidth,
10863 html : this.fieldLabel
10867 cls : "col-sm-" + (12 - this.labelWidth),
10874 } else if ( this.fieldLabel.length) {
10880 //cls : 'input-group-addon',
10881 html : this.fieldLabel
10891 Roo.log(" no label && no align");
10898 ['xs','sm','md','lg'].map(function(size){
10899 if (settings[size]) {
10900 cfg.cls += ' col-' + size + '-' + settings[size];
10909 initEvents: function()
10913 throw "can not find store for combo";
10915 this.store = Roo.factory(this.store, Roo.data);
10918 this.initTickableEvents();
10922 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10924 if(this.hiddenName){
10926 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10928 this.hiddenField.dom.value =
10929 this.hiddenValue !== undefined ? this.hiddenValue :
10930 this.value !== undefined ? this.value : '';
10932 // prevent input submission
10933 this.el.dom.removeAttribute('name');
10934 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10939 // this.el.dom.setAttribute('autocomplete', 'off');
10942 var cls = 'x-combo-list';
10944 //this.list = new Roo.Layer({
10945 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10951 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10952 _this.list.setWidth(lw);
10955 this.list.on('mouseover', this.onViewOver, this);
10956 this.list.on('mousemove', this.onViewMove, this);
10958 this.list.on('scroll', this.onViewScroll, this);
10961 this.list.swallowEvent('mousewheel');
10962 this.assetHeight = 0;
10965 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10966 this.assetHeight += this.header.getHeight();
10969 this.innerList = this.list.createChild({cls:cls+'-inner'});
10970 this.innerList.on('mouseover', this.onViewOver, this);
10971 this.innerList.on('mousemove', this.onViewMove, this);
10972 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10974 if(this.allowBlank && !this.pageSize && !this.disableClear){
10975 this.footer = this.list.createChild({cls:cls+'-ft'});
10976 this.pageTb = new Roo.Toolbar(this.footer);
10980 this.footer = this.list.createChild({cls:cls+'-ft'});
10981 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10982 {pageSize: this.pageSize});
10986 if (this.pageTb && this.allowBlank && !this.disableClear) {
10988 this.pageTb.add(new Roo.Toolbar.Fill(), {
10989 cls: 'x-btn-icon x-btn-clear',
10991 handler: function()
10994 _this.clearValue();
10995 _this.onSelect(false, -1);
11000 this.assetHeight += this.footer.getHeight();
11005 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11008 this.view = new Roo.View(this.list, this.tpl, {
11009 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11011 //this.view.wrapEl.setDisplayed(false);
11012 this.view.on('click', this.onViewClick, this);
11016 this.store.on('beforeload', this.onBeforeLoad, this);
11017 this.store.on('load', this.onLoad, this);
11018 this.store.on('loadexception', this.onLoadException, this);
11020 if(this.resizable){
11021 this.resizer = new Roo.Resizable(this.list, {
11022 pinned:true, handles:'se'
11024 this.resizer.on('resize', function(r, w, h){
11025 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11026 this.listWidth = w;
11027 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11028 this.restrictHeight();
11030 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11033 if(!this.editable){
11034 this.editable = true;
11035 this.setEditable(false);
11040 if (typeof(this.events.add.listeners) != 'undefined') {
11042 this.addicon = this.wrap.createChild(
11043 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11045 this.addicon.on('click', function(e) {
11046 this.fireEvent('add', this);
11049 if (typeof(this.events.edit.listeners) != 'undefined') {
11051 this.editicon = this.wrap.createChild(
11052 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11053 if (this.addicon) {
11054 this.editicon.setStyle('margin-left', '40px');
11056 this.editicon.on('click', function(e) {
11058 // we fire even if inothing is selected..
11059 this.fireEvent('edit', this, this.lastData );
11065 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11066 "up" : function(e){
11067 this.inKeyMode = true;
11071 "down" : function(e){
11072 if(!this.isExpanded()){
11073 this.onTriggerClick();
11075 this.inKeyMode = true;
11080 "enter" : function(e){
11081 // this.onViewClick();
11085 if(this.fireEvent("specialkey", this, e)){
11086 this.onViewClick(false);
11092 "esc" : function(e){
11096 "tab" : function(e){
11099 if(this.fireEvent("specialkey", this, e)){
11100 this.onViewClick(false);
11108 doRelay : function(foo, bar, hname){
11109 if(hname == 'down' || this.scope.isExpanded()){
11110 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11119 this.queryDelay = Math.max(this.queryDelay || 10,
11120 this.mode == 'local' ? 10 : 250);
11123 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11125 if(this.typeAhead){
11126 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11128 if(this.editable !== false){
11129 this.inputEl().on("keyup", this.onKeyUp, this);
11131 if(this.forceSelection){
11132 this.inputEl().on('blur', this.doForce, this);
11136 this.choices = this.el.select('ul.select2-choices', true).first();
11137 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11141 initTickableEvents: function()
11145 if(this.hiddenName){
11147 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11149 this.hiddenField.dom.value =
11150 this.hiddenValue !== undefined ? this.hiddenValue :
11151 this.value !== undefined ? this.value : '';
11153 // prevent input submission
11154 this.el.dom.removeAttribute('name');
11155 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11160 // this.list = this.el.select('ul.dropdown-menu',true).first();
11162 this.choices = this.el.select('ul.select2-choices', true).first();
11163 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11164 if(this.triggerList){
11165 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11168 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11169 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11171 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11172 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11174 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11175 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11177 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11178 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11179 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11182 this.cancelBtn.hide();
11187 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11188 _this.list.setWidth(lw);
11191 this.list.on('mouseover', this.onViewOver, this);
11192 this.list.on('mousemove', this.onViewMove, this);
11194 this.list.on('scroll', this.onViewScroll, this);
11197 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>';
11200 this.view = new Roo.View(this.list, this.tpl, {
11201 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11204 //this.view.wrapEl.setDisplayed(false);
11205 this.view.on('click', this.onViewClick, this);
11209 this.store.on('beforeload', this.onBeforeLoad, this);
11210 this.store.on('load', this.onLoad, this);
11211 this.store.on('loadexception', this.onLoadException, this);
11213 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11214 // "up" : function(e){
11215 // this.inKeyMode = true;
11216 // this.selectPrev();
11219 // "down" : function(e){
11220 // if(!this.isExpanded()){
11221 // this.onTriggerClick();
11223 // this.inKeyMode = true;
11224 // this.selectNext();
11228 // "enter" : function(e){
11229 //// this.onViewClick();
11231 // this.collapse();
11233 // if(this.fireEvent("specialkey", this, e)){
11234 // this.onViewClick(false);
11240 // "esc" : function(e){
11241 // this.collapse();
11244 // "tab" : function(e){
11245 // this.collapse();
11247 // if(this.fireEvent("specialkey", this, e)){
11248 // this.onViewClick(false);
11256 // doRelay : function(foo, bar, hname){
11257 // if(hname == 'down' || this.scope.isExpanded()){
11258 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11263 // forceKeyDown: true
11267 this.queryDelay = Math.max(this.queryDelay || 10,
11268 this.mode == 'local' ? 10 : 250);
11271 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11273 if(this.typeAhead){
11274 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11279 onDestroy : function(){
11281 this.view.setStore(null);
11282 this.view.el.removeAllListeners();
11283 this.view.el.remove();
11284 this.view.purgeListeners();
11287 this.list.dom.innerHTML = '';
11291 this.store.un('beforeload', this.onBeforeLoad, this);
11292 this.store.un('load', this.onLoad, this);
11293 this.store.un('loadexception', this.onLoadException, this);
11295 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11299 fireKey : function(e){
11300 if(e.isNavKeyPress() && !this.list.isVisible()){
11301 this.fireEvent("specialkey", this, e);
11306 onResize: function(w, h){
11307 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11309 // if(typeof w != 'number'){
11310 // // we do not handle it!?!?
11313 // var tw = this.trigger.getWidth();
11314 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11315 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11317 // this.inputEl().setWidth( this.adjustWidth('input', x));
11319 // //this.trigger.setStyle('left', x+'px');
11321 // if(this.list && this.listWidth === undefined){
11322 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11323 // this.list.setWidth(lw);
11324 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11332 * Allow or prevent the user from directly editing the field text. If false is passed,
11333 * the user will only be able to select from the items defined in the dropdown list. This method
11334 * is the runtime equivalent of setting the 'editable' config option at config time.
11335 * @param {Boolean} value True to allow the user to directly edit the field text
11337 setEditable : function(value){
11338 if(value == this.editable){
11341 this.editable = value;
11343 this.inputEl().dom.setAttribute('readOnly', true);
11344 this.inputEl().on('mousedown', this.onTriggerClick, this);
11345 this.inputEl().addClass('x-combo-noedit');
11347 this.inputEl().dom.setAttribute('readOnly', false);
11348 this.inputEl().un('mousedown', this.onTriggerClick, this);
11349 this.inputEl().removeClass('x-combo-noedit');
11355 onBeforeLoad : function(combo,opts){
11356 if(!this.hasFocus){
11360 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11362 this.restrictHeight();
11363 this.selectedIndex = -1;
11367 onLoad : function(){
11369 this.hasQuery = false;
11371 if(!this.hasFocus){
11375 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11376 this.loading.hide();
11379 if(this.store.getCount() > 0){
11381 // this.restrictHeight();
11382 if(this.lastQuery == this.allQuery){
11383 if(this.editable && !this.tickable){
11384 this.inputEl().dom.select();
11388 !this.selectByValue(this.value, true) &&
11389 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11390 this.store.lastOptions.add != true)
11392 this.select(0, true);
11395 if(this.autoFocus){
11398 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11399 this.taTask.delay(this.typeAheadDelay);
11403 this.onEmptyResults();
11409 onLoadException : function()
11411 this.hasQuery = false;
11413 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11414 this.loading.hide();
11418 Roo.log(this.store.reader.jsonData);
11419 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11421 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11427 onTypeAhead : function(){
11428 if(this.store.getCount() > 0){
11429 var r = this.store.getAt(0);
11430 var newValue = r.data[this.displayField];
11431 var len = newValue.length;
11432 var selStart = this.getRawValue().length;
11434 if(selStart != len){
11435 this.setRawValue(newValue);
11436 this.selectText(selStart, newValue.length);
11442 onSelect : function(record, index){
11444 if(this.fireEvent('beforeselect', this, record, index) !== false){
11446 this.setFromData(index > -1 ? record.data : false);
11449 this.fireEvent('select', this, record, index);
11454 * Returns the currently selected field value or empty string if no value is set.
11455 * @return {String} value The selected value
11457 getValue : function(){
11460 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11463 if(this.valueField){
11464 return typeof this.value != 'undefined' ? this.value : '';
11466 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11471 * Clears any text/value currently set in the field
11473 clearValue : function(){
11474 if(this.hiddenField){
11475 this.hiddenField.dom.value = '';
11478 this.setRawValue('');
11479 this.lastSelectionText = '';
11484 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11485 * will be displayed in the field. If the value does not match the data value of an existing item,
11486 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11487 * Otherwise the field will be blank (although the value will still be set).
11488 * @param {String} value The value to match
11490 setValue : function(v){
11497 if(this.valueField){
11498 var r = this.findRecord(this.valueField, v);
11500 text = r.data[this.displayField];
11501 }else if(this.valueNotFoundText !== undefined){
11502 text = this.valueNotFoundText;
11505 this.lastSelectionText = text;
11506 if(this.hiddenField){
11507 this.hiddenField.dom.value = v;
11509 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11513 * @property {Object} the last set data for the element
11518 * Sets the value of the field based on a object which is related to the record format for the store.
11519 * @param {Object} value the value to set as. or false on reset?
11521 setFromData : function(o){
11528 var dv = ''; // display value
11529 var vv = ''; // value value..
11531 if (this.displayField) {
11532 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11534 // this is an error condition!!!
11535 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11538 if(this.valueField){
11539 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11542 if(this.hiddenField){
11543 this.hiddenField.dom.value = vv;
11545 this.lastSelectionText = dv;
11546 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11550 // no hidden field.. - we store the value in 'value', but still display
11551 // display field!!!!
11552 this.lastSelectionText = dv;
11553 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11559 reset : function(){
11560 // overridden so that last data is reset..
11561 this.setValue(this.originalValue);
11562 this.clearInvalid();
11563 this.lastData = false;
11565 this.view.clearSelections();
11569 findRecord : function(prop, value){
11571 if(this.store.getCount() > 0){
11572 this.store.each(function(r){
11573 if(r.data[prop] == value){
11583 getName: function()
11585 // returns hidden if it's set..
11586 if (!this.rendered) {return ''};
11587 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11591 onViewMove : function(e, t){
11592 this.inKeyMode = false;
11596 onViewOver : function(e, t){
11597 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11600 var item = this.view.findItemFromChild(t);
11603 var index = this.view.indexOf(item);
11604 this.select(index, false);
11609 onViewClick : function(view, doFocus, el, e)
11611 var index = this.view.getSelectedIndexes()[0];
11613 var r = this.store.getAt(index);
11617 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11624 Roo.each(this.tickItems, function(v,k){
11626 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11627 _this.tickItems.splice(k, 1);
11637 this.tickItems.push(r.data);
11642 this.onSelect(r, index);
11644 if(doFocus !== false && !this.blockFocus){
11645 this.inputEl().focus();
11650 restrictHeight : function(){
11651 //this.innerList.dom.style.height = '';
11652 //var inner = this.innerList.dom;
11653 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11654 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11655 //this.list.beginUpdate();
11656 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11657 this.list.alignTo(this.inputEl(), this.listAlign);
11658 this.list.alignTo(this.inputEl(), this.listAlign);
11659 //this.list.endUpdate();
11663 onEmptyResults : function(){
11668 * Returns true if the dropdown list is expanded, else false.
11670 isExpanded : function(){
11671 return this.list.isVisible();
11675 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11676 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11677 * @param {String} value The data value of the item to select
11678 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11679 * selected item if it is not currently in view (defaults to true)
11680 * @return {Boolean} True if the value matched an item in the list, else false
11682 selectByValue : function(v, scrollIntoView){
11683 if(v !== undefined && v !== null){
11684 var r = this.findRecord(this.valueField || this.displayField, v);
11686 this.select(this.store.indexOf(r), scrollIntoView);
11694 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11695 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11696 * @param {Number} index The zero-based index of the list item to select
11697 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11698 * selected item if it is not currently in view (defaults to true)
11700 select : function(index, scrollIntoView){
11701 this.selectedIndex = index;
11702 this.view.select(index);
11703 if(scrollIntoView !== false){
11704 var el = this.view.getNode(index);
11705 if(el && !this.multiple && !this.tickable){
11706 this.list.scrollChildIntoView(el, false);
11712 selectNext : function(){
11713 var ct = this.store.getCount();
11715 if(this.selectedIndex == -1){
11717 }else if(this.selectedIndex < ct-1){
11718 this.select(this.selectedIndex+1);
11724 selectPrev : function(){
11725 var ct = this.store.getCount();
11727 if(this.selectedIndex == -1){
11729 }else if(this.selectedIndex != 0){
11730 this.select(this.selectedIndex-1);
11736 onKeyUp : function(e){
11737 if(this.editable !== false && !e.isSpecialKey()){
11738 this.lastKey = e.getKey();
11739 this.dqTask.delay(this.queryDelay);
11744 validateBlur : function(){
11745 return !this.list || !this.list.isVisible();
11749 initQuery : function(){
11750 this.doQuery(this.getRawValue());
11754 doForce : function(){
11755 if(this.inputEl().dom.value.length > 0){
11756 this.inputEl().dom.value =
11757 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11763 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11764 * query allowing the query action to be canceled if needed.
11765 * @param {String} query The SQL query to execute
11766 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11767 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11768 * saved in the current store (defaults to false)
11770 doQuery : function(q, forceAll){
11772 if(q === undefined || q === null){
11777 forceAll: forceAll,
11781 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11786 forceAll = qe.forceAll;
11787 if(forceAll === true || (q.length >= this.minChars)){
11789 this.hasQuery = true;
11791 if(this.lastQuery != q || this.alwaysQuery){
11792 this.lastQuery = q;
11793 if(this.mode == 'local'){
11794 this.selectedIndex = -1;
11796 this.store.clearFilter();
11798 this.store.filter(this.displayField, q);
11802 this.store.baseParams[this.queryParam] = q;
11804 var options = {params : this.getParams(q)};
11807 options.add = true;
11808 options.params.start = this.page * this.pageSize;
11811 this.store.load(options);
11813 * this code will make the page width larger, at the beginning, the list not align correctly,
11814 * we should expand the list on onLoad
11815 * so command out it
11820 this.selectedIndex = -1;
11825 this.loadNext = false;
11829 getParams : function(q){
11831 //p[this.queryParam] = q;
11835 p.limit = this.pageSize;
11841 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11843 collapse : function(){
11844 if(!this.isExpanded()){
11851 this.hasFocus = false;
11853 this.cancelBtn.hide();
11854 this.trigger.show();
11857 Roo.get(document).un('mousedown', this.collapseIf, this);
11858 Roo.get(document).un('mousewheel', this.collapseIf, this);
11859 if (!this.editable) {
11860 Roo.get(document).un('keydown', this.listKeyPress, this);
11862 this.fireEvent('collapse', this);
11866 collapseIf : function(e){
11867 var in_combo = e.within(this.el);
11868 var in_list = e.within(this.list);
11869 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11871 if (in_combo || in_list || is_list) {
11872 //e.stopPropagation();
11877 this.onTickableFooterButtonClick(e, false, false);
11885 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11887 expand : function(){
11889 if(this.isExpanded() || !this.hasFocus){
11893 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11894 this.list.setWidth(lw);
11901 this.restrictHeight();
11905 this.tickItems = Roo.apply([], this.item);
11908 this.cancelBtn.show();
11909 this.trigger.hide();
11913 Roo.get(document).on('mousedown', this.collapseIf, this);
11914 Roo.get(document).on('mousewheel', this.collapseIf, this);
11915 if (!this.editable) {
11916 Roo.get(document).on('keydown', this.listKeyPress, this);
11919 this.fireEvent('expand', this);
11923 // Implements the default empty TriggerField.onTriggerClick function
11924 onTriggerClick : function(e)
11926 Roo.log('trigger click');
11928 if(this.disabled || !this.triggerList){
11933 this.loadNext = false;
11935 if(this.isExpanded()){
11937 if (!this.blockFocus) {
11938 this.inputEl().focus();
11942 this.hasFocus = true;
11943 if(this.triggerAction == 'all') {
11944 this.doQuery(this.allQuery, true);
11946 this.doQuery(this.getRawValue());
11948 if (!this.blockFocus) {
11949 this.inputEl().focus();
11954 onTickableTriggerClick : function(e)
11961 this.loadNext = false;
11962 this.hasFocus = true;
11964 if(this.triggerAction == 'all') {
11965 this.doQuery(this.allQuery, true);
11967 this.doQuery(this.getRawValue());
11971 onSearchFieldClick : function(e)
11973 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
11974 this.onTickableFooterButtonClick(e, false, false);
11978 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11983 this.loadNext = false;
11984 this.hasFocus = true;
11986 if(this.triggerAction == 'all') {
11987 this.doQuery(this.allQuery, true);
11989 this.doQuery(this.getRawValue());
11993 listKeyPress : function(e)
11995 //Roo.log('listkeypress');
11996 // scroll to first matching element based on key pres..
11997 if (e.isSpecialKey()) {
12000 var k = String.fromCharCode(e.getKey()).toUpperCase();
12003 var csel = this.view.getSelectedNodes();
12004 var cselitem = false;
12006 var ix = this.view.indexOf(csel[0]);
12007 cselitem = this.store.getAt(ix);
12008 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12014 this.store.each(function(v) {
12016 // start at existing selection.
12017 if (cselitem.id == v.id) {
12023 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12024 match = this.store.indexOf(v);
12030 if (match === false) {
12031 return true; // no more action?
12034 this.view.select(match);
12035 var sn = Roo.get(this.view.getSelectedNodes()[0])
12036 sn.scrollIntoView(sn.dom.parentNode, false);
12039 onViewScroll : function(e, t){
12041 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){
12045 this.hasQuery = true;
12047 this.loading = this.list.select('.loading', true).first();
12049 if(this.loading === null){
12050 this.list.createChild({
12052 cls: 'loading select2-more-results select2-active',
12053 html: 'Loading more results...'
12056 this.loading = this.list.select('.loading', true).first();
12058 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12060 this.loading.hide();
12063 this.loading.show();
12068 this.loadNext = true;
12070 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12075 addItem : function(o)
12077 var dv = ''; // display value
12079 if (this.displayField) {
12080 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12082 // this is an error condition!!!
12083 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12090 var choice = this.choices.createChild({
12092 cls: 'select2-search-choice',
12101 cls: 'select2-search-choice-close',
12106 }, this.searchField);
12108 var close = choice.select('a.select2-search-choice-close', true).first()
12110 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12118 this.inputEl().dom.value = '';
12122 onRemoveItem : function(e, _self, o)
12124 e.preventDefault();
12125 var index = this.item.indexOf(o.data) * 1;
12128 Roo.log('not this item?!');
12132 this.item.splice(index, 1);
12137 this.fireEvent('remove', this, e);
12141 syncValue : function()
12143 if(!this.item.length){
12150 Roo.each(this.item, function(i){
12151 if(_this.valueField){
12152 value.push(i[_this.valueField]);
12159 this.value = value.join(',');
12161 if(this.hiddenField){
12162 this.hiddenField.dom.value = this.value;
12166 clearItem : function()
12168 if(!this.multiple){
12174 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12181 inputEl: function ()
12184 return this.searchField;
12186 return this.el.select('input.form-control',true).first();
12190 onTickableFooterButtonClick : function(e, btn, el)
12192 e.preventDefault();
12194 if(btn && btn.name == 'cancel'){
12195 this.tickItems = Roo.apply([], this.item);
12204 Roo.each(this.tickItems, function(o){
12212 validate : function()
12214 var v = this.getRawValue();
12217 v = this.getValue();
12220 if(this.disabled || this.validateValue(v)){
12221 this.clearInvalid();
12230 * @cfg {Boolean} grow
12234 * @cfg {Number} growMin
12238 * @cfg {Number} growMax
12248 * Ext JS Library 1.1.1
12249 * Copyright(c) 2006-2007, Ext JS, LLC.
12251 * Originally Released Under LGPL - original licence link has changed is not relivant.
12254 * <script type="text/javascript">
12259 * @extends Roo.util.Observable
12260 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12261 * This class also supports single and multi selection modes. <br>
12262 * Create a data model bound view:
12264 var store = new Roo.data.Store(...);
12266 var view = new Roo.View({
12268 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12270 singleSelect: true,
12271 selectedClass: "ydataview-selected",
12275 // listen for node click?
12276 view.on("click", function(vw, index, node, e){
12277 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12281 dataModel.load("foobar.xml");
12283 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12285 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12286 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12288 * Note: old style constructor is still suported (container, template, config)
12291 * Create a new View
12292 * @param {Object} config The config object
12295 Roo.View = function(config, depreciated_tpl, depreciated_config){
12297 this.parent = false;
12299 if (typeof(depreciated_tpl) == 'undefined') {
12300 // new way.. - universal constructor.
12301 Roo.apply(this, config);
12302 this.el = Roo.get(this.el);
12305 this.el = Roo.get(config);
12306 this.tpl = depreciated_tpl;
12307 Roo.apply(this, depreciated_config);
12309 this.wrapEl = this.el.wrap().wrap();
12310 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12313 if(typeof(this.tpl) == "string"){
12314 this.tpl = new Roo.Template(this.tpl);
12316 // support xtype ctors..
12317 this.tpl = new Roo.factory(this.tpl, Roo);
12321 this.tpl.compile();
12326 * @event beforeclick
12327 * Fires before a click is processed. Returns false to cancel the default action.
12328 * @param {Roo.View} this
12329 * @param {Number} index The index of the target node
12330 * @param {HTMLElement} node The target node
12331 * @param {Roo.EventObject} e The raw event object
12333 "beforeclick" : true,
12336 * Fires when a template node is clicked.
12337 * @param {Roo.View} this
12338 * @param {Number} index The index of the target node
12339 * @param {HTMLElement} node The target node
12340 * @param {Roo.EventObject} e The raw event object
12345 * Fires when a template node is double clicked.
12346 * @param {Roo.View} this
12347 * @param {Number} index The index of the target node
12348 * @param {HTMLElement} node The target node
12349 * @param {Roo.EventObject} e The raw event object
12353 * @event contextmenu
12354 * Fires when a template node is right clicked.
12355 * @param {Roo.View} this
12356 * @param {Number} index The index of the target node
12357 * @param {HTMLElement} node The target node
12358 * @param {Roo.EventObject} e The raw event object
12360 "contextmenu" : true,
12362 * @event selectionchange
12363 * Fires when the selected nodes change.
12364 * @param {Roo.View} this
12365 * @param {Array} selections Array of the selected nodes
12367 "selectionchange" : true,
12370 * @event beforeselect
12371 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12372 * @param {Roo.View} this
12373 * @param {HTMLElement} node The node to be selected
12374 * @param {Array} selections Array of currently selected nodes
12376 "beforeselect" : true,
12378 * @event preparedata
12379 * Fires on every row to render, to allow you to change the data.
12380 * @param {Roo.View} this
12381 * @param {Object} data to be rendered (change this)
12383 "preparedata" : true
12391 "click": this.onClick,
12392 "dblclick": this.onDblClick,
12393 "contextmenu": this.onContextMenu,
12397 this.selections = [];
12399 this.cmp = new Roo.CompositeElementLite([]);
12401 this.store = Roo.factory(this.store, Roo.data);
12402 this.setStore(this.store, true);
12405 if ( this.footer && this.footer.xtype) {
12407 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12409 this.footer.dataSource = this.store
12410 this.footer.container = fctr;
12411 this.footer = Roo.factory(this.footer, Roo);
12412 fctr.insertFirst(this.el);
12414 // this is a bit insane - as the paging toolbar seems to detach the el..
12415 // dom.parentNode.parentNode.parentNode
12416 // they get detached?
12420 Roo.View.superclass.constructor.call(this);
12425 Roo.extend(Roo.View, Roo.util.Observable, {
12428 * @cfg {Roo.data.Store} store Data store to load data from.
12433 * @cfg {String|Roo.Element} el The container element.
12438 * @cfg {String|Roo.Template} tpl The template used by this View
12442 * @cfg {String} dataName the named area of the template to use as the data area
12443 * Works with domtemplates roo-name="name"
12447 * @cfg {String} selectedClass The css class to add to selected nodes
12449 selectedClass : "x-view-selected",
12451 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12456 * @cfg {String} text to display on mask (default Loading)
12460 * @cfg {Boolean} multiSelect Allow multiple selection
12462 multiSelect : false,
12464 * @cfg {Boolean} singleSelect Allow single selection
12466 singleSelect: false,
12469 * @cfg {Boolean} toggleSelect - selecting
12471 toggleSelect : false,
12474 * @cfg {Boolean} tickable - selecting
12479 * Returns the element this view is bound to.
12480 * @return {Roo.Element}
12482 getEl : function(){
12483 return this.wrapEl;
12489 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12491 refresh : function(){
12492 //Roo.log('refresh');
12495 // if we are using something like 'domtemplate', then
12496 // the what gets used is:
12497 // t.applySubtemplate(NAME, data, wrapping data..)
12498 // the outer template then get' applied with
12499 // the store 'extra data'
12500 // and the body get's added to the
12501 // roo-name="data" node?
12502 // <span class='roo-tpl-{name}'></span> ?????
12506 this.clearSelections();
12507 this.el.update("");
12509 var records = this.store.getRange();
12510 if(records.length < 1) {
12512 // is this valid?? = should it render a template??
12514 this.el.update(this.emptyText);
12518 if (this.dataName) {
12519 this.el.update(t.apply(this.store.meta)); //????
12520 el = this.el.child('.roo-tpl-' + this.dataName);
12523 for(var i = 0, len = records.length; i < len; i++){
12524 var data = this.prepareData(records[i].data, i, records[i]);
12525 this.fireEvent("preparedata", this, data, i, records[i]);
12527 var d = Roo.apply({}, data);
12530 Roo.apply(d, {'roo-id' : Roo.id()});
12534 Roo.each(this.parent.item, function(item){
12535 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12538 Roo.apply(d, {'roo-data-checked' : 'checked'});
12542 html[html.length] = Roo.util.Format.trim(
12544 t.applySubtemplate(this.dataName, d, this.store.meta) :
12551 el.update(html.join(""));
12552 this.nodes = el.dom.childNodes;
12553 this.updateIndexes(0);
12558 * Function to override to reformat the data that is sent to
12559 * the template for each node.
12560 * DEPRICATED - use the preparedata event handler.
12561 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12562 * a JSON object for an UpdateManager bound view).
12564 prepareData : function(data, index, record)
12566 this.fireEvent("preparedata", this, data, index, record);
12570 onUpdate : function(ds, record){
12571 // Roo.log('on update');
12572 this.clearSelections();
12573 var index = this.store.indexOf(record);
12574 var n = this.nodes[index];
12575 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12576 n.parentNode.removeChild(n);
12577 this.updateIndexes(index, index);
12583 onAdd : function(ds, records, index)
12585 //Roo.log(['on Add', ds, records, index] );
12586 this.clearSelections();
12587 if(this.nodes.length == 0){
12591 var n = this.nodes[index];
12592 for(var i = 0, len = records.length; i < len; i++){
12593 var d = this.prepareData(records[i].data, i, records[i]);
12595 this.tpl.insertBefore(n, d);
12598 this.tpl.append(this.el, d);
12601 this.updateIndexes(index);
12604 onRemove : function(ds, record, index){
12605 // Roo.log('onRemove');
12606 this.clearSelections();
12607 var el = this.dataName ?
12608 this.el.child('.roo-tpl-' + this.dataName) :
12611 el.dom.removeChild(this.nodes[index]);
12612 this.updateIndexes(index);
12616 * Refresh an individual node.
12617 * @param {Number} index
12619 refreshNode : function(index){
12620 this.onUpdate(this.store, this.store.getAt(index));
12623 updateIndexes : function(startIndex, endIndex){
12624 var ns = this.nodes;
12625 startIndex = startIndex || 0;
12626 endIndex = endIndex || ns.length - 1;
12627 for(var i = startIndex; i <= endIndex; i++){
12628 ns[i].nodeIndex = i;
12633 * Changes the data store this view uses and refresh the view.
12634 * @param {Store} store
12636 setStore : function(store, initial){
12637 if(!initial && this.store){
12638 this.store.un("datachanged", this.refresh);
12639 this.store.un("add", this.onAdd);
12640 this.store.un("remove", this.onRemove);
12641 this.store.un("update", this.onUpdate);
12642 this.store.un("clear", this.refresh);
12643 this.store.un("beforeload", this.onBeforeLoad);
12644 this.store.un("load", this.onLoad);
12645 this.store.un("loadexception", this.onLoad);
12649 store.on("datachanged", this.refresh, this);
12650 store.on("add", this.onAdd, this);
12651 store.on("remove", this.onRemove, this);
12652 store.on("update", this.onUpdate, this);
12653 store.on("clear", this.refresh, this);
12654 store.on("beforeload", this.onBeforeLoad, this);
12655 store.on("load", this.onLoad, this);
12656 store.on("loadexception", this.onLoad, this);
12664 * onbeforeLoad - masks the loading area.
12667 onBeforeLoad : function(store,opts)
12669 //Roo.log('onBeforeLoad');
12671 this.el.update("");
12673 this.el.mask(this.mask ? this.mask : "Loading" );
12675 onLoad : function ()
12682 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12683 * @param {HTMLElement} node
12684 * @return {HTMLElement} The template node
12686 findItemFromChild : function(node){
12687 var el = this.dataName ?
12688 this.el.child('.roo-tpl-' + this.dataName,true) :
12691 if(!node || node.parentNode == el){
12694 var p = node.parentNode;
12695 while(p && p != el){
12696 if(p.parentNode == el){
12705 onClick : function(e){
12706 var item = this.findItemFromChild(e.getTarget());
12708 var index = this.indexOf(item);
12709 if(this.onItemClick(item, index, e) !== false){
12710 this.fireEvent("click", this, index, item, e);
12713 this.clearSelections();
12718 onContextMenu : function(e){
12719 var item = this.findItemFromChild(e.getTarget());
12721 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12726 onDblClick : function(e){
12727 var item = this.findItemFromChild(e.getTarget());
12729 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12733 onItemClick : function(item, index, e)
12735 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12738 if (this.toggleSelect) {
12739 var m = this.isSelected(item) ? 'unselect' : 'select';
12742 _t[m](item, true, false);
12745 if(this.multiSelect || this.singleSelect){
12746 if(this.multiSelect && e.shiftKey && this.lastSelection){
12747 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12749 this.select(item, this.multiSelect && e.ctrlKey);
12750 this.lastSelection = item;
12753 if(!this.tickable){
12754 e.preventDefault();
12762 * Get the number of selected nodes.
12765 getSelectionCount : function(){
12766 return this.selections.length;
12770 * Get the currently selected nodes.
12771 * @return {Array} An array of HTMLElements
12773 getSelectedNodes : function(){
12774 return this.selections;
12778 * Get the indexes of the selected nodes.
12781 getSelectedIndexes : function(){
12782 var indexes = [], s = this.selections;
12783 for(var i = 0, len = s.length; i < len; i++){
12784 indexes.push(s[i].nodeIndex);
12790 * Clear all selections
12791 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12793 clearSelections : function(suppressEvent){
12794 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12795 this.cmp.elements = this.selections;
12796 this.cmp.removeClass(this.selectedClass);
12797 this.selections = [];
12798 if(!suppressEvent){
12799 this.fireEvent("selectionchange", this, this.selections);
12805 * Returns true if the passed node is selected
12806 * @param {HTMLElement/Number} node The node or node index
12807 * @return {Boolean}
12809 isSelected : function(node){
12810 var s = this.selections;
12814 node = this.getNode(node);
12815 return s.indexOf(node) !== -1;
12820 * @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
12821 * @param {Boolean} keepExisting (optional) true to keep existing selections
12822 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12824 select : function(nodeInfo, keepExisting, suppressEvent){
12825 if(nodeInfo instanceof Array){
12827 this.clearSelections(true);
12829 for(var i = 0, len = nodeInfo.length; i < len; i++){
12830 this.select(nodeInfo[i], true, true);
12834 var node = this.getNode(nodeInfo);
12835 if(!node || this.isSelected(node)){
12836 return; // already selected.
12839 this.clearSelections(true);
12842 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12843 Roo.fly(node).addClass(this.selectedClass);
12844 this.selections.push(node);
12845 if(!suppressEvent){
12846 this.fireEvent("selectionchange", this, this.selections);
12854 * @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
12855 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12856 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12858 unselect : function(nodeInfo, keepExisting, suppressEvent)
12860 if(nodeInfo instanceof Array){
12861 Roo.each(this.selections, function(s) {
12862 this.unselect(s, nodeInfo);
12866 var node = this.getNode(nodeInfo);
12867 if(!node || !this.isSelected(node)){
12868 //Roo.log("not selected");
12869 return; // not selected.
12873 Roo.each(this.selections, function(s) {
12875 Roo.fly(node).removeClass(this.selectedClass);
12882 this.selections= ns;
12883 this.fireEvent("selectionchange", this, this.selections);
12887 * Gets a template node.
12888 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12889 * @return {HTMLElement} The node or null if it wasn't found
12891 getNode : function(nodeInfo){
12892 if(typeof nodeInfo == "string"){
12893 return document.getElementById(nodeInfo);
12894 }else if(typeof nodeInfo == "number"){
12895 return this.nodes[nodeInfo];
12901 * Gets a range template nodes.
12902 * @param {Number} startIndex
12903 * @param {Number} endIndex
12904 * @return {Array} An array of nodes
12906 getNodes : function(start, end){
12907 var ns = this.nodes;
12908 start = start || 0;
12909 end = typeof end == "undefined" ? ns.length - 1 : end;
12912 for(var i = start; i <= end; i++){
12916 for(var i = start; i >= end; i--){
12924 * Finds the index of the passed node
12925 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12926 * @return {Number} The index of the node or -1
12928 indexOf : function(node){
12929 node = this.getNode(node);
12930 if(typeof node.nodeIndex == "number"){
12931 return node.nodeIndex;
12933 var ns = this.nodes;
12934 for(var i = 0, len = ns.length; i < len; i++){
12945 * based on jquery fullcalendar
12949 Roo.bootstrap = Roo.bootstrap || {};
12951 * @class Roo.bootstrap.Calendar
12952 * @extends Roo.bootstrap.Component
12953 * Bootstrap Calendar class
12954 * @cfg {Boolean} loadMask (true|false) default false
12955 * @cfg {Object} header generate the user specific header of the calendar, default false
12958 * Create a new Container
12959 * @param {Object} config The config object
12964 Roo.bootstrap.Calendar = function(config){
12965 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12969 * Fires when a date is selected
12970 * @param {DatePicker} this
12971 * @param {Date} date The selected date
12975 * @event monthchange
12976 * Fires when the displayed month changes
12977 * @param {DatePicker} this
12978 * @param {Date} date The selected month
12980 'monthchange': true,
12982 * @event evententer
12983 * Fires when mouse over an event
12984 * @param {Calendar} this
12985 * @param {event} Event
12987 'evententer': true,
12989 * @event eventleave
12990 * Fires when the mouse leaves an
12991 * @param {Calendar} this
12994 'eventleave': true,
12996 * @event eventclick
12997 * Fires when the mouse click an
12998 * @param {Calendar} this
13007 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13010 * @cfg {Number} startDay
13011 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13019 getAutoCreate : function(){
13022 var fc_button = function(name, corner, style, content ) {
13023 return Roo.apply({},{
13025 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13027 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13030 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13041 style : 'width:100%',
13048 cls : 'fc-header-left',
13050 fc_button('prev', 'left', 'arrow', '‹' ),
13051 fc_button('next', 'right', 'arrow', '›' ),
13052 { tag: 'span', cls: 'fc-header-space' },
13053 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13061 cls : 'fc-header-center',
13065 cls: 'fc-header-title',
13068 html : 'month / year'
13076 cls : 'fc-header-right',
13078 /* fc_button('month', 'left', '', 'month' ),
13079 fc_button('week', '', '', 'week' ),
13080 fc_button('day', 'right', '', 'day' )
13092 header = this.header;
13095 var cal_heads = function() {
13097 // fixme - handle this.
13099 for (var i =0; i < Date.dayNames.length; i++) {
13100 var d = Date.dayNames[i];
13103 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13104 html : d.substring(0,3)
13108 ret[0].cls += ' fc-first';
13109 ret[6].cls += ' fc-last';
13112 var cal_cell = function(n) {
13115 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13120 cls: 'fc-day-number',
13124 cls: 'fc-day-content',
13128 style: 'position: relative;' // height: 17px;
13140 var cal_rows = function() {
13143 for (var r = 0; r < 6; r++) {
13150 for (var i =0; i < Date.dayNames.length; i++) {
13151 var d = Date.dayNames[i];
13152 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13155 row.cn[0].cls+=' fc-first';
13156 row.cn[0].cn[0].style = 'min-height:90px';
13157 row.cn[6].cls+=' fc-last';
13161 ret[0].cls += ' fc-first';
13162 ret[4].cls += ' fc-prev-last';
13163 ret[5].cls += ' fc-last';
13170 cls: 'fc-border-separate',
13171 style : 'width:100%',
13179 cls : 'fc-first fc-last',
13197 cls : 'fc-content',
13198 style : "position: relative;",
13201 cls : 'fc-view fc-view-month fc-grid',
13202 style : 'position: relative',
13203 unselectable : 'on',
13206 cls : 'fc-event-container',
13207 style : 'position:absolute;z-index:8;top:0;left:0;'
13225 initEvents : function()
13228 throw "can not find store for calendar";
13234 style: "text-align:center",
13238 style: "background-color:white;width:50%;margin:250 auto",
13242 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13253 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13255 var size = this.el.select('.fc-content', true).first().getSize();
13256 this.maskEl.setSize(size.width, size.height);
13257 this.maskEl.enableDisplayMode("block");
13258 if(!this.loadMask){
13259 this.maskEl.hide();
13262 this.store = Roo.factory(this.store, Roo.data);
13263 this.store.on('load', this.onLoad, this);
13264 this.store.on('beforeload', this.onBeforeLoad, this);
13268 this.cells = this.el.select('.fc-day',true);
13269 //Roo.log(this.cells);
13270 this.textNodes = this.el.query('.fc-day-number');
13271 this.cells.addClassOnOver('fc-state-hover');
13273 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13274 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13275 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13276 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13278 this.on('monthchange', this.onMonthChange, this);
13280 this.update(new Date().clearTime());
13283 resize : function() {
13284 var sz = this.el.getSize();
13286 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13287 this.el.select('.fc-day-content div',true).setHeight(34);
13292 showPrevMonth : function(e){
13293 this.update(this.activeDate.add("mo", -1));
13295 showToday : function(e){
13296 this.update(new Date().clearTime());
13299 showNextMonth : function(e){
13300 this.update(this.activeDate.add("mo", 1));
13304 showPrevYear : function(){
13305 this.update(this.activeDate.add("y", -1));
13309 showNextYear : function(){
13310 this.update(this.activeDate.add("y", 1));
13315 update : function(date)
13317 var vd = this.activeDate;
13318 this.activeDate = date;
13319 // if(vd && this.el){
13320 // var t = date.getTime();
13321 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13322 // Roo.log('using add remove');
13324 // this.fireEvent('monthchange', this, date);
13326 // this.cells.removeClass("fc-state-highlight");
13327 // this.cells.each(function(c){
13328 // if(c.dateValue == t){
13329 // c.addClass("fc-state-highlight");
13330 // setTimeout(function(){
13331 // try{c.dom.firstChild.focus();}catch(e){}
13341 var days = date.getDaysInMonth();
13343 var firstOfMonth = date.getFirstDateOfMonth();
13344 var startingPos = firstOfMonth.getDay()-this.startDay;
13346 if(startingPos < this.startDay){
13350 var pm = date.add(Date.MONTH, -1);
13351 var prevStart = pm.getDaysInMonth()-startingPos;
13353 this.cells = this.el.select('.fc-day',true);
13354 this.textNodes = this.el.query('.fc-day-number');
13355 this.cells.addClassOnOver('fc-state-hover');
13357 var cells = this.cells.elements;
13358 var textEls = this.textNodes;
13360 Roo.each(cells, function(cell){
13361 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13364 days += startingPos;
13366 // convert everything to numbers so it's fast
13367 var day = 86400000;
13368 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13371 //Roo.log(prevStart);
13373 var today = new Date().clearTime().getTime();
13374 var sel = date.clearTime().getTime();
13375 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13376 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13377 var ddMatch = this.disabledDatesRE;
13378 var ddText = this.disabledDatesText;
13379 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13380 var ddaysText = this.disabledDaysText;
13381 var format = this.format;
13383 var setCellClass = function(cal, cell){
13387 //Roo.log('set Cell Class');
13389 var t = d.getTime();
13393 cell.dateValue = t;
13395 cell.className += " fc-today";
13396 cell.className += " fc-state-highlight";
13397 cell.title = cal.todayText;
13400 // disable highlight in other month..
13401 //cell.className += " fc-state-highlight";
13406 cell.className = " fc-state-disabled";
13407 cell.title = cal.minText;
13411 cell.className = " fc-state-disabled";
13412 cell.title = cal.maxText;
13416 if(ddays.indexOf(d.getDay()) != -1){
13417 cell.title = ddaysText;
13418 cell.className = " fc-state-disabled";
13421 if(ddMatch && format){
13422 var fvalue = d.dateFormat(format);
13423 if(ddMatch.test(fvalue)){
13424 cell.title = ddText.replace("%0", fvalue);
13425 cell.className = " fc-state-disabled";
13429 if (!cell.initialClassName) {
13430 cell.initialClassName = cell.dom.className;
13433 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13438 for(; i < startingPos; i++) {
13439 textEls[i].innerHTML = (++prevStart);
13440 d.setDate(d.getDate()+1);
13442 cells[i].className = "fc-past fc-other-month";
13443 setCellClass(this, cells[i]);
13448 for(; i < days; i++){
13449 intDay = i - startingPos + 1;
13450 textEls[i].innerHTML = (intDay);
13451 d.setDate(d.getDate()+1);
13453 cells[i].className = ''; // "x-date-active";
13454 setCellClass(this, cells[i]);
13458 for(; i < 42; i++) {
13459 textEls[i].innerHTML = (++extraDays);
13460 d.setDate(d.getDate()+1);
13462 cells[i].className = "fc-future fc-other-month";
13463 setCellClass(this, cells[i]);
13466 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13468 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13470 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13471 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13473 if(totalRows != 6){
13474 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13475 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13478 this.fireEvent('monthchange', this, date);
13482 if(!this.internalRender){
13483 var main = this.el.dom.firstChild;
13484 var w = main.offsetWidth;
13485 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13486 Roo.fly(main).setWidth(w);
13487 this.internalRender = true;
13488 // opera does not respect the auto grow header center column
13489 // then, after it gets a width opera refuses to recalculate
13490 // without a second pass
13491 if(Roo.isOpera && !this.secondPass){
13492 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13493 this.secondPass = true;
13494 this.update.defer(10, this, [date]);
13501 findCell : function(dt) {
13502 dt = dt.clearTime().getTime();
13504 this.cells.each(function(c){
13505 //Roo.log("check " +c.dateValue + '?=' + dt);
13506 if(c.dateValue == dt){
13516 findCells : function(ev) {
13517 var s = ev.start.clone().clearTime().getTime();
13519 var e= ev.end.clone().clearTime().getTime();
13522 this.cells.each(function(c){
13523 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13525 if(c.dateValue > e){
13528 if(c.dateValue < s){
13537 // findBestRow: function(cells)
13541 // for (var i =0 ; i < cells.length;i++) {
13542 // ret = Math.max(cells[i].rows || 0,ret);
13549 addItem : function(ev)
13551 // look for vertical location slot in
13552 var cells = this.findCells(ev);
13554 // ev.row = this.findBestRow(cells);
13556 // work out the location.
13560 for(var i =0; i < cells.length; i++) {
13562 cells[i].row = cells[0].row;
13565 cells[i].row = cells[i].row + 1;
13575 if (crow.start.getY() == cells[i].getY()) {
13577 crow.end = cells[i];
13594 cells[0].events.push(ev);
13596 this.calevents.push(ev);
13599 clearEvents: function() {
13601 if(!this.calevents){
13605 Roo.each(this.cells.elements, function(c){
13611 Roo.each(this.calevents, function(e) {
13612 Roo.each(e.els, function(el) {
13613 el.un('mouseenter' ,this.onEventEnter, this);
13614 el.un('mouseleave' ,this.onEventLeave, this);
13619 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13625 renderEvents: function()
13629 this.cells.each(function(c) {
13638 if(c.row != c.events.length){
13639 r = 4 - (4 - (c.row - c.events.length));
13642 c.events = ev.slice(0, r);
13643 c.more = ev.slice(r);
13645 if(c.more.length && c.more.length == 1){
13646 c.events.push(c.more.pop());
13649 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13653 this.cells.each(function(c) {
13655 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13658 for (var e = 0; e < c.events.length; e++){
13659 var ev = c.events[e];
13660 var rows = ev.rows;
13662 for(var i = 0; i < rows.length; i++) {
13664 // how many rows should it span..
13667 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13668 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13670 unselectable : "on",
13673 cls: 'fc-event-inner',
13677 // cls: 'fc-event-time',
13678 // html : cells.length > 1 ? '' : ev.time
13682 cls: 'fc-event-title',
13683 html : String.format('{0}', ev.title)
13690 cls: 'ui-resizable-handle ui-resizable-e',
13691 html : '  '
13698 cfg.cls += ' fc-event-start';
13700 if ((i+1) == rows.length) {
13701 cfg.cls += ' fc-event-end';
13704 var ctr = _this.el.select('.fc-event-container',true).first();
13705 var cg = ctr.createChild(cfg);
13707 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13708 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13710 var r = (c.more.length) ? 1 : 0;
13711 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13712 cg.setWidth(ebox.right - sbox.x -2);
13714 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13715 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13716 cg.on('click', _this.onEventClick, _this, ev);
13727 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13728 style : 'position: absolute',
13729 unselectable : "on",
13732 cls: 'fc-event-inner',
13736 cls: 'fc-event-title',
13744 cls: 'ui-resizable-handle ui-resizable-e',
13745 html : '  '
13751 var ctr = _this.el.select('.fc-event-container',true).first();
13752 var cg = ctr.createChild(cfg);
13754 var sbox = c.select('.fc-day-content',true).first().getBox();
13755 var ebox = c.select('.fc-day-content',true).first().getBox();
13757 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13758 cg.setWidth(ebox.right - sbox.x -2);
13760 cg.on('click', _this.onMoreEventClick, _this, c.more);
13770 onEventEnter: function (e, el,event,d) {
13771 this.fireEvent('evententer', this, el, event);
13774 onEventLeave: function (e, el,event,d) {
13775 this.fireEvent('eventleave', this, el, event);
13778 onEventClick: function (e, el,event,d) {
13779 this.fireEvent('eventclick', this, el, event);
13782 onMonthChange: function () {
13786 onMoreEventClick: function(e, el, more)
13790 this.calpopover.placement = 'right';
13791 this.calpopover.setTitle('More');
13793 this.calpopover.setContent('');
13795 var ctr = this.calpopover.el.select('.popover-content', true).first();
13797 Roo.each(more, function(m){
13799 cls : 'fc-event-hori fc-event-draggable',
13802 var cg = ctr.createChild(cfg);
13804 cg.on('click', _this.onEventClick, _this, m);
13807 this.calpopover.show(el);
13812 onLoad: function ()
13814 this.calevents = [];
13817 if(this.store.getCount() > 0){
13818 this.store.data.each(function(d){
13821 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13822 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13823 time : d.data.start_time,
13824 title : d.data.title,
13825 description : d.data.description,
13826 venue : d.data.venue
13831 this.renderEvents();
13833 if(this.calevents.length && this.loadMask){
13834 this.maskEl.hide();
13838 onBeforeLoad: function()
13840 this.clearEvents();
13842 this.maskEl.show();
13856 * @class Roo.bootstrap.Popover
13857 * @extends Roo.bootstrap.Component
13858 * Bootstrap Popover class
13859 * @cfg {String} html contents of the popover (or false to use children..)
13860 * @cfg {String} title of popover (or false to hide)
13861 * @cfg {String} placement how it is placed
13862 * @cfg {String} trigger click || hover (or false to trigger manually)
13863 * @cfg {String} over what (parent or false to trigger manually.)
13864 * @cfg {Number} delay - delay before showing
13867 * Create a new Popover
13868 * @param {Object} config The config object
13871 Roo.bootstrap.Popover = function(config){
13872 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13875 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13877 title: 'Fill in a title',
13880 placement : 'right',
13881 trigger : 'hover', // hover
13887 can_build_overlaid : false,
13889 getChildContainer : function()
13891 return this.el.select('.popover-content',true).first();
13894 getAutoCreate : function(){
13895 Roo.log('make popover?');
13897 cls : 'popover roo-dynamic',
13898 style: 'display:block',
13904 cls : 'popover-inner',
13908 cls: 'popover-title',
13912 cls : 'popover-content',
13923 setTitle: function(str)
13925 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13927 setContent: function(str)
13929 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13931 // as it get's added to the bottom of the page.
13932 onRender : function(ct, position)
13934 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13936 var cfg = Roo.apply({}, this.getAutoCreate());
13940 cfg.cls += ' ' + this.cls;
13943 cfg.style = this.style;
13945 Roo.log("adding to ")
13946 this.el = Roo.get(document.body).createChild(cfg, position);
13952 initEvents : function()
13954 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13955 this.el.enableDisplayMode('block');
13957 if (this.over === false) {
13960 if (this.triggers === false) {
13963 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13964 var triggers = this.trigger ? this.trigger.split(' ') : [];
13965 Roo.each(triggers, function(trigger) {
13967 if (trigger == 'click') {
13968 on_el.on('click', this.toggle, this);
13969 } else if (trigger != 'manual') {
13970 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
13971 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
13973 on_el.on(eventIn ,this.enter, this);
13974 on_el.on(eventOut, this.leave, this);
13985 toggle : function () {
13986 this.hoverState == 'in' ? this.leave() : this.enter();
13989 enter : function () {
13992 clearTimeout(this.timeout);
13994 this.hoverState = 'in';
13996 if (!this.delay || !this.delay.show) {
14001 this.timeout = setTimeout(function () {
14002 if (_t.hoverState == 'in') {
14005 }, this.delay.show)
14007 leave : function() {
14008 clearTimeout(this.timeout);
14010 this.hoverState = 'out';
14012 if (!this.delay || !this.delay.hide) {
14017 this.timeout = setTimeout(function () {
14018 if (_t.hoverState == 'out') {
14021 }, this.delay.hide)
14024 show : function (on_el)
14027 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14030 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14031 if (this.html !== false) {
14032 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14034 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14035 if (!this.title.length) {
14036 this.el.select('.popover-title',true).hide();
14039 var placement = typeof this.placement == 'function' ?
14040 this.placement.call(this, this.el, on_el) :
14043 var autoToken = /\s?auto?\s?/i;
14044 var autoPlace = autoToken.test(placement);
14046 placement = placement.replace(autoToken, '') || 'top';
14050 //this.el.setXY([0,0]);
14052 this.el.dom.style.display='block';
14053 this.el.addClass(placement);
14055 //this.el.appendTo(on_el);
14057 var p = this.getPosition();
14058 var box = this.el.getBox();
14063 var align = Roo.bootstrap.Popover.alignment[placement];
14064 this.el.alignTo(on_el, align[0],align[1]);
14065 //var arrow = this.el.select('.arrow',true).first();
14066 //arrow.set(align[2],
14068 this.el.addClass('in');
14069 this.hoverState = null;
14071 if (this.el.hasClass('fade')) {
14078 this.el.setXY([0,0]);
14079 this.el.removeClass('in');
14086 Roo.bootstrap.Popover.alignment = {
14087 'left' : ['r-l', [-10,0], 'right'],
14088 'right' : ['l-r', [10,0], 'left'],
14089 'bottom' : ['t-b', [0,10], 'top'],
14090 'top' : [ 'b-t', [0,-10], 'bottom']
14101 * @class Roo.bootstrap.Progress
14102 * @extends Roo.bootstrap.Component
14103 * Bootstrap Progress class
14104 * @cfg {Boolean} striped striped of the progress bar
14105 * @cfg {Boolean} active animated of the progress bar
14109 * Create a new Progress
14110 * @param {Object} config The config object
14113 Roo.bootstrap.Progress = function(config){
14114 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14117 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14122 getAutoCreate : function(){
14130 cfg.cls += ' progress-striped';
14134 cfg.cls += ' active';
14153 * @class Roo.bootstrap.ProgressBar
14154 * @extends Roo.bootstrap.Component
14155 * Bootstrap ProgressBar class
14156 * @cfg {Number} aria_valuenow aria-value now
14157 * @cfg {Number} aria_valuemin aria-value min
14158 * @cfg {Number} aria_valuemax aria-value max
14159 * @cfg {String} label label for the progress bar
14160 * @cfg {String} panel (success | info | warning | danger )
14161 * @cfg {String} role role of the progress bar
14162 * @cfg {String} sr_only text
14166 * Create a new ProgressBar
14167 * @param {Object} config The config object
14170 Roo.bootstrap.ProgressBar = function(config){
14171 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14174 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14178 aria_valuemax : 100,
14184 getAutoCreate : function()
14189 cls: 'progress-bar',
14190 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14202 cfg.role = this.role;
14205 if(this.aria_valuenow){
14206 cfg['aria-valuenow'] = this.aria_valuenow;
14209 if(this.aria_valuemin){
14210 cfg['aria-valuemin'] = this.aria_valuemin;
14213 if(this.aria_valuemax){
14214 cfg['aria-valuemax'] = this.aria_valuemax;
14217 if(this.label && !this.sr_only){
14218 cfg.html = this.label;
14222 cfg.cls += ' progress-bar-' + this.panel;
14228 update : function(aria_valuenow)
14230 this.aria_valuenow = aria_valuenow;
14232 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14247 * @class Roo.bootstrap.TabGroup
14248 * @extends Roo.bootstrap.Column
14249 * Bootstrap Column class
14250 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14251 * @cfg {Boolean} carousel true to make the group behave like a carousel
14254 * Create a new TabGroup
14255 * @param {Object} config The config object
14258 Roo.bootstrap.TabGroup = function(config){
14259 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14261 this.navId = Roo.id();
14264 Roo.bootstrap.TabGroup.register(this);
14268 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14271 transition : false,
14273 getAutoCreate : function()
14275 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14277 cfg.cls += ' tab-content';
14279 if (this.carousel) {
14280 cfg.cls += ' carousel slide';
14282 cls : 'carousel-inner'
14289 getChildContainer : function()
14291 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14295 * register a Navigation item
14296 * @param {Roo.bootstrap.NavItem} the navitem to add
14298 register : function(item)
14300 this.tabs.push( item);
14301 item.navId = this.navId; // not really needed..
14305 getActivePanel : function()
14308 Roo.each(this.tabs, function(t) {
14318 getPanelByName : function(n)
14321 Roo.each(this.tabs, function(t) {
14322 if (t.tabId == n) {
14330 indexOfPanel : function(p)
14333 Roo.each(this.tabs, function(t,i) {
14334 if (t.tabId == p.tabId) {
14343 * show a specific panel
14344 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14345 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14347 showPanel : function (pan)
14350 if (typeof(pan) == 'number') {
14351 pan = this.tabs[pan];
14353 if (typeof(pan) == 'string') {
14354 pan = this.getPanelByName(pan);
14356 if (pan.tabId == this.getActivePanel().tabId) {
14359 var cur = this.getActivePanel();
14361 if (false === cur.fireEvent('beforedeactivate')) {
14365 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14367 this.transition = true;
14368 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14369 var lr = dir == 'next' ? 'left' : 'right';
14370 pan.el.addClass(dir); // or prev
14371 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14372 cur.el.addClass(lr); // or right
14373 pan.el.addClass(lr);
14376 cur.el.on('transitionend', function() {
14377 Roo.log("trans end?");
14379 pan.el.removeClass([lr,dir]);
14380 pan.setActive(true);
14382 cur.el.removeClass([lr]);
14383 cur.setActive(false);
14385 _this.transition = false;
14387 }, this, { single: true } );
14391 cur.setActive(false);
14392 pan.setActive(true);
14396 showPanelNext : function()
14398 var i = this.indexOfPanel(this.getActivePanel());
14399 if (i > this.tabs.length) {
14402 this.showPanel(this.tabs[i+1]);
14404 showPanelPrev : function()
14406 var i = this.indexOfPanel(this.getActivePanel());
14410 this.showPanel(this.tabs[i-1]);
14421 Roo.apply(Roo.bootstrap.TabGroup, {
14425 * register a Navigation Group
14426 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14428 register : function(navgrp)
14430 this.groups[navgrp.navId] = navgrp;
14434 * fetch a Navigation Group based on the navigation ID
14435 * if one does not exist , it will get created.
14436 * @param {string} the navgroup to add
14437 * @returns {Roo.bootstrap.NavGroup} the navgroup
14439 get: function(navId) {
14440 if (typeof(this.groups[navId]) == 'undefined') {
14441 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14443 return this.groups[navId] ;
14458 * @class Roo.bootstrap.TabPanel
14459 * @extends Roo.bootstrap.Component
14460 * Bootstrap TabPanel class
14461 * @cfg {Boolean} active panel active
14462 * @cfg {String} html panel content
14463 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14464 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14468 * Create a new TabPanel
14469 * @param {Object} config The config object
14472 Roo.bootstrap.TabPanel = function(config){
14473 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14477 * Fires when the active status changes
14478 * @param {Roo.bootstrap.TabPanel} this
14479 * @param {Boolean} state the new state
14484 * @event beforedeactivate
14485 * Fires before a tab is de-activated - can be used to do validation on a form.
14486 * @param {Roo.bootstrap.TabPanel} this
14487 * @return {Boolean} false if there is an error
14490 'beforedeactivate': true
14493 this.tabId = this.tabId || Roo.id();
14497 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14504 getAutoCreate : function(){
14507 // item is needed for carousel - not sure if it has any effect otherwise
14508 cls: 'tab-pane item',
14509 html: this.html || ''
14513 cfg.cls += ' active';
14517 cfg.tabId = this.tabId;
14524 initEvents: function()
14526 Roo.log('-------- init events on tab panel ---------');
14528 var p = this.parent();
14529 this.navId = this.navId || p.navId;
14531 if (typeof(this.navId) != 'undefined') {
14532 // not really needed.. but just in case.. parent should be a NavGroup.
14533 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14534 Roo.log(['register', tg, this]);
14540 onRender : function(ct, position)
14542 // Roo.log("Call onRender: " + this.xtype);
14544 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14552 setActive: function(state)
14554 Roo.log("panel - set active " + this.tabId + "=" + state);
14556 this.active = state;
14558 this.el.removeClass('active');
14560 } else if (!this.el.hasClass('active')) {
14561 this.el.addClass('active');
14563 this.fireEvent('changed', this, state);
14580 * @class Roo.bootstrap.DateField
14581 * @extends Roo.bootstrap.Input
14582 * Bootstrap DateField class
14583 * @cfg {Number} weekStart default 0
14584 * @cfg {String} viewMode default empty, (months|years)
14585 * @cfg {String} minViewMode default empty, (months|years)
14586 * @cfg {Number} startDate default -Infinity
14587 * @cfg {Number} endDate default Infinity
14588 * @cfg {Boolean} todayHighlight default false
14589 * @cfg {Boolean} todayBtn default false
14590 * @cfg {Boolean} calendarWeeks default false
14591 * @cfg {Object} daysOfWeekDisabled default empty
14592 * @cfg {Boolean} singleMode default false (true | false)
14594 * @cfg {Boolean} keyboardNavigation default true
14595 * @cfg {String} language default en
14598 * Create a new DateField
14599 * @param {Object} config The config object
14602 Roo.bootstrap.DateField = function(config){
14603 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14607 * Fires when this field show.
14608 * @param {Roo.bootstrap.DateField} this
14609 * @param {Mixed} date The date value
14614 * Fires when this field hide.
14615 * @param {Roo.bootstrap.DateField} this
14616 * @param {Mixed} date The date value
14621 * Fires when select a date.
14622 * @param {Roo.bootstrap.DateField} this
14623 * @param {Mixed} date The date value
14629 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14632 * @cfg {String} format
14633 * The default date format string which can be overriden for localization support. The format must be
14634 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14638 * @cfg {String} altFormats
14639 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14640 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14642 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14650 todayHighlight : false,
14656 keyboardNavigation: true,
14658 calendarWeeks: false,
14660 startDate: -Infinity,
14664 daysOfWeekDisabled: [],
14668 singleMode : false,
14670 UTCDate: function()
14672 return new Date(Date.UTC.apply(Date, arguments));
14675 UTCToday: function()
14677 var today = new Date();
14678 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14681 getDate: function() {
14682 var d = this.getUTCDate();
14683 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14686 getUTCDate: function() {
14690 setDate: function(d) {
14691 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14694 setUTCDate: function(d) {
14696 this.setValue(this.formatDate(this.date));
14699 onRender: function(ct, position)
14702 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14704 this.language = this.language || 'en';
14705 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14706 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14708 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14709 this.format = this.format || 'm/d/y';
14710 this.isInline = false;
14711 this.isInput = true;
14712 this.component = this.el.select('.add-on', true).first() || false;
14713 this.component = (this.component && this.component.length === 0) ? false : this.component;
14714 this.hasInput = this.component && this.inputEL().length;
14716 if (typeof(this.minViewMode === 'string')) {
14717 switch (this.minViewMode) {
14719 this.minViewMode = 1;
14722 this.minViewMode = 2;
14725 this.minViewMode = 0;
14730 if (typeof(this.viewMode === 'string')) {
14731 switch (this.viewMode) {
14744 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14746 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14748 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14750 this.picker().on('mousedown', this.onMousedown, this);
14751 this.picker().on('click', this.onClick, this);
14753 this.picker().addClass('datepicker-dropdown');
14755 this.startViewMode = this.viewMode;
14757 if(this.singleMode){
14758 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14759 v.setVisibilityMode(Roo.Element.DISPLAY)
14763 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14764 v.setStyle('width', '189px');
14768 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14769 if(!this.calendarWeeks){
14774 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14775 v.attr('colspan', function(i, val){
14776 return parseInt(val) + 1;
14781 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14783 this.setStartDate(this.startDate);
14784 this.setEndDate(this.endDate);
14786 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14793 if(this.isInline) {
14798 picker : function()
14800 return this.pickerEl;
14801 // return this.el.select('.datepicker', true).first();
14804 fillDow: function()
14806 var dowCnt = this.weekStart;
14815 if(this.calendarWeeks){
14823 while (dowCnt < this.weekStart + 7) {
14827 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14831 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14834 fillMonths: function()
14837 var months = this.picker().select('>.datepicker-months td', true).first();
14839 months.dom.innerHTML = '';
14845 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14848 months.createChild(month);
14855 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;
14857 if (this.date < this.startDate) {
14858 this.viewDate = new Date(this.startDate);
14859 } else if (this.date > this.endDate) {
14860 this.viewDate = new Date(this.endDate);
14862 this.viewDate = new Date(this.date);
14870 var d = new Date(this.viewDate),
14871 year = d.getUTCFullYear(),
14872 month = d.getUTCMonth(),
14873 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14874 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14875 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14876 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14877 currentDate = this.date && this.date.valueOf(),
14878 today = this.UTCToday();
14880 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14882 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14884 // this.picker.select('>tfoot th.today').
14885 // .text(dates[this.language].today)
14886 // .toggle(this.todayBtn !== false);
14888 this.updateNavArrows();
14891 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14893 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14895 prevMonth.setUTCDate(day);
14897 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14899 var nextMonth = new Date(prevMonth);
14901 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14903 nextMonth = nextMonth.valueOf();
14905 var fillMonths = false;
14907 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14909 while(prevMonth.valueOf() < nextMonth) {
14912 if (prevMonth.getUTCDay() === this.weekStart) {
14914 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14922 if(this.calendarWeeks){
14923 // ISO 8601: First week contains first thursday.
14924 // ISO also states week starts on Monday, but we can be more abstract here.
14926 // Start of current week: based on weekstart/current date
14927 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14928 // Thursday of this week
14929 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14930 // First Thursday of year, year from thursday
14931 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14932 // Calendar week: ms between thursdays, div ms per day, div 7 days
14933 calWeek = (th - yth) / 864e5 / 7 + 1;
14935 fillMonths.cn.push({
14943 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14945 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14948 if (this.todayHighlight &&
14949 prevMonth.getUTCFullYear() == today.getFullYear() &&
14950 prevMonth.getUTCMonth() == today.getMonth() &&
14951 prevMonth.getUTCDate() == today.getDate()) {
14952 clsName += ' today';
14955 if (currentDate && prevMonth.valueOf() === currentDate) {
14956 clsName += ' active';
14959 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14960 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14961 clsName += ' disabled';
14964 fillMonths.cn.push({
14966 cls: 'day ' + clsName,
14967 html: prevMonth.getDate()
14970 prevMonth.setDate(prevMonth.getDate()+1);
14973 var currentYear = this.date && this.date.getUTCFullYear();
14974 var currentMonth = this.date && this.date.getUTCMonth();
14976 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14978 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14979 v.removeClass('active');
14981 if(currentYear === year && k === currentMonth){
14982 v.addClass('active');
14985 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14986 v.addClass('disabled');
14992 year = parseInt(year/10, 10) * 10;
14994 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14996 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14999 for (var i = -1; i < 11; i++) {
15000 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15002 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15010 showMode: function(dir)
15013 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15016 Roo.each(this.picker().select('>div',true).elements, function(v){
15017 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15020 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15025 if(this.isInline) return;
15027 this.picker().removeClass(['bottom', 'top']);
15029 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15031 * place to the top of element!
15035 this.picker().addClass('top');
15036 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15041 this.picker().addClass('bottom');
15043 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15046 parseDate : function(value)
15048 if(!value || value instanceof Date){
15051 var v = Date.parseDate(value, this.format);
15052 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15053 v = Date.parseDate(value, 'Y-m-d');
15055 if(!v && this.altFormats){
15056 if(!this.altFormatsArray){
15057 this.altFormatsArray = this.altFormats.split("|");
15059 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15060 v = Date.parseDate(value, this.altFormatsArray[i]);
15066 formatDate : function(date, fmt)
15068 return (!date || !(date instanceof Date)) ?
15069 date : date.dateFormat(fmt || this.format);
15072 onFocus : function()
15074 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15078 onBlur : function()
15080 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15082 var d = this.inputEl().getValue();
15091 this.picker().show();
15095 this.fireEvent('show', this, this.date);
15100 if(this.isInline) return;
15101 this.picker().hide();
15102 this.viewMode = this.startViewMode;
15105 this.fireEvent('hide', this, this.date);
15109 onMousedown: function(e)
15111 e.stopPropagation();
15112 e.preventDefault();
15117 Roo.bootstrap.DateField.superclass.keyup.call(this);
15121 setValue: function(v)
15124 // v can be a string or a date..
15127 var d = new Date(this.parseDate(v) ).clearTime();
15129 if(isNaN(d.getTime())){
15130 this.date = this.viewDate = '';
15131 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15135 v = this.formatDate(d);
15137 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15139 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15143 this.fireEvent('select', this, this.date);
15147 getValue: function()
15149 return this.formatDate(this.date);
15152 fireKey: function(e)
15154 if (!this.picker().isVisible()){
15155 if (e.keyCode == 27) // allow escape to hide and re-show picker
15160 var dateChanged = false,
15162 newDate, newViewDate;
15167 e.preventDefault();
15171 if (!this.keyboardNavigation) break;
15172 dir = e.keyCode == 37 ? -1 : 1;
15175 newDate = this.moveYear(this.date, dir);
15176 newViewDate = this.moveYear(this.viewDate, dir);
15177 } else if (e.shiftKey){
15178 newDate = this.moveMonth(this.date, dir);
15179 newViewDate = this.moveMonth(this.viewDate, dir);
15181 newDate = new Date(this.date);
15182 newDate.setUTCDate(this.date.getUTCDate() + dir);
15183 newViewDate = new Date(this.viewDate);
15184 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15186 if (this.dateWithinRange(newDate)){
15187 this.date = newDate;
15188 this.viewDate = newViewDate;
15189 this.setValue(this.formatDate(this.date));
15191 e.preventDefault();
15192 dateChanged = true;
15197 if (!this.keyboardNavigation) break;
15198 dir = e.keyCode == 38 ? -1 : 1;
15200 newDate = this.moveYear(this.date, dir);
15201 newViewDate = this.moveYear(this.viewDate, dir);
15202 } else if (e.shiftKey){
15203 newDate = this.moveMonth(this.date, dir);
15204 newViewDate = this.moveMonth(this.viewDate, dir);
15206 newDate = new Date(this.date);
15207 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15208 newViewDate = new Date(this.viewDate);
15209 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15211 if (this.dateWithinRange(newDate)){
15212 this.date = newDate;
15213 this.viewDate = newViewDate;
15214 this.setValue(this.formatDate(this.date));
15216 e.preventDefault();
15217 dateChanged = true;
15221 this.setValue(this.formatDate(this.date));
15223 e.preventDefault();
15226 this.setValue(this.formatDate(this.date));
15240 onClick: function(e)
15242 e.stopPropagation();
15243 e.preventDefault();
15245 var target = e.getTarget();
15247 if(target.nodeName.toLowerCase() === 'i'){
15248 target = Roo.get(target).dom.parentNode;
15251 var nodeName = target.nodeName;
15252 var className = target.className;
15253 var html = target.innerHTML;
15254 //Roo.log(nodeName);
15256 switch(nodeName.toLowerCase()) {
15258 switch(className) {
15264 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15265 switch(this.viewMode){
15267 this.viewDate = this.moveMonth(this.viewDate, dir);
15271 this.viewDate = this.moveYear(this.viewDate, dir);
15277 var date = new Date();
15278 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15280 this.setValue(this.formatDate(this.date));
15287 if (className.indexOf('disabled') < 0) {
15288 this.viewDate.setUTCDate(1);
15289 if (className.indexOf('month') > -1) {
15290 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15292 var year = parseInt(html, 10) || 0;
15293 this.viewDate.setUTCFullYear(year);
15297 if(this.singleMode){
15298 this.setValue(this.formatDate(this.viewDate));
15309 //Roo.log(className);
15310 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15311 var day = parseInt(html, 10) || 1;
15312 var year = this.viewDate.getUTCFullYear(),
15313 month = this.viewDate.getUTCMonth();
15315 if (className.indexOf('old') > -1) {
15322 } else if (className.indexOf('new') > -1) {
15330 //Roo.log([year,month,day]);
15331 this.date = this.UTCDate(year, month, day,0,0,0,0);
15332 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15334 //Roo.log(this.formatDate(this.date));
15335 this.setValue(this.formatDate(this.date));
15342 setStartDate: function(startDate)
15344 this.startDate = startDate || -Infinity;
15345 if (this.startDate !== -Infinity) {
15346 this.startDate = this.parseDate(this.startDate);
15349 this.updateNavArrows();
15352 setEndDate: function(endDate)
15354 this.endDate = endDate || Infinity;
15355 if (this.endDate !== Infinity) {
15356 this.endDate = this.parseDate(this.endDate);
15359 this.updateNavArrows();
15362 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15364 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15365 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15366 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15368 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15369 return parseInt(d, 10);
15372 this.updateNavArrows();
15375 updateNavArrows: function()
15377 if(this.singleMode){
15381 var d = new Date(this.viewDate),
15382 year = d.getUTCFullYear(),
15383 month = d.getUTCMonth();
15385 Roo.each(this.picker().select('.prev', true).elements, function(v){
15387 switch (this.viewMode) {
15390 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15396 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15403 Roo.each(this.picker().select('.next', true).elements, function(v){
15405 switch (this.viewMode) {
15408 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15414 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15422 moveMonth: function(date, dir)
15424 if (!dir) return date;
15425 var new_date = new Date(date.valueOf()),
15426 day = new_date.getUTCDate(),
15427 month = new_date.getUTCMonth(),
15428 mag = Math.abs(dir),
15430 dir = dir > 0 ? 1 : -1;
15433 // If going back one month, make sure month is not current month
15434 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15436 return new_date.getUTCMonth() == month;
15438 // If going forward one month, make sure month is as expected
15439 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15441 return new_date.getUTCMonth() != new_month;
15443 new_month = month + dir;
15444 new_date.setUTCMonth(new_month);
15445 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15446 if (new_month < 0 || new_month > 11)
15447 new_month = (new_month + 12) % 12;
15449 // For magnitudes >1, move one month at a time...
15450 for (var i=0; i<mag; i++)
15451 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15452 new_date = this.moveMonth(new_date, dir);
15453 // ...then reset the day, keeping it in the new month
15454 new_month = new_date.getUTCMonth();
15455 new_date.setUTCDate(day);
15457 return new_month != new_date.getUTCMonth();
15460 // Common date-resetting loop -- if date is beyond end of month, make it
15463 new_date.setUTCDate(--day);
15464 new_date.setUTCMonth(new_month);
15469 moveYear: function(date, dir)
15471 return this.moveMonth(date, dir*12);
15474 dateWithinRange: function(date)
15476 return date >= this.startDate && date <= this.endDate;
15482 this.picker().remove();
15487 Roo.apply(Roo.bootstrap.DateField, {
15498 html: '<i class="fa fa-arrow-left"/>'
15508 html: '<i class="fa fa-arrow-right"/>'
15550 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15551 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15552 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15553 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15554 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15567 navFnc: 'FullYear',
15572 navFnc: 'FullYear',
15577 Roo.apply(Roo.bootstrap.DateField, {
15581 cls: 'datepicker dropdown-menu roo-dynamic',
15585 cls: 'datepicker-days',
15589 cls: 'table-condensed',
15591 Roo.bootstrap.DateField.head,
15595 Roo.bootstrap.DateField.footer
15602 cls: 'datepicker-months',
15606 cls: 'table-condensed',
15608 Roo.bootstrap.DateField.head,
15609 Roo.bootstrap.DateField.content,
15610 Roo.bootstrap.DateField.footer
15617 cls: 'datepicker-years',
15621 cls: 'table-condensed',
15623 Roo.bootstrap.DateField.head,
15624 Roo.bootstrap.DateField.content,
15625 Roo.bootstrap.DateField.footer
15644 * @class Roo.bootstrap.TimeField
15645 * @extends Roo.bootstrap.Input
15646 * Bootstrap DateField class
15650 * Create a new TimeField
15651 * @param {Object} config The config object
15654 Roo.bootstrap.TimeField = function(config){
15655 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15659 * Fires when this field show.
15660 * @param {Roo.bootstrap.DateField} thisthis
15661 * @param {Mixed} date The date value
15666 * Fires when this field hide.
15667 * @param {Roo.bootstrap.DateField} this
15668 * @param {Mixed} date The date value
15673 * Fires when select a date.
15674 * @param {Roo.bootstrap.DateField} this
15675 * @param {Mixed} date The date value
15681 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15684 * @cfg {String} format
15685 * The default time format string which can be overriden for localization support. The format must be
15686 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15690 onRender: function(ct, position)
15693 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15695 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15697 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15699 this.pop = this.picker().select('>.datepicker-time',true).first();
15700 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15702 this.picker().on('mousedown', this.onMousedown, this);
15703 this.picker().on('click', this.onClick, this);
15705 this.picker().addClass('datepicker-dropdown');
15710 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15711 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15712 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15713 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15714 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15715 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15719 fireKey: function(e){
15720 if (!this.picker().isVisible()){
15721 if (e.keyCode == 27) { // allow escape to hide and re-show picker
15727 e.preventDefault();
15735 this.onTogglePeriod();
15738 this.onIncrementMinutes();
15741 this.onDecrementMinutes();
15750 onClick: function(e) {
15751 e.stopPropagation();
15752 e.preventDefault();
15755 picker : function()
15757 return this.el.select('.datepicker', true).first();
15760 fillTime: function()
15762 var time = this.pop.select('tbody', true).first();
15764 time.dom.innerHTML = '';
15779 cls: 'hours-up glyphicon glyphicon-chevron-up'
15799 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15820 cls: 'timepicker-hour',
15835 cls: 'timepicker-minute',
15850 cls: 'btn btn-primary period',
15872 cls: 'hours-down glyphicon glyphicon-chevron-down'
15892 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15910 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15917 var hours = this.time.getHours();
15918 var minutes = this.time.getMinutes();
15931 hours = hours - 12;
15935 hours = '0' + hours;
15939 minutes = '0' + minutes;
15942 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15943 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15944 this.pop.select('button', true).first().dom.innerHTML = period;
15950 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15952 var cls = ['bottom'];
15954 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15961 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15966 this.picker().addClass(cls.join('-'));
15970 Roo.each(cls, function(c){
15972 _this.picker().setTop(_this.inputEl().getHeight());
15976 _this.picker().setTop(0 - _this.picker().getHeight());
15981 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15985 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15992 onFocus : function()
15994 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15998 onBlur : function()
16000 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16006 this.picker().show();
16011 this.fireEvent('show', this, this.date);
16016 this.picker().hide();
16019 this.fireEvent('hide', this, this.date);
16022 setTime : function()
16025 this.setValue(this.time.format(this.format));
16027 this.fireEvent('select', this, this.date);
16032 onMousedown: function(e){
16033 e.stopPropagation();
16034 e.preventDefault();
16037 onIncrementHours: function()
16039 Roo.log('onIncrementHours');
16040 this.time = this.time.add(Date.HOUR, 1);
16045 onDecrementHours: function()
16047 Roo.log('onDecrementHours');
16048 this.time = this.time.add(Date.HOUR, -1);
16052 onIncrementMinutes: function()
16054 Roo.log('onIncrementMinutes');
16055 this.time = this.time.add(Date.MINUTE, 1);
16059 onDecrementMinutes: function()
16061 Roo.log('onDecrementMinutes');
16062 this.time = this.time.add(Date.MINUTE, -1);
16066 onTogglePeriod: function()
16068 Roo.log('onTogglePeriod');
16069 this.time = this.time.add(Date.HOUR, 12);
16076 Roo.apply(Roo.bootstrap.TimeField, {
16106 cls: 'btn btn-info ok',
16118 Roo.apply(Roo.bootstrap.TimeField, {
16122 cls: 'datepicker dropdown-menu',
16126 cls: 'datepicker-time',
16130 cls: 'table-condensed',
16132 Roo.bootstrap.TimeField.content,
16133 Roo.bootstrap.TimeField.footer
16152 * @class Roo.bootstrap.MonthField
16153 * @extends Roo.bootstrap.Input
16154 * Bootstrap MonthField class
16156 * @cfg {String} language default en
16159 * Create a new MonthField
16160 * @param {Object} config The config object
16163 Roo.bootstrap.MonthField = function(config){
16164 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16169 * Fires when this field show.
16170 * @param {Roo.bootstrap.MonthField} this
16171 * @param {Mixed} date The date value
16176 * Fires when this field hide.
16177 * @param {Roo.bootstrap.MonthField} this
16178 * @param {Mixed} date The date value
16183 * Fires when select a date.
16184 * @param {Roo.bootstrap.MonthField} this
16185 * @param {Mixed} date The date value
16191 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16193 onRender: function(ct, position)
16196 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16198 this.language = this.language || 'en';
16199 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16200 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16202 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16203 this.isInline = false;
16204 this.isInput = true;
16205 this.component = this.el.select('.add-on', true).first() || false;
16206 this.component = (this.component && this.component.length === 0) ? false : this.component;
16207 this.hasInput = this.component && this.inputEL().length;
16209 this.minViewMode = 1;
16212 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16214 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16216 this.picker().on('mousedown', this.onMousedown, this);
16217 this.picker().on('click', this.onClick, this);
16219 this.picker().addClass('datepicker-dropdown');
16221 this.startViewMode = this.viewMode;
16223 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16224 v.setStyle('width', '189px');
16230 if(this.isInline) {
16235 setValue: function(v)
16237 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16241 this.fireEvent('select', this, this.date);
16245 getValue: function()
16250 onClick: function(e)
16252 e.stopPropagation();
16253 e.preventDefault();
16255 var target = e.getTarget();
16257 if(target.nodeName.toLowerCase() === 'i'){
16258 target = Roo.get(target).dom.parentNode;
16261 var nodeName = target.nodeName;
16262 var className = target.className;
16263 var html = target.innerHTML;
16265 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16269 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16271 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16277 picker : function()
16279 return this.pickerEl;
16282 fillMonths: function()
16285 var months = this.picker().select('>.datepicker-months td', true).first();
16287 months.dom.innerHTML = '';
16293 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16296 months.createChild(month);
16305 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16306 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16309 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16310 e.removeClass('active');
16312 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16313 e.addClass('active');
16320 if(this.isInline) return;
16322 this.picker().removeClass(['bottom', 'top']);
16324 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16326 * place to the top of element!
16330 this.picker().addClass('top');
16331 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16336 this.picker().addClass('bottom');
16338 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16341 onFocus : function()
16343 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16347 onBlur : function()
16349 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16351 var d = this.inputEl().getValue();
16360 this.picker().show();
16361 this.picker().select('>.datepicker-months', true).first().show();
16365 this.fireEvent('show', this, this.date);
16370 if(this.isInline) return;
16371 this.picker().hide();
16372 this.fireEvent('hide', this, this.date);
16376 onMousedown: function(e)
16378 e.stopPropagation();
16379 e.preventDefault();
16384 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16388 fireKey: function(e)
16390 if (!this.picker().isVisible()){
16391 if (e.keyCode == 27) // allow escape to hide and re-show picker
16401 e.preventDefault();
16405 dir = e.keyCode == 37 ? -1 : 1;
16407 this.vIndex = this.vIndex + dir;
16409 if(this.vIndex < 0){
16413 if(this.vIndex > 11){
16417 if(isNaN(this.vIndex)){
16421 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16427 dir = e.keyCode == 38 ? -1 : 1;
16429 this.vIndex = this.vIndex + dir * 4;
16431 if(this.vIndex < 0){
16435 if(this.vIndex > 11){
16439 if(isNaN(this.vIndex)){
16443 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16448 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16449 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16453 e.preventDefault();
16456 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16457 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16473 this.picker().remove();
16478 Roo.apply(Roo.bootstrap.MonthField, {
16497 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16498 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16503 Roo.apply(Roo.bootstrap.MonthField, {
16507 cls: 'datepicker dropdown-menu roo-dynamic',
16511 cls: 'datepicker-months',
16515 cls: 'table-condensed',
16517 Roo.bootstrap.DateField.content
16537 * @class Roo.bootstrap.CheckBox
16538 * @extends Roo.bootstrap.Input
16539 * Bootstrap CheckBox class
16541 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16542 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16543 * @cfg {String} boxLabel The text that appears beside the checkbox
16544 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16545 * @cfg {Boolean} checked initnal the element
16546 * @cfg {Boolean} inline inline the element (default false)
16549 * Create a new CheckBox
16550 * @param {Object} config The config object
16553 Roo.bootstrap.CheckBox = function(config){
16554 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16559 * Fires when the element is checked or unchecked.
16560 * @param {Roo.bootstrap.CheckBox} this This input
16561 * @param {Boolean} checked The new checked value
16567 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16569 inputType: 'checkbox',
16577 getAutoCreate : function()
16579 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16585 cfg.cls = 'form-group ' + this.inputType; //input-group
16588 cfg.cls += ' ' + this.inputType + '-inline';
16594 type : this.inputType,
16595 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16596 cls : 'roo-' + this.inputType, //'form-box',
16597 placeholder : this.placeholder || ''
16601 if (this.weight) { // Validity check?
16602 cfg.cls += " " + this.inputType + "-" + this.weight;
16605 if (this.disabled) {
16606 input.disabled=true;
16610 input.checked = this.checked;
16614 input.name = this.name;
16618 input.cls += ' input-' + this.size;
16623 ['xs','sm','md','lg'].map(function(size){
16624 if (settings[size]) {
16625 cfg.cls += ' col-' + size + '-' + settings[size];
16631 var inputblock = input;
16636 if (this.before || this.after) {
16639 cls : 'input-group',
16644 inputblock.cn.push({
16646 cls : 'input-group-addon',
16651 inputblock.cn.push(input);
16654 inputblock.cn.push({
16656 cls : 'input-group-addon',
16663 if (align ==='left' && this.fieldLabel.length) {
16664 Roo.log("left and has label");
16670 cls : 'control-label col-md-' + this.labelWidth,
16671 html : this.fieldLabel
16675 cls : "col-md-" + (12 - this.labelWidth),
16682 } else if ( this.fieldLabel.length) {
16687 tag: this.boxLabel ? 'span' : 'label',
16689 cls: 'control-label box-input-label',
16690 //cls : 'input-group-addon',
16691 html : this.fieldLabel
16701 Roo.log(" no label && no align");
16702 cfg.cn = [ inputblock ] ;
16707 var boxLabelCfg = {
16709 //'for': id, // box label is handled by onclick - so no for...
16711 html: this.boxLabel
16715 boxLabelCfg.tooltip = this.tooltip;
16718 cfg.cn.push(boxLabelCfg);
16728 * return the real input element.
16730 inputEl: function ()
16732 return this.el.select('input.roo-' + this.inputType,true).first();
16735 labelEl: function()
16737 return this.el.select('label.control-label',true).first();
16739 /* depricated... */
16743 return this.labelEl();
16746 initEvents : function()
16748 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16750 this.inputEl().on('click', this.onClick, this);
16751 if (this.boxLabel) {
16752 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16757 onClick : function()
16759 this.setChecked(!this.checked);
16762 setChecked : function(state,suppressEvent)
16764 if(this.inputType == 'radio'){
16766 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16767 e.dom.checked = false;
16770 this.inputEl().dom.checked = true;
16772 if(suppressEvent !== true){
16773 this.fireEvent('check', this, true);
16776 this.inputEl().dom.value = this.inputValue;
16781 this.checked = state;
16783 if(suppressEvent !== true){
16784 this.fireEvent('check', this, state);
16787 this.inputEl().dom.checked = state;
16789 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16793 getValue : function()
16795 if(this.inputType == 'radio'){
16796 return this.getGroupValue();
16799 return this.inputEl().getValue();
16803 getGroupValue : function()
16805 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16809 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16812 setValue : function(v,suppressEvent)
16814 if(this.inputType == 'radio'){
16815 this.setGroupValue(v, suppressEvent);
16819 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16822 setGroupValue : function(v, suppressEvent)
16824 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16825 e.dom.checked = false;
16827 if(e.dom.value == v){
16828 e.dom.checked = true;
16832 if(suppressEvent !== true){
16833 this.fireEvent('check', this, true);
16849 *<div class="radio">
16851 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
16852 Option one is this and that—be sure to include why it's great
16859 *<label class="radio-inline">fieldLabel</label>
16860 *<label class="radio-inline">
16861 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
16869 * @class Roo.bootstrap.Radio
16870 * @extends Roo.bootstrap.CheckBox
16871 * Bootstrap Radio class
16874 * Create a new Radio
16875 * @param {Object} config The config object
16878 Roo.bootstrap.Radio = function(config){
16879 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16883 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16885 inputType: 'radio',
16889 getAutoCreate : function()
16891 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16892 align = align || 'left'; // default...
16899 tag : this.inline ? 'span' : 'div',
16904 var inline = this.inline ? ' radio-inline' : '';
16908 // does not need for, as we wrap the input with it..
16910 cls : 'control-label box-label' + inline,
16913 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
16917 //cls : 'control-label' + inline,
16918 html : this.fieldLabel,
16919 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
16928 type : this.inputType,
16929 //value : (!this.checked) ? this.valueOff : this.inputValue,
16930 value : this.inputValue,
16932 placeholder : this.placeholder || '' // ?? needed????
16935 if (this.weight) { // Validity check?
16936 input.cls += " radio-" + this.weight;
16938 if (this.disabled) {
16939 input.disabled=true;
16943 input.checked = this.checked;
16947 input.name = this.name;
16951 input.cls += ' input-' + this.size;
16954 //?? can span's inline have a width??
16957 ['xs','sm','md','lg'].map(function(size){
16958 if (settings[size]) {
16959 cfg.cls += ' col-' + size + '-' + settings[size];
16963 var inputblock = input;
16965 if (this.before || this.after) {
16968 cls : 'input-group',
16973 inputblock.cn.push({
16975 cls : 'input-group-addon',
16979 inputblock.cn.push(input);
16981 inputblock.cn.push({
16983 cls : 'input-group-addon',
16991 if (this.fieldLabel && this.fieldLabel.length) {
16992 cfg.cn.push(fieldLabel);
16995 // normal bootstrap puts the input inside the label.
16996 // however with our styled version - it has to go after the input.
16998 //lbl.cn.push(inputblock);
17002 cls: 'radio' + inline,
17009 cfg.cn.push( lblwrap);
17014 html: this.boxLabel
17023 initEvents : function()
17025 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17027 this.inputEl().on('click', this.onClick, this);
17028 if (this.boxLabel) {
17029 Roo.log('find label')
17030 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17035 inputEl: function ()
17037 return this.el.select('input.roo-radio',true).first();
17039 onClick : function()
17042 this.setChecked(true);
17045 setChecked : function(state,suppressEvent)
17048 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17049 v.dom.checked = false;
17052 Roo.log(this.inputEl().dom);
17053 this.checked = state;
17054 this.inputEl().dom.checked = state;
17056 if(suppressEvent !== true){
17057 this.fireEvent('check', this, state);
17060 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17064 getGroupValue : function()
17067 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17068 if(v.dom.checked == true){
17069 value = v.dom.value;
17077 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17078 * @return {Mixed} value The field value
17080 getValue : function(){
17081 return this.getGroupValue();
17087 //<script type="text/javascript">
17090 * Based Ext JS Library 1.1.1
17091 * Copyright(c) 2006-2007, Ext JS, LLC.
17097 * @class Roo.HtmlEditorCore
17098 * @extends Roo.Component
17099 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17101 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17104 Roo.HtmlEditorCore = function(config){
17107 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17112 * @event initialize
17113 * Fires when the editor is fully initialized (including the iframe)
17114 * @param {Roo.HtmlEditorCore} this
17119 * Fires when the editor is first receives the focus. Any insertion must wait
17120 * until after this event.
17121 * @param {Roo.HtmlEditorCore} this
17125 * @event beforesync
17126 * Fires before the textarea is updated with content from the editor iframe. Return false
17127 * to cancel the sync.
17128 * @param {Roo.HtmlEditorCore} this
17129 * @param {String} html
17133 * @event beforepush
17134 * Fires before the iframe editor is updated with content from the textarea. Return false
17135 * to cancel the push.
17136 * @param {Roo.HtmlEditorCore} this
17137 * @param {String} html
17142 * Fires when the textarea is updated with content from the editor iframe.
17143 * @param {Roo.HtmlEditorCore} this
17144 * @param {String} html
17149 * Fires when the iframe editor is updated with content from the textarea.
17150 * @param {Roo.HtmlEditorCore} this
17151 * @param {String} html
17156 * @event editorevent
17157 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17158 * @param {Roo.HtmlEditorCore} this
17164 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17166 // defaults : white / black...
17167 this.applyBlacklists();
17174 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17178 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17184 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17189 * @cfg {Number} height (in pixels)
17193 * @cfg {Number} width (in pixels)
17198 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17201 stylesheets: false,
17206 // private properties
17207 validationEvent : false,
17209 initialized : false,
17211 sourceEditMode : false,
17212 onFocus : Roo.emptyFn,
17214 hideMode:'offsets',
17218 // blacklist + whitelisted elements..
17225 * Protected method that will not generally be called directly. It
17226 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17227 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17229 getDocMarkup : function(){
17233 // inherit styels from page...??
17234 if (this.stylesheets === false) {
17236 Roo.get(document.head).select('style').each(function(node) {
17237 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17240 Roo.get(document.head).select('link').each(function(node) {
17241 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17244 } else if (!this.stylesheets.length) {
17246 st = '<style type="text/css">' +
17247 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17253 st += '<style type="text/css">' +
17254 'IMG { cursor: pointer } ' +
17258 return '<html><head>' + st +
17259 //<style type="text/css">' +
17260 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17262 ' </head><body class="roo-htmleditor-body"></body></html>';
17266 onRender : function(ct, position)
17269 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17270 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17273 this.el.dom.style.border = '0 none';
17274 this.el.dom.setAttribute('tabIndex', -1);
17275 this.el.addClass('x-hidden hide');
17279 if(Roo.isIE){ // fix IE 1px bogus margin
17280 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17284 this.frameId = Roo.id();
17288 var iframe = this.owner.wrap.createChild({
17290 cls: 'form-control', // bootstrap..
17292 name: this.frameId,
17293 frameBorder : 'no',
17294 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17299 this.iframe = iframe.dom;
17301 this.assignDocWin();
17303 this.doc.designMode = 'on';
17306 this.doc.write(this.getDocMarkup());
17310 var task = { // must defer to wait for browser to be ready
17312 //console.log("run task?" + this.doc.readyState);
17313 this.assignDocWin();
17314 if(this.doc.body || this.doc.readyState == 'complete'){
17316 this.doc.designMode="on";
17320 Roo.TaskMgr.stop(task);
17321 this.initEditor.defer(10, this);
17328 Roo.TaskMgr.start(task);
17333 onResize : function(w, h)
17335 Roo.log('resize: ' +w + ',' + h );
17336 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17340 if(typeof w == 'number'){
17342 this.iframe.style.width = w + 'px';
17344 if(typeof h == 'number'){
17346 this.iframe.style.height = h + 'px';
17348 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17355 * Toggles the editor between standard and source edit mode.
17356 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17358 toggleSourceEdit : function(sourceEditMode){
17360 this.sourceEditMode = sourceEditMode === true;
17362 if(this.sourceEditMode){
17364 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17367 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17368 //this.iframe.className = '';
17371 //this.setSize(this.owner.wrap.getSize());
17372 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17379 * Protected method that will not generally be called directly. If you need/want
17380 * custom HTML cleanup, this is the method you should override.
17381 * @param {String} html The HTML to be cleaned
17382 * return {String} The cleaned HTML
17384 cleanHtml : function(html){
17385 html = String(html);
17386 if(html.length > 5){
17387 if(Roo.isSafari){ // strip safari nonsense
17388 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17391 if(html == ' '){
17398 * HTML Editor -> Textarea
17399 * Protected method that will not generally be called directly. Syncs the contents
17400 * of the editor iframe with the textarea.
17402 syncValue : function(){
17403 if(this.initialized){
17404 var bd = (this.doc.body || this.doc.documentElement);
17405 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17406 var html = bd.innerHTML;
17408 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17409 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17411 html = '<div style="'+m[0]+'">' + html + '</div>';
17414 html = this.cleanHtml(html);
17415 // fix up the special chars.. normaly like back quotes in word...
17416 // however we do not want to do this with chinese..
17417 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17418 var cc = b.charCodeAt();
17420 (cc >= 0x4E00 && cc < 0xA000 ) ||
17421 (cc >= 0x3400 && cc < 0x4E00 ) ||
17422 (cc >= 0xf900 && cc < 0xfb00 )
17428 if(this.owner.fireEvent('beforesync', this, html) !== false){
17429 this.el.dom.value = html;
17430 this.owner.fireEvent('sync', this, html);
17436 * Protected method that will not generally be called directly. Pushes the value of the textarea
17437 * into the iframe editor.
17439 pushValue : function(){
17440 if(this.initialized){
17441 var v = this.el.dom.value.trim();
17443 // if(v.length < 1){
17447 if(this.owner.fireEvent('beforepush', this, v) !== false){
17448 var d = (this.doc.body || this.doc.documentElement);
17450 this.cleanUpPaste();
17451 this.el.dom.value = d.innerHTML;
17452 this.owner.fireEvent('push', this, v);
17458 deferFocus : function(){
17459 this.focus.defer(10, this);
17463 focus : function(){
17464 if(this.win && !this.sourceEditMode){
17471 assignDocWin: function()
17473 var iframe = this.iframe;
17476 this.doc = iframe.contentWindow.document;
17477 this.win = iframe.contentWindow;
17479 // if (!Roo.get(this.frameId)) {
17482 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17483 // this.win = Roo.get(this.frameId).dom.contentWindow;
17485 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17489 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17490 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17495 initEditor : function(){
17496 //console.log("INIT EDITOR");
17497 this.assignDocWin();
17501 this.doc.designMode="on";
17503 this.doc.write(this.getDocMarkup());
17506 var dbody = (this.doc.body || this.doc.documentElement);
17507 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17508 // this copies styles from the containing element into thsi one..
17509 // not sure why we need all of this..
17510 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17512 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17513 //ss['background-attachment'] = 'fixed'; // w3c
17514 dbody.bgProperties = 'fixed'; // ie
17515 //Roo.DomHelper.applyStyles(dbody, ss);
17516 Roo.EventManager.on(this.doc, {
17517 //'mousedown': this.onEditorEvent,
17518 'mouseup': this.onEditorEvent,
17519 'dblclick': this.onEditorEvent,
17520 'click': this.onEditorEvent,
17521 'keyup': this.onEditorEvent,
17526 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17528 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17529 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17531 this.initialized = true;
17533 this.owner.fireEvent('initialize', this);
17538 onDestroy : function(){
17544 //for (var i =0; i < this.toolbars.length;i++) {
17545 // // fixme - ask toolbars for heights?
17546 // this.toolbars[i].onDestroy();
17549 //this.wrap.dom.innerHTML = '';
17550 //this.wrap.remove();
17555 onFirstFocus : function(){
17557 this.assignDocWin();
17560 this.activated = true;
17563 if(Roo.isGecko){ // prevent silly gecko errors
17565 var s = this.win.getSelection();
17566 if(!s.focusNode || s.focusNode.nodeType != 3){
17567 var r = s.getRangeAt(0);
17568 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17573 this.execCmd('useCSS', true);
17574 this.execCmd('styleWithCSS', false);
17577 this.owner.fireEvent('activate', this);
17581 adjustFont: function(btn){
17582 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17583 //if(Roo.isSafari){ // safari
17586 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17587 if(Roo.isSafari){ // safari
17588 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17589 v = (v < 10) ? 10 : v;
17590 v = (v > 48) ? 48 : v;
17591 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17596 v = Math.max(1, v+adjust);
17598 this.execCmd('FontSize', v );
17601 onEditorEvent : function(e){
17602 this.owner.fireEvent('editorevent', this, e);
17603 // this.updateToolbar();
17604 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17607 insertTag : function(tg)
17609 // could be a bit smarter... -> wrap the current selected tRoo..
17610 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17612 range = this.createRange(this.getSelection());
17613 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17614 wrappingNode.appendChild(range.extractContents());
17615 range.insertNode(wrappingNode);
17622 this.execCmd("formatblock", tg);
17626 insertText : function(txt)
17630 var range = this.createRange();
17631 range.deleteContents();
17632 //alert(Sender.getAttribute('label'));
17634 range.insertNode(this.doc.createTextNode(txt));
17640 * Executes a Midas editor command on the editor document and performs necessary focus and
17641 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17642 * @param {String} cmd The Midas command
17643 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17645 relayCmd : function(cmd, value){
17647 this.execCmd(cmd, value);
17648 this.owner.fireEvent('editorevent', this);
17649 //this.updateToolbar();
17650 this.owner.deferFocus();
17654 * Executes a Midas editor command directly on the editor document.
17655 * For visual commands, you should use {@link #relayCmd} instead.
17656 * <b>This should only be called after the editor is initialized.</b>
17657 * @param {String} cmd The Midas command
17658 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17660 execCmd : function(cmd, value){
17661 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17668 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17670 * @param {String} text | dom node..
17672 insertAtCursor : function(text)
17677 if(!this.activated){
17683 var r = this.doc.selection.createRange();
17694 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17698 // from jquery ui (MIT licenced)
17700 var win = this.win;
17702 if (win.getSelection && win.getSelection().getRangeAt) {
17703 range = win.getSelection().getRangeAt(0);
17704 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17705 range.insertNode(node);
17706 } else if (win.document.selection && win.document.selection.createRange) {
17707 // no firefox support
17708 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17709 win.document.selection.createRange().pasteHTML(txt);
17711 // no firefox support
17712 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17713 this.execCmd('InsertHTML', txt);
17722 mozKeyPress : function(e){
17724 var c = e.getCharCode(), cmd;
17727 c = String.fromCharCode(c).toLowerCase();
17741 this.cleanUpPaste.defer(100, this);
17749 e.preventDefault();
17757 fixKeys : function(){ // load time branching for fastest keydown performance
17759 return function(e){
17760 var k = e.getKey(), r;
17763 r = this.doc.selection.createRange();
17766 r.pasteHTML('    ');
17773 r = this.doc.selection.createRange();
17775 var target = r.parentElement();
17776 if(!target || target.tagName.toLowerCase() != 'li'){
17778 r.pasteHTML('<br />');
17784 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17785 this.cleanUpPaste.defer(100, this);
17791 }else if(Roo.isOpera){
17792 return function(e){
17793 var k = e.getKey();
17797 this.execCmd('InsertHTML','    ');
17800 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17801 this.cleanUpPaste.defer(100, this);
17806 }else if(Roo.isSafari){
17807 return function(e){
17808 var k = e.getKey();
17812 this.execCmd('InsertText','\t');
17816 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17817 this.cleanUpPaste.defer(100, this);
17825 getAllAncestors: function()
17827 var p = this.getSelectedNode();
17830 a.push(p); // push blank onto stack..
17831 p = this.getParentElement();
17835 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17839 a.push(this.doc.body);
17843 lastSelNode : false,
17846 getSelection : function()
17848 this.assignDocWin();
17849 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17852 getSelectedNode: function()
17854 // this may only work on Gecko!!!
17856 // should we cache this!!!!
17861 var range = this.createRange(this.getSelection()).cloneRange();
17864 var parent = range.parentElement();
17866 var testRange = range.duplicate();
17867 testRange.moveToElementText(parent);
17868 if (testRange.inRange(range)) {
17871 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17874 parent = parent.parentElement;
17879 // is ancestor a text element.
17880 var ac = range.commonAncestorContainer;
17881 if (ac.nodeType == 3) {
17882 ac = ac.parentNode;
17885 var ar = ac.childNodes;
17888 var other_nodes = [];
17889 var has_other_nodes = false;
17890 for (var i=0;i<ar.length;i++) {
17891 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17894 // fullly contained node.
17896 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17901 // probably selected..
17902 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17903 other_nodes.push(ar[i]);
17907 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17912 has_other_nodes = true;
17914 if (!nodes.length && other_nodes.length) {
17915 nodes= other_nodes;
17917 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17923 createRange: function(sel)
17925 // this has strange effects when using with
17926 // top toolbar - not sure if it's a great idea.
17927 //this.editor.contentWindow.focus();
17928 if (typeof sel != "undefined") {
17930 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17932 return this.doc.createRange();
17935 return this.doc.createRange();
17938 getParentElement: function()
17941 this.assignDocWin();
17942 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17944 var range = this.createRange(sel);
17947 var p = range.commonAncestorContainer;
17948 while (p.nodeType == 3) { // text node
17959 * Range intersection.. the hard stuff...
17963 * [ -- selected range --- ]
17967 * if end is before start or hits it. fail.
17968 * if start is after end or hits it fail.
17970 * if either hits (but other is outside. - then it's not
17976 // @see http://www.thismuchiknow.co.uk/?p=64.
17977 rangeIntersectsNode : function(range, node)
17979 var nodeRange = node.ownerDocument.createRange();
17981 nodeRange.selectNode(node);
17983 nodeRange.selectNodeContents(node);
17986 var rangeStartRange = range.cloneRange();
17987 rangeStartRange.collapse(true);
17989 var rangeEndRange = range.cloneRange();
17990 rangeEndRange.collapse(false);
17992 var nodeStartRange = nodeRange.cloneRange();
17993 nodeStartRange.collapse(true);
17995 var nodeEndRange = nodeRange.cloneRange();
17996 nodeEndRange.collapse(false);
17998 return rangeStartRange.compareBoundaryPoints(
17999 Range.START_TO_START, nodeEndRange) == -1 &&
18000 rangeEndRange.compareBoundaryPoints(
18001 Range.START_TO_START, nodeStartRange) == 1;
18005 rangeCompareNode : function(range, node)
18007 var nodeRange = node.ownerDocument.createRange();
18009 nodeRange.selectNode(node);
18011 nodeRange.selectNodeContents(node);
18015 range.collapse(true);
18017 nodeRange.collapse(true);
18019 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18020 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18022 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18024 var nodeIsBefore = ss == 1;
18025 var nodeIsAfter = ee == -1;
18027 if (nodeIsBefore && nodeIsAfter)
18029 if (!nodeIsBefore && nodeIsAfter)
18030 return 1; //right trailed.
18032 if (nodeIsBefore && !nodeIsAfter)
18033 return 2; // left trailed.
18038 // private? - in a new class?
18039 cleanUpPaste : function()
18041 // cleans up the whole document..
18042 Roo.log('cleanuppaste');
18044 this.cleanUpChildren(this.doc.body);
18045 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18046 if (clean != this.doc.body.innerHTML) {
18047 this.doc.body.innerHTML = clean;
18052 cleanWordChars : function(input) {// change the chars to hex code
18053 var he = Roo.HtmlEditorCore;
18055 var output = input;
18056 Roo.each(he.swapCodes, function(sw) {
18057 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18059 output = output.replace(swapper, sw[1]);
18066 cleanUpChildren : function (n)
18068 if (!n.childNodes.length) {
18071 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18072 this.cleanUpChild(n.childNodes[i]);
18079 cleanUpChild : function (node)
18082 //console.log(node);
18083 if (node.nodeName == "#text") {
18084 // clean up silly Windows -- stuff?
18087 if (node.nodeName == "#comment") {
18088 node.parentNode.removeChild(node);
18089 // clean up silly Windows -- stuff?
18092 var lcname = node.tagName.toLowerCase();
18093 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18094 // whitelist of tags..
18096 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18098 node.parentNode.removeChild(node);
18103 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18105 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18106 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18108 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18109 // remove_keep_children = true;
18112 if (remove_keep_children) {
18113 this.cleanUpChildren(node);
18114 // inserts everything just before this node...
18115 while (node.childNodes.length) {
18116 var cn = node.childNodes[0];
18117 node.removeChild(cn);
18118 node.parentNode.insertBefore(cn, node);
18120 node.parentNode.removeChild(node);
18124 if (!node.attributes || !node.attributes.length) {
18125 this.cleanUpChildren(node);
18129 function cleanAttr(n,v)
18132 if (v.match(/^\./) || v.match(/^\//)) {
18135 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18138 if (v.match(/^#/)) {
18141 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18142 node.removeAttribute(n);
18146 var cwhite = this.cwhite;
18147 var cblack = this.cblack;
18149 function cleanStyle(n,v)
18151 if (v.match(/expression/)) { //XSS?? should we even bother..
18152 node.removeAttribute(n);
18156 var parts = v.split(/;/);
18159 Roo.each(parts, function(p) {
18160 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18164 var l = p.split(':').shift().replace(/\s+/g,'');
18165 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18167 if ( cwhite.length && cblack.indexOf(l) > -1) {
18168 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18169 //node.removeAttribute(n);
18173 // only allow 'c whitelisted system attributes'
18174 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18175 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18176 //node.removeAttribute(n);
18186 if (clean.length) {
18187 node.setAttribute(n, clean.join(';'));
18189 node.removeAttribute(n);
18195 for (var i = node.attributes.length-1; i > -1 ; i--) {
18196 var a = node.attributes[i];
18199 if (a.name.toLowerCase().substr(0,2)=='on') {
18200 node.removeAttribute(a.name);
18203 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18204 node.removeAttribute(a.name);
18207 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18208 cleanAttr(a.name,a.value); // fixme..
18211 if (a.name == 'style') {
18212 cleanStyle(a.name,a.value);
18215 /// clean up MS crap..
18216 // tecnically this should be a list of valid class'es..
18219 if (a.name == 'class') {
18220 if (a.value.match(/^Mso/)) {
18221 node.className = '';
18224 if (a.value.match(/body/)) {
18225 node.className = '';
18236 this.cleanUpChildren(node);
18241 * Clean up MS wordisms...
18243 cleanWord : function(node)
18246 var cleanWordChildren = function()
18248 if (!node.childNodes.length) {
18251 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18252 _t.cleanWord(node.childNodes[i]);
18258 this.cleanWord(this.doc.body);
18261 if (node.nodeName == "#text") {
18262 // clean up silly Windows -- stuff?
18265 if (node.nodeName == "#comment") {
18266 node.parentNode.removeChild(node);
18267 // clean up silly Windows -- stuff?
18271 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18272 node.parentNode.removeChild(node);
18276 // remove - but keep children..
18277 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18278 while (node.childNodes.length) {
18279 var cn = node.childNodes[0];
18280 node.removeChild(cn);
18281 node.parentNode.insertBefore(cn, node);
18283 node.parentNode.removeChild(node);
18284 cleanWordChildren();
18288 if (node.className.length) {
18290 var cn = node.className.split(/\W+/);
18292 Roo.each(cn, function(cls) {
18293 if (cls.match(/Mso[a-zA-Z]+/)) {
18298 node.className = cna.length ? cna.join(' ') : '';
18300 node.removeAttribute("class");
18304 if (node.hasAttribute("lang")) {
18305 node.removeAttribute("lang");
18308 if (node.hasAttribute("style")) {
18310 var styles = node.getAttribute("style").split(";");
18312 Roo.each(styles, function(s) {
18313 if (!s.match(/:/)) {
18316 var kv = s.split(":");
18317 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18320 // what ever is left... we allow.
18323 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18324 if (!nstyle.length) {
18325 node.removeAttribute('style');
18329 cleanWordChildren();
18333 domToHTML : function(currentElement, depth, nopadtext) {
18335 depth = depth || 0;
18336 nopadtext = nopadtext || false;
18338 if (!currentElement) {
18339 return this.domToHTML(this.doc.body);
18342 //Roo.log(currentElement);
18344 var allText = false;
18345 var nodeName = currentElement.nodeName;
18346 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18348 if (nodeName == '#text') {
18350 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18355 if (nodeName != 'BODY') {
18358 // Prints the node tagName, such as <A>, <IMG>, etc
18361 for(i = 0; i < currentElement.attributes.length;i++) {
18363 var aname = currentElement.attributes.item(i).name;
18364 if (!currentElement.attributes.item(i).value.length) {
18367 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18370 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18379 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18382 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18387 // Traverse the tree
18389 var currentElementChild = currentElement.childNodes.item(i);
18390 var allText = true;
18391 var innerHTML = '';
18393 while (currentElementChild) {
18394 // Formatting code (indent the tree so it looks nice on the screen)
18395 var nopad = nopadtext;
18396 if (lastnode == 'SPAN') {
18400 if (currentElementChild.nodeName == '#text') {
18401 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18402 toadd = nopadtext ? toadd : toadd.trim();
18403 if (!nopad && toadd.length > 80) {
18404 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18406 innerHTML += toadd;
18409 currentElementChild = currentElement.childNodes.item(i);
18415 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18417 // Recursively traverse the tree structure of the child node
18418 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18419 lastnode = currentElementChild.nodeName;
18421 currentElementChild=currentElement.childNodes.item(i);
18427 // The remaining code is mostly for formatting the tree
18428 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18433 ret+= "</"+tagName+">";
18439 applyBlacklists : function()
18441 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18442 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18446 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18447 if (b.indexOf(tag) > -1) {
18450 this.white.push(tag);
18454 Roo.each(w, function(tag) {
18455 if (b.indexOf(tag) > -1) {
18458 if (this.white.indexOf(tag) > -1) {
18461 this.white.push(tag);
18466 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18467 if (w.indexOf(tag) > -1) {
18470 this.black.push(tag);
18474 Roo.each(b, function(tag) {
18475 if (w.indexOf(tag) > -1) {
18478 if (this.black.indexOf(tag) > -1) {
18481 this.black.push(tag);
18486 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18487 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18491 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18492 if (b.indexOf(tag) > -1) {
18495 this.cwhite.push(tag);
18499 Roo.each(w, function(tag) {
18500 if (b.indexOf(tag) > -1) {
18503 if (this.cwhite.indexOf(tag) > -1) {
18506 this.cwhite.push(tag);
18511 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18512 if (w.indexOf(tag) > -1) {
18515 this.cblack.push(tag);
18519 Roo.each(b, function(tag) {
18520 if (w.indexOf(tag) > -1) {
18523 if (this.cblack.indexOf(tag) > -1) {
18526 this.cblack.push(tag);
18531 setStylesheets : function(stylesheets)
18533 if(typeof(stylesheets) == 'string'){
18534 Roo.get(this.iframe.contentDocument.head).createChild({
18536 rel : 'stylesheet',
18545 Roo.each(stylesheets, function(s) {
18550 Roo.get(_this.iframe.contentDocument.head).createChild({
18552 rel : 'stylesheet',
18561 removeStylesheets : function()
18565 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18570 // hide stuff that is not compatible
18584 * @event specialkey
18588 * @cfg {String} fieldClass @hide
18591 * @cfg {String} focusClass @hide
18594 * @cfg {String} autoCreate @hide
18597 * @cfg {String} inputType @hide
18600 * @cfg {String} invalidClass @hide
18603 * @cfg {String} invalidText @hide
18606 * @cfg {String} msgFx @hide
18609 * @cfg {String} validateOnBlur @hide
18613 Roo.HtmlEditorCore.white = [
18614 'area', 'br', 'img', 'input', 'hr', 'wbr',
18616 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18617 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18618 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18619 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18620 'table', 'ul', 'xmp',
18622 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18625 'dir', 'menu', 'ol', 'ul', 'dl',
18631 Roo.HtmlEditorCore.black = [
18632 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18634 'base', 'basefont', 'bgsound', 'blink', 'body',
18635 'frame', 'frameset', 'head', 'html', 'ilayer',
18636 'iframe', 'layer', 'link', 'meta', 'object',
18637 'script', 'style' ,'title', 'xml' // clean later..
18639 Roo.HtmlEditorCore.clean = [
18640 'script', 'style', 'title', 'xml'
18642 Roo.HtmlEditorCore.remove = [
18647 Roo.HtmlEditorCore.ablack = [
18651 Roo.HtmlEditorCore.aclean = [
18652 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18656 Roo.HtmlEditorCore.pwhite= [
18657 'http', 'https', 'mailto'
18660 // white listed style attributes.
18661 Roo.HtmlEditorCore.cwhite= [
18662 // 'text-align', /// default is to allow most things..
18668 // black listed style attributes.
18669 Roo.HtmlEditorCore.cblack= [
18670 // 'font-size' -- this can be set by the project
18674 Roo.HtmlEditorCore.swapCodes =[
18693 * @class Roo.bootstrap.HtmlEditor
18694 * @extends Roo.bootstrap.TextArea
18695 * Bootstrap HtmlEditor class
18698 * Create a new HtmlEditor
18699 * @param {Object} config The config object
18702 Roo.bootstrap.HtmlEditor = function(config){
18703 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18704 if (!this.toolbars) {
18705 this.toolbars = [];
18707 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18710 * @event initialize
18711 * Fires when the editor is fully initialized (including the iframe)
18712 * @param {HtmlEditor} this
18717 * Fires when the editor is first receives the focus. Any insertion must wait
18718 * until after this event.
18719 * @param {HtmlEditor} this
18723 * @event beforesync
18724 * Fires before the textarea is updated with content from the editor iframe. Return false
18725 * to cancel the sync.
18726 * @param {HtmlEditor} this
18727 * @param {String} html
18731 * @event beforepush
18732 * Fires before the iframe editor is updated with content from the textarea. Return false
18733 * to cancel the push.
18734 * @param {HtmlEditor} this
18735 * @param {String} html
18740 * Fires when the textarea is updated with content from the editor iframe.
18741 * @param {HtmlEditor} this
18742 * @param {String} html
18747 * Fires when the iframe editor is updated with content from the textarea.
18748 * @param {HtmlEditor} this
18749 * @param {String} html
18753 * @event editmodechange
18754 * Fires when the editor switches edit modes
18755 * @param {HtmlEditor} this
18756 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18758 editmodechange: true,
18760 * @event editorevent
18761 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18762 * @param {HtmlEditor} this
18766 * @event firstfocus
18767 * Fires when on first focus - needed by toolbars..
18768 * @param {HtmlEditor} this
18773 * Auto save the htmlEditor value as a file into Events
18774 * @param {HtmlEditor} this
18778 * @event savedpreview
18779 * preview the saved version of htmlEditor
18780 * @param {HtmlEditor} this
18787 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18791 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18796 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18801 * @cfg {Number} height (in pixels)
18805 * @cfg {Number} width (in pixels)
18810 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18813 stylesheets: false,
18818 // private properties
18819 validationEvent : false,
18821 initialized : false,
18824 onFocus : Roo.emptyFn,
18826 hideMode:'offsets',
18829 tbContainer : false,
18831 toolbarContainer :function() {
18832 return this.wrap.select('.x-html-editor-tb',true).first();
18836 * Protected method that will not generally be called directly. It
18837 * is called when the editor creates its toolbar. Override this method if you need to
18838 * add custom toolbar buttons.
18839 * @param {HtmlEditor} editor
18841 createToolbar : function(){
18843 Roo.log("create toolbars");
18845 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18846 this.toolbars[0].render(this.toolbarContainer());
18850 // if (!editor.toolbars || !editor.toolbars.length) {
18851 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18854 // for (var i =0 ; i < editor.toolbars.length;i++) {
18855 // editor.toolbars[i] = Roo.factory(
18856 // typeof(editor.toolbars[i]) == 'string' ?
18857 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18858 // Roo.bootstrap.HtmlEditor);
18859 // editor.toolbars[i].init(editor);
18865 onRender : function(ct, position)
18867 // Roo.log("Call onRender: " + this.xtype);
18869 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18871 this.wrap = this.inputEl().wrap({
18872 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18875 this.editorcore.onRender(ct, position);
18877 if (this.resizable) {
18878 this.resizeEl = new Roo.Resizable(this.wrap, {
18882 minHeight : this.height,
18883 height: this.height,
18884 handles : this.resizable,
18887 resize : function(r, w, h) {
18888 _t.onResize(w,h); // -something
18894 this.createToolbar(this);
18897 if(!this.width && this.resizable){
18898 this.setSize(this.wrap.getSize());
18900 if (this.resizeEl) {
18901 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18902 // should trigger onReize..
18908 onResize : function(w, h)
18910 Roo.log('resize: ' +w + ',' + h );
18911 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18915 if(this.inputEl() ){
18916 if(typeof w == 'number'){
18917 var aw = w - this.wrap.getFrameWidth('lr');
18918 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18921 if(typeof h == 'number'){
18922 var tbh = -11; // fixme it needs to tool bar size!
18923 for (var i =0; i < this.toolbars.length;i++) {
18924 // fixme - ask toolbars for heights?
18925 tbh += this.toolbars[i].el.getHeight();
18926 //if (this.toolbars[i].footer) {
18927 // tbh += this.toolbars[i].footer.el.getHeight();
18935 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18936 ah -= 5; // knock a few pixes off for look..
18937 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18941 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18942 this.editorcore.onResize(ew,eh);
18947 * Toggles the editor between standard and source edit mode.
18948 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18950 toggleSourceEdit : function(sourceEditMode)
18952 this.editorcore.toggleSourceEdit(sourceEditMode);
18954 if(this.editorcore.sourceEditMode){
18955 Roo.log('editor - showing textarea');
18958 // Roo.log(this.syncValue());
18960 this.inputEl().removeClass(['hide', 'x-hidden']);
18961 this.inputEl().dom.removeAttribute('tabIndex');
18962 this.inputEl().focus();
18964 Roo.log('editor - hiding textarea');
18966 // Roo.log(this.pushValue());
18969 this.inputEl().addClass(['hide', 'x-hidden']);
18970 this.inputEl().dom.setAttribute('tabIndex', -1);
18971 //this.deferFocus();
18974 if(this.resizable){
18975 this.setSize(this.wrap.getSize());
18978 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18981 // private (for BoxComponent)
18982 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18984 // private (for BoxComponent)
18985 getResizeEl : function(){
18989 // private (for BoxComponent)
18990 getPositionEl : function(){
18995 initEvents : function(){
18996 this.originalValue = this.getValue();
19000 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19003 // markInvalid : Roo.emptyFn,
19005 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19008 // clearInvalid : Roo.emptyFn,
19010 setValue : function(v){
19011 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19012 this.editorcore.pushValue();
19017 deferFocus : function(){
19018 this.focus.defer(10, this);
19022 focus : function(){
19023 this.editorcore.focus();
19029 onDestroy : function(){
19035 for (var i =0; i < this.toolbars.length;i++) {
19036 // fixme - ask toolbars for heights?
19037 this.toolbars[i].onDestroy();
19040 this.wrap.dom.innerHTML = '';
19041 this.wrap.remove();
19046 onFirstFocus : function(){
19047 //Roo.log("onFirstFocus");
19048 this.editorcore.onFirstFocus();
19049 for (var i =0; i < this.toolbars.length;i++) {
19050 this.toolbars[i].onFirstFocus();
19056 syncValue : function()
19058 this.editorcore.syncValue();
19061 pushValue : function()
19063 this.editorcore.pushValue();
19067 // hide stuff that is not compatible
19081 * @event specialkey
19085 * @cfg {String} fieldClass @hide
19088 * @cfg {String} focusClass @hide
19091 * @cfg {String} autoCreate @hide
19094 * @cfg {String} inputType @hide
19097 * @cfg {String} invalidClass @hide
19100 * @cfg {String} invalidText @hide
19103 * @cfg {String} msgFx @hide
19106 * @cfg {String} validateOnBlur @hide
19115 Roo.namespace('Roo.bootstrap.htmleditor');
19117 * @class Roo.bootstrap.HtmlEditorToolbar1
19122 new Roo.bootstrap.HtmlEditor({
19125 new Roo.bootstrap.HtmlEditorToolbar1({
19126 disable : { fonts: 1 , format: 1, ..., ... , ...],
19132 * @cfg {Object} disable List of elements to disable..
19133 * @cfg {Array} btns List of additional buttons.
19137 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19140 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19143 Roo.apply(this, config);
19145 // default disabled, based on 'good practice'..
19146 this.disable = this.disable || {};
19147 Roo.applyIf(this.disable, {
19150 specialElements : true
19152 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19154 this.editor = config.editor;
19155 this.editorcore = config.editor.editorcore;
19157 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19159 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19160 // dont call parent... till later.
19162 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19167 editorcore : false,
19172 "h1","h2","h3","h4","h5","h6",
19174 "abbr", "acronym", "address", "cite", "samp", "var",
19178 onRender : function(ct, position)
19180 // Roo.log("Call onRender: " + this.xtype);
19182 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19184 this.el.dom.style.marginBottom = '0';
19186 var editorcore = this.editorcore;
19187 var editor= this.editor;
19190 var btn = function(id,cmd , toggle, handler){
19192 var event = toggle ? 'toggle' : 'click';
19197 xns: Roo.bootstrap,
19200 enableToggle:toggle !== false,
19202 pressed : toggle ? false : null,
19205 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19206 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19215 xns: Roo.bootstrap,
19216 glyphicon : 'font',
19220 xns: Roo.bootstrap,
19224 Roo.each(this.formats, function(f) {
19225 style.menu.items.push({
19227 xns: Roo.bootstrap,
19228 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19233 editorcore.insertTag(this.tagname);
19240 children.push(style);
19243 btn('bold',false,true);
19244 btn('italic',false,true);
19245 btn('align-left', 'justifyleft',true);
19246 btn('align-center', 'justifycenter',true);
19247 btn('align-right' , 'justifyright',true);
19248 btn('link', false, false, function(btn) {
19249 //Roo.log("create link?");
19250 var url = prompt(this.createLinkText, this.defaultLinkValue);
19251 if(url && url != 'http:/'+'/'){
19252 this.editorcore.relayCmd('createlink', url);
19255 btn('list','insertunorderedlist',true);
19256 btn('pencil', false,true, function(btn){
19259 this.toggleSourceEdit(btn.pressed);
19265 xns: Roo.bootstrap,
19270 xns: Roo.bootstrap,
19275 cog.menu.items.push({
19277 xns: Roo.bootstrap,
19278 html : Clean styles,
19283 editorcore.insertTag(this.tagname);
19292 this.xtype = 'NavSimplebar';
19294 for(var i=0;i< children.length;i++) {
19296 this.buttons.add(this.addxtypeChild(children[i]));
19300 editor.on('editorevent', this.updateToolbar, this);
19302 onBtnClick : function(id)
19304 this.editorcore.relayCmd(id);
19305 this.editorcore.focus();
19309 * Protected method that will not generally be called directly. It triggers
19310 * a toolbar update by reading the markup state of the current selection in the editor.
19312 updateToolbar: function(){
19314 if(!this.editorcore.activated){
19315 this.editor.onFirstFocus(); // is this neeed?
19319 var btns = this.buttons;
19320 var doc = this.editorcore.doc;
19321 btns.get('bold').setActive(doc.queryCommandState('bold'));
19322 btns.get('italic').setActive(doc.queryCommandState('italic'));
19323 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19325 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19326 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19327 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19329 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19330 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19333 var ans = this.editorcore.getAllAncestors();
19334 if (this.formatCombo) {
19337 var store = this.formatCombo.store;
19338 this.formatCombo.setValue("");
19339 for (var i =0; i < ans.length;i++) {
19340 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19342 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19350 // hides menus... - so this cant be on a menu...
19351 Roo.bootstrap.MenuMgr.hideAll();
19353 Roo.bootstrap.MenuMgr.hideAll();
19354 //this.editorsyncValue();
19356 onFirstFocus: function() {
19357 this.buttons.each(function(item){
19361 toggleSourceEdit : function(sourceEditMode){
19364 if(sourceEditMode){
19365 Roo.log("disabling buttons");
19366 this.buttons.each( function(item){
19367 if(item.cmd != 'pencil'){
19373 Roo.log("enabling buttons");
19374 if(this.editorcore.initialized){
19375 this.buttons.each( function(item){
19381 Roo.log("calling toggole on editor");
19382 // tell the editor that it's been pressed..
19383 this.editor.toggleSourceEdit(sourceEditMode);
19393 * @class Roo.bootstrap.Table.AbstractSelectionModel
19394 * @extends Roo.util.Observable
19395 * Abstract base class for grid SelectionModels. It provides the interface that should be
19396 * implemented by descendant classes. This class should not be directly instantiated.
19399 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19400 this.locked = false;
19401 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19405 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19406 /** @ignore Called by the grid automatically. Do not call directly. */
19407 init : function(grid){
19413 * Locks the selections.
19416 this.locked = true;
19420 * Unlocks the selections.
19422 unlock : function(){
19423 this.locked = false;
19427 * Returns true if the selections are locked.
19428 * @return {Boolean}
19430 isLocked : function(){
19431 return this.locked;
19435 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19436 * @class Roo.bootstrap.Table.RowSelectionModel
19437 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19438 * It supports multiple selections and keyboard selection/navigation.
19440 * @param {Object} config
19443 Roo.bootstrap.Table.RowSelectionModel = function(config){
19444 Roo.apply(this, config);
19445 this.selections = new Roo.util.MixedCollection(false, function(o){
19450 this.lastActive = false;
19454 * @event selectionchange
19455 * Fires when the selection changes
19456 * @param {SelectionModel} this
19458 "selectionchange" : true,
19460 * @event afterselectionchange
19461 * Fires after the selection changes (eg. by key press or clicking)
19462 * @param {SelectionModel} this
19464 "afterselectionchange" : true,
19466 * @event beforerowselect
19467 * Fires when a row is selected being selected, return false to cancel.
19468 * @param {SelectionModel} this
19469 * @param {Number} rowIndex The selected index
19470 * @param {Boolean} keepExisting False if other selections will be cleared
19472 "beforerowselect" : true,
19475 * Fires when a row is selected.
19476 * @param {SelectionModel} this
19477 * @param {Number} rowIndex The selected index
19478 * @param {Roo.data.Record} r The record
19480 "rowselect" : true,
19482 * @event rowdeselect
19483 * Fires when a row is deselected.
19484 * @param {SelectionModel} this
19485 * @param {Number} rowIndex The selected index
19487 "rowdeselect" : true
19489 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19490 this.locked = false;
19493 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19495 * @cfg {Boolean} singleSelect
19496 * True to allow selection of only one row at a time (defaults to false)
19498 singleSelect : false,
19501 initEvents : function(){
19503 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19504 this.grid.on("mousedown", this.handleMouseDown, this);
19505 }else{ // allow click to work like normal
19506 this.grid.on("rowclick", this.handleDragableRowClick, this);
19509 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19510 "up" : function(e){
19512 this.selectPrevious(e.shiftKey);
19513 }else if(this.last !== false && this.lastActive !== false){
19514 var last = this.last;
19515 this.selectRange(this.last, this.lastActive-1);
19516 this.grid.getView().focusRow(this.lastActive);
19517 if(last !== false){
19521 this.selectFirstRow();
19523 this.fireEvent("afterselectionchange", this);
19525 "down" : function(e){
19527 this.selectNext(e.shiftKey);
19528 }else if(this.last !== false && this.lastActive !== false){
19529 var last = this.last;
19530 this.selectRange(this.last, this.lastActive+1);
19531 this.grid.getView().focusRow(this.lastActive);
19532 if(last !== false){
19536 this.selectFirstRow();
19538 this.fireEvent("afterselectionchange", this);
19543 var view = this.grid.view;
19544 view.on("refresh", this.onRefresh, this);
19545 view.on("rowupdated", this.onRowUpdated, this);
19546 view.on("rowremoved", this.onRemove, this);
19550 onRefresh : function(){
19551 var ds = this.grid.dataSource, i, v = this.grid.view;
19552 var s = this.selections;
19553 s.each(function(r){
19554 if((i = ds.indexOfId(r.id)) != -1){
19563 onRemove : function(v, index, r){
19564 this.selections.remove(r);
19568 onRowUpdated : function(v, index, r){
19569 if(this.isSelected(r)){
19570 v.onRowSelect(index);
19576 * @param {Array} records The records to select
19577 * @param {Boolean} keepExisting (optional) True to keep existing selections
19579 selectRecords : function(records, keepExisting){
19581 this.clearSelections();
19583 var ds = this.grid.dataSource;
19584 for(var i = 0, len = records.length; i < len; i++){
19585 this.selectRow(ds.indexOf(records[i]), true);
19590 * Gets the number of selected rows.
19593 getCount : function(){
19594 return this.selections.length;
19598 * Selects the first row in the grid.
19600 selectFirstRow : function(){
19605 * Select the last row.
19606 * @param {Boolean} keepExisting (optional) True to keep existing selections
19608 selectLastRow : function(keepExisting){
19609 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19613 * Selects the row immediately following the last selected row.
19614 * @param {Boolean} keepExisting (optional) True to keep existing selections
19616 selectNext : function(keepExisting){
19617 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19618 this.selectRow(this.last+1, keepExisting);
19619 this.grid.getView().focusRow(this.last);
19624 * Selects the row that precedes the last selected row.
19625 * @param {Boolean} keepExisting (optional) True to keep existing selections
19627 selectPrevious : function(keepExisting){
19629 this.selectRow(this.last-1, keepExisting);
19630 this.grid.getView().focusRow(this.last);
19635 * Returns the selected records
19636 * @return {Array} Array of selected records
19638 getSelections : function(){
19639 return [].concat(this.selections.items);
19643 * Returns the first selected record.
19646 getSelected : function(){
19647 return this.selections.itemAt(0);
19652 * Clears all selections.
19654 clearSelections : function(fast){
19655 if(this.locked) return;
19657 var ds = this.grid.dataSource;
19658 var s = this.selections;
19659 s.each(function(r){
19660 this.deselectRow(ds.indexOfId(r.id));
19664 this.selections.clear();
19671 * Selects all rows.
19673 selectAll : function(){
19674 if(this.locked) return;
19675 this.selections.clear();
19676 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19677 this.selectRow(i, true);
19682 * Returns True if there is a selection.
19683 * @return {Boolean}
19685 hasSelection : function(){
19686 return this.selections.length > 0;
19690 * Returns True if the specified row is selected.
19691 * @param {Number/Record} record The record or index of the record to check
19692 * @return {Boolean}
19694 isSelected : function(index){
19695 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19696 return (r && this.selections.key(r.id) ? true : false);
19700 * Returns True if the specified record id is selected.
19701 * @param {String} id The id of record to check
19702 * @return {Boolean}
19704 isIdSelected : function(id){
19705 return (this.selections.key(id) ? true : false);
19709 handleMouseDown : function(e, t){
19710 var view = this.grid.getView(), rowIndex;
19711 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19714 if(e.shiftKey && this.last !== false){
19715 var last = this.last;
19716 this.selectRange(last, rowIndex, e.ctrlKey);
19717 this.last = last; // reset the last
19718 view.focusRow(rowIndex);
19720 var isSelected = this.isSelected(rowIndex);
19721 if(e.button !== 0 && isSelected){
19722 view.focusRow(rowIndex);
19723 }else if(e.ctrlKey && isSelected){
19724 this.deselectRow(rowIndex);
19725 }else if(!isSelected){
19726 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19727 view.focusRow(rowIndex);
19730 this.fireEvent("afterselectionchange", this);
19733 handleDragableRowClick : function(grid, rowIndex, e)
19735 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19736 this.selectRow(rowIndex, false);
19737 grid.view.focusRow(rowIndex);
19738 this.fireEvent("afterselectionchange", this);
19743 * Selects multiple rows.
19744 * @param {Array} rows Array of the indexes of the row to select
19745 * @param {Boolean} keepExisting (optional) True to keep existing selections
19747 selectRows : function(rows, keepExisting){
19749 this.clearSelections();
19751 for(var i = 0, len = rows.length; i < len; i++){
19752 this.selectRow(rows[i], true);
19757 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19758 * @param {Number} startRow The index of the first row in the range
19759 * @param {Number} endRow The index of the last row in the range
19760 * @param {Boolean} keepExisting (optional) True to retain existing selections
19762 selectRange : function(startRow, endRow, keepExisting){
19763 if(this.locked) return;
19765 this.clearSelections();
19767 if(startRow <= endRow){
19768 for(var i = startRow; i <= endRow; i++){
19769 this.selectRow(i, true);
19772 for(var i = startRow; i >= endRow; i--){
19773 this.selectRow(i, true);
19779 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19780 * @param {Number} startRow The index of the first row in the range
19781 * @param {Number} endRow The index of the last row in the range
19783 deselectRange : function(startRow, endRow, preventViewNotify){
19784 if(this.locked) return;
19785 for(var i = startRow; i <= endRow; i++){
19786 this.deselectRow(i, preventViewNotify);
19792 * @param {Number} row The index of the row to select
19793 * @param {Boolean} keepExisting (optional) True to keep existing selections
19795 selectRow : function(index, keepExisting, preventViewNotify){
19796 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19797 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19798 if(!keepExisting || this.singleSelect){
19799 this.clearSelections();
19801 var r = this.grid.dataSource.getAt(index);
19802 this.selections.add(r);
19803 this.last = this.lastActive = index;
19804 if(!preventViewNotify){
19805 this.grid.getView().onRowSelect(index);
19807 this.fireEvent("rowselect", this, index, r);
19808 this.fireEvent("selectionchange", this);
19814 * @param {Number} row The index of the row to deselect
19816 deselectRow : function(index, preventViewNotify){
19817 if(this.locked) return;
19818 if(this.last == index){
19821 if(this.lastActive == index){
19822 this.lastActive = false;
19824 var r = this.grid.dataSource.getAt(index);
19825 this.selections.remove(r);
19826 if(!preventViewNotify){
19827 this.grid.getView().onRowDeselect(index);
19829 this.fireEvent("rowdeselect", this, index);
19830 this.fireEvent("selectionchange", this);
19834 restoreLast : function(){
19836 this.last = this._last;
19841 acceptsNav : function(row, col, cm){
19842 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19846 onEditorKey : function(field, e){
19847 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19852 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19854 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19856 }else if(k == e.ENTER && !e.ctrlKey){
19860 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19862 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19864 }else if(k == e.ESC){
19868 g.startEditing(newCell[0], newCell[1]);
19873 * Ext JS Library 1.1.1
19874 * Copyright(c) 2006-2007, Ext JS, LLC.
19876 * Originally Released Under LGPL - original licence link has changed is not relivant.
19879 * <script type="text/javascript">
19883 * @class Roo.bootstrap.PagingToolbar
19885 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19887 * Create a new PagingToolbar
19888 * @param {Object} config The config object
19890 Roo.bootstrap.PagingToolbar = function(config)
19892 // old args format still supported... - xtype is prefered..
19893 // created from xtype...
19894 var ds = config.dataSource;
19895 this.toolbarItems = [];
19896 if (config.items) {
19897 this.toolbarItems = config.items;
19898 // config.items = [];
19901 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19908 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19912 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19914 * @cfg {Roo.data.Store} dataSource
19915 * The underlying data store providing the paged data
19918 * @cfg {String/HTMLElement/Element} container
19919 * container The id or element that will contain the toolbar
19922 * @cfg {Boolean} displayInfo
19923 * True to display the displayMsg (defaults to false)
19926 * @cfg {Number} pageSize
19927 * The number of records to display per page (defaults to 20)
19931 * @cfg {String} displayMsg
19932 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19934 displayMsg : 'Displaying {0} - {1} of {2}',
19936 * @cfg {String} emptyMsg
19937 * The message to display when no records are found (defaults to "No data to display")
19939 emptyMsg : 'No data to display',
19941 * Customizable piece of the default paging text (defaults to "Page")
19944 beforePageText : "Page",
19946 * Customizable piece of the default paging text (defaults to "of %0")
19949 afterPageText : "of {0}",
19951 * Customizable piece of the default paging text (defaults to "First Page")
19954 firstText : "First Page",
19956 * Customizable piece of the default paging text (defaults to "Previous Page")
19959 prevText : "Previous Page",
19961 * Customizable piece of the default paging text (defaults to "Next Page")
19964 nextText : "Next Page",
19966 * Customizable piece of the default paging text (defaults to "Last Page")
19969 lastText : "Last Page",
19971 * Customizable piece of the default paging text (defaults to "Refresh")
19974 refreshText : "Refresh",
19978 onRender : function(ct, position)
19980 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19981 this.navgroup.parentId = this.id;
19982 this.navgroup.onRender(this.el, null);
19983 // add the buttons to the navgroup
19985 if(this.displayInfo){
19986 Roo.log(this.el.select('ul.navbar-nav',true).first());
19987 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19988 this.displayEl = this.el.select('.x-paging-info', true).first();
19989 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19990 // this.displayEl = navel.el.select('span',true).first();
19996 Roo.each(_this.buttons, function(e){
19997 Roo.factory(e).onRender(_this.el, null);
20001 Roo.each(_this.toolbarItems, function(e) {
20002 _this.navgroup.addItem(e);
20006 this.first = this.navgroup.addItem({
20007 tooltip: this.firstText,
20009 icon : 'fa fa-backward',
20011 preventDefault: true,
20012 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20015 this.prev = this.navgroup.addItem({
20016 tooltip: this.prevText,
20018 icon : 'fa fa-step-backward',
20020 preventDefault: true,
20021 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20023 //this.addSeparator();
20026 var field = this.navgroup.addItem( {
20028 cls : 'x-paging-position',
20030 html : this.beforePageText +
20031 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20032 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20035 this.field = field.el.select('input', true).first();
20036 this.field.on("keydown", this.onPagingKeydown, this);
20037 this.field.on("focus", function(){this.dom.select();});
20040 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20041 //this.field.setHeight(18);
20042 //this.addSeparator();
20043 this.next = this.navgroup.addItem({
20044 tooltip: this.nextText,
20046 html : ' <i class="fa fa-step-forward">',
20048 preventDefault: true,
20049 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20051 this.last = this.navgroup.addItem({
20052 tooltip: this.lastText,
20053 icon : 'fa fa-forward',
20056 preventDefault: true,
20057 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20059 //this.addSeparator();
20060 this.loading = this.navgroup.addItem({
20061 tooltip: this.refreshText,
20062 icon: 'fa fa-refresh',
20063 preventDefault: true,
20064 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20070 updateInfo : function(){
20071 if(this.displayEl){
20072 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20073 var msg = count == 0 ?
20077 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20079 this.displayEl.update(msg);
20084 onLoad : function(ds, r, o){
20085 this.cursor = o.params ? o.params.start : 0;
20086 var d = this.getPageData(),
20090 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20091 this.field.dom.value = ap;
20092 this.first.setDisabled(ap == 1);
20093 this.prev.setDisabled(ap == 1);
20094 this.next.setDisabled(ap == ps);
20095 this.last.setDisabled(ap == ps);
20096 this.loading.enable();
20101 getPageData : function(){
20102 var total = this.ds.getTotalCount();
20105 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20106 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20111 onLoadError : function(){
20112 this.loading.enable();
20116 onPagingKeydown : function(e){
20117 var k = e.getKey();
20118 var d = this.getPageData();
20120 var v = this.field.dom.value, pageNum;
20121 if(!v || isNaN(pageNum = parseInt(v, 10))){
20122 this.field.dom.value = d.activePage;
20125 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20126 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20129 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))
20131 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20132 this.field.dom.value = pageNum;
20133 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20136 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20138 var v = this.field.dom.value, pageNum;
20139 var increment = (e.shiftKey) ? 10 : 1;
20140 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20142 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20143 this.field.dom.value = d.activePage;
20146 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20148 this.field.dom.value = parseInt(v, 10) + increment;
20149 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20150 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20157 beforeLoad : function(){
20159 this.loading.disable();
20164 onClick : function(which){
20173 ds.load({params:{start: 0, limit: this.pageSize}});
20176 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20179 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20182 var total = ds.getTotalCount();
20183 var extra = total % this.pageSize;
20184 var lastStart = extra ? (total - extra) : total-this.pageSize;
20185 ds.load({params:{start: lastStart, limit: this.pageSize}});
20188 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20194 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20195 * @param {Roo.data.Store} store The data store to unbind
20197 unbind : function(ds){
20198 ds.un("beforeload", this.beforeLoad, this);
20199 ds.un("load", this.onLoad, this);
20200 ds.un("loadexception", this.onLoadError, this);
20201 ds.un("remove", this.updateInfo, this);
20202 ds.un("add", this.updateInfo, this);
20203 this.ds = undefined;
20207 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20208 * @param {Roo.data.Store} store The data store to bind
20210 bind : function(ds){
20211 ds.on("beforeload", this.beforeLoad, this);
20212 ds.on("load", this.onLoad, this);
20213 ds.on("loadexception", this.onLoadError, this);
20214 ds.on("remove", this.updateInfo, this);
20215 ds.on("add", this.updateInfo, this);
20226 * @class Roo.bootstrap.MessageBar
20227 * @extends Roo.bootstrap.Component
20228 * Bootstrap MessageBar class
20229 * @cfg {String} html contents of the MessageBar
20230 * @cfg {String} weight (info | success | warning | danger) default info
20231 * @cfg {String} beforeClass insert the bar before the given class
20232 * @cfg {Boolean} closable (true | false) default false
20233 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20236 * Create a new Element
20237 * @param {Object} config The config object
20240 Roo.bootstrap.MessageBar = function(config){
20241 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20244 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20250 beforeClass: 'bootstrap-sticky-wrap',
20252 getAutoCreate : function(){
20256 cls: 'alert alert-dismissable alert-' + this.weight,
20261 html: this.html || ''
20267 cfg.cls += ' alert-messages-fixed';
20281 onRender : function(ct, position)
20283 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20286 var cfg = Roo.apply({}, this.getAutoCreate());
20290 cfg.cls += ' ' + this.cls;
20293 cfg.style = this.style;
20295 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20297 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20300 this.el.select('>button.close').on('click', this.hide, this);
20306 if (!this.rendered) {
20312 this.fireEvent('show', this);
20318 if (!this.rendered) {
20324 this.fireEvent('hide', this);
20327 update : function()
20329 // var e = this.el.dom.firstChild;
20331 // if(this.closable){
20332 // e = e.nextSibling;
20335 // e.data = this.html || '';
20337 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20353 * @class Roo.bootstrap.Graph
20354 * @extends Roo.bootstrap.Component
20355 * Bootstrap Graph class
20359 @cfg {String} graphtype bar | vbar | pie
20360 @cfg {number} g_x coodinator | centre x (pie)
20361 @cfg {number} g_y coodinator | centre y (pie)
20362 @cfg {number} g_r radius (pie)
20363 @cfg {number} g_height height of the chart (respected by all elements in the set)
20364 @cfg {number} g_width width of the chart (respected by all elements in the set)
20365 @cfg {Object} title The title of the chart
20368 -opts (object) options for the chart
20370 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20371 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20373 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.
20374 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20376 o stretch (boolean)
20378 -opts (object) options for the pie
20381 o startAngle (number)
20382 o endAngle (number)
20386 * Create a new Input
20387 * @param {Object} config The config object
20390 Roo.bootstrap.Graph = function(config){
20391 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20397 * The img click event for the img.
20398 * @param {Roo.EventObject} e
20404 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20415 //g_colors: this.colors,
20422 getAutoCreate : function(){
20433 onRender : function(ct,position){
20434 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20435 this.raphael = Raphael(this.el.dom);
20437 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20438 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20439 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20440 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20442 r.text(160, 10, "Single Series Chart").attr(txtattr);
20443 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20444 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20445 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20447 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20448 r.barchart(330, 10, 300, 220, data1);
20449 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20450 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20453 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20454 // r.barchart(30, 30, 560, 250, xdata, {
20455 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20456 // axis : "0 0 1 1",
20457 // axisxlabels : xdata
20458 // //yvalues : cols,
20461 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20463 // this.load(null,xdata,{
20464 // axis : "0 0 1 1",
20465 // axisxlabels : xdata
20470 load : function(graphtype,xdata,opts){
20471 this.raphael.clear();
20473 graphtype = this.graphtype;
20478 var r = this.raphael,
20479 fin = function () {
20480 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20482 fout = function () {
20483 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20485 pfin = function() {
20486 this.sector.stop();
20487 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20490 this.label[0].stop();
20491 this.label[0].attr({ r: 7.5 });
20492 this.label[1].attr({ "font-weight": 800 });
20495 pfout = function() {
20496 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20499 this.label[0].animate({ r: 5 }, 500, "bounce");
20500 this.label[1].attr({ "font-weight": 400 });
20506 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20509 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20512 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20513 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20515 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20522 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20527 setTitle: function(o)
20532 initEvents: function() {
20535 this.el.on('click', this.onClick, this);
20539 onClick : function(e)
20541 Roo.log('img onclick');
20542 this.fireEvent('click', this, e);
20554 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20557 * @class Roo.bootstrap.dash.NumberBox
20558 * @extends Roo.bootstrap.Component
20559 * Bootstrap NumberBox class
20560 * @cfg {String} headline Box headline
20561 * @cfg {String} content Box content
20562 * @cfg {String} icon Box icon
20563 * @cfg {String} footer Footer text
20564 * @cfg {String} fhref Footer href
20567 * Create a new NumberBox
20568 * @param {Object} config The config object
20572 Roo.bootstrap.dash.NumberBox = function(config){
20573 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20577 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20586 getAutoCreate : function(){
20590 cls : 'small-box ',
20598 cls : 'roo-headline',
20599 html : this.headline
20603 cls : 'roo-content',
20604 html : this.content
20618 cls : 'ion ' + this.icon
20627 cls : 'small-box-footer',
20628 href : this.fhref || '#',
20632 cfg.cn.push(footer);
20639 onRender : function(ct,position){
20640 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20647 setHeadline: function (value)
20649 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20652 setFooter: function (value, href)
20654 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20657 this.el.select('a.small-box-footer',true).first().attr('href', href);
20662 setContent: function (value)
20664 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20667 initEvents: function()
20681 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20684 * @class Roo.bootstrap.dash.TabBox
20685 * @extends Roo.bootstrap.Component
20686 * Bootstrap TabBox class
20687 * @cfg {String} title Title of the TabBox
20688 * @cfg {String} icon Icon of the TabBox
20689 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20690 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20693 * Create a new TabBox
20694 * @param {Object} config The config object
20698 Roo.bootstrap.dash.TabBox = function(config){
20699 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20704 * When a pane is added
20705 * @param {Roo.bootstrap.dash.TabPane} pane
20709 * @event activatepane
20710 * When a pane is activated
20711 * @param {Roo.bootstrap.dash.TabPane} pane
20713 "activatepane" : true
20721 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20726 tabScrollable : false,
20728 getChildContainer : function()
20730 return this.el.select('.tab-content', true).first();
20733 getAutoCreate : function(){
20737 cls: 'pull-left header',
20745 cls: 'fa ' + this.icon
20751 cls: 'nav nav-tabs pull-right',
20757 if(this.tabScrollable){
20764 cls: 'nav nav-tabs pull-right',
20775 cls: 'nav-tabs-custom',
20780 cls: 'tab-content no-padding',
20788 initEvents : function()
20790 //Roo.log('add add pane handler');
20791 this.on('addpane', this.onAddPane, this);
20794 * Updates the box title
20795 * @param {String} html to set the title to.
20797 setTitle : function(value)
20799 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20801 onAddPane : function(pane)
20803 this.panes.push(pane);
20804 //Roo.log('addpane');
20806 // tabs are rendere left to right..
20807 if(!this.showtabs){
20811 var ctr = this.el.select('.nav-tabs', true).first();
20814 var existing = ctr.select('.nav-tab',true);
20815 var qty = existing.getCount();;
20818 var tab = ctr.createChild({
20820 cls : 'nav-tab' + (qty ? '' : ' active'),
20828 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20831 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20833 pane.el.addClass('active');
20838 onTabClick : function(ev,un,ob,pane)
20840 //Roo.log('tab - prev default');
20841 ev.preventDefault();
20844 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20845 pane.tab.addClass('active');
20846 //Roo.log(pane.title);
20847 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20848 // technically we should have a deactivate event.. but maybe add later.
20849 // and it should not de-activate the selected tab...
20850 this.fireEvent('activatepane', pane);
20851 pane.el.addClass('active');
20852 pane.fireEvent('activate');
20857 getActivePane : function()
20860 Roo.each(this.panes, function(p) {
20861 if(p.el.hasClass('active')){
20882 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20884 * @class Roo.bootstrap.TabPane
20885 * @extends Roo.bootstrap.Component
20886 * Bootstrap TabPane class
20887 * @cfg {Boolean} active (false | true) Default false
20888 * @cfg {String} title title of panel
20892 * Create a new TabPane
20893 * @param {Object} config The config object
20896 Roo.bootstrap.dash.TabPane = function(config){
20897 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20903 * When a pane is activated
20904 * @param {Roo.bootstrap.dash.TabPane} pane
20911 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20916 // the tabBox that this is attached to.
20919 getAutoCreate : function()
20927 cfg.cls += ' active';
20932 initEvents : function()
20934 //Roo.log('trigger add pane handler');
20935 this.parent().fireEvent('addpane', this)
20939 * Updates the tab title
20940 * @param {String} html to set the title to.
20942 setTitle: function(str)
20948 this.tab.select('a', true).first().dom.innerHTML = str;
20965 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20968 * @class Roo.bootstrap.menu.Menu
20969 * @extends Roo.bootstrap.Component
20970 * Bootstrap Menu class - container for Menu
20971 * @cfg {String} html Text of the menu
20972 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20973 * @cfg {String} icon Font awesome icon
20974 * @cfg {String} pos Menu align to (top | bottom) default bottom
20978 * Create a new Menu
20979 * @param {Object} config The config object
20983 Roo.bootstrap.menu.Menu = function(config){
20984 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20988 * @event beforeshow
20989 * Fires before this menu is displayed
20990 * @param {Roo.bootstrap.menu.Menu} this
20994 * @event beforehide
20995 * Fires before this menu is hidden
20996 * @param {Roo.bootstrap.menu.Menu} this
21001 * Fires after this menu is displayed
21002 * @param {Roo.bootstrap.menu.Menu} this
21007 * Fires after this menu is hidden
21008 * @param {Roo.bootstrap.menu.Menu} this
21013 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21014 * @param {Roo.bootstrap.menu.Menu} this
21015 * @param {Roo.EventObject} e
21022 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21026 weight : 'default',
21031 getChildContainer : function() {
21032 if(this.isSubMenu){
21036 return this.el.select('ul.dropdown-menu', true).first();
21039 getAutoCreate : function()
21044 cls : 'roo-menu-text',
21052 cls : 'fa ' + this.icon
21063 cls : 'dropdown-button btn btn-' + this.weight,
21068 cls : 'dropdown-toggle btn btn-' + this.weight,
21078 cls : 'dropdown-menu'
21084 if(this.pos == 'top'){
21085 cfg.cls += ' dropup';
21088 if(this.isSubMenu){
21091 cls : 'dropdown-menu'
21098 onRender : function(ct, position)
21100 this.isSubMenu = ct.hasClass('dropdown-submenu');
21102 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21105 initEvents : function()
21107 if(this.isSubMenu){
21111 this.hidden = true;
21113 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21114 this.triggerEl.on('click', this.onTriggerPress, this);
21116 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21117 this.buttonEl.on('click', this.onClick, this);
21123 if(this.isSubMenu){
21127 return this.el.select('ul.dropdown-menu', true).first();
21130 onClick : function(e)
21132 this.fireEvent("click", this, e);
21135 onTriggerPress : function(e)
21137 if (this.isVisible()) {
21144 isVisible : function(){
21145 return !this.hidden;
21150 this.fireEvent("beforeshow", this);
21152 this.hidden = false;
21153 this.el.addClass('open');
21155 Roo.get(document).on("mouseup", this.onMouseUp, this);
21157 this.fireEvent("show", this);
21164 this.fireEvent("beforehide", this);
21166 this.hidden = true;
21167 this.el.removeClass('open');
21169 Roo.get(document).un("mouseup", this.onMouseUp);
21171 this.fireEvent("hide", this);
21174 onMouseUp : function()
21188 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21191 * @class Roo.bootstrap.menu.Item
21192 * @extends Roo.bootstrap.Component
21193 * Bootstrap MenuItem class
21194 * @cfg {Boolean} submenu (true | false) default false
21195 * @cfg {String} html text of the item
21196 * @cfg {String} href the link
21197 * @cfg {Boolean} disable (true | false) default false
21198 * @cfg {Boolean} preventDefault (true | false) default true
21199 * @cfg {String} icon Font awesome icon
21200 * @cfg {String} pos Submenu align to (left | right) default right
21204 * Create a new Item
21205 * @param {Object} config The config object
21209 Roo.bootstrap.menu.Item = function(config){
21210 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21214 * Fires when the mouse is hovering over this menu
21215 * @param {Roo.bootstrap.menu.Item} this
21216 * @param {Roo.EventObject} e
21221 * Fires when the mouse exits this menu
21222 * @param {Roo.bootstrap.menu.Item} this
21223 * @param {Roo.EventObject} e
21229 * The raw click event for the entire grid.
21230 * @param {Roo.EventObject} e
21236 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21241 preventDefault: true,
21246 getAutoCreate : function()
21251 cls : 'roo-menu-item-text',
21259 cls : 'fa ' + this.icon
21268 href : this.href || '#',
21275 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21279 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21281 if(this.pos == 'left'){
21282 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21289 initEvents : function()
21291 this.el.on('mouseover', this.onMouseOver, this);
21292 this.el.on('mouseout', this.onMouseOut, this);
21294 this.el.select('a', true).first().on('click', this.onClick, this);
21298 onClick : function(e)
21300 if(this.preventDefault){
21301 e.preventDefault();
21304 this.fireEvent("click", this, e);
21307 onMouseOver : function(e)
21309 if(this.submenu && this.pos == 'left'){
21310 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21313 this.fireEvent("mouseover", this, e);
21316 onMouseOut : function(e)
21318 this.fireEvent("mouseout", this, e);
21330 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21333 * @class Roo.bootstrap.menu.Separator
21334 * @extends Roo.bootstrap.Component
21335 * Bootstrap Separator class
21338 * Create a new Separator
21339 * @param {Object} config The config object
21343 Roo.bootstrap.menu.Separator = function(config){
21344 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21347 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21349 getAutoCreate : function(){
21370 * @class Roo.bootstrap.Tooltip
21371 * Bootstrap Tooltip class
21372 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21373 * to determine which dom element triggers the tooltip.
21375 * It needs to add support for additional attributes like tooltip-position
21378 * Create a new Toolti
21379 * @param {Object} config The config object
21382 Roo.bootstrap.Tooltip = function(config){
21383 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21386 Roo.apply(Roo.bootstrap.Tooltip, {
21388 * @function init initialize tooltip monitoring.
21392 currentTip : false,
21393 currentRegion : false,
21399 Roo.get(document).on('mouseover', this.enter ,this);
21400 Roo.get(document).on('mouseout', this.leave, this);
21403 this.currentTip = new Roo.bootstrap.Tooltip();
21406 enter : function(ev)
21408 var dom = ev.getTarget();
21409 //Roo.log(['enter',dom]);
21410 var el = Roo.fly(dom);
21411 if (this.currentEl) {
21413 //Roo.log(this.currentEl);
21414 //Roo.log(this.currentEl.contains(dom));
21415 if (this.currentEl == el) {
21418 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21426 if (this.currentTip.el) {
21427 this.currentTip.el.hide(); // force hiding...
21430 if (!el.attr('tooltip')) { // parents who have tip?
21433 this.currentEl = el;
21434 this.currentTip.bind(el);
21435 this.currentRegion = Roo.lib.Region.getRegion(dom);
21436 this.currentTip.enter();
21439 leave : function(ev)
21441 var dom = ev.getTarget();
21442 //Roo.log(['leave',dom]);
21443 if (!this.currentEl) {
21448 if (dom != this.currentEl.dom) {
21451 var xy = ev.getXY();
21452 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21455 // only activate leave if mouse cursor is outside... bounding box..
21460 if (this.currentTip) {
21461 this.currentTip.leave();
21463 //Roo.log('clear currentEl');
21464 this.currentEl = false;
21469 'left' : ['r-l', [-2,0], 'right'],
21470 'right' : ['l-r', [2,0], 'left'],
21471 'bottom' : ['t-b', [0,2], 'top'],
21472 'top' : [ 'b-t', [0,-2], 'bottom']
21478 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21483 delay : null, // can be { show : 300 , hide: 500}
21487 hoverState : null, //???
21489 placement : 'bottom',
21491 getAutoCreate : function(){
21498 cls : 'tooltip-arrow'
21501 cls : 'tooltip-inner'
21508 bind : function(el)
21514 enter : function () {
21516 if (this.timeout != null) {
21517 clearTimeout(this.timeout);
21520 this.hoverState = 'in';
21521 //Roo.log("enter - show");
21522 if (!this.delay || !this.delay.show) {
21527 this.timeout = setTimeout(function () {
21528 if (_t.hoverState == 'in') {
21531 }, this.delay.show);
21535 clearTimeout(this.timeout);
21537 this.hoverState = 'out';
21538 if (!this.delay || !this.delay.hide) {
21544 this.timeout = setTimeout(function () {
21545 //Roo.log("leave - timeout");
21547 if (_t.hoverState == 'out') {
21549 Roo.bootstrap.Tooltip.currentEl = false;
21557 this.render(document.body);
21560 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21561 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21563 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21565 var placement = typeof this.placement == 'function' ?
21566 this.placement.call(this, this.el, on_el) :
21569 var autoToken = /\s?auto?\s?/i;
21570 var autoPlace = autoToken.test(placement);
21572 placement = placement.replace(autoToken, '') || 'top';
21576 //this.el.setXY([0,0]);
21578 //this.el.dom.style.display='block';
21579 this.el.addClass(placement);
21581 //this.el.appendTo(on_el);
21583 var p = this.getPosition();
21584 var box = this.el.getBox();
21589 var align = Roo.bootstrap.Tooltip.alignment[placement];
21590 this.el.alignTo(this.bindEl, align[0],align[1]);
21591 //var arrow = this.el.select('.arrow',true).first();
21592 //arrow.set(align[2],
21594 this.el.addClass('in fade');
21595 this.hoverState = null;
21597 if (this.el.hasClass('fade')) {
21608 //this.el.setXY([0,0]);
21609 this.el.removeClass('in');
21625 * @class Roo.bootstrap.LocationPicker
21626 * @extends Roo.bootstrap.Component
21627 * Bootstrap LocationPicker class
21628 * @cfg {Number} latitude Position when init default 0
21629 * @cfg {Number} longitude Position when init default 0
21630 * @cfg {Number} zoom default 15
21631 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21632 * @cfg {Boolean} mapTypeControl default false
21633 * @cfg {Boolean} disableDoubleClickZoom default false
21634 * @cfg {Boolean} scrollwheel default true
21635 * @cfg {Boolean} streetViewControl default false
21636 * @cfg {Number} radius default 0
21637 * @cfg {String} locationName
21638 * @cfg {Boolean} draggable default true
21639 * @cfg {Boolean} enableAutocomplete default false
21640 * @cfg {Boolean} enableReverseGeocode default true
21641 * @cfg {String} markerTitle
21644 * Create a new LocationPicker
21645 * @param {Object} config The config object
21649 Roo.bootstrap.LocationPicker = function(config){
21651 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21656 * Fires when the picker initialized.
21657 * @param {Roo.bootstrap.LocationPicker} this
21658 * @param {Google Location} location
21662 * @event positionchanged
21663 * Fires when the picker position changed.
21664 * @param {Roo.bootstrap.LocationPicker} this
21665 * @param {Google Location} location
21667 positionchanged : true,
21670 * Fires when the map resize.
21671 * @param {Roo.bootstrap.LocationPicker} this
21676 * Fires when the map show.
21677 * @param {Roo.bootstrap.LocationPicker} this
21682 * Fires when the map hide.
21683 * @param {Roo.bootstrap.LocationPicker} this
21688 * Fires when click the map.
21689 * @param {Roo.bootstrap.LocationPicker} this
21690 * @param {Map event} e
21694 * @event mapRightClick
21695 * Fires when right click the map.
21696 * @param {Roo.bootstrap.LocationPicker} this
21697 * @param {Map event} e
21699 mapRightClick : true,
21701 * @event markerClick
21702 * Fires when click the marker.
21703 * @param {Roo.bootstrap.LocationPicker} this
21704 * @param {Map event} e
21706 markerClick : true,
21708 * @event markerRightClick
21709 * Fires when right click the marker.
21710 * @param {Roo.bootstrap.LocationPicker} this
21711 * @param {Map event} e
21713 markerRightClick : true,
21715 * @event OverlayViewDraw
21716 * Fires when OverlayView Draw
21717 * @param {Roo.bootstrap.LocationPicker} this
21719 OverlayViewDraw : true,
21721 * @event OverlayViewOnAdd
21722 * Fires when OverlayView Draw
21723 * @param {Roo.bootstrap.LocationPicker} this
21725 OverlayViewOnAdd : true,
21727 * @event OverlayViewOnRemove
21728 * Fires when OverlayView Draw
21729 * @param {Roo.bootstrap.LocationPicker} this
21731 OverlayViewOnRemove : true,
21733 * @event OverlayViewShow
21734 * Fires when OverlayView Draw
21735 * @param {Roo.bootstrap.LocationPicker} this
21736 * @param {Pixel} cpx
21738 OverlayViewShow : true,
21740 * @event OverlayViewHide
21741 * Fires when OverlayView Draw
21742 * @param {Roo.bootstrap.LocationPicker} this
21744 OverlayViewHide : true
21749 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
21751 gMapContext: false,
21757 mapTypeControl: false,
21758 disableDoubleClickZoom: false,
21760 streetViewControl: false,
21764 enableAutocomplete: false,
21765 enableReverseGeocode: true,
21768 getAutoCreate: function()
21773 cls: 'roo-location-picker'
21779 initEvents: function(ct, position)
21781 if(!this.el.getWidth() || this.isApplied()){
21785 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21790 initial: function()
21792 if(!this.mapTypeId){
21793 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
21796 this.gMapContext = this.GMapContext();
21798 this.initOverlayView();
21800 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
21804 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
21805 _this.setPosition(_this.gMapContext.marker.position);
21808 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
21809 Roo.log('mapClick');
21810 _this.fireEvent('mapClick', this, event);
21814 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
21815 Roo.log('mapRightClick');
21816 _this.fireEvent('mapRightClick', this, event);
21820 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
21821 Roo.log('markerClick');
21822 _this.fireEvent('markerClick', this, event);
21826 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
21827 Roo.log('markerRightClick');
21828 _this.fireEvent('markerRightClick', this, event);
21832 this.setPosition(this.gMapContext.location);
21834 this.fireEvent('initial', this, this.gMapContext.location);
21837 initOverlayView: function()
21841 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
21845 Roo.log('OverlayView draw');
21846 _this.fireEvent('OverlayViewDraw', _this);
21851 Roo.log('OverlayView onAdd');
21852 _this.fireEvent('OverlayViewOnAdd', _this);
21855 onRemove: function()
21857 Roo.log('OverlayView onRemove');
21858 _this.fireEvent('OverlayViewOnRemove', _this);
21861 show: function(cpx)
21863 Roo.log('OverlayView show');
21864 _this.fireEvent('OverlayViewShow', _this, cpx);
21869 Roo.log('OverlayView hide');
21870 _this.fireEvent('OverlayViewHide', _this);
21876 fromLatLngToContainerPixel: function(event)
21878 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
21881 isApplied: function()
21883 return this.getGmapContext() == false ? false : true;
21886 getGmapContext: function()
21888 return this.gMapContext
21891 GMapContext: function()
21893 var _map = new google.maps.Map(this.el.dom, this);
21894 var _marker = new google.maps.Marker({
21895 position: new google.maps.LatLng(this.latitude, this.longitude),
21897 title: this.markerTitle,
21898 draggable: this.draggable
21905 location: _marker.position,
21906 radius: this.radius,
21907 locationName: this.locationName,
21908 addressComponents: {
21909 formatted_address: null,
21910 addressLine1: null,
21911 addressLine2: null,
21913 streetNumber: null,
21917 stateOrProvince: null
21920 domContainer: this.el.dom,
21921 geodecoder: new google.maps.Geocoder()
21925 drawCircle: function(center, radius, options)
21927 if (this.gMapContext.circle != null) {
21928 this.gMapContext.circle.setMap(null);
21932 options = Roo.apply({}, options, {
21933 strokeColor: "#0000FF",
21934 strokeOpacity: .35,
21936 fillColor: "#0000FF",
21940 options.map = this.gMapContext.map;
21941 options.radius = radius;
21942 options.center = center;
21943 this.gMapContext.circle = new google.maps.Circle(options);
21944 return this.gMapContext.circle;
21950 setPosition: function(location)
21952 this.gMapContext.location = location;
21953 this.gMapContext.marker.setPosition(location);
21954 this.gMapContext.map.panTo(location);
21955 this.drawCircle(location, this.gMapContext.radius, {});
21959 if (this.gMapContext.settings.enableReverseGeocode) {
21960 this.gMapContext.geodecoder.geocode({
21961 latLng: this.gMapContext.location
21962 }, function(results, status) {
21964 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21965 _this.gMapContext.locationName = results[0].formatted_address;
21966 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21968 _this.fireEvent('positionchanged', this, location);
21975 this.fireEvent('positionchanged', this, location);
21980 google.maps.event.trigger(this.gMapContext.map, "resize");
21982 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
21984 this.fireEvent('resize', this);
21987 setPositionByLatLng: function(latitude, longitude)
21989 this.setPosition(new google.maps.LatLng(latitude, longitude));
21992 getCurrentPosition: function()
21995 latitude: this.gMapContext.location.lat(),
21996 longitude: this.gMapContext.location.lng()
22000 getAddressName: function()
22002 return this.gMapContext.locationName;
22005 getAddressComponents: function()
22007 return this.gMapContext.addressComponents;
22010 address_component_from_google_geocode: function(address_components)
22014 for (var i = 0; i < address_components.length; i++) {
22015 var component = address_components[i];
22016 if (component.types.indexOf("postal_code") >= 0) {
22017 result.postalCode = component.short_name;
22018 } else if (component.types.indexOf("street_number") >= 0) {
22019 result.streetNumber = component.short_name;
22020 } else if (component.types.indexOf("route") >= 0) {
22021 result.streetName = component.short_name;
22022 } else if (component.types.indexOf("neighborhood") >= 0) {
22023 result.city = component.short_name;
22024 } else if (component.types.indexOf("locality") >= 0) {
22025 result.city = component.short_name;
22026 } else if (component.types.indexOf("sublocality") >= 0) {
22027 result.district = component.short_name;
22028 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22029 result.stateOrProvince = component.short_name;
22030 } else if (component.types.indexOf("country") >= 0) {
22031 result.country = component.short_name;
22035 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22036 result.addressLine2 = "";
22040 setZoomLevel: function(zoom)
22042 this.gMapContext.map.setZoom(zoom);
22055 this.fireEvent('show', this);
22066 this.fireEvent('hide', this);
22071 Roo.apply(Roo.bootstrap.LocationPicker, {
22073 OverlayView : function(map, options)
22075 options = options || {};
22089 * @class Roo.bootstrap.Alert
22090 * @extends Roo.bootstrap.Component
22091 * Bootstrap Alert class
22092 * @cfg {String} title The title of alert
22093 * @cfg {String} html The content of alert
22094 * @cfg {String} weight ( success | info | warning | danger )
22095 * @cfg {String} faicon font-awesomeicon
22098 * Create a new alert
22099 * @param {Object} config The config object
22103 Roo.bootstrap.Alert = function(config){
22104 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22108 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22115 getAutoCreate : function()
22124 cls : 'roo-alert-icon'
22129 cls : 'roo-alert-title',
22134 cls : 'roo-alert-text',
22141 cfg.cn[0].cls += ' fa ' + this.faicon;
22145 cfg.cls += ' alert-' + this.weight;
22151 initEvents: function()
22153 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22156 setTitle : function(str)
22158 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22161 setText : function(str)
22163 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22166 setWeight : function(weight)
22169 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22172 this.weight = weight;
22174 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22177 setIcon : function(icon)
22180 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22185 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);