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;
1139 * @class Roo.bootstrap.Img
1140 * @extends Roo.bootstrap.Component
1141 * Bootstrap Img class
1142 * @cfg {Boolean} imgResponsive false | true
1143 * @cfg {String} border rounded | circle | thumbnail
1144 * @cfg {String} src image source
1145 * @cfg {String} alt image alternative text
1146 * @cfg {String} href a tag href
1147 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1150 * Create a new Input
1151 * @param {Object} config The config object
1154 Roo.bootstrap.Img = function(config){
1155 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1161 * The img click event for the img.
1162 * @param {Roo.EventObject} e
1168 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1170 imgResponsive: true,
1176 getAutoCreate : function(){
1180 cls: (this.imgResponsive) ? 'img-responsive' : '',
1184 cfg.html = this.html || cfg.html;
1186 cfg.src = this.src || cfg.src;
1188 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1189 cfg.cls += ' img-' + this.border;
1206 a.target = this.target;
1212 return (this.href) ? a : cfg;
1215 initEvents: function() {
1218 this.el.on('click', this.onClick, this);
1222 onClick : function(e)
1224 Roo.log('img onclick');
1225 this.fireEvent('click', this, e);
1239 * @class Roo.bootstrap.Link
1240 * @extends Roo.bootstrap.Component
1241 * Bootstrap Link Class
1242 * @cfg {String} alt image alternative text
1243 * @cfg {String} href a tag href
1244 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1245 * @cfg {String} html the content of the link.
1246 * @cfg {String} anchor name for the anchor link
1248 * @cfg {Boolean} preventDefault (true | false) default false
1252 * Create a new Input
1253 * @param {Object} config The config object
1256 Roo.bootstrap.Link = function(config){
1257 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1263 * The img click event for the img.
1264 * @param {Roo.EventObject} e
1270 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1274 preventDefault: false,
1278 getAutoCreate : function()
1284 // anchor's do not require html/href...
1285 if (this.anchor === false) {
1286 cfg.html = this.html || 'html-missing';
1287 cfg.href = this.href || '#';
1289 cfg.name = this.anchor;
1290 if (this.html !== false) {
1291 cfg.html = this.html;
1293 if (this.href !== false) {
1294 cfg.href = this.href;
1298 if(this.alt !== false){
1303 if(this.target !== false) {
1304 cfg.target = this.target;
1310 initEvents: function() {
1312 if(!this.href || this.preventDefault){
1313 this.el.on('click', this.onClick, this);
1317 onClick : function(e)
1319 if(this.preventDefault){
1322 //Roo.log('img onclick');
1323 this.fireEvent('click', this, e);
1336 * @class Roo.bootstrap.Header
1337 * @extends Roo.bootstrap.Component
1338 * Bootstrap Header class
1339 * @cfg {String} html content of header
1340 * @cfg {Number} level (1|2|3|4|5|6) default 1
1343 * Create a new Header
1344 * @param {Object} config The config object
1348 Roo.bootstrap.Header = function(config){
1349 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1352 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1360 getAutoCreate : function(){
1363 tag: 'h' + (1 *this.level),
1364 html: this.html || 'fill in html'
1376 * Ext JS Library 1.1.1
1377 * Copyright(c) 2006-2007, Ext JS, LLC.
1379 * Originally Released Under LGPL - original licence link has changed is not relivant.
1382 * <script type="text/javascript">
1386 * @class Roo.bootstrap.MenuMgr
1387 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1390 Roo.bootstrap.MenuMgr = function(){
1391 var menus, active, groups = {}, attached = false, lastShow = new Date();
1393 // private - called when first menu is created
1396 active = new Roo.util.MixedCollection();
1397 Roo.get(document).addKeyListener(27, function(){
1398 if(active.length > 0){
1406 if(active && active.length > 0){
1407 var c = active.clone();
1417 if(active.length < 1){
1418 Roo.get(document).un("mouseup", onMouseDown);
1426 var last = active.last();
1427 lastShow = new Date();
1430 Roo.get(document).on("mouseup", onMouseDown);
1435 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1436 m.parentMenu.activeChild = m;
1437 }else if(last && last.isVisible()){
1438 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1443 function onBeforeHide(m){
1445 m.activeChild.hide();
1447 if(m.autoHideTimer){
1448 clearTimeout(m.autoHideTimer);
1449 delete m.autoHideTimer;
1454 function onBeforeShow(m){
1455 var pm = m.parentMenu;
1456 if(!pm && !m.allowOtherMenus){
1458 }else if(pm && pm.activeChild && active != m){
1459 pm.activeChild.hide();
1464 function onMouseDown(e){
1465 Roo.log("on MouseDown");
1466 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1474 function onBeforeCheck(mi, state){
1476 var g = groups[mi.group];
1477 for(var i = 0, l = g.length; i < l; i++){
1479 g[i].setChecked(false);
1488 * Hides all menus that are currently visible
1490 hideAll : function(){
1495 register : function(menu){
1499 menus[menu.id] = menu;
1500 menu.on("beforehide", onBeforeHide);
1501 menu.on("hide", onHide);
1502 menu.on("beforeshow", onBeforeShow);
1503 menu.on("show", onShow);
1505 if(g && menu.events["checkchange"]){
1509 groups[g].push(menu);
1510 menu.on("checkchange", onCheck);
1515 * Returns a {@link Roo.menu.Menu} object
1516 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1517 * be used to generate and return a new Menu instance.
1519 get : function(menu){
1520 if(typeof menu == "string"){ // menu id
1522 }else if(menu.events){ // menu instance
1525 /*else if(typeof menu.length == 'number'){ // array of menu items?
1526 return new Roo.bootstrap.Menu({items:menu});
1527 }else{ // otherwise, must be a config
1528 return new Roo.bootstrap.Menu(menu);
1535 unregister : function(menu){
1536 delete menus[menu.id];
1537 menu.un("beforehide", onBeforeHide);
1538 menu.un("hide", onHide);
1539 menu.un("beforeshow", onBeforeShow);
1540 menu.un("show", onShow);
1542 if(g && menu.events["checkchange"]){
1543 groups[g].remove(menu);
1544 menu.un("checkchange", onCheck);
1549 registerCheckable : function(menuItem){
1550 var g = menuItem.group;
1555 groups[g].push(menuItem);
1556 menuItem.on("beforecheckchange", onBeforeCheck);
1561 unregisterCheckable : function(menuItem){
1562 var g = menuItem.group;
1564 groups[g].remove(menuItem);
1565 menuItem.un("beforecheckchange", onBeforeCheck);
1577 * @class Roo.bootstrap.Menu
1578 * @extends Roo.bootstrap.Component
1579 * Bootstrap Menu class - container for MenuItems
1580 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1584 * @param {Object} config The config object
1588 Roo.bootstrap.Menu = function(config){
1589 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1590 if (this.registerMenu) {
1591 Roo.bootstrap.MenuMgr.register(this);
1596 * Fires before this menu is displayed
1597 * @param {Roo.menu.Menu} this
1602 * Fires before this menu is hidden
1603 * @param {Roo.menu.Menu} this
1608 * Fires after this menu is displayed
1609 * @param {Roo.menu.Menu} this
1614 * Fires after this menu is hidden
1615 * @param {Roo.menu.Menu} this
1620 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1621 * @param {Roo.menu.Menu} this
1622 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1623 * @param {Roo.EventObject} e
1628 * Fires when the mouse is hovering over this menu
1629 * @param {Roo.menu.Menu} this
1630 * @param {Roo.EventObject} e
1631 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1636 * Fires when the mouse exits this menu
1637 * @param {Roo.menu.Menu} this
1638 * @param {Roo.EventObject} e
1639 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1644 * Fires when a menu item contained in this menu is clicked
1645 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1646 * @param {Roo.EventObject} e
1650 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1653 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1657 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1660 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1662 registerMenu : true,
1664 menuItems :false, // stores the menu items..
1670 getChildContainer : function() {
1674 getAutoCreate : function(){
1676 //if (['right'].indexOf(this.align)!==-1) {
1677 // cfg.cn[1].cls += ' pull-right'
1683 cls : 'dropdown-menu' ,
1684 style : 'z-index:1000'
1688 if (this.type === 'submenu') {
1689 cfg.cls = 'submenu active';
1691 if (this.type === 'treeview') {
1692 cfg.cls = 'treeview-menu';
1697 initEvents : function() {
1699 // Roo.log("ADD event");
1700 // Roo.log(this.triggerEl.dom);
1701 this.triggerEl.on('click', this.onTriggerPress, this);
1702 this.triggerEl.addClass('dropdown-toggle');
1703 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1705 this.el.on("mouseover", this.onMouseOver, this);
1706 this.el.on("mouseout", this.onMouseOut, this);
1710 findTargetItem : function(e){
1711 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1715 //Roo.log(t); Roo.log(t.id);
1717 //Roo.log(this.menuitems);
1718 return this.menuitems.get(t.id);
1720 //return this.items.get(t.menuItemId);
1725 onClick : function(e){
1726 Roo.log("menu.onClick");
1727 var t = this.findTargetItem(e);
1728 if(!t || t.isContainer){
1733 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1734 if(t == this.activeItem && t.shouldDeactivate(e)){
1735 this.activeItem.deactivate();
1736 delete this.activeItem;
1740 this.setActiveItem(t, true);
1748 Roo.log('pass click event');
1752 this.fireEvent("click", this, t, e);
1756 onMouseOver : function(e){
1757 var t = this.findTargetItem(e);
1760 // if(t.canActivate && !t.disabled){
1761 // this.setActiveItem(t, true);
1765 this.fireEvent("mouseover", this, e, t);
1767 isVisible : function(){
1768 return !this.hidden;
1770 onMouseOut : function(e){
1771 var t = this.findTargetItem(e);
1774 // if(t == this.activeItem && t.shouldDeactivate(e)){
1775 // this.activeItem.deactivate();
1776 // delete this.activeItem;
1779 this.fireEvent("mouseout", this, e, t);
1784 * Displays this menu relative to another element
1785 * @param {String/HTMLElement/Roo.Element} element The element to align to
1786 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1787 * the element (defaults to this.defaultAlign)
1788 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1790 show : function(el, pos, parentMenu){
1791 this.parentMenu = parentMenu;
1795 this.fireEvent("beforeshow", this);
1796 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1799 * Displays this menu at a specific xy position
1800 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1801 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1803 showAt : function(xy, parentMenu, /* private: */_e){
1804 this.parentMenu = parentMenu;
1809 this.fireEvent("beforeshow", this);
1811 //xy = this.el.adjustForConstraints(xy);
1813 //this.el.setXY(xy);
1815 this.hideMenuItems();
1816 this.hidden = false;
1817 this.triggerEl.addClass('open');
1819 this.fireEvent("show", this);
1825 this.doFocus.defer(50, this);
1829 doFocus : function(){
1831 this.focusEl.focus();
1836 * Hides this menu and optionally all parent menus
1837 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1839 hide : function(deep){
1841 this.hideMenuItems();
1842 if(this.el && this.isVisible()){
1843 this.fireEvent("beforehide", this);
1844 if(this.activeItem){
1845 this.activeItem.deactivate();
1846 this.activeItem = null;
1848 this.triggerEl.removeClass('open');;
1850 this.fireEvent("hide", this);
1852 if(deep === true && this.parentMenu){
1853 this.parentMenu.hide(true);
1857 onTriggerPress : function(e)
1860 Roo.log('trigger press');
1861 //Roo.log(e.getTarget());
1862 // Roo.log(this.triggerEl.dom);
1863 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1866 if (this.isVisible()) {
1870 this.show(this.triggerEl, false, false);
1879 hideMenuItems : function()
1881 //$(backdrop).remove()
1882 Roo.select('.open',true).each(function(aa) {
1884 aa.removeClass('open');
1885 //var parent = getParent($(this))
1886 //var relatedTarget = { relatedTarget: this }
1888 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1889 //if (e.isDefaultPrevented()) return
1890 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1893 addxtypeChild : function (tree, cntr) {
1894 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1896 this.menuitems.add(comp);
1917 * @class Roo.bootstrap.MenuItem
1918 * @extends Roo.bootstrap.Component
1919 * Bootstrap MenuItem class
1920 * @cfg {String} html the menu label
1921 * @cfg {String} href the link
1922 * @cfg {Boolean} preventDefault (true | false) default true
1923 * @cfg {Boolean} isContainer (true | false) default false
1927 * Create a new MenuItem
1928 * @param {Object} config The config object
1932 Roo.bootstrap.MenuItem = function(config){
1933 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1938 * The raw click event for the entire grid.
1939 * @param {Roo.EventObject} e
1945 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1949 preventDefault: true,
1950 isContainer : false,
1952 getAutoCreate : function(){
1954 if(this.isContainer){
1957 cls: 'dropdown-menu-item'
1963 cls: 'dropdown-menu-item',
1972 if (this.parent().type == 'treeview') {
1973 cfg.cls = 'treeview-menu';
1976 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1977 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1981 initEvents: function() {
1983 //this.el.select('a').on('click', this.onClick, this);
1986 onClick : function(e)
1988 Roo.log('item on click ');
1989 //if(this.preventDefault){
1990 // e.preventDefault();
1992 //this.parent().hideMenuItems();
1994 this.fireEvent('click', this, e);
2013 * @class Roo.bootstrap.MenuSeparator
2014 * @extends Roo.bootstrap.Component
2015 * Bootstrap MenuSeparator class
2018 * Create a new MenuItem
2019 * @param {Object} config The config object
2023 Roo.bootstrap.MenuSeparator = function(config){
2024 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2027 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2029 getAutoCreate : function(){
2044 <div class="modal fade">
2045 <div class="modal-dialog">
2046 <div class="modal-content">
2047 <div class="modal-header">
2048 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
2049 <h4 class="modal-title">Modal title</h4>
2051 <div class="modal-body">
2052 <p>One fine body…</p>
2054 <div class="modal-footer">
2055 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2056 <button type="button" class="btn btn-primary">Save changes</button>
2058 </div><!-- /.modal-content -->
2059 </div><!-- /.modal-dialog -->
2060 </div><!-- /.modal -->
2070 * @class Roo.bootstrap.Modal
2071 * @extends Roo.bootstrap.Component
2072 * Bootstrap Modal class
2073 * @cfg {String} title Title of dialog
2074 * @cfg {Boolean} specificTitle default false
2075 * @cfg {Array} buttons Array of buttons or standard button set..
2076 * @cfg {String} buttonPosition (left|right|center) default right
2077 * @cfg {Boolean} animate default true
2078 * @cfg {Boolean} allow_close default true
2081 * Create a new Modal Dialog
2082 * @param {Object} config The config object
2085 Roo.bootstrap.Modal = function(config){
2086 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2091 * The raw btnclick event for the button
2092 * @param {Roo.EventObject} e
2096 this.buttons = this.buttons || [];
2099 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2101 title : 'test dialog',
2108 specificTitle: false,
2110 buttonPosition: 'right',
2116 onRender : function(ct, position)
2118 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2121 var cfg = Roo.apply({}, this.getAutoCreate());
2124 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2126 //if (!cfg.name.length) {
2130 cfg.cls += ' ' + this.cls;
2133 cfg.style = this.style;
2135 this.el = Roo.get(document.body).createChild(cfg, position);
2137 //var type = this.el.dom.type;
2139 if(this.tabIndex !== undefined){
2140 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2145 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2146 this.maskEl.enableDisplayMode("block");
2148 //this.el.addClass("x-dlg-modal");
2150 if (this.buttons.length) {
2151 Roo.each(this.buttons, function(bb) {
2152 b = Roo.apply({}, bb);
2153 b.xns = b.xns || Roo.bootstrap;
2154 b.xtype = b.xtype || 'Button';
2155 if (typeof(b.listeners) == 'undefined') {
2156 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2159 var btn = Roo.factory(b);
2161 btn.onRender(this.el.select('.modal-footer div').first());
2165 // render the children.
2168 if(typeof(this.items) != 'undefined'){
2169 var items = this.items;
2172 for(var i =0;i < items.length;i++) {
2173 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2177 this.items = nitems;
2179 this.body = this.el.select('.modal-body',true).first();
2180 this.close = this.el.select('.modal-header .close', true).first();
2181 this.footer = this.el.select('.modal-footer',true).first();
2183 //this.el.addClass([this.fieldClass, this.cls]);
2186 getAutoCreate : function(){
2191 html : this.html || ''
2196 cls : 'modal-title',
2200 if(this.specificTitle){
2206 if (this.allow_close) {
2217 style : 'display: none',
2220 cls: "modal-dialog",
2223 cls : "modal-content",
2226 cls : 'modal-header',
2231 cls : 'modal-footer',
2235 cls: 'btn-' + this.buttonPosition
2252 modal.cls += ' fade';
2258 getChildContainer : function() {
2260 return this.el.select('.modal-body',true).first();
2263 getButtonContainer : function() {
2264 return this.el.select('.modal-footer div',true).first();
2267 initEvents : function()
2269 this.el.select('.modal-header .close').on('click', this.hide, this);
2271 // this.addxtype(this);
2275 if (!this.rendered) {
2279 this.el.setStyle('display', 'block');
2283 (function(){ _this.el.addClass('in'); }).defer(50);
2285 this.el.addClass('in');
2288 Roo.get(document.body).addClass("x-body-masked");
2289 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2291 this.el.setStyle('zIndex', '10001');
2293 this.fireEvent('show', this);
2300 Roo.get(document.body).removeClass("x-body-masked");
2301 this.el.removeClass('in');
2305 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2307 this.el.setStyle('display', 'none');
2310 this.fireEvent('hide', this);
2313 addButton : function(str, cb)
2317 var b = Roo.apply({}, { html : str } );
2318 b.xns = b.xns || Roo.bootstrap;
2319 b.xtype = b.xtype || 'Button';
2320 if (typeof(b.listeners) == 'undefined') {
2321 b.listeners = { click : cb.createDelegate(this) };
2324 var btn = Roo.factory(b);
2326 btn.onRender(this.el.select('.modal-footer div').first());
2332 setDefaultButton : function(btn)
2334 //this.el.select('.modal-footer').()
2336 resizeTo: function(w,h)
2340 setContentSize : function(w, h)
2344 onButtonClick: function(btn,e)
2347 this.fireEvent('btnclick', btn.name, e);
2349 setTitle: function(str) {
2350 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2356 Roo.apply(Roo.bootstrap.Modal, {
2358 * Button config that displays a single OK button
2367 * Button config that displays Yes and No buttons
2383 * Button config that displays OK and Cancel buttons
2398 * Button config that displays Yes, No and Cancel buttons
2420 * messagebox - can be used as a replace
2424 * @class Roo.MessageBox
2425 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2429 Roo.Msg.alert('Status', 'Changes saved successfully.');
2431 // Prompt for user data:
2432 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2434 // process text value...
2438 // Show a dialog using config options:
2440 title:'Save Changes?',
2441 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2442 buttons: Roo.Msg.YESNOCANCEL,
2449 Roo.bootstrap.MessageBox = function(){
2450 var dlg, opt, mask, waitTimer;
2451 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2452 var buttons, activeTextEl, bwidth;
2456 var handleButton = function(button){
2458 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2462 var handleHide = function(){
2464 dlg.el.removeClass(opt.cls);
2467 // Roo.TaskMgr.stop(waitTimer);
2468 // waitTimer = null;
2473 var updateButtons = function(b){
2476 buttons["ok"].hide();
2477 buttons["cancel"].hide();
2478 buttons["yes"].hide();
2479 buttons["no"].hide();
2480 //dlg.footer.dom.style.display = 'none';
2483 dlg.footer.dom.style.display = '';
2484 for(var k in buttons){
2485 if(typeof buttons[k] != "function"){
2488 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2489 width += buttons[k].el.getWidth()+15;
2499 var handleEsc = function(d, k, e){
2500 if(opt && opt.closable !== false){
2510 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2511 * @return {Roo.BasicDialog} The BasicDialog element
2513 getDialog : function(){
2515 dlg = new Roo.bootstrap.Modal( {
2518 //constraintoviewport:false,
2520 //collapsible : false,
2525 //buttonAlign:"center",
2526 closeClick : function(){
2527 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2530 handleButton("cancel");
2535 dlg.on("hide", handleHide);
2537 //dlg.addKeyListener(27, handleEsc);
2539 this.buttons = buttons;
2540 var bt = this.buttonText;
2541 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2542 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2543 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2544 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2546 bodyEl = dlg.body.createChild({
2548 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2549 '<textarea class="roo-mb-textarea"></textarea>' +
2550 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2552 msgEl = bodyEl.dom.firstChild;
2553 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2554 textboxEl.enableDisplayMode();
2555 textboxEl.addKeyListener([10,13], function(){
2556 if(dlg.isVisible() && opt && opt.buttons){
2559 }else if(opt.buttons.yes){
2560 handleButton("yes");
2564 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2565 textareaEl.enableDisplayMode();
2566 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2567 progressEl.enableDisplayMode();
2568 var pf = progressEl.dom.firstChild;
2570 pp = Roo.get(pf.firstChild);
2571 pp.setHeight(pf.offsetHeight);
2579 * Updates the message box body text
2580 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2581 * the XHTML-compliant non-breaking space character '&#160;')
2582 * @return {Roo.MessageBox} This message box
2584 updateText : function(text){
2585 if(!dlg.isVisible() && !opt.width){
2586 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2588 msgEl.innerHTML = text || ' ';
2590 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2591 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2593 Math.min(opt.width || cw , this.maxWidth),
2594 Math.max(opt.minWidth || this.minWidth, bwidth)
2597 activeTextEl.setWidth(w);
2599 if(dlg.isVisible()){
2600 dlg.fixedcenter = false;
2602 // to big, make it scroll. = But as usual stupid IE does not support
2605 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2606 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2607 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2609 bodyEl.dom.style.height = '';
2610 bodyEl.dom.style.overflowY = '';
2613 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2615 bodyEl.dom.style.overflowX = '';
2618 dlg.setContentSize(w, bodyEl.getHeight());
2619 if(dlg.isVisible()){
2620 dlg.fixedcenter = true;
2626 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2627 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2628 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2629 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2630 * @return {Roo.MessageBox} This message box
2632 updateProgress : function(value, text){
2634 this.updateText(text);
2636 if (pp) { // weird bug on my firefox - for some reason this is not defined
2637 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2643 * Returns true if the message box is currently displayed
2644 * @return {Boolean} True if the message box is visible, else false
2646 isVisible : function(){
2647 return dlg && dlg.isVisible();
2651 * Hides the message box if it is displayed
2654 if(this.isVisible()){
2660 * Displays a new message box, or reinitializes an existing message box, based on the config options
2661 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2662 * The following config object properties are supported:
2664 Property Type Description
2665 ---------- --------------- ------------------------------------------------------------------------------------
2666 animEl String/Element An id or Element from which the message box should animate as it opens and
2667 closes (defaults to undefined)
2668 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2669 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2670 closable Boolean False to hide the top-right close button (defaults to true). Note that
2671 progress and wait dialogs will ignore this property and always hide the
2672 close button as they can only be closed programmatically.
2673 cls String A custom CSS class to apply to the message box element
2674 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2675 displayed (defaults to 75)
2676 fn Function A callback function to execute after closing the dialog. The arguments to the
2677 function will be btn (the name of the button that was clicked, if applicable,
2678 e.g. "ok"), and text (the value of the active text field, if applicable).
2679 Progress and wait dialogs will ignore this option since they do not respond to
2680 user actions and can only be closed programmatically, so any required function
2681 should be called by the same code after it closes the dialog.
2682 icon String A CSS class that provides a background image to be used as an icon for
2683 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2684 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2685 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2686 modal Boolean False to allow user interaction with the page while the message box is
2687 displayed (defaults to true)
2688 msg String A string that will replace the existing message box body text (defaults
2689 to the XHTML-compliant non-breaking space character ' ')
2690 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2691 progress Boolean True to display a progress bar (defaults to false)
2692 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2693 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2694 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2695 title String The title text
2696 value String The string value to set into the active textbox element if displayed
2697 wait Boolean True to display a progress bar (defaults to false)
2698 width Number The width of the dialog in pixels
2705 msg: 'Please enter your address:',
2707 buttons: Roo.MessageBox.OKCANCEL,
2710 animEl: 'addAddressBtn'
2713 * @param {Object} config Configuration options
2714 * @return {Roo.MessageBox} This message box
2716 show : function(options)
2719 // this causes nightmares if you show one dialog after another
2720 // especially on callbacks..
2722 if(this.isVisible()){
2725 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2726 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2727 Roo.log("New Dialog Message:" + options.msg )
2728 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2729 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2732 var d = this.getDialog();
2734 d.setTitle(opt.title || " ");
2735 d.close.setDisplayed(opt.closable !== false);
2736 activeTextEl = textboxEl;
2737 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2742 textareaEl.setHeight(typeof opt.multiline == "number" ?
2743 opt.multiline : this.defaultTextHeight);
2744 activeTextEl = textareaEl;
2753 progressEl.setDisplayed(opt.progress === true);
2754 this.updateProgress(0);
2755 activeTextEl.dom.value = opt.value || "";
2757 dlg.setDefaultButton(activeTextEl);
2759 var bs = opt.buttons;
2763 }else if(bs && bs.yes){
2764 db = buttons["yes"];
2766 dlg.setDefaultButton(db);
2768 bwidth = updateButtons(opt.buttons);
2769 this.updateText(opt.msg);
2771 d.el.addClass(opt.cls);
2773 d.proxyDrag = opt.proxyDrag === true;
2774 d.modal = opt.modal !== false;
2775 d.mask = opt.modal !== false ? mask : false;
2777 // force it to the end of the z-index stack so it gets a cursor in FF
2778 document.body.appendChild(dlg.el.dom);
2779 d.animateTarget = null;
2780 d.show(options.animEl);
2786 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2787 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2788 * and closing the message box when the process is complete.
2789 * @param {String} title The title bar text
2790 * @param {String} msg The message box body text
2791 * @return {Roo.MessageBox} This message box
2793 progress : function(title, msg){
2800 minWidth: this.minProgressWidth,
2807 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2808 * If a callback function is passed it will be called after the user clicks the button, and the
2809 * id of the button that was clicked will be passed as the only parameter to the callback
2810 * (could also be the top-right close button).
2811 * @param {String} title The title bar text
2812 * @param {String} msg The message box body text
2813 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2814 * @param {Object} scope (optional) The scope of the callback function
2815 * @return {Roo.MessageBox} This message box
2817 alert : function(title, msg, fn, scope){
2830 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2831 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2832 * You are responsible for closing the message box when the process is complete.
2833 * @param {String} msg The message box body text
2834 * @param {String} title (optional) The title bar text
2835 * @return {Roo.MessageBox} This message box
2837 wait : function(msg, title){
2848 waitTimer = Roo.TaskMgr.start({
2850 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2858 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2859 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2860 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2861 * @param {String} title The title bar text
2862 * @param {String} msg The message box body text
2863 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2864 * @param {Object} scope (optional) The scope of the callback function
2865 * @return {Roo.MessageBox} This message box
2867 confirm : function(title, msg, fn, scope){
2871 buttons: this.YESNO,
2880 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2881 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2882 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2883 * (could also be the top-right close button) and the text that was entered will be passed as the two
2884 * parameters to the callback.
2885 * @param {String} title The title bar text
2886 * @param {String} msg The message box body text
2887 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2888 * @param {Object} scope (optional) The scope of the callback function
2889 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2890 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2891 * @return {Roo.MessageBox} This message box
2893 prompt : function(title, msg, fn, scope, multiline){
2897 buttons: this.OKCANCEL,
2902 multiline: multiline,
2909 * Button config that displays a single OK button
2914 * Button config that displays Yes and No buttons
2917 YESNO : {yes:true, no:true},
2919 * Button config that displays OK and Cancel buttons
2922 OKCANCEL : {ok:true, cancel:true},
2924 * Button config that displays Yes, No and Cancel buttons
2927 YESNOCANCEL : {yes:true, no:true, cancel:true},
2930 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2933 defaultTextHeight : 75,
2935 * The maximum width in pixels of the message box (defaults to 600)
2940 * The minimum width in pixels of the message box (defaults to 100)
2945 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2946 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2949 minProgressWidth : 250,
2951 * An object containing the default button text strings that can be overriden for localized language support.
2952 * Supported properties are: ok, cancel, yes and no.
2953 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2966 * Shorthand for {@link Roo.MessageBox}
2968 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2969 Roo.Msg = Roo.Msg || Roo.MessageBox;
2978 * @class Roo.bootstrap.Navbar
2979 * @extends Roo.bootstrap.Component
2980 * Bootstrap Navbar class
2983 * Create a new Navbar
2984 * @param {Object} config The config object
2988 Roo.bootstrap.Navbar = function(config){
2989 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2993 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3002 getAutoCreate : function(){
3005 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3009 initEvents :function ()
3011 //Roo.log(this.el.select('.navbar-toggle',true));
3012 this.el.select('.navbar-toggle',true).on('click', function() {
3013 // Roo.log('click');
3014 this.el.select('.navbar-collapse',true).toggleClass('in');
3022 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3024 var size = this.el.getSize();
3025 this.maskEl.setSize(size.width, size.height);
3026 this.maskEl.enableDisplayMode("block");
3035 getChildContainer : function()
3037 if (this.el.select('.collapse').getCount()) {
3038 return this.el.select('.collapse',true).first();
3071 * @class Roo.bootstrap.NavSimplebar
3072 * @extends Roo.bootstrap.Navbar
3073 * Bootstrap Sidebar class
3075 * @cfg {Boolean} inverse is inverted color
3077 * @cfg {String} type (nav | pills | tabs)
3078 * @cfg {Boolean} arrangement stacked | justified
3079 * @cfg {String} align (left | right) alignment
3081 * @cfg {Boolean} main (true|false) main nav bar? default false
3082 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3084 * @cfg {String} tag (header|footer|nav|div) default is nav
3090 * Create a new Sidebar
3091 * @param {Object} config The config object
3095 Roo.bootstrap.NavSimplebar = function(config){
3096 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3099 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3115 getAutoCreate : function(){
3119 tag : this.tag || 'div',
3132 this.type = this.type || 'nav';
3133 if (['tabs','pills'].indexOf(this.type)!==-1) {
3134 cfg.cn[0].cls += ' nav-' + this.type
3138 if (this.type!=='nav') {
3139 Roo.log('nav type must be nav/tabs/pills')
3141 cfg.cn[0].cls += ' navbar-nav'
3147 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3148 cfg.cn[0].cls += ' nav-' + this.arrangement;
3152 if (this.align === 'right') {
3153 cfg.cn[0].cls += ' navbar-right';
3157 cfg.cls += ' navbar-inverse';
3184 * @class Roo.bootstrap.NavHeaderbar
3185 * @extends Roo.bootstrap.NavSimplebar
3186 * Bootstrap Sidebar class
3188 * @cfg {String} brand what is brand
3189 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3190 * @cfg {String} brand_href href of the brand
3191 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3192 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3193 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3194 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3197 * Create a new Sidebar
3198 * @param {Object} config The config object
3202 Roo.bootstrap.NavHeaderbar = function(config){
3203 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3207 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3214 desktopCenter : false,
3217 getAutoCreate : function(){
3220 tag: this.nav || 'nav',
3227 if (this.desktopCenter) {
3228 cn.push({cls : 'container', cn : []});
3235 cls: 'navbar-header',
3240 cls: 'navbar-toggle',
3241 'data-toggle': 'collapse',
3246 html: 'Toggle navigation'
3268 cls: 'collapse navbar-collapse',
3272 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3274 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3275 cfg.cls += ' navbar-' + this.position;
3277 // tag can override this..
3279 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3282 if (this.brand !== '') {
3285 href: this.brand_href ? this.brand_href : '#',
3286 cls: 'navbar-brand',
3294 cfg.cls += ' main-nav';
3302 getHeaderChildContainer : function()
3304 if (this.el.select('.navbar-header').getCount()) {
3305 return this.el.select('.navbar-header',true).first();
3308 return this.getChildContainer();
3312 initEvents : function()
3314 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3316 if (this.autohide) {
3321 Roo.get(document).on('scroll',function(e) {
3322 var ns = Roo.get(document).getScroll().top;
3323 var os = prevScroll;
3327 ft.removeClass('slideDown');
3328 ft.addClass('slideUp');
3331 ft.removeClass('slideUp');
3332 ft.addClass('slideDown');
3356 * @class Roo.bootstrap.NavSidebar
3357 * @extends Roo.bootstrap.Navbar
3358 * Bootstrap Sidebar class
3361 * Create a new Sidebar
3362 * @param {Object} config The config object
3366 Roo.bootstrap.NavSidebar = function(config){
3367 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3370 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3372 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3374 getAutoCreate : function(){
3379 cls: 'sidebar sidebar-nav'
3401 * @class Roo.bootstrap.NavGroup
3402 * @extends Roo.bootstrap.Component
3403 * Bootstrap NavGroup class
3404 * @cfg {String} align left | right
3405 * @cfg {Boolean} inverse false | true
3406 * @cfg {String} type (nav|pills|tab) default nav
3407 * @cfg {String} navId - reference Id for navbar.
3411 * Create a new nav group
3412 * @param {Object} config The config object
3415 Roo.bootstrap.NavGroup = function(config){
3416 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3419 Roo.bootstrap.NavGroup.register(this);
3423 * Fires when the active item changes
3424 * @param {Roo.bootstrap.NavGroup} this
3425 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3426 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3433 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3444 getAutoCreate : function()
3446 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3453 if (['tabs','pills'].indexOf(this.type)!==-1) {
3454 cfg.cls += ' nav-' + this.type
3456 if (this.type!=='nav') {
3457 Roo.log('nav type must be nav/tabs/pills')
3459 cfg.cls += ' navbar-nav'
3462 if (this.parent().sidebar) {
3465 cls: 'dashboard-menu sidebar-menu'
3471 if (this.form === true) {
3477 if (this.align === 'right') {
3478 cfg.cls += ' navbar-right';
3480 cfg.cls += ' navbar-left';
3484 if (this.align === 'right') {
3485 cfg.cls += ' navbar-right';
3489 cfg.cls += ' navbar-inverse';
3497 * sets the active Navigation item
3498 * @param {Roo.bootstrap.NavItem} the new current navitem
3500 setActiveItem : function(item)
3503 Roo.each(this.navItems, function(v){
3508 v.setActive(false, true);
3515 item.setActive(true, true);
3516 this.fireEvent('changed', this, item, prev);
3521 * gets the active Navigation item
3522 * @return {Roo.bootstrap.NavItem} the current navitem
3524 getActive : function()
3528 Roo.each(this.navItems, function(v){
3539 indexOfNav : function()
3543 Roo.each(this.navItems, function(v,i){
3554 * adds a Navigation item
3555 * @param {Roo.bootstrap.NavItem} the navitem to add
3557 addItem : function(cfg)
3559 var cn = new Roo.bootstrap.NavItem(cfg);
3561 cn.parentId = this.id;
3562 cn.onRender(this.el, null);
3566 * register a Navigation item
3567 * @param {Roo.bootstrap.NavItem} the navitem to add
3569 register : function(item)
3571 this.navItems.push( item);
3572 item.navId = this.navId;
3577 * clear all the Navigation item
3580 clearAll : function()
3583 this.el.dom.innerHTML = '';
3586 getNavItem: function(tabId)
3589 Roo.each(this.navItems, function(e) {
3590 if (e.tabId == tabId) {
3600 setActiveNext : function()
3602 var i = this.indexOfNav(this.getActive());
3603 if (i > this.navItems.length) {
3606 this.setActiveItem(this.navItems[i+1]);
3608 setActivePrev : function()
3610 var i = this.indexOfNav(this.getActive());
3614 this.setActiveItem(this.navItems[i-1]);
3616 clearWasActive : function(except) {
3617 Roo.each(this.navItems, function(e) {
3618 if (e.tabId != except.tabId && e.was_active) {
3619 e.was_active = false;
3626 getWasActive : function ()
3629 Roo.each(this.navItems, function(e) {
3644 Roo.apply(Roo.bootstrap.NavGroup, {
3648 * register a Navigation Group
3649 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3651 register : function(navgrp)
3653 this.groups[navgrp.navId] = navgrp;
3657 * fetch a Navigation Group based on the navigation ID
3658 * @param {string} the navgroup to add
3659 * @returns {Roo.bootstrap.NavGroup} the navgroup
3661 get: function(navId) {
3662 if (typeof(this.groups[navId]) == 'undefined') {
3664 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3666 return this.groups[navId] ;
3681 * @class Roo.bootstrap.NavItem
3682 * @extends Roo.bootstrap.Component
3683 * Bootstrap Navbar.NavItem class
3684 * @cfg {String} href link to
3685 * @cfg {String} html content of button
3686 * @cfg {String} badge text inside badge
3687 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3688 * @cfg {String} glyphicon name of glyphicon
3689 * @cfg {String} icon name of font awesome icon
3690 * @cfg {Boolean} active Is item active
3691 * @cfg {Boolean} disabled Is item disabled
3693 * @cfg {Boolean} preventDefault (true | false) default false
3694 * @cfg {String} tabId the tab that this item activates.
3695 * @cfg {String} tagtype (a|span) render as a href or span?
3698 * Create a new Navbar Item
3699 * @param {Object} config The config object
3701 Roo.bootstrap.NavItem = function(config){
3702 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3707 * The raw click event for the entire grid.
3708 * @param {Roo.EventObject} e
3713 * Fires when the active item active state changes
3714 * @param {Roo.bootstrap.NavItem} this
3715 * @param {boolean} state the new state
3723 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3731 preventDefault : false,
3738 getAutoCreate : function(){
3746 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3748 if (this.disabled) {
3749 cfg.cls += ' disabled';
3752 if (this.href || this.html || this.glyphicon || this.icon) {
3756 href : this.href || "#",
3757 html: this.html || ''
3762 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3765 if(this.glyphicon) {
3766 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3771 cfg.cn[0].html += " <span class='caret'></span>";
3775 if (this.badge !== '') {
3777 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3785 initEvents: function()
3787 if (typeof (this.menu) != 'undefined') {
3788 this.menu.parentType = this.xtype;
3789 this.menu.triggerEl = this.el;
3790 this.menu = this.addxtype(Roo.apply({}, this.menu));
3793 this.el.select('a',true).on('click', this.onClick, this);
3795 if(this.tagtype == 'span'){
3796 this.el.select('span',true).on('click', this.onClick, this);
3799 // at this point parent should be available..
3800 this.parent().register(this);
3803 onClick : function(e)
3806 if(this.preventDefault){
3809 if (this.disabled) {
3813 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3814 if (tg && tg.transition) {
3815 Roo.log("waiting for the transitionend");
3819 Roo.log("fire event clicked");
3820 if(this.fireEvent('click', this, e) === false){
3824 if(this.tagtype == 'span'){
3828 var p = this.parent();
3829 if (['tabs','pills'].indexOf(p.type)!==-1) {
3830 if (typeof(p.setActiveItem) !== 'undefined') {
3831 p.setActiveItem(this);
3834 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3835 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3836 // remove the collapsed menu expand...
3837 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3842 isActive: function () {
3845 setActive : function(state, fire, is_was_active)
3847 if (this.active && !state & this.navId) {
3848 this.was_active = true;
3849 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3851 nv.clearWasActive(this);
3855 this.active = state;
3858 this.el.removeClass('active');
3859 } else if (!this.el.hasClass('active')) {
3860 this.el.addClass('active');
3863 this.fireEvent('changed', this, state);
3866 // show a panel if it's registered and related..
3868 if (!this.navId || !this.tabId || !state || is_was_active) {
3872 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3876 var pan = tg.getPanelByName(this.tabId);
3880 // if we can not flip to new panel - go back to old nav highlight..
3881 if (false == tg.showPanel(pan)) {
3882 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3884 var onav = nv.getWasActive();
3886 onav.setActive(true, false, true);
3895 // this should not be here...
3896 setDisabled : function(state)
3898 this.disabled = state;
3900 this.el.removeClass('disabled');
3901 } else if (!this.el.hasClass('disabled')) {
3902 this.el.addClass('disabled');
3908 * Fetch the element to display the tooltip on.
3909 * @return {Roo.Element} defaults to this.el
3911 tooltipEl : function()
3913 return this.el.select('' + this.tagtype + '', true).first();
3924 * <span> icon </span>
3925 * <span> text </span>
3926 * <span>badge </span>
3930 * @class Roo.bootstrap.NavSidebarItem
3931 * @extends Roo.bootstrap.NavItem
3932 * Bootstrap Navbar.NavSidebarItem class
3934 * Create a new Navbar Button
3935 * @param {Object} config The config object
3937 Roo.bootstrap.NavSidebarItem = function(config){
3938 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3943 * The raw click event for the entire grid.
3944 * @param {Roo.EventObject} e
3949 * Fires when the active item active state changes
3950 * @param {Roo.bootstrap.NavSidebarItem} this
3951 * @param {boolean} state the new state
3959 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3962 getAutoCreate : function(){
3967 href : this.href || '#',
3979 html : this.html || ''
3984 cfg.cls += ' active';
3988 if (this.glyphicon || this.icon) {
3989 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3990 a.cn.push({ tag : 'i', cls : c }) ;
3995 if (this.badge !== '') {
3996 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4000 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4001 a.cls += 'dropdown-toggle treeview' ;
4025 * @class Roo.bootstrap.Row
4026 * @extends Roo.bootstrap.Component
4027 * Bootstrap Row class (contains columns...)
4031 * @param {Object} config The config object
4034 Roo.bootstrap.Row = function(config){
4035 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4038 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4040 getAutoCreate : function(){
4059 * @class Roo.bootstrap.Element
4060 * @extends Roo.bootstrap.Component
4061 * Bootstrap Element class
4062 * @cfg {String} html contents of the element
4063 * @cfg {String} tag tag of the element
4064 * @cfg {String} cls class of the element
4067 * Create a new Element
4068 * @param {Object} config The config object
4071 Roo.bootstrap.Element = function(config){
4072 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4075 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4082 getAutoCreate : function(){
4107 * @class Roo.bootstrap.Pagination
4108 * @extends Roo.bootstrap.Component
4109 * Bootstrap Pagination class
4110 * @cfg {String} size xs | sm | md | lg
4111 * @cfg {Boolean} inverse false | true
4114 * Create a new Pagination
4115 * @param {Object} config The config object
4118 Roo.bootstrap.Pagination = function(config){
4119 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4122 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4128 getAutoCreate : function(){
4134 cfg.cls += ' inverse';
4140 cfg.cls += " " + this.cls;
4158 * @class Roo.bootstrap.PaginationItem
4159 * @extends Roo.bootstrap.Component
4160 * Bootstrap PaginationItem class
4161 * @cfg {String} html text
4162 * @cfg {String} href the link
4163 * @cfg {Boolean} preventDefault (true | false) default true
4164 * @cfg {Boolean} active (true | false) default false
4165 * @cfg {Boolean} disabled default false
4169 * Create a new PaginationItem
4170 * @param {Object} config The config object
4174 Roo.bootstrap.PaginationItem = function(config){
4175 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4180 * The raw click event for the entire grid.
4181 * @param {Roo.EventObject} e
4187 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4191 preventDefault: true,
4196 getAutoCreate : function(){
4202 href : this.href ? this.href : '#',
4203 html : this.html ? this.html : ''
4213 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4217 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4223 initEvents: function() {
4225 this.el.on('click', this.onClick, this);
4228 onClick : function(e)
4230 Roo.log('PaginationItem on click ');
4231 if(this.preventDefault){
4239 this.fireEvent('click', this, e);
4255 * @class Roo.bootstrap.Slider
4256 * @extends Roo.bootstrap.Component
4257 * Bootstrap Slider class
4260 * Create a new Slider
4261 * @param {Object} config The config object
4264 Roo.bootstrap.Slider = function(config){
4265 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4268 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4270 getAutoCreate : function(){
4274 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4278 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4290 * Ext JS Library 1.1.1
4291 * Copyright(c) 2006-2007, Ext JS, LLC.
4293 * Originally Released Under LGPL - original licence link has changed is not relivant.
4296 * <script type="text/javascript">
4301 * @class Roo.grid.ColumnModel
4302 * @extends Roo.util.Observable
4303 * This is the default implementation of a ColumnModel used by the Grid. It defines
4304 * the columns in the grid.
4307 var colModel = new Roo.grid.ColumnModel([
4308 {header: "Ticker", width: 60, sortable: true, locked: true},
4309 {header: "Company Name", width: 150, sortable: true},
4310 {header: "Market Cap.", width: 100, sortable: true},
4311 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4312 {header: "Employees", width: 100, sortable: true, resizable: false}
4317 * The config options listed for this class are options which may appear in each
4318 * individual column definition.
4319 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4321 * @param {Object} config An Array of column config objects. See this class's
4322 * config objects for details.
4324 Roo.grid.ColumnModel = function(config){
4326 * The config passed into the constructor
4328 this.config = config;
4331 // if no id, create one
4332 // if the column does not have a dataIndex mapping,
4333 // map it to the order it is in the config
4334 for(var i = 0, len = config.length; i < len; i++){
4336 if(typeof c.dataIndex == "undefined"){
4339 if(typeof c.renderer == "string"){
4340 c.renderer = Roo.util.Format[c.renderer];
4342 if(typeof c.id == "undefined"){
4345 if(c.editor && c.editor.xtype){
4346 c.editor = Roo.factory(c.editor, Roo.grid);
4348 if(c.editor && c.editor.isFormField){
4349 c.editor = new Roo.grid.GridEditor(c.editor);
4351 this.lookup[c.id] = c;
4355 * The width of columns which have no width specified (defaults to 100)
4358 this.defaultWidth = 100;
4361 * Default sortable of columns which have no sortable specified (defaults to false)
4364 this.defaultSortable = false;
4368 * @event widthchange
4369 * Fires when the width of a column changes.
4370 * @param {ColumnModel} this
4371 * @param {Number} columnIndex The column index
4372 * @param {Number} newWidth The new width
4374 "widthchange": true,
4376 * @event headerchange
4377 * Fires when the text of a header changes.
4378 * @param {ColumnModel} this
4379 * @param {Number} columnIndex The column index
4380 * @param {Number} newText The new header text
4382 "headerchange": true,
4384 * @event hiddenchange
4385 * Fires when a column is hidden or "unhidden".
4386 * @param {ColumnModel} this
4387 * @param {Number} columnIndex The column index
4388 * @param {Boolean} hidden true if hidden, false otherwise
4390 "hiddenchange": true,
4392 * @event columnmoved
4393 * Fires when a column is moved.
4394 * @param {ColumnModel} this
4395 * @param {Number} oldIndex
4396 * @param {Number} newIndex
4398 "columnmoved" : true,
4400 * @event columlockchange
4401 * Fires when a column's locked state is changed
4402 * @param {ColumnModel} this
4403 * @param {Number} colIndex
4404 * @param {Boolean} locked true if locked
4406 "columnlockchange" : true
4408 Roo.grid.ColumnModel.superclass.constructor.call(this);
4410 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4412 * @cfg {String} header The header text to display in the Grid view.
4415 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4416 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4417 * specified, the column's index is used as an index into the Record's data Array.
4420 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4421 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4424 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4425 * Defaults to the value of the {@link #defaultSortable} property.
4426 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4429 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4432 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4435 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4438 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4441 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4442 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4443 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4444 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4447 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4450 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4453 * @cfg {String} cursor (Optional)
4456 * @cfg {String} tooltip (Optional)
4459 * Returns the id of the column at the specified index.
4460 * @param {Number} index The column index
4461 * @return {String} the id
4463 getColumnId : function(index){
4464 return this.config[index].id;
4468 * Returns the column for a specified id.
4469 * @param {String} id The column id
4470 * @return {Object} the column
4472 getColumnById : function(id){
4473 return this.lookup[id];
4478 * Returns the column for a specified dataIndex.
4479 * @param {String} dataIndex The column dataIndex
4480 * @return {Object|Boolean} the column or false if not found
4482 getColumnByDataIndex: function(dataIndex){
4483 var index = this.findColumnIndex(dataIndex);
4484 return index > -1 ? this.config[index] : false;
4488 * Returns the index for a specified column id.
4489 * @param {String} id The column id
4490 * @return {Number} the index, or -1 if not found
4492 getIndexById : function(id){
4493 for(var i = 0, len = this.config.length; i < len; i++){
4494 if(this.config[i].id == id){
4502 * Returns the index for a specified column dataIndex.
4503 * @param {String} dataIndex The column dataIndex
4504 * @return {Number} the index, or -1 if not found
4507 findColumnIndex : function(dataIndex){
4508 for(var i = 0, len = this.config.length; i < len; i++){
4509 if(this.config[i].dataIndex == dataIndex){
4517 moveColumn : function(oldIndex, newIndex){
4518 var c = this.config[oldIndex];
4519 this.config.splice(oldIndex, 1);
4520 this.config.splice(newIndex, 0, c);
4521 this.dataMap = null;
4522 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4525 isLocked : function(colIndex){
4526 return this.config[colIndex].locked === true;
4529 setLocked : function(colIndex, value, suppressEvent){
4530 if(this.isLocked(colIndex) == value){
4533 this.config[colIndex].locked = value;
4535 this.fireEvent("columnlockchange", this, colIndex, value);
4539 getTotalLockedWidth : function(){
4541 for(var i = 0; i < this.config.length; i++){
4542 if(this.isLocked(i) && !this.isHidden(i)){
4543 this.totalWidth += this.getColumnWidth(i);
4549 getLockedCount : function(){
4550 for(var i = 0, len = this.config.length; i < len; i++){
4551 if(!this.isLocked(i)){
4558 * Returns the number of columns.
4561 getColumnCount : function(visibleOnly){
4562 if(visibleOnly === true){
4564 for(var i = 0, len = this.config.length; i < len; i++){
4565 if(!this.isHidden(i)){
4571 return this.config.length;
4575 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4576 * @param {Function} fn
4577 * @param {Object} scope (optional)
4578 * @return {Array} result
4580 getColumnsBy : function(fn, scope){
4582 for(var i = 0, len = this.config.length; i < len; i++){
4583 var c = this.config[i];
4584 if(fn.call(scope||this, c, i) === true){
4592 * Returns true if the specified column is sortable.
4593 * @param {Number} col The column index
4596 isSortable : function(col){
4597 if(typeof this.config[col].sortable == "undefined"){
4598 return this.defaultSortable;
4600 return this.config[col].sortable;
4604 * Returns the rendering (formatting) function defined for the column.
4605 * @param {Number} col The column index.
4606 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4608 getRenderer : function(col){
4609 if(!this.config[col].renderer){
4610 return Roo.grid.ColumnModel.defaultRenderer;
4612 return this.config[col].renderer;
4616 * Sets the rendering (formatting) function for a column.
4617 * @param {Number} col The column index
4618 * @param {Function} fn The function to use to process the cell's raw data
4619 * to return HTML markup for the grid view. The render function is called with
4620 * the following parameters:<ul>
4621 * <li>Data value.</li>
4622 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4623 * <li>css A CSS style string to apply to the table cell.</li>
4624 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4625 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4626 * <li>Row index</li>
4627 * <li>Column index</li>
4628 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4630 setRenderer : function(col, fn){
4631 this.config[col].renderer = fn;
4635 * Returns the width for the specified column.
4636 * @param {Number} col The column index
4639 getColumnWidth : function(col){
4640 return this.config[col].width * 1 || this.defaultWidth;
4644 * Sets the width for a column.
4645 * @param {Number} col The column index
4646 * @param {Number} width The new width
4648 setColumnWidth : function(col, width, suppressEvent){
4649 this.config[col].width = width;
4650 this.totalWidth = null;
4652 this.fireEvent("widthchange", this, col, width);
4657 * Returns the total width of all columns.
4658 * @param {Boolean} includeHidden True to include hidden column widths
4661 getTotalWidth : function(includeHidden){
4662 if(!this.totalWidth){
4663 this.totalWidth = 0;
4664 for(var i = 0, len = this.config.length; i < len; i++){
4665 if(includeHidden || !this.isHidden(i)){
4666 this.totalWidth += this.getColumnWidth(i);
4670 return this.totalWidth;
4674 * Returns the header for the specified column.
4675 * @param {Number} col The column index
4678 getColumnHeader : function(col){
4679 return this.config[col].header;
4683 * Sets the header for a column.
4684 * @param {Number} col The column index
4685 * @param {String} header The new header
4687 setColumnHeader : function(col, header){
4688 this.config[col].header = header;
4689 this.fireEvent("headerchange", this, col, header);
4693 * Returns the tooltip for the specified column.
4694 * @param {Number} col The column index
4697 getColumnTooltip : function(col){
4698 return this.config[col].tooltip;
4701 * Sets the tooltip for a column.
4702 * @param {Number} col The column index
4703 * @param {String} tooltip The new tooltip
4705 setColumnTooltip : function(col, tooltip){
4706 this.config[col].tooltip = tooltip;
4710 * Returns the dataIndex for the specified column.
4711 * @param {Number} col The column index
4714 getDataIndex : function(col){
4715 return this.config[col].dataIndex;
4719 * Sets the dataIndex for a column.
4720 * @param {Number} col The column index
4721 * @param {Number} dataIndex The new dataIndex
4723 setDataIndex : function(col, dataIndex){
4724 this.config[col].dataIndex = dataIndex;
4730 * Returns true if the cell is editable.
4731 * @param {Number} colIndex The column index
4732 * @param {Number} rowIndex The row index
4735 isCellEditable : function(colIndex, rowIndex){
4736 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4740 * Returns the editor defined for the cell/column.
4741 * return false or null to disable editing.
4742 * @param {Number} colIndex The column index
4743 * @param {Number} rowIndex The row index
4746 getCellEditor : function(colIndex, rowIndex){
4747 return this.config[colIndex].editor;
4751 * Sets if a column is editable.
4752 * @param {Number} col The column index
4753 * @param {Boolean} editable True if the column is editable
4755 setEditable : function(col, editable){
4756 this.config[col].editable = editable;
4761 * Returns true if the column is hidden.
4762 * @param {Number} colIndex The column index
4765 isHidden : function(colIndex){
4766 return this.config[colIndex].hidden;
4771 * Returns true if the column width cannot be changed
4773 isFixed : function(colIndex){
4774 return this.config[colIndex].fixed;
4778 * Returns true if the column can be resized
4781 isResizable : function(colIndex){
4782 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4785 * Sets if a column is hidden.
4786 * @param {Number} colIndex The column index
4787 * @param {Boolean} hidden True if the column is hidden
4789 setHidden : function(colIndex, hidden){
4790 this.config[colIndex].hidden = hidden;
4791 this.totalWidth = null;
4792 this.fireEvent("hiddenchange", this, colIndex, hidden);
4796 * Sets the editor for a column.
4797 * @param {Number} col The column index
4798 * @param {Object} editor The editor object
4800 setEditor : function(col, editor){
4801 this.config[col].editor = editor;
4805 Roo.grid.ColumnModel.defaultRenderer = function(value){
4806 if(typeof value == "string" && value.length < 1){
4812 // Alias for backwards compatibility
4813 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4816 * Ext JS Library 1.1.1
4817 * Copyright(c) 2006-2007, Ext JS, LLC.
4819 * Originally Released Under LGPL - original licence link has changed is not relivant.
4822 * <script type="text/javascript">
4826 * @class Roo.LoadMask
4827 * A simple utility class for generically masking elements while loading data. If the element being masked has
4828 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4829 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4830 * element's UpdateManager load indicator and will be destroyed after the initial load.
4832 * Create a new LoadMask
4833 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4834 * @param {Object} config The config object
4836 Roo.LoadMask = function(el, config){
4837 this.el = Roo.get(el);
4838 Roo.apply(this, config);
4840 this.store.on('beforeload', this.onBeforeLoad, this);
4841 this.store.on('load', this.onLoad, this);
4842 this.store.on('loadexception', this.onLoadException, this);
4843 this.removeMask = false;
4845 var um = this.el.getUpdateManager();
4846 um.showLoadIndicator = false; // disable the default indicator
4847 um.on('beforeupdate', this.onBeforeLoad, this);
4848 um.on('update', this.onLoad, this);
4849 um.on('failure', this.onLoad, this);
4850 this.removeMask = true;
4854 Roo.LoadMask.prototype = {
4856 * @cfg {Boolean} removeMask
4857 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4858 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4862 * The text to display in a centered loading message box (defaults to 'Loading...')
4866 * @cfg {String} msgCls
4867 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4869 msgCls : 'x-mask-loading',
4872 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4878 * Disables the mask to prevent it from being displayed
4880 disable : function(){
4881 this.disabled = true;
4885 * Enables the mask so that it can be displayed
4887 enable : function(){
4888 this.disabled = false;
4891 onLoadException : function()
4895 if (typeof(arguments[3]) != 'undefined') {
4896 Roo.MessageBox.alert("Error loading",arguments[3]);
4900 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4901 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4910 this.el.unmask(this.removeMask);
4915 this.el.unmask(this.removeMask);
4919 onBeforeLoad : function(){
4921 this.el.mask(this.msg, this.msgCls);
4926 destroy : function(){
4928 this.store.un('beforeload', this.onBeforeLoad, this);
4929 this.store.un('load', this.onLoad, this);
4930 this.store.un('loadexception', this.onLoadException, this);
4932 var um = this.el.getUpdateManager();
4933 um.un('beforeupdate', this.onBeforeLoad, this);
4934 um.un('update', this.onLoad, this);
4935 um.un('failure', this.onLoad, this);
4946 * @class Roo.bootstrap.Table
4947 * @extends Roo.bootstrap.Component
4948 * Bootstrap Table class
4949 * @cfg {String} cls table class
4950 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4951 * @cfg {String} bgcolor Specifies the background color for a table
4952 * @cfg {Number} border Specifies whether the table cells should have borders or not
4953 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4954 * @cfg {Number} cellspacing Specifies the space between cells
4955 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4956 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4957 * @cfg {String} sortable Specifies that the table should be sortable
4958 * @cfg {String} summary Specifies a summary of the content of a table
4959 * @cfg {Number} width Specifies the width of a table
4960 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4962 * @cfg {boolean} striped Should the rows be alternative striped
4963 * @cfg {boolean} bordered Add borders to the table
4964 * @cfg {boolean} hover Add hover highlighting
4965 * @cfg {boolean} condensed Format condensed
4966 * @cfg {boolean} responsive Format condensed
4967 * @cfg {Boolean} loadMask (true|false) default false
4968 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4969 * @cfg {Boolean} thead (true|false) generate thead, default true
4970 * @cfg {Boolean} RowSelection (true|false) default false
4971 * @cfg {Boolean} CellSelection (true|false) default false
4972 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4976 * Create a new Table
4977 * @param {Object} config The config object
4980 Roo.bootstrap.Table = function(config){
4981 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4984 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4985 this.sm = this.selModel;
4986 this.sm.xmodule = this.xmodule || false;
4988 if (this.cm && typeof(this.cm.config) == 'undefined') {
4989 this.colModel = new Roo.grid.ColumnModel(this.cm);
4990 this.cm = this.colModel;
4991 this.cm.xmodule = this.xmodule || false;
4994 this.store= Roo.factory(this.store, Roo.data);
4995 this.ds = this.store;
4996 this.ds.xmodule = this.xmodule || false;
4999 if (this.footer && this.store) {
5000 this.footer.dataSource = this.ds;
5001 this.footer = Roo.factory(this.footer);
5008 * Fires when a cell is clicked
5009 * @param {Roo.bootstrap.Table} this
5010 * @param {Roo.Element} el
5011 * @param {Number} rowIndex
5012 * @param {Number} columnIndex
5013 * @param {Roo.EventObject} e
5017 * @event celldblclick
5018 * Fires when a cell is double 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
5025 "celldblclick" : true,
5028 * Fires when a row is clicked
5029 * @param {Roo.bootstrap.Table} this
5030 * @param {Roo.Element} el
5031 * @param {Number} rowIndex
5032 * @param {Roo.EventObject} e
5036 * @event rowdblclick
5037 * Fires when a row is double clicked
5038 * @param {Roo.bootstrap.Table} this
5039 * @param {Roo.Element} el
5040 * @param {Number} rowIndex
5041 * @param {Roo.EventObject} e
5043 "rowdblclick" : true,
5046 * Fires when a mouseover occur
5047 * @param {Roo.bootstrap.Table} this
5048 * @param {Roo.Element} el
5049 * @param {Number} rowIndex
5050 * @param {Number} columnIndex
5051 * @param {Roo.EventObject} e
5056 * Fires when a mouseout 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 row is rendered, so you can change add a style to it.
5067 * @param {Roo.bootstrap.Table} this
5068 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5072 * @event rowsrendered
5073 * Fires when all the rows have been rendered
5074 * @param {Roo.bootstrap.Table} this
5076 'rowsrendered' : true
5081 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5105 RowSelection : false,
5106 CellSelection : false,
5109 // Roo.Element - the tbody
5112 getAutoCreate : function(){
5113 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5122 cfg.cls += ' table-striped';
5126 cfg.cls += ' table-hover';
5128 if (this.bordered) {
5129 cfg.cls += ' table-bordered';
5131 if (this.condensed) {
5132 cfg.cls += ' table-condensed';
5134 if (this.responsive) {
5135 cfg.cls += ' table-responsive';
5139 cfg.cls+= ' ' +this.cls;
5142 // this lot should be simplifed...
5145 cfg.align=this.align;
5148 cfg.bgcolor=this.bgcolor;
5151 cfg.border=this.border;
5153 if (this.cellpadding) {
5154 cfg.cellpadding=this.cellpadding;
5156 if (this.cellspacing) {
5157 cfg.cellspacing=this.cellspacing;
5160 cfg.frame=this.frame;
5163 cfg.rules=this.rules;
5165 if (this.sortable) {
5166 cfg.sortable=this.sortable;
5169 cfg.summary=this.summary;
5172 cfg.width=this.width;
5175 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5178 if(this.store || this.cm){
5180 cfg.cn.push(this.renderHeader());
5183 cfg.cn.push(this.renderBody());
5186 cfg.cn.push(this.renderFooter());
5189 cfg.cls+= ' TableGrid';
5192 return { cn : [ cfg ] };
5195 initEvents : function()
5197 if(!this.store || !this.cm){
5201 //Roo.log('initEvents with ds!!!!');
5203 this.mainBody = this.el.select('tbody', true).first();
5208 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5209 e.on('click', _this.sort, _this);
5212 this.el.on("click", this.onClick, this);
5213 this.el.on("dblclick", this.onDblClick, this);
5215 // why is this done????? = it breaks dialogs??
5216 //this.parent().el.setStyle('position', 'relative');
5220 this.footer.parentId = this.id;
5221 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5224 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5226 this.store.on('load', this.onLoad, this);
5227 this.store.on('beforeload', this.onBeforeLoad, this);
5228 this.store.on('update', this.onUpdate, this);
5229 this.store.on('add', this.onAdd, this);
5233 onMouseover : function(e, el)
5235 var cell = Roo.get(el);
5241 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5242 cell = cell.findParent('td', false, true);
5245 var row = cell.findParent('tr', false, true);
5246 var cellIndex = cell.dom.cellIndex;
5247 var rowIndex = row.dom.rowIndex - 1; // start from 0
5249 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5253 onMouseout : function(e, el)
5255 var cell = Roo.get(el);
5261 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5262 cell = cell.findParent('td', false, true);
5265 var row = cell.findParent('tr', false, true);
5266 var cellIndex = cell.dom.cellIndex;
5267 var rowIndex = row.dom.rowIndex - 1; // start from 0
5269 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5273 onClick : function(e, el)
5275 var cell = Roo.get(el);
5277 if(!cell || (!this.CellSelection && !this.RowSelection)){
5282 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5283 cell = cell.findParent('td', false, true);
5286 var row = cell.findParent('tr', false, true);
5287 var cellIndex = cell.dom.cellIndex;
5288 var rowIndex = this.getRowIndex(row);
5290 if(this.CellSelection){
5291 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5294 if(this.RowSelection){
5295 this.fireEvent('rowclick', this, row, rowIndex, e);
5301 onDblClick : function(e,el)
5303 var cell = Roo.get(el);
5305 if(!cell || (!this.CellSelection && !this.RowSelection)){
5309 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5310 cell = cell.findParent('td', false, true);
5313 var row = cell.findParent('tr', false, true);
5314 var cellIndex = cell.dom.cellIndex;
5315 var rowIndex = this.getRowIndex(row);
5317 if(this.CellSelection){
5318 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5321 if(this.RowSelection){
5322 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5326 sort : function(e,el)
5328 var col = Roo.get(el)
5330 if(!col.hasClass('sortable')){
5334 var sort = col.attr('sort');
5337 if(col.hasClass('glyphicon-arrow-up')){
5341 this.store.sortInfo = {field : sort, direction : dir};
5344 Roo.log("calling footer first");
5345 this.footer.onClick('first');
5348 this.store.load({ params : { start : 0 } });
5352 renderHeader : function()
5361 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5363 var config = cm.config[i];
5368 html: cm.getColumnHeader(i)
5371 if(typeof(config.tooltip != 'undefined')){
5372 c.tooltip = config.tooltip;
5375 if(typeof(config.hidden) != 'undefined' && config.hidden){
5376 c.style += ' display:none;';
5379 if(typeof(config.dataIndex) != 'undefined'){
5380 c.sort = config.dataIndex;
5383 if(typeof(config.sortable) != 'undefined' && config.sortable){
5387 if(typeof(config.align) != 'undefined' && config.align.length){
5388 c.style += ' text-align:' + config.align + ';';
5391 if(typeof(config.width) != 'undefined'){
5392 c.style += ' width:' + config.width + 'px;';
5401 renderBody : function()
5411 colspan : this.cm.getColumnCount()
5421 renderFooter : function()
5431 colspan : this.cm.getColumnCount()
5445 Roo.log('ds onload');
5450 var ds = this.store;
5452 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5453 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5455 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5456 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5459 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5460 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5464 var tbody = this.mainBody;
5466 if(ds.getCount() > 0){
5467 ds.data.each(function(d,rowIndex){
5468 var row = this.renderRow(cm, ds, rowIndex);
5470 tbody.createChild(row);
5474 if(row.cellObjects.length){
5475 Roo.each(row.cellObjects, function(r){
5476 _this.renderCellObject(r);
5483 Roo.each(this.el.select('tbody td', true).elements, function(e){
5484 e.on('mouseover', _this.onMouseover, _this);
5487 Roo.each(this.el.select('tbody td', true).elements, function(e){
5488 e.on('mouseout', _this.onMouseout, _this);
5490 this.fireEvent('rowsrendered', this);
5491 //if(this.loadMask){
5492 // this.maskEl.hide();
5497 onUpdate : function(ds,record)
5499 this.refreshRow(record);
5502 onRemove : function(ds, record, index, isUpdate){
5503 if(isUpdate !== true){
5504 this.fireEvent("beforerowremoved", this, index, record);
5506 var bt = this.mainBody.dom;
5508 var rows = this.el.select('tbody > tr', true).elements;
5510 if(typeof(rows[index]) != 'undefined'){
5511 bt.removeChild(rows[index].dom);
5514 // if(bt.rows[index]){
5515 // bt.removeChild(bt.rows[index]);
5518 if(isUpdate !== true){
5519 //this.stripeRows(index);
5520 //this.syncRowHeights(index, index);
5522 this.fireEvent("rowremoved", this, index, record);
5526 onAdd : function(ds, records, rowIndex)
5528 //Roo.log('on Add called');
5529 // - note this does not handle multiple adding very well..
5530 var bt = this.mainBody.dom;
5531 for (var i =0 ; i < records.length;i++) {
5532 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5533 //Roo.log(records[i]);
5534 //Roo.log(this.store.getAt(rowIndex+i));
5535 this.insertRow(this.store, rowIndex + i, false);
5542 refreshRow : function(record){
5543 var ds = this.store, index;
5544 if(typeof record == 'number'){
5546 record = ds.getAt(index);
5548 index = ds.indexOf(record);
5550 this.insertRow(ds, index, true);
5551 this.onRemove(ds, record, index+1, true);
5552 //this.syncRowHeights(index, index);
5554 this.fireEvent("rowupdated", this, index, record);
5557 insertRow : function(dm, rowIndex, isUpdate){
5560 this.fireEvent("beforerowsinserted", this, rowIndex);
5562 //var s = this.getScrollState();
5563 var row = this.renderRow(this.cm, this.store, rowIndex);
5564 // insert before rowIndex..
5565 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5569 if(row.cellObjects.length){
5570 Roo.each(row.cellObjects, function(r){
5571 _this.renderCellObject(r);
5576 this.fireEvent("rowsinserted", this, rowIndex);
5577 //this.syncRowHeights(firstRow, lastRow);
5578 //this.stripeRows(firstRow);
5585 getRowDom : function(rowIndex)
5587 var rows = this.el.select('tbody > tr', true).elements;
5589 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5592 // returns the object tree for a tr..
5595 renderRow : function(cm, ds, rowIndex)
5598 var d = ds.getAt(rowIndex);
5605 var cellObjects = [];
5607 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5608 var config = cm.config[i];
5610 var renderer = cm.getRenderer(i);
5614 if(typeof(renderer) !== 'undefined'){
5615 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5617 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5618 // and are rendered into the cells after the row is rendered - using the id for the element.
5620 if(typeof(value) === 'object'){
5630 rowIndex : rowIndex,
5635 this.fireEvent('rowclass', this, rowcfg);
5639 cls : rowcfg.rowClass,
5641 html: (typeof(value) === 'object') ? '' : value
5648 if(typeof(config.hidden) != 'undefined' && config.hidden){
5649 td.style += ' display:none;';
5652 if(typeof(config.align) != 'undefined' && config.align.length){
5653 td.style += ' text-align:' + config.align + ';';
5656 if(typeof(config.width) != 'undefined'){
5657 td.style += ' width:' + config.width + 'px;';
5660 if(typeof(config.cursor) != 'undefined'){
5661 td.style += ' cursor:' + config.cursor + ';';
5668 row.cellObjects = cellObjects;
5676 onBeforeLoad : function()
5678 //Roo.log('ds onBeforeLoad');
5682 //if(this.loadMask){
5683 // this.maskEl.show();
5691 this.el.select('tbody', true).first().dom.innerHTML = '';
5694 * Show or hide a row.
5695 * @param {Number} rowIndex to show or hide
5696 * @param {Boolean} state hide
5698 setRowVisibility : function(rowIndex, state)
5700 var bt = this.mainBody.dom;
5702 var rows = this.el.select('tbody > tr', true).elements;
5704 if(typeof(rows[rowIndex]) == 'undefined'){
5707 rows[rowIndex].dom.style.display = state ? '' : 'none';
5711 getSelectionModel : function(){
5713 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5715 return this.selModel;
5718 * Render the Roo.bootstrap object from renderder
5720 renderCellObject : function(r)
5724 var t = r.cfg.render(r.container);
5727 Roo.each(r.cfg.cn, function(c){
5729 container: t.getChildContainer(),
5732 _this.renderCellObject(child);
5737 getRowIndex : function(row)
5741 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5764 * @class Roo.bootstrap.TableCell
5765 * @extends Roo.bootstrap.Component
5766 * Bootstrap TableCell class
5767 * @cfg {String} html cell contain text
5768 * @cfg {String} cls cell class
5769 * @cfg {String} tag cell tag (td|th) default td
5770 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5771 * @cfg {String} align Aligns the content in a cell
5772 * @cfg {String} axis Categorizes cells
5773 * @cfg {String} bgcolor Specifies the background color of a cell
5774 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5775 * @cfg {Number} colspan Specifies the number of columns a cell should span
5776 * @cfg {String} headers Specifies one or more header cells a cell is related to
5777 * @cfg {Number} height Sets the height of a cell
5778 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5779 * @cfg {Number} rowspan Sets the number of rows a cell should span
5780 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5781 * @cfg {String} valign Vertical aligns the content in a cell
5782 * @cfg {Number} width Specifies the width of a cell
5785 * Create a new TableCell
5786 * @param {Object} config The config object
5789 Roo.bootstrap.TableCell = function(config){
5790 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5793 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5813 getAutoCreate : function(){
5814 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5834 cfg.align=this.align
5840 cfg.bgcolor=this.bgcolor
5843 cfg.charoff=this.charoff
5846 cfg.colspan=this.colspan
5849 cfg.headers=this.headers
5852 cfg.height=this.height
5855 cfg.nowrap=this.nowrap
5858 cfg.rowspan=this.rowspan
5861 cfg.scope=this.scope
5864 cfg.valign=this.valign
5867 cfg.width=this.width
5886 * @class Roo.bootstrap.TableRow
5887 * @extends Roo.bootstrap.Component
5888 * Bootstrap TableRow class
5889 * @cfg {String} cls row class
5890 * @cfg {String} align Aligns the content in a table row
5891 * @cfg {String} bgcolor Specifies a background color for a table row
5892 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5893 * @cfg {String} valign Vertical aligns the content in a table row
5896 * Create a new TableRow
5897 * @param {Object} config The config object
5900 Roo.bootstrap.TableRow = function(config){
5901 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5904 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5912 getAutoCreate : function(){
5913 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5923 cfg.align = this.align;
5926 cfg.bgcolor = this.bgcolor;
5929 cfg.charoff = this.charoff;
5932 cfg.valign = this.valign;
5950 * @class Roo.bootstrap.TableBody
5951 * @extends Roo.bootstrap.Component
5952 * Bootstrap TableBody class
5953 * @cfg {String} cls element class
5954 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5955 * @cfg {String} align Aligns the content inside the element
5956 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5957 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5960 * Create a new TableBody
5961 * @param {Object} config The config object
5964 Roo.bootstrap.TableBody = function(config){
5965 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5968 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5976 getAutoCreate : function(){
5977 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5991 cfg.align = this.align;
5994 cfg.charoff = this.charoff;
5997 cfg.valign = this.valign;
6004 // initEvents : function()
6011 // this.store = Roo.factory(this.store, Roo.data);
6012 // this.store.on('load', this.onLoad, this);
6014 // this.store.load();
6018 // onLoad: function ()
6020 // this.fireEvent('load', this);
6030 * Ext JS Library 1.1.1
6031 * Copyright(c) 2006-2007, Ext JS, LLC.
6033 * Originally Released Under LGPL - original licence link has changed is not relivant.
6036 * <script type="text/javascript">
6039 // as we use this in bootstrap.
6040 Roo.namespace('Roo.form');
6042 * @class Roo.form.Action
6043 * Internal Class used to handle form actions
6045 * @param {Roo.form.BasicForm} el The form element or its id
6046 * @param {Object} config Configuration options
6051 // define the action interface
6052 Roo.form.Action = function(form, options){
6054 this.options = options || {};
6057 * Client Validation Failed
6060 Roo.form.Action.CLIENT_INVALID = 'client';
6062 * Server Validation Failed
6065 Roo.form.Action.SERVER_INVALID = 'server';
6067 * Connect to Server Failed
6070 Roo.form.Action.CONNECT_FAILURE = 'connect';
6072 * Reading Data from Server Failed
6075 Roo.form.Action.LOAD_FAILURE = 'load';
6077 Roo.form.Action.prototype = {
6079 failureType : undefined,
6080 response : undefined,
6084 run : function(options){
6089 success : function(response){
6094 handleResponse : function(response){
6098 // default connection failure
6099 failure : function(response){
6101 this.response = response;
6102 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6103 this.form.afterAction(this, false);
6106 processResponse : function(response){
6107 this.response = response;
6108 if(!response.responseText){
6111 this.result = this.handleResponse(response);
6115 // utility functions used internally
6116 getUrl : function(appendParams){
6117 var url = this.options.url || this.form.url || this.form.el.dom.action;
6119 var p = this.getParams();
6121 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6127 getMethod : function(){
6128 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6131 getParams : function(){
6132 var bp = this.form.baseParams;
6133 var p = this.options.params;
6135 if(typeof p == "object"){
6136 p = Roo.urlEncode(Roo.applyIf(p, bp));
6137 }else if(typeof p == 'string' && bp){
6138 p += '&' + Roo.urlEncode(bp);
6141 p = Roo.urlEncode(bp);
6146 createCallback : function(){
6148 success: this.success,
6149 failure: this.failure,
6151 timeout: (this.form.timeout*1000),
6152 upload: this.form.fileUpload ? this.success : undefined
6157 Roo.form.Action.Submit = function(form, options){
6158 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6161 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6164 haveProgress : false,
6165 uploadComplete : false,
6167 // uploadProgress indicator.
6168 uploadProgress : function()
6170 if (!this.form.progressUrl) {
6174 if (!this.haveProgress) {
6175 Roo.MessageBox.progress("Uploading", "Uploading");
6177 if (this.uploadComplete) {
6178 Roo.MessageBox.hide();
6182 this.haveProgress = true;
6184 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6186 var c = new Roo.data.Connection();
6188 url : this.form.progressUrl,
6193 success : function(req){
6194 //console.log(data);
6198 rdata = Roo.decode(req.responseText)
6200 Roo.log("Invalid data from server..");
6204 if (!rdata || !rdata.success) {
6206 Roo.MessageBox.alert(Roo.encode(rdata));
6209 var data = rdata.data;
6211 if (this.uploadComplete) {
6212 Roo.MessageBox.hide();
6217 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6218 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6221 this.uploadProgress.defer(2000,this);
6224 failure: function(data) {
6225 Roo.log('progress url failed ');
6236 // run get Values on the form, so it syncs any secondary forms.
6237 this.form.getValues();
6239 var o = this.options;
6240 var method = this.getMethod();
6241 var isPost = method == 'POST';
6242 if(o.clientValidation === false || this.form.isValid()){
6244 if (this.form.progressUrl) {
6245 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6246 (new Date() * 1) + '' + Math.random());
6251 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6252 form:this.form.el.dom,
6253 url:this.getUrl(!isPost),
6255 params:isPost ? this.getParams() : null,
6256 isUpload: this.form.fileUpload
6259 this.uploadProgress();
6261 }else if (o.clientValidation !== false){ // client validation failed
6262 this.failureType = Roo.form.Action.CLIENT_INVALID;
6263 this.form.afterAction(this, false);
6267 success : function(response)
6269 this.uploadComplete= true;
6270 if (this.haveProgress) {
6271 Roo.MessageBox.hide();
6275 var result = this.processResponse(response);
6276 if(result === true || result.success){
6277 this.form.afterAction(this, true);
6281 this.form.markInvalid(result.errors);
6282 this.failureType = Roo.form.Action.SERVER_INVALID;
6284 this.form.afterAction(this, false);
6286 failure : function(response)
6288 this.uploadComplete= true;
6289 if (this.haveProgress) {
6290 Roo.MessageBox.hide();
6293 this.response = response;
6294 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6295 this.form.afterAction(this, false);
6298 handleResponse : function(response){
6299 if(this.form.errorReader){
6300 var rs = this.form.errorReader.read(response);
6303 for(var i = 0, len = rs.records.length; i < len; i++) {
6304 var r = rs.records[i];
6308 if(errors.length < 1){
6312 success : rs.success,
6318 ret = Roo.decode(response.responseText);
6322 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6332 Roo.form.Action.Load = function(form, options){
6333 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6334 this.reader = this.form.reader;
6337 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6342 Roo.Ajax.request(Roo.apply(
6343 this.createCallback(), {
6344 method:this.getMethod(),
6345 url:this.getUrl(false),
6346 params:this.getParams()
6350 success : function(response){
6352 var result = this.processResponse(response);
6353 if(result === true || !result.success || !result.data){
6354 this.failureType = Roo.form.Action.LOAD_FAILURE;
6355 this.form.afterAction(this, false);
6358 this.form.clearInvalid();
6359 this.form.setValues(result.data);
6360 this.form.afterAction(this, true);
6363 handleResponse : function(response){
6364 if(this.form.reader){
6365 var rs = this.form.reader.read(response);
6366 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6368 success : rs.success,
6372 return Roo.decode(response.responseText);
6376 Roo.form.Action.ACTION_TYPES = {
6377 'load' : Roo.form.Action.Load,
6378 'submit' : Roo.form.Action.Submit
6387 * @class Roo.bootstrap.Form
6388 * @extends Roo.bootstrap.Component
6389 * Bootstrap Form class
6390 * @cfg {String} method GET | POST (default POST)
6391 * @cfg {String} labelAlign top | left (default top)
6392 * @cfg {String} align left | right - for navbars
6393 * @cfg {Boolean} loadMask load mask when submit (default true)
6398 * @param {Object} config The config object
6402 Roo.bootstrap.Form = function(config){
6403 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6406 * @event clientvalidation
6407 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6408 * @param {Form} this
6409 * @param {Boolean} valid true if the form has passed client-side validation
6411 clientvalidation: true,
6413 * @event beforeaction
6414 * Fires before any action is performed. Return false to cancel the action.
6415 * @param {Form} this
6416 * @param {Action} action The action to be performed
6420 * @event actionfailed
6421 * Fires when an action fails.
6422 * @param {Form} this
6423 * @param {Action} action The action that failed
6425 actionfailed : true,
6427 * @event actioncomplete
6428 * Fires when an action is completed.
6429 * @param {Form} this
6430 * @param {Action} action The action that completed
6432 actioncomplete : true
6437 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6440 * @cfg {String} method
6441 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6446 * The URL to use for form actions if one isn't supplied in the action options.
6449 * @cfg {Boolean} fileUpload
6450 * Set to true if this form is a file upload.
6454 * @cfg {Object} baseParams
6455 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6459 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6463 * @cfg {Sting} align (left|right) for navbar forms
6468 activeAction : null,
6471 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6472 * element by passing it or its id or mask the form itself by passing in true.
6475 waitMsgTarget : false,
6479 getAutoCreate : function(){
6483 method : this.method || 'POST',
6484 id : this.id || Roo.id(),
6487 if (this.parent().xtype.match(/^Nav/)) {
6488 cfg.cls = 'navbar-form navbar-' + this.align;
6492 if (this.labelAlign == 'left' ) {
6493 cfg.cls += ' form-horizontal';
6499 initEvents : function()
6501 this.el.on('submit', this.onSubmit, this);
6502 // this was added as random key presses on the form where triggering form submit.
6503 this.el.on('keypress', function(e) {
6504 if (e.getCharCode() != 13) {
6507 // we might need to allow it for textareas.. and some other items.
6508 // check e.getTarget().
6510 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6514 Roo.log("keypress blocked");
6522 onSubmit : function(e){
6527 * Returns true if client-side validation on the form is successful.
6530 isValid : function(){
6531 var items = this.getItems();
6533 items.each(function(f){
6542 * Returns true if any fields in this form have changed since their original load.
6545 isDirty : function(){
6547 var items = this.getItems();
6548 items.each(function(f){
6558 * Performs a predefined action (submit or load) or custom actions you define on this form.
6559 * @param {String} actionName The name of the action type
6560 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6561 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6562 * accept other config options):
6564 Property Type Description
6565 ---------------- --------------- ----------------------------------------------------------------------------------
6566 url String The url for the action (defaults to the form's url)
6567 method String The form method to use (defaults to the form's method, or POST if not defined)
6568 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6569 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6570 validate the form on the client (defaults to false)
6572 * @return {BasicForm} this
6574 doAction : function(action, options){
6575 if(typeof action == 'string'){
6576 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6578 if(this.fireEvent('beforeaction', this, action) !== false){
6579 this.beforeAction(action);
6580 action.run.defer(100, action);
6586 beforeAction : function(action){
6587 var o = action.options;
6590 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6592 // not really supported yet.. ??
6594 //if(this.waitMsgTarget === true){
6595 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6596 //}else if(this.waitMsgTarget){
6597 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6598 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6600 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6606 afterAction : function(action, success){
6607 this.activeAction = null;
6608 var o = action.options;
6610 //if(this.waitMsgTarget === true){
6612 //}else if(this.waitMsgTarget){
6613 // this.waitMsgTarget.unmask();
6615 // Roo.MessageBox.updateProgress(1);
6616 // Roo.MessageBox.hide();
6623 Roo.callback(o.success, o.scope, [this, action]);
6624 this.fireEvent('actioncomplete', this, action);
6628 // failure condition..
6629 // we have a scenario where updates need confirming.
6630 // eg. if a locking scenario exists..
6631 // we look for { errors : { needs_confirm : true }} in the response.
6633 (typeof(action.result) != 'undefined') &&
6634 (typeof(action.result.errors) != 'undefined') &&
6635 (typeof(action.result.errors.needs_confirm) != 'undefined')
6638 Roo.log("not supported yet");
6641 Roo.MessageBox.confirm(
6642 "Change requires confirmation",
6643 action.result.errorMsg,
6648 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6658 Roo.callback(o.failure, o.scope, [this, action]);
6659 // show an error message if no failed handler is set..
6660 if (!this.hasListener('actionfailed')) {
6661 Roo.log("need to add dialog support");
6663 Roo.MessageBox.alert("Error",
6664 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6665 action.result.errorMsg :
6666 "Saving Failed, please check your entries or try again"
6671 this.fireEvent('actionfailed', this, action);
6676 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6677 * @param {String} id The value to search for
6680 findField : function(id){
6681 var items = this.getItems();
6682 var field = items.get(id);
6684 items.each(function(f){
6685 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6692 return field || null;
6695 * Mark fields in this form invalid in bulk.
6696 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6697 * @return {BasicForm} this
6699 markInvalid : function(errors){
6700 if(errors instanceof Array){
6701 for(var i = 0, len = errors.length; i < len; i++){
6702 var fieldError = errors[i];
6703 var f = this.findField(fieldError.id);
6705 f.markInvalid(fieldError.msg);
6711 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6712 field.markInvalid(errors[id]);
6716 //Roo.each(this.childForms || [], function (f) {
6717 // f.markInvalid(errors);
6724 * Set values for fields in this form in bulk.
6725 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6726 * @return {BasicForm} this
6728 setValues : function(values){
6729 if(values instanceof Array){ // array of objects
6730 for(var i = 0, len = values.length; i < len; i++){
6732 var f = this.findField(v.id);
6734 f.setValue(v.value);
6735 if(this.trackResetOnLoad){
6736 f.originalValue = f.getValue();
6740 }else{ // object hash
6743 if(typeof values[id] != 'function' && (field = this.findField(id))){
6745 if (field.setFromData &&
6747 field.displayField &&
6748 // combos' with local stores can
6749 // be queried via setValue()
6750 // to set their value..
6751 (field.store && !field.store.isLocal)
6755 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6756 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6757 field.setFromData(sd);
6760 field.setValue(values[id]);
6764 if(this.trackResetOnLoad){
6765 field.originalValue = field.getValue();
6771 //Roo.each(this.childForms || [], function (f) {
6772 // f.setValues(values);
6779 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6780 * they are returned as an array.
6781 * @param {Boolean} asString
6784 getValues : function(asString){
6785 //if (this.childForms) {
6786 // copy values from the child forms
6787 // Roo.each(this.childForms, function (f) {
6788 // this.setValues(f.getValues());
6794 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6795 if(asString === true){
6798 return Roo.urlDecode(fs);
6802 * Returns the fields in this form as an object with key/value pairs.
6803 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6806 getFieldValues : function(with_hidden)
6808 var items = this.getItems();
6810 items.each(function(f){
6814 var v = f.getValue();
6815 if (f.inputType =='radio') {
6816 if (typeof(ret[f.getName()]) == 'undefined') {
6817 ret[f.getName()] = ''; // empty..
6820 if (!f.el.dom.checked) {
6828 // not sure if this supported any more..
6829 if ((typeof(v) == 'object') && f.getRawValue) {
6830 v = f.getRawValue() ; // dates..
6832 // combo boxes where name != hiddenName...
6833 if (f.name != f.getName()) {
6834 ret[f.name] = f.getRawValue();
6836 ret[f.getName()] = v;
6843 * Clears all invalid messages in this form.
6844 * @return {BasicForm} this
6846 clearInvalid : function(){
6847 var items = this.getItems();
6849 items.each(function(f){
6860 * @return {BasicForm} this
6863 var items = this.getItems();
6864 items.each(function(f){
6868 Roo.each(this.childForms || [], function (f) {
6875 getItems : function()
6877 var r=new Roo.util.MixedCollection(false, function(o){
6878 return o.id || (o.id = Roo.id());
6880 var iter = function(el) {
6887 Roo.each(el.items,function(e) {
6906 * Ext JS Library 1.1.1
6907 * Copyright(c) 2006-2007, Ext JS, LLC.
6909 * Originally Released Under LGPL - original licence link has changed is not relivant.
6912 * <script type="text/javascript">
6915 * @class Roo.form.VTypes
6916 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6919 Roo.form.VTypes = function(){
6920 // closure these in so they are only created once.
6921 var alpha = /^[a-zA-Z_]+$/;
6922 var alphanum = /^[a-zA-Z0-9_]+$/;
6923 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6924 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6926 // All these messages and functions are configurable
6929 * The function used to validate email addresses
6930 * @param {String} value The email address
6932 'email' : function(v){
6933 return email.test(v);
6936 * The error text to display when the email validation function returns false
6939 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6941 * The keystroke filter mask to be applied on email input
6944 'emailMask' : /[a-z0-9_\.\-@]/i,
6947 * The function used to validate URLs
6948 * @param {String} value The URL
6950 'url' : function(v){
6954 * The error text to display when the url validation function returns false
6957 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6960 * The function used to validate alpha values
6961 * @param {String} value The value
6963 'alpha' : function(v){
6964 return alpha.test(v);
6967 * The error text to display when the alpha validation function returns false
6970 'alphaText' : 'This field should only contain letters and _',
6972 * The keystroke filter mask to be applied on alpha input
6975 'alphaMask' : /[a-z_]/i,
6978 * The function used to validate alphanumeric values
6979 * @param {String} value The value
6981 'alphanum' : function(v){
6982 return alphanum.test(v);
6985 * The error text to display when the alphanumeric validation function returns false
6988 'alphanumText' : 'This field should only contain letters, numbers and _',
6990 * The keystroke filter mask to be applied on alphanumeric input
6993 'alphanumMask' : /[a-z0-9_]/i
7003 * @class Roo.bootstrap.Input
7004 * @extends Roo.bootstrap.Component
7005 * Bootstrap Input class
7006 * @cfg {Boolean} disabled is it disabled
7007 * @cfg {String} fieldLabel - the label associated
7008 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7009 * @cfg {String} name name of the input
7010 * @cfg {string} fieldLabel - the label associated
7011 * @cfg {string} inputType - input / file submit ...
7012 * @cfg {string} placeholder - placeholder to put in text.
7013 * @cfg {string} before - input group add on before
7014 * @cfg {string} after - input group add on after
7015 * @cfg {string} size - (lg|sm) or leave empty..
7016 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7017 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7018 * @cfg {Number} md colspan out of 12 for computer-sized screens
7019 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7020 * @cfg {string} value default value of the input
7021 * @cfg {Number} labelWidth set the width of label (0-12)
7022 * @cfg {String} labelAlign (top|left)
7023 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7024 * @cfg {String} align (left|center|right) Default left
7028 * Create a new Input
7029 * @param {Object} config The config object
7032 Roo.bootstrap.Input = function(config){
7033 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7038 * Fires when this field receives input focus.
7039 * @param {Roo.form.Field} this
7044 * Fires when this field loses input focus.
7045 * @param {Roo.form.Field} this
7050 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7051 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7052 * @param {Roo.form.Field} this
7053 * @param {Roo.EventObject} e The event object
7058 * Fires just before the field blurs if the field value has changed.
7059 * @param {Roo.form.Field} this
7060 * @param {Mixed} newValue The new value
7061 * @param {Mixed} oldValue The original value
7066 * Fires after the field has been marked as invalid.
7067 * @param {Roo.form.Field} this
7068 * @param {String} msg The validation message
7073 * Fires after the field has been validated with no errors.
7074 * @param {Roo.form.Field} this
7079 * Fires after the key up
7080 * @param {Roo.form.Field} this
7081 * @param {Roo.EventObject} e The event Object
7087 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7089 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7090 automatic validation (defaults to "keyup").
7092 validationEvent : "keyup",
7094 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7096 validateOnBlur : true,
7098 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7100 validationDelay : 250,
7102 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7104 focusClass : "x-form-focus", // not needed???
7108 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7110 invalidClass : "has-error",
7113 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7115 selectOnFocus : false,
7118 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7122 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7127 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7129 disableKeyFilter : false,
7132 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7136 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7140 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7142 blankText : "This field is required",
7145 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7149 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7151 maxLength : Number.MAX_VALUE,
7153 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7155 minLengthText : "The minimum length for this field is {0}",
7157 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7159 maxLengthText : "The maximum length for this field is {0}",
7163 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7164 * If available, this function will be called only after the basic validators all return true, and will be passed the
7165 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7169 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7170 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7171 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7175 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7198 formatedValue : false,
7200 parentLabelAlign : function()
7203 while (parent.parent()) {
7204 parent = parent.parent();
7205 if (typeof(parent.labelAlign) !='undefined') {
7206 return parent.labelAlign;
7213 getAutoCreate : function(){
7215 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7221 if(this.inputType != 'hidden'){
7222 cfg.cls = 'form-group' //input-group
7228 type : this.inputType,
7230 cls : 'form-control',
7231 placeholder : this.placeholder || ''
7236 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7239 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7240 input.maxLength = this.maxLength;
7243 if (this.disabled) {
7244 input.disabled=true;
7247 if (this.readOnly) {
7248 input.readonly=true;
7252 input.name = this.name;
7255 input.cls += ' input-' + this.size;
7258 ['xs','sm','md','lg'].map(function(size){
7259 if (settings[size]) {
7260 cfg.cls += ' col-' + size + '-' + settings[size];
7264 var inputblock = input;
7266 if (this.before || this.after) {
7269 cls : 'input-group',
7272 if (this.before && typeof(this.before) == 'string') {
7274 inputblock.cn.push({
7276 cls : 'roo-input-before input-group-addon',
7280 if (this.before && typeof(this.before) == 'object') {
7281 this.before = Roo.factory(this.before);
7282 Roo.log(this.before);
7283 inputblock.cn.push({
7285 cls : 'roo-input-before input-group-' +
7286 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7290 inputblock.cn.push(input);
7292 if (this.after && typeof(this.after) == 'string') {
7293 inputblock.cn.push({
7295 cls : 'roo-input-after input-group-addon',
7299 if (this.after && typeof(this.after) == 'object') {
7300 this.after = Roo.factory(this.after);
7301 Roo.log(this.after);
7302 inputblock.cn.push({
7304 cls : 'roo-input-after input-group-' +
7305 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7310 if (align ==='left' && this.fieldLabel.length) {
7311 Roo.log("left and has label");
7317 cls : 'control-label col-sm-' + this.labelWidth,
7318 html : this.fieldLabel
7322 cls : "col-sm-" + (12 - this.labelWidth),
7329 } else if ( this.fieldLabel.length) {
7335 //cls : 'input-group-addon',
7336 html : this.fieldLabel
7346 Roo.log(" no label && no align");
7355 Roo.log('input-parentType: ' + this.parentType);
7357 if (this.parentType === 'Navbar' && this.parent().bar) {
7358 cfg.cls += ' navbar-form';
7366 * return the real input element.
7368 inputEl: function ()
7370 return this.el.select('input.form-control',true).first();
7373 tooltipEl : function()
7375 return this.inputEl();
7378 setDisabled : function(v)
7380 var i = this.inputEl().dom;
7382 i.removeAttribute('disabled');
7386 i.setAttribute('disabled','true');
7388 initEvents : function()
7391 this.inputEl().on("keydown" , this.fireKey, this);
7392 this.inputEl().on("focus", this.onFocus, this);
7393 this.inputEl().on("blur", this.onBlur, this);
7395 this.inputEl().relayEvent('keyup', this);
7397 // reference to original value for reset
7398 this.originalValue = this.getValue();
7399 //Roo.form.TextField.superclass.initEvents.call(this);
7400 if(this.validationEvent == 'keyup'){
7401 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7402 this.inputEl().on('keyup', this.filterValidation, this);
7404 else if(this.validationEvent !== false){
7405 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7408 if(this.selectOnFocus){
7409 this.on("focus", this.preFocus, this);
7412 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7413 this.inputEl().on("keypress", this.filterKeys, this);
7416 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7417 this.el.on("click", this.autoSize, this);
7420 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7421 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7424 if (typeof(this.before) == 'object') {
7425 this.before.render(this.el.select('.roo-input-before',true).first());
7427 if (typeof(this.after) == 'object') {
7428 this.after.render(this.el.select('.roo-input-after',true).first());
7433 filterValidation : function(e){
7434 if(!e.isNavKeyPress()){
7435 this.validationTask.delay(this.validationDelay);
7439 * Validates the field value
7440 * @return {Boolean} True if the value is valid, else false
7442 validate : function(){
7443 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7444 if(this.disabled || this.validateValue(this.getRawValue())){
7445 this.clearInvalid();
7453 * Validates a value according to the field's validation rules and marks the field as invalid
7454 * if the validation fails
7455 * @param {Mixed} value The value to validate
7456 * @return {Boolean} True if the value is valid, else false
7458 validateValue : function(value){
7459 if(value.length < 1) { // if it's blank
7460 if(this.allowBlank){
7461 this.clearInvalid();
7464 this.markInvalid(this.blankText);
7468 if(value.length < this.minLength){
7469 this.markInvalid(String.format(this.minLengthText, this.minLength));
7472 if(value.length > this.maxLength){
7473 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7477 var vt = Roo.form.VTypes;
7478 if(!vt[this.vtype](value, this)){
7479 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7483 if(typeof this.validator == "function"){
7484 var msg = this.validator(value);
7486 this.markInvalid(msg);
7490 if(this.regex && !this.regex.test(value)){
7491 this.markInvalid(this.regexText);
7500 fireKey : function(e){
7501 //Roo.log('field ' + e.getKey());
7502 if(e.isNavKeyPress()){
7503 this.fireEvent("specialkey", this, e);
7506 focus : function (selectText){
7508 this.inputEl().focus();
7509 if(selectText === true){
7510 this.inputEl().dom.select();
7516 onFocus : function(){
7517 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7518 // this.el.addClass(this.focusClass);
7521 this.hasFocus = true;
7522 this.startValue = this.getValue();
7523 this.fireEvent("focus", this);
7527 beforeBlur : Roo.emptyFn,
7531 onBlur : function(){
7533 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7534 //this.el.removeClass(this.focusClass);
7536 this.hasFocus = false;
7537 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7540 var v = this.getValue();
7541 if(String(v) !== String(this.startValue)){
7542 this.fireEvent('change', this, v, this.startValue);
7544 this.fireEvent("blur", this);
7548 * Resets the current field value to the originally loaded value and clears any validation messages
7551 this.setValue(this.originalValue);
7552 this.clearInvalid();
7555 * Returns the name of the field
7556 * @return {Mixed} name The name field
7558 getName: function(){
7562 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7563 * @return {Mixed} value The field value
7565 getValue : function(){
7567 var v = this.inputEl().getValue();
7572 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7573 * @return {Mixed} value The field value
7575 getRawValue : function(){
7576 var v = this.inputEl().getValue();
7582 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7583 * @param {Mixed} value The value to set
7585 setRawValue : function(v){
7586 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7589 selectText : function(start, end){
7590 var v = this.getRawValue();
7592 start = start === undefined ? 0 : start;
7593 end = end === undefined ? v.length : end;
7594 var d = this.inputEl().dom;
7595 if(d.setSelectionRange){
7596 d.setSelectionRange(start, end);
7597 }else if(d.createTextRange){
7598 var range = d.createTextRange();
7599 range.moveStart("character", start);
7600 range.moveEnd("character", v.length-end);
7607 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7608 * @param {Mixed} value The value to set
7610 setValue : function(v){
7613 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7619 processValue : function(value){
7620 if(this.stripCharsRe){
7621 var newValue = value.replace(this.stripCharsRe, '');
7622 if(newValue !== value){
7623 this.setRawValue(newValue);
7630 preFocus : function(){
7632 if(this.selectOnFocus){
7633 this.inputEl().dom.select();
7636 filterKeys : function(e){
7638 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7641 var c = e.getCharCode(), cc = String.fromCharCode(c);
7642 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7645 if(!this.maskRe.test(cc)){
7650 * Clear any invalid styles/messages for this field
7652 clearInvalid : function(){
7654 if(!this.el || this.preventMark){ // not rendered
7657 this.el.removeClass(this.invalidClass);
7659 switch(this.msgTarget){
7661 this.el.dom.qtip = '';
7664 this.el.dom.title = '';
7668 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7673 this.errorIcon.dom.qtip = '';
7674 this.errorIcon.hide();
7675 this.un('resize', this.alignErrorIcon, this);
7679 var t = Roo.getDom(this.msgTarget);
7681 t.style.display = 'none';
7685 this.fireEvent('valid', this);
7688 * Mark this field as invalid
7689 * @param {String} msg The validation message
7691 markInvalid : function(msg){
7692 if(!this.el || this.preventMark){ // not rendered
7695 this.el.addClass(this.invalidClass);
7697 msg = msg || this.invalidText;
7698 switch(this.msgTarget){
7700 this.el.dom.qtip = msg;
7701 this.el.dom.qclass = 'x-form-invalid-tip';
7702 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7703 Roo.QuickTips.enable();
7707 this.el.dom.title = msg;
7711 var elp = this.el.findParent('.x-form-element', 5, true);
7712 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7713 this.errorEl.setWidth(elp.getWidth(true)-20);
7715 this.errorEl.update(msg);
7716 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7719 if(!this.errorIcon){
7720 var elp = this.el.findParent('.x-form-element', 5, true);
7721 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7723 this.alignErrorIcon();
7724 this.errorIcon.dom.qtip = msg;
7725 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7726 this.errorIcon.show();
7727 this.on('resize', this.alignErrorIcon, this);
7730 var t = Roo.getDom(this.msgTarget);
7732 t.style.display = this.msgDisplay;
7736 this.fireEvent('invalid', this, msg);
7739 SafariOnKeyDown : function(event)
7741 // this is a workaround for a password hang bug on chrome/ webkit.
7743 var isSelectAll = false;
7745 if(this.inputEl().dom.selectionEnd > 0){
7746 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7748 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7749 event.preventDefault();
7754 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7756 event.preventDefault();
7757 // this is very hacky as keydown always get's upper case.
7759 var cc = String.fromCharCode(event.getCharCode());
7760 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7764 adjustWidth : function(tag, w){
7765 tag = tag.toLowerCase();
7766 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7767 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7771 if(tag == 'textarea'){
7774 }else if(Roo.isOpera){
7778 if(tag == 'textarea'){
7797 * @class Roo.bootstrap.TextArea
7798 * @extends Roo.bootstrap.Input
7799 * Bootstrap TextArea class
7800 * @cfg {Number} cols Specifies the visible width of a text area
7801 * @cfg {Number} rows Specifies the visible number of lines in a text area
7802 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7803 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7804 * @cfg {string} html text
7807 * Create a new TextArea
7808 * @param {Object} config The config object
7811 Roo.bootstrap.TextArea = function(config){
7812 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7816 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7826 getAutoCreate : function(){
7828 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7839 value : this.value || '',
7840 html: this.html || '',
7841 cls : 'form-control',
7842 placeholder : this.placeholder || ''
7846 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7847 input.maxLength = this.maxLength;
7851 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7855 input.cols = this.cols;
7858 if (this.readOnly) {
7859 input.readonly = true;
7863 input.name = this.name;
7867 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7871 ['xs','sm','md','lg'].map(function(size){
7872 if (settings[size]) {
7873 cfg.cls += ' col-' + size + '-' + settings[size];
7877 var inputblock = input;
7879 if (this.before || this.after) {
7882 cls : 'input-group',
7886 inputblock.cn.push({
7888 cls : 'input-group-addon',
7892 inputblock.cn.push(input);
7894 inputblock.cn.push({
7896 cls : 'input-group-addon',
7903 if (align ==='left' && this.fieldLabel.length) {
7904 Roo.log("left and has label");
7910 cls : 'control-label col-sm-' + this.labelWidth,
7911 html : this.fieldLabel
7915 cls : "col-sm-" + (12 - this.labelWidth),
7922 } else if ( this.fieldLabel.length) {
7928 //cls : 'input-group-addon',
7929 html : this.fieldLabel
7939 Roo.log(" no label && no align");
7949 if (this.disabled) {
7950 input.disabled=true;
7957 * return the real textarea element.
7959 inputEl: function ()
7961 return this.el.select('textarea.form-control',true).first();
7969 * trigger field - base class for combo..
7974 * @class Roo.bootstrap.TriggerField
7975 * @extends Roo.bootstrap.Input
7976 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7977 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7978 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7979 * for which you can provide a custom implementation. For example:
7981 var trigger = new Roo.bootstrap.TriggerField();
7982 trigger.onTriggerClick = myTriggerFn;
7983 trigger.applyTo('my-field');
7986 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7987 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7988 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7989 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7990 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
7993 * Create a new TriggerField.
7994 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7995 * to the base TextField)
7997 Roo.bootstrap.TriggerField = function(config){
7998 this.mimicing = false;
7999 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8002 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8004 * @cfg {String} triggerClass A CSS class to apply to the trigger
8007 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8011 /** @cfg {Boolean} grow @hide */
8012 /** @cfg {Number} growMin @hide */
8013 /** @cfg {Number} growMax @hide */
8019 autoSize: Roo.emptyFn,
8026 actionMode : 'wrap',
8031 getAutoCreate : function(){
8033 var align = this.labelAlign || this.parentLabelAlign();
8038 cls: 'form-group' //input-group
8045 type : this.inputType,
8046 cls : 'form-control',
8047 autocomplete: 'false',
8048 placeholder : this.placeholder || ''
8052 input.name = this.name;
8055 input.cls += ' input-' + this.size;
8058 if (this.disabled) {
8059 input.disabled=true;
8062 var inputblock = input;
8064 if (this.before || this.after) {
8067 cls : 'input-group',
8071 inputblock.cn.push({
8073 cls : 'input-group-addon',
8077 inputblock.cn.push(input);
8079 inputblock.cn.push({
8081 cls : 'input-group-addon',
8094 cls: 'form-hidden-field'
8102 Roo.log('multiple');
8110 cls: 'form-hidden-field'
8114 cls: 'select2-choices',
8118 cls: 'select2-search-field',
8131 cls: 'select2-container input-group',
8136 // cls: 'typeahead typeahead-long dropdown-menu',
8137 // style: 'display:none'
8142 if(!this.multiple && this.showToggleBtn){
8148 if (this.caret != false) {
8151 cls: 'fa fa-' + this.caret
8158 cls : 'input-group-addon btn dropdown-toggle',
8163 cls: 'combobox-clear',
8177 combobox.cls += ' select2-container-multi';
8180 if (align ==='left' && this.fieldLabel.length) {
8182 Roo.log("left and has label");
8188 cls : 'control-label col-sm-' + this.labelWidth,
8189 html : this.fieldLabel
8193 cls : "col-sm-" + (12 - this.labelWidth),
8200 } else if ( this.fieldLabel.length) {
8206 //cls : 'input-group-addon',
8207 html : this.fieldLabel
8217 Roo.log(" no label && no align");
8224 ['xs','sm','md','lg'].map(function(size){
8225 if (settings[size]) {
8226 cfg.cls += ' col-' + size + '-' + settings[size];
8237 onResize : function(w, h){
8238 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8239 // if(typeof w == 'number'){
8240 // var x = w - this.trigger.getWidth();
8241 // this.inputEl().setWidth(this.adjustWidth('input', x));
8242 // this.trigger.setStyle('left', x+'px');
8247 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8250 getResizeEl : function(){
8251 return this.inputEl();
8255 getPositionEl : function(){
8256 return this.inputEl();
8260 alignErrorIcon : function(){
8261 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8265 initEvents : function(){
8269 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8270 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8271 if(!this.multiple && this.showToggleBtn){
8272 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8273 if(this.hideTrigger){
8274 this.trigger.setDisplayed(false);
8276 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8280 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8283 //this.trigger.addClassOnOver('x-form-trigger-over');
8284 //this.trigger.addClassOnClick('x-form-trigger-click');
8287 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8291 createList : function()
8293 this.list = Roo.get(document.body).createChild({
8295 cls: 'typeahead typeahead-long dropdown-menu',
8296 style: 'display:none'
8299 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8304 initTrigger : function(){
8309 onDestroy : function(){
8311 this.trigger.removeAllListeners();
8312 // this.trigger.remove();
8315 // this.wrap.remove();
8317 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8321 onFocus : function(){
8322 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8325 this.wrap.addClass('x-trigger-wrap-focus');
8326 this.mimicing = true;
8327 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8328 if(this.monitorTab){
8329 this.el.on("keydown", this.checkTab, this);
8336 checkTab : function(e){
8337 if(e.getKey() == e.TAB){
8343 onBlur : function(){
8348 mimicBlur : function(e, t){
8350 if(!this.wrap.contains(t) && this.validateBlur()){
8357 triggerBlur : function(){
8358 this.mimicing = false;
8359 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8360 if(this.monitorTab){
8361 this.el.un("keydown", this.checkTab, this);
8363 //this.wrap.removeClass('x-trigger-wrap-focus');
8364 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8368 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8369 validateBlur : function(e, t){
8374 onDisable : function(){
8375 this.inputEl().dom.disabled = true;
8376 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8378 // this.wrap.addClass('x-item-disabled');
8383 onEnable : function(){
8384 this.inputEl().dom.disabled = false;
8385 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8387 // this.el.removeClass('x-item-disabled');
8392 onShow : function(){
8393 var ae = this.getActionEl();
8396 ae.dom.style.display = '';
8397 ae.dom.style.visibility = 'visible';
8403 onHide : function(){
8404 var ae = this.getActionEl();
8405 ae.dom.style.display = 'none';
8409 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8410 * by an implementing function.
8412 * @param {EventObject} e
8414 onTriggerClick : Roo.emptyFn
8418 * Ext JS Library 1.1.1
8419 * Copyright(c) 2006-2007, Ext JS, LLC.
8421 * Originally Released Under LGPL - original licence link has changed is not relivant.
8424 * <script type="text/javascript">
8429 * @class Roo.data.SortTypes
8431 * Defines the default sorting (casting?) comparison functions used when sorting data.
8433 Roo.data.SortTypes = {
8435 * Default sort that does nothing
8436 * @param {Mixed} s The value being converted
8437 * @return {Mixed} The comparison value
8444 * The regular expression used to strip tags
8448 stripTagsRE : /<\/?[^>]+>/gi,
8451 * Strips all HTML tags to sort on text only
8452 * @param {Mixed} s The value being converted
8453 * @return {String} The comparison value
8455 asText : function(s){
8456 return String(s).replace(this.stripTagsRE, "");
8460 * Strips all HTML tags to sort on text only - Case insensitive
8461 * @param {Mixed} s The value being converted
8462 * @return {String} The comparison value
8464 asUCText : function(s){
8465 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8469 * Case insensitive string
8470 * @param {Mixed} s The value being converted
8471 * @return {String} The comparison value
8473 asUCString : function(s) {
8474 return String(s).toUpperCase();
8479 * @param {Mixed} s The value being converted
8480 * @return {Number} The comparison value
8482 asDate : function(s) {
8486 if(s instanceof Date){
8489 return Date.parse(String(s));
8494 * @param {Mixed} s The value being converted
8495 * @return {Float} The comparison value
8497 asFloat : function(s) {
8498 var val = parseFloat(String(s).replace(/,/g, ""));
8499 if(isNaN(val)) val = 0;
8505 * @param {Mixed} s The value being converted
8506 * @return {Number} The comparison value
8508 asInt : function(s) {
8509 var val = parseInt(String(s).replace(/,/g, ""));
8510 if(isNaN(val)) val = 0;
8515 * Ext JS Library 1.1.1
8516 * Copyright(c) 2006-2007, Ext JS, LLC.
8518 * Originally Released Under LGPL - original licence link has changed is not relivant.
8521 * <script type="text/javascript">
8525 * @class Roo.data.Record
8526 * Instances of this class encapsulate both record <em>definition</em> information, and record
8527 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8528 * to access Records cached in an {@link Roo.data.Store} object.<br>
8530 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8531 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8534 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8536 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8537 * {@link #create}. The parameters are the same.
8538 * @param {Array} data An associative Array of data values keyed by the field name.
8539 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8540 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8541 * not specified an integer id is generated.
8543 Roo.data.Record = function(data, id){
8544 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8549 * Generate a constructor for a specific record layout.
8550 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8551 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8552 * Each field definition object may contain the following properties: <ul>
8553 * <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,
8554 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8555 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8556 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8557 * is being used, then this is a string containing the javascript expression to reference the data relative to
8558 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8559 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8560 * this may be omitted.</p></li>
8561 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8562 * <ul><li>auto (Default, implies no conversion)</li>
8567 * <li>date</li></ul></p></li>
8568 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8569 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8570 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8571 * by the Reader into an object that will be stored in the Record. It is passed the
8572 * following parameters:<ul>
8573 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8575 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8577 * <br>usage:<br><pre><code>
8578 var TopicRecord = Roo.data.Record.create(
8579 {name: 'title', mapping: 'topic_title'},
8580 {name: 'author', mapping: 'username'},
8581 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8582 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8583 {name: 'lastPoster', mapping: 'user2'},
8584 {name: 'excerpt', mapping: 'post_text'}
8587 var myNewRecord = new TopicRecord({
8588 title: 'Do my job please',
8591 lastPost: new Date(),
8592 lastPoster: 'Animal',
8593 excerpt: 'No way dude!'
8595 myStore.add(myNewRecord);
8600 Roo.data.Record.create = function(o){
8602 f.superclass.constructor.apply(this, arguments);
8604 Roo.extend(f, Roo.data.Record);
8605 var p = f.prototype;
8606 p.fields = new Roo.util.MixedCollection(false, function(field){
8609 for(var i = 0, len = o.length; i < len; i++){
8610 p.fields.add(new Roo.data.Field(o[i]));
8612 f.getField = function(name){
8613 return p.fields.get(name);
8618 Roo.data.Record.AUTO_ID = 1000;
8619 Roo.data.Record.EDIT = 'edit';
8620 Roo.data.Record.REJECT = 'reject';
8621 Roo.data.Record.COMMIT = 'commit';
8623 Roo.data.Record.prototype = {
8625 * Readonly flag - true if this record has been modified.
8634 join : function(store){
8639 * Set the named field to the specified value.
8640 * @param {String} name The name of the field to set.
8641 * @param {Object} value The value to set the field to.
8643 set : function(name, value){
8644 if(this.data[name] == value){
8651 if(typeof this.modified[name] == 'undefined'){
8652 this.modified[name] = this.data[name];
8654 this.data[name] = value;
8655 if(!this.editing && this.store){
8656 this.store.afterEdit(this);
8661 * Get the value of the named field.
8662 * @param {String} name The name of the field to get the value of.
8663 * @return {Object} The value of the field.
8665 get : function(name){
8666 return this.data[name];
8670 beginEdit : function(){
8671 this.editing = true;
8676 cancelEdit : function(){
8677 this.editing = false;
8678 delete this.modified;
8682 endEdit : function(){
8683 this.editing = false;
8684 if(this.dirty && this.store){
8685 this.store.afterEdit(this);
8690 * Usually called by the {@link Roo.data.Store} which owns the Record.
8691 * Rejects all changes made to the Record since either creation, or the last commit operation.
8692 * Modified fields are reverted to their original values.
8694 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8695 * of reject operations.
8697 reject : function(){
8698 var m = this.modified;
8700 if(typeof m[n] != "function"){
8701 this.data[n] = m[n];
8705 delete this.modified;
8706 this.editing = false;
8708 this.store.afterReject(this);
8713 * Usually called by the {@link Roo.data.Store} which owns the Record.
8714 * Commits all changes made to the Record since either creation, or the last commit operation.
8716 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8717 * of commit operations.
8719 commit : function(){
8721 delete this.modified;
8722 this.editing = false;
8724 this.store.afterCommit(this);
8729 hasError : function(){
8730 return this.error != null;
8734 clearError : function(){
8739 * Creates a copy of this record.
8740 * @param {String} id (optional) A new record id if you don't want to use this record's id
8743 copy : function(newId) {
8744 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8748 * Ext JS Library 1.1.1
8749 * Copyright(c) 2006-2007, Ext JS, LLC.
8751 * Originally Released Under LGPL - original licence link has changed is not relivant.
8754 * <script type="text/javascript">
8760 * @class Roo.data.Store
8761 * @extends Roo.util.Observable
8762 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8763 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8765 * 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
8766 * has no knowledge of the format of the data returned by the Proxy.<br>
8768 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8769 * instances from the data object. These records are cached and made available through accessor functions.
8771 * Creates a new Store.
8772 * @param {Object} config A config object containing the objects needed for the Store to access data,
8773 * and read the data into Records.
8775 Roo.data.Store = function(config){
8776 this.data = new Roo.util.MixedCollection(false);
8777 this.data.getKey = function(o){
8780 this.baseParams = {};
8787 "multisort" : "_multisort"
8790 if(config && config.data){
8791 this.inlineData = config.data;
8795 Roo.apply(this, config);
8797 if(this.reader){ // reader passed
8798 this.reader = Roo.factory(this.reader, Roo.data);
8799 this.reader.xmodule = this.xmodule || false;
8800 if(!this.recordType){
8801 this.recordType = this.reader.recordType;
8803 if(this.reader.onMetaChange){
8804 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8808 if(this.recordType){
8809 this.fields = this.recordType.prototype.fields;
8815 * @event datachanged
8816 * Fires when the data cache has changed, and a widget which is using this Store
8817 * as a Record cache should refresh its view.
8818 * @param {Store} this
8823 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8824 * @param {Store} this
8825 * @param {Object} meta The JSON metadata
8830 * Fires when Records have been added to the Store
8831 * @param {Store} this
8832 * @param {Roo.data.Record[]} records The array of Records added
8833 * @param {Number} index The index at which the record(s) were added
8838 * Fires when a Record has been removed from the Store
8839 * @param {Store} this
8840 * @param {Roo.data.Record} record The Record that was removed
8841 * @param {Number} index The index at which the record was removed
8846 * Fires when a Record has been updated
8847 * @param {Store} this
8848 * @param {Roo.data.Record} record The Record that was updated
8849 * @param {String} operation The update operation being performed. Value may be one of:
8851 Roo.data.Record.EDIT
8852 Roo.data.Record.REJECT
8853 Roo.data.Record.COMMIT
8859 * Fires when the data cache has been cleared.
8860 * @param {Store} this
8865 * Fires before a request is made for a new data object. If the beforeload handler returns false
8866 * the load action will be canceled.
8867 * @param {Store} this
8868 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8872 * @event beforeloadadd
8873 * Fires after a new set of Records has been loaded.
8874 * @param {Store} this
8875 * @param {Roo.data.Record[]} records The Records that were loaded
8876 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8878 beforeloadadd : true,
8881 * Fires after a new set of Records has been loaded, before they are added to the store.
8882 * @param {Store} this
8883 * @param {Roo.data.Record[]} records The Records that were loaded
8884 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8885 * @params {Object} return from reader
8889 * @event loadexception
8890 * Fires if an exception occurs in the Proxy during loading.
8891 * Called with the signature of the Proxy's "loadexception" event.
8892 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8895 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8896 * @param {Object} load options
8897 * @param {Object} jsonData from your request (normally this contains the Exception)
8899 loadexception : true
8903 this.proxy = Roo.factory(this.proxy, Roo.data);
8904 this.proxy.xmodule = this.xmodule || false;
8905 this.relayEvents(this.proxy, ["loadexception"]);
8907 this.sortToggle = {};
8908 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8910 Roo.data.Store.superclass.constructor.call(this);
8912 if(this.inlineData){
8913 this.loadData(this.inlineData);
8914 delete this.inlineData;
8918 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8920 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8921 * without a remote query - used by combo/forms at present.
8925 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8928 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8931 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8932 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8935 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8936 * on any HTTP request
8939 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8942 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8946 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8947 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8952 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8953 * loaded or when a record is removed. (defaults to false).
8955 pruneModifiedRecords : false,
8961 * Add Records to the Store and fires the add event.
8962 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8964 add : function(records){
8965 records = [].concat(records);
8966 for(var i = 0, len = records.length; i < len; i++){
8967 records[i].join(this);
8969 var index = this.data.length;
8970 this.data.addAll(records);
8971 this.fireEvent("add", this, records, index);
8975 * Remove a Record from the Store and fires the remove event.
8976 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8978 remove : function(record){
8979 var index = this.data.indexOf(record);
8980 this.data.removeAt(index);
8981 if(this.pruneModifiedRecords){
8982 this.modified.remove(record);
8984 this.fireEvent("remove", this, record, index);
8988 * Remove all Records from the Store and fires the clear event.
8990 removeAll : function(){
8992 if(this.pruneModifiedRecords){
8995 this.fireEvent("clear", this);
8999 * Inserts Records to the Store at the given index and fires the add event.
9000 * @param {Number} index The start index at which to insert the passed Records.
9001 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9003 insert : function(index, records){
9004 records = [].concat(records);
9005 for(var i = 0, len = records.length; i < len; i++){
9006 this.data.insert(index, records[i]);
9007 records[i].join(this);
9009 this.fireEvent("add", this, records, index);
9013 * Get the index within the cache of the passed Record.
9014 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9015 * @return {Number} The index of the passed Record. Returns -1 if not found.
9017 indexOf : function(record){
9018 return this.data.indexOf(record);
9022 * Get the index within the cache of the Record with the passed id.
9023 * @param {String} id The id of the Record to find.
9024 * @return {Number} The index of the Record. Returns -1 if not found.
9026 indexOfId : function(id){
9027 return this.data.indexOfKey(id);
9031 * Get the Record with the specified id.
9032 * @param {String} id The id of the Record to find.
9033 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9035 getById : function(id){
9036 return this.data.key(id);
9040 * Get the Record at the specified index.
9041 * @param {Number} index The index of the Record to find.
9042 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9044 getAt : function(index){
9045 return this.data.itemAt(index);
9049 * Returns a range of Records between specified indices.
9050 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9051 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9052 * @return {Roo.data.Record[]} An array of Records
9054 getRange : function(start, end){
9055 return this.data.getRange(start, end);
9059 storeOptions : function(o){
9060 o = Roo.apply({}, o);
9063 this.lastOptions = o;
9067 * Loads the Record cache from the configured Proxy using the configured Reader.
9069 * If using remote paging, then the first load call must specify the <em>start</em>
9070 * and <em>limit</em> properties in the options.params property to establish the initial
9071 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9073 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9074 * and this call will return before the new data has been loaded. Perform any post-processing
9075 * in a callback function, or in a "load" event handler.</strong>
9077 * @param {Object} options An object containing properties which control loading options:<ul>
9078 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9079 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9080 * passed the following arguments:<ul>
9081 * <li>r : Roo.data.Record[]</li>
9082 * <li>options: Options object from the load call</li>
9083 * <li>success: Boolean success indicator</li></ul></li>
9084 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9085 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9088 load : function(options){
9089 options = options || {};
9090 if(this.fireEvent("beforeload", this, options) !== false){
9091 this.storeOptions(options);
9092 var p = Roo.apply(options.params || {}, this.baseParams);
9093 // if meta was not loaded from remote source.. try requesting it.
9094 if (!this.reader.metaFromRemote) {
9097 if(this.sortInfo && this.remoteSort){
9098 var pn = this.paramNames;
9099 p[pn["sort"]] = this.sortInfo.field;
9100 p[pn["dir"]] = this.sortInfo.direction;
9102 if (this.multiSort) {
9103 var pn = this.paramNames;
9104 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9107 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9112 * Reloads the Record cache from the configured Proxy using the configured Reader and
9113 * the options from the last load operation performed.
9114 * @param {Object} options (optional) An object containing properties which may override the options
9115 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9116 * the most recently used options are reused).
9118 reload : function(options){
9119 this.load(Roo.applyIf(options||{}, this.lastOptions));
9123 // Called as a callback by the Reader during a load operation.
9124 loadRecords : function(o, options, success){
9125 if(!o || success === false){
9126 if(success !== false){
9127 this.fireEvent("load", this, [], options, o);
9129 if(options.callback){
9130 options.callback.call(options.scope || this, [], options, false);
9134 // if data returned failure - throw an exception.
9135 if (o.success === false) {
9136 // show a message if no listener is registered.
9137 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9138 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9140 // loadmask wil be hooked into this..
9141 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9144 var r = o.records, t = o.totalRecords || r.length;
9146 this.fireEvent("beforeloadadd", this, r, options, o);
9148 if(!options || options.add !== true){
9149 if(this.pruneModifiedRecords){
9152 for(var i = 0, len = r.length; i < len; i++){
9156 this.data = this.snapshot;
9157 delete this.snapshot;
9160 this.data.addAll(r);
9161 this.totalLength = t;
9163 this.fireEvent("datachanged", this);
9165 this.totalLength = Math.max(t, this.data.length+r.length);
9168 this.fireEvent("load", this, r, options, o);
9169 if(options.callback){
9170 options.callback.call(options.scope || this, r, options, true);
9176 * Loads data from a passed data block. A Reader which understands the format of the data
9177 * must have been configured in the constructor.
9178 * @param {Object} data The data block from which to read the Records. The format of the data expected
9179 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9180 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9182 loadData : function(o, append){
9183 var r = this.reader.readRecords(o);
9184 this.loadRecords(r, {add: append}, true);
9188 * Gets the number of cached records.
9190 * <em>If using paging, this may not be the total size of the dataset. If the data object
9191 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9192 * the data set size</em>
9194 getCount : function(){
9195 return this.data.length || 0;
9199 * Gets the total number of records in the dataset as returned by the server.
9201 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9202 * the dataset size</em>
9204 getTotalCount : function(){
9205 return this.totalLength || 0;
9209 * Returns the sort state of the Store as an object with two properties:
9211 field {String} The name of the field by which the Records are sorted
9212 direction {String} The sort order, "ASC" or "DESC"
9215 getSortState : function(){
9216 return this.sortInfo;
9220 applySort : function(){
9221 if(this.sortInfo && !this.remoteSort){
9222 var s = this.sortInfo, f = s.field;
9223 var st = this.fields.get(f).sortType;
9224 var fn = function(r1, r2){
9225 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9226 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9228 this.data.sort(s.direction, fn);
9229 if(this.snapshot && this.snapshot != this.data){
9230 this.snapshot.sort(s.direction, fn);
9236 * Sets the default sort column and order to be used by the next load operation.
9237 * @param {String} fieldName The name of the field to sort by.
9238 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9240 setDefaultSort : function(field, dir){
9241 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9246 * If remote sorting is used, the sort is performed on the server, and the cache is
9247 * reloaded. If local sorting is used, the cache is sorted internally.
9248 * @param {String} fieldName The name of the field to sort by.
9249 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9251 sort : function(fieldName, dir){
9252 var f = this.fields.get(fieldName);
9254 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9256 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9257 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9262 this.sortToggle[f.name] = dir;
9263 this.sortInfo = {field: f.name, direction: dir};
9264 if(!this.remoteSort){
9266 this.fireEvent("datachanged", this);
9268 this.load(this.lastOptions);
9273 * Calls the specified function for each of the Records in the cache.
9274 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9275 * Returning <em>false</em> aborts and exits the iteration.
9276 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9278 each : function(fn, scope){
9279 this.data.each(fn, scope);
9283 * Gets all records modified since the last commit. Modified records are persisted across load operations
9284 * (e.g., during paging).
9285 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9287 getModifiedRecords : function(){
9288 return this.modified;
9292 createFilterFn : function(property, value, anyMatch){
9293 if(!value.exec){ // not a regex
9294 value = String(value);
9295 if(value.length == 0){
9298 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9301 return value.test(r.data[property]);
9306 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9307 * @param {String} property A field on your records
9308 * @param {Number} start The record index to start at (defaults to 0)
9309 * @param {Number} end The last record index to include (defaults to length - 1)
9310 * @return {Number} The sum
9312 sum : function(property, start, end){
9313 var rs = this.data.items, v = 0;
9315 end = (end || end === 0) ? end : rs.length-1;
9317 for(var i = start; i <= end; i++){
9318 v += (rs[i].data[property] || 0);
9324 * Filter the records by a specified property.
9325 * @param {String} field A field on your records
9326 * @param {String/RegExp} value Either a string that the field
9327 * should start with or a RegExp to test against the field
9328 * @param {Boolean} anyMatch True to match any part not just the beginning
9330 filter : function(property, value, anyMatch){
9331 var fn = this.createFilterFn(property, value, anyMatch);
9332 return fn ? this.filterBy(fn) : this.clearFilter();
9336 * Filter by a function. The specified function will be called with each
9337 * record in this data source. If the function returns true the record is included,
9338 * otherwise it is filtered.
9339 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9340 * @param {Object} scope (optional) The scope of the function (defaults to this)
9342 filterBy : function(fn, scope){
9343 this.snapshot = this.snapshot || this.data;
9344 this.data = this.queryBy(fn, scope||this);
9345 this.fireEvent("datachanged", this);
9349 * Query the records by a specified property.
9350 * @param {String} field A field on your records
9351 * @param {String/RegExp} value Either a string that the field
9352 * should start with or a RegExp to test against the field
9353 * @param {Boolean} anyMatch True to match any part not just the beginning
9354 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9356 query : function(property, value, anyMatch){
9357 var fn = this.createFilterFn(property, value, anyMatch);
9358 return fn ? this.queryBy(fn) : this.data.clone();
9362 * Query by a function. The specified function will be called with each
9363 * record in this data source. If the function returns true the record is included
9365 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9366 * @param {Object} scope (optional) The scope of the function (defaults to this)
9367 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9369 queryBy : function(fn, scope){
9370 var data = this.snapshot || this.data;
9371 return data.filterBy(fn, scope||this);
9375 * Collects unique values for a particular dataIndex from this store.
9376 * @param {String} dataIndex The property to collect
9377 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9378 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9379 * @return {Array} An array of the unique values
9381 collect : function(dataIndex, allowNull, bypassFilter){
9382 var d = (bypassFilter === true && this.snapshot) ?
9383 this.snapshot.items : this.data.items;
9384 var v, sv, r = [], l = {};
9385 for(var i = 0, len = d.length; i < len; i++){
9386 v = d[i].data[dataIndex];
9388 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9397 * Revert to a view of the Record cache with no filtering applied.
9398 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9400 clearFilter : function(suppressEvent){
9401 if(this.snapshot && this.snapshot != this.data){
9402 this.data = this.snapshot;
9403 delete this.snapshot;
9404 if(suppressEvent !== true){
9405 this.fireEvent("datachanged", this);
9411 afterEdit : function(record){
9412 if(this.modified.indexOf(record) == -1){
9413 this.modified.push(record);
9415 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9419 afterReject : function(record){
9420 this.modified.remove(record);
9421 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9425 afterCommit : function(record){
9426 this.modified.remove(record);
9427 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9431 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9432 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9434 commitChanges : function(){
9435 var m = this.modified.slice(0);
9437 for(var i = 0, len = m.length; i < len; i++){
9443 * Cancel outstanding changes on all changed records.
9445 rejectChanges : function(){
9446 var m = this.modified.slice(0);
9448 for(var i = 0, len = m.length; i < len; i++){
9453 onMetaChange : function(meta, rtype, o){
9454 this.recordType = rtype;
9455 this.fields = rtype.prototype.fields;
9456 delete this.snapshot;
9457 this.sortInfo = meta.sortInfo || this.sortInfo;
9459 this.fireEvent('metachange', this, this.reader.meta);
9462 moveIndex : function(data, type)
9464 var index = this.indexOf(data);
9466 var newIndex = index + type;
9470 this.insert(newIndex, data);
9475 * Ext JS Library 1.1.1
9476 * Copyright(c) 2006-2007, Ext JS, LLC.
9478 * Originally Released Under LGPL - original licence link has changed is not relivant.
9481 * <script type="text/javascript">
9485 * @class Roo.data.SimpleStore
9486 * @extends Roo.data.Store
9487 * Small helper class to make creating Stores from Array data easier.
9488 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9489 * @cfg {Array} fields An array of field definition objects, or field name strings.
9490 * @cfg {Array} data The multi-dimensional array of data
9492 * @param {Object} config
9494 Roo.data.SimpleStore = function(config){
9495 Roo.data.SimpleStore.superclass.constructor.call(this, {
9497 reader: new Roo.data.ArrayReader({
9500 Roo.data.Record.create(config.fields)
9502 proxy : new Roo.data.MemoryProxy(config.data)
9506 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9508 * Ext JS Library 1.1.1
9509 * Copyright(c) 2006-2007, Ext JS, LLC.
9511 * Originally Released Under LGPL - original licence link has changed is not relivant.
9514 * <script type="text/javascript">
9519 * @extends Roo.data.Store
9520 * @class Roo.data.JsonStore
9521 * Small helper class to make creating Stores for JSON data easier. <br/>
9523 var store = new Roo.data.JsonStore({
9524 url: 'get-images.php',
9526 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9529 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9530 * JsonReader and HttpProxy (unless inline data is provided).</b>
9531 * @cfg {Array} fields An array of field definition objects, or field name strings.
9533 * @param {Object} config
9535 Roo.data.JsonStore = function(c){
9536 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9537 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9538 reader: new Roo.data.JsonReader(c, c.fields)
9541 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9543 * Ext JS Library 1.1.1
9544 * Copyright(c) 2006-2007, Ext JS, LLC.
9546 * Originally Released Under LGPL - original licence link has changed is not relivant.
9549 * <script type="text/javascript">
9553 Roo.data.Field = function(config){
9554 if(typeof config == "string"){
9555 config = {name: config};
9557 Roo.apply(this, config);
9563 var st = Roo.data.SortTypes;
9564 // named sortTypes are supported, here we look them up
9565 if(typeof this.sortType == "string"){
9566 this.sortType = st[this.sortType];
9569 // set default sortType for strings and dates
9573 this.sortType = st.asUCString;
9576 this.sortType = st.asDate;
9579 this.sortType = st.none;
9584 var stripRe = /[\$,%]/g;
9586 // prebuilt conversion function for this field, instead of
9587 // switching every time we're reading a value
9589 var cv, dateFormat = this.dateFormat;
9594 cv = function(v){ return v; };
9597 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9601 return v !== undefined && v !== null && v !== '' ?
9602 parseInt(String(v).replace(stripRe, ""), 10) : '';
9607 return v !== undefined && v !== null && v !== '' ?
9608 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9613 cv = function(v){ return v === true || v === "true" || v == 1; };
9620 if(v instanceof Date){
9624 if(dateFormat == "timestamp"){
9625 return new Date(v*1000);
9627 return Date.parseDate(v, dateFormat);
9629 var parsed = Date.parse(v);
9630 return parsed ? new Date(parsed) : null;
9639 Roo.data.Field.prototype = {
9647 * Ext JS Library 1.1.1
9648 * Copyright(c) 2006-2007, Ext JS, LLC.
9650 * Originally Released Under LGPL - original licence link has changed is not relivant.
9653 * <script type="text/javascript">
9656 // Base class for reading structured data from a data source. This class is intended to be
9657 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9660 * @class Roo.data.DataReader
9661 * Base class for reading structured data from a data source. This class is intended to be
9662 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9665 Roo.data.DataReader = function(meta, recordType){
9669 this.recordType = recordType instanceof Array ?
9670 Roo.data.Record.create(recordType) : recordType;
9673 Roo.data.DataReader.prototype = {
9675 * Create an empty record
9676 * @param {Object} data (optional) - overlay some values
9677 * @return {Roo.data.Record} record created.
9679 newRow : function(d) {
9681 this.recordType.prototype.fields.each(function(c) {
9683 case 'int' : da[c.name] = 0; break;
9684 case 'date' : da[c.name] = new Date(); break;
9685 case 'float' : da[c.name] = 0.0; break;
9686 case 'boolean' : da[c.name] = false; break;
9687 default : da[c.name] = ""; break;
9691 return new this.recordType(Roo.apply(da, d));
9696 * Ext JS Library 1.1.1
9697 * Copyright(c) 2006-2007, Ext JS, LLC.
9699 * Originally Released Under LGPL - original licence link has changed is not relivant.
9702 * <script type="text/javascript">
9706 * @class Roo.data.DataProxy
9707 * @extends Roo.data.Observable
9708 * This class is an abstract base class for implementations which provide retrieval of
9709 * unformatted data objects.<br>
9711 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9712 * (of the appropriate type which knows how to parse the data object) to provide a block of
9713 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9715 * Custom implementations must implement the load method as described in
9716 * {@link Roo.data.HttpProxy#load}.
9718 Roo.data.DataProxy = function(){
9722 * Fires before a network request is made to retrieve a data object.
9723 * @param {Object} This DataProxy object.
9724 * @param {Object} params The params parameter to the load function.
9729 * Fires before the load method's callback is called.
9730 * @param {Object} This DataProxy object.
9731 * @param {Object} o The data object.
9732 * @param {Object} arg The callback argument object passed to the load function.
9736 * @event loadexception
9737 * Fires if an Exception occurs during data retrieval.
9738 * @param {Object} This DataProxy object.
9739 * @param {Object} o The data object.
9740 * @param {Object} arg The callback argument object passed to the load function.
9741 * @param {Object} e The Exception.
9743 loadexception : true
9745 Roo.data.DataProxy.superclass.constructor.call(this);
9748 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9751 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9755 * Ext JS Library 1.1.1
9756 * Copyright(c) 2006-2007, Ext JS, LLC.
9758 * Originally Released Under LGPL - original licence link has changed is not relivant.
9761 * <script type="text/javascript">
9764 * @class Roo.data.MemoryProxy
9765 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9766 * to the Reader when its load method is called.
9768 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9770 Roo.data.MemoryProxy = function(data){
9774 Roo.data.MemoryProxy.superclass.constructor.call(this);
9778 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9780 * Load data from the requested source (in this case an in-memory
9781 * data object passed to the constructor), read the data object into
9782 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9783 * process that block using the passed callback.
9784 * @param {Object} params This parameter is not used by the MemoryProxy class.
9785 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9786 * object into a block of Roo.data.Records.
9787 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9788 * The function must be passed <ul>
9789 * <li>The Record block object</li>
9790 * <li>The "arg" argument from the load function</li>
9791 * <li>A boolean success indicator</li>
9793 * @param {Object} scope The scope in which to call the callback
9794 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9796 load : function(params, reader, callback, scope, arg){
9797 params = params || {};
9800 result = reader.readRecords(this.data);
9802 this.fireEvent("loadexception", this, arg, null, e);
9803 callback.call(scope, null, arg, false);
9806 callback.call(scope, result, arg, true);
9810 update : function(params, records){
9815 * Ext JS Library 1.1.1
9816 * Copyright(c) 2006-2007, Ext JS, LLC.
9818 * Originally Released Under LGPL - original licence link has changed is not relivant.
9821 * <script type="text/javascript">
9824 * @class Roo.data.HttpProxy
9825 * @extends Roo.data.DataProxy
9826 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9827 * configured to reference a certain URL.<br><br>
9829 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9830 * from which the running page was served.<br><br>
9832 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9834 * Be aware that to enable the browser to parse an XML document, the server must set
9835 * the Content-Type header in the HTTP response to "text/xml".
9837 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9838 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9839 * will be used to make the request.
9841 Roo.data.HttpProxy = function(conn){
9842 Roo.data.HttpProxy.superclass.constructor.call(this);
9843 // is conn a conn config or a real conn?
9845 this.useAjax = !conn || !conn.events;
9849 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9850 // thse are take from connection...
9853 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9856 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9857 * extra parameters to each request made by this object. (defaults to undefined)
9860 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9861 * to each request made by this object. (defaults to undefined)
9864 * @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)
9867 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9870 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9876 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9880 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9881 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9882 * a finer-grained basis than the DataProxy events.
9884 getConnection : function(){
9885 return this.useAjax ? Roo.Ajax : this.conn;
9889 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9890 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9891 * process that block using the passed callback.
9892 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9893 * for the request to the remote server.
9894 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9895 * object into a block of Roo.data.Records.
9896 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9897 * The function must be passed <ul>
9898 * <li>The Record block object</li>
9899 * <li>The "arg" argument from the load function</li>
9900 * <li>A boolean success indicator</li>
9902 * @param {Object} scope The scope in which to call the callback
9903 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9905 load : function(params, reader, callback, scope, arg){
9906 if(this.fireEvent("beforeload", this, params) !== false){
9908 params : params || {},
9910 callback : callback,
9915 callback : this.loadResponse,
9919 Roo.applyIf(o, this.conn);
9920 if(this.activeRequest){
9921 Roo.Ajax.abort(this.activeRequest);
9923 this.activeRequest = Roo.Ajax.request(o);
9925 this.conn.request(o);
9928 callback.call(scope||this, null, arg, false);
9933 loadResponse : function(o, success, response){
9934 delete this.activeRequest;
9936 this.fireEvent("loadexception", this, o, response);
9937 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9942 result = o.reader.read(response);
9944 this.fireEvent("loadexception", this, o, response, e);
9945 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9949 this.fireEvent("load", this, o, o.request.arg);
9950 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9954 update : function(dataSet){
9959 updateResponse : function(dataSet){
9964 * Ext JS Library 1.1.1
9965 * Copyright(c) 2006-2007, Ext JS, LLC.
9967 * Originally Released Under LGPL - original licence link has changed is not relivant.
9970 * <script type="text/javascript">
9974 * @class Roo.data.ScriptTagProxy
9975 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9976 * other than the originating domain of the running page.<br><br>
9978 * <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
9979 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9981 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9982 * source code that is used as the source inside a <script> tag.<br><br>
9984 * In order for the browser to process the returned data, the server must wrap the data object
9985 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9986 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9987 * depending on whether the callback name was passed:
9990 boolean scriptTag = false;
9991 String cb = request.getParameter("callback");
9994 response.setContentType("text/javascript");
9996 response.setContentType("application/x-json");
9998 Writer out = response.getWriter();
10000 out.write(cb + "(");
10002 out.print(dataBlock.toJsonString());
10009 * @param {Object} config A configuration object.
10011 Roo.data.ScriptTagProxy = function(config){
10012 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10013 Roo.apply(this, config);
10014 this.head = document.getElementsByTagName("head")[0];
10017 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10019 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10021 * @cfg {String} url The URL from which to request the data object.
10024 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10028 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10029 * the server the name of the callback function set up by the load call to process the returned data object.
10030 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10031 * javascript output which calls this named function passing the data object as its only parameter.
10033 callbackParam : "callback",
10035 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10036 * name to the request.
10041 * Load data from the configured URL, read the data object into
10042 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10043 * process that block using the passed callback.
10044 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10045 * for the request to the remote server.
10046 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10047 * object into a block of Roo.data.Records.
10048 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10049 * The function must be passed <ul>
10050 * <li>The Record block object</li>
10051 * <li>The "arg" argument from the load function</li>
10052 * <li>A boolean success indicator</li>
10054 * @param {Object} scope The scope in which to call the callback
10055 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10057 load : function(params, reader, callback, scope, arg){
10058 if(this.fireEvent("beforeload", this, params) !== false){
10060 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10062 var url = this.url;
10063 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10065 url += "&_dc=" + (new Date().getTime());
10067 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10070 cb : "stcCallback"+transId,
10071 scriptId : "stcScript"+transId,
10075 callback : callback,
10081 window[trans.cb] = function(o){
10082 conn.handleResponse(o, trans);
10085 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10087 if(this.autoAbort !== false){
10091 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10093 var script = document.createElement("script");
10094 script.setAttribute("src", url);
10095 script.setAttribute("type", "text/javascript");
10096 script.setAttribute("id", trans.scriptId);
10097 this.head.appendChild(script);
10099 this.trans = trans;
10101 callback.call(scope||this, null, arg, false);
10106 isLoading : function(){
10107 return this.trans ? true : false;
10111 * Abort the current server request.
10113 abort : function(){
10114 if(this.isLoading()){
10115 this.destroyTrans(this.trans);
10120 destroyTrans : function(trans, isLoaded){
10121 this.head.removeChild(document.getElementById(trans.scriptId));
10122 clearTimeout(trans.timeoutId);
10124 window[trans.cb] = undefined;
10126 delete window[trans.cb];
10129 // if hasn't been loaded, wait for load to remove it to prevent script error
10130 window[trans.cb] = function(){
10131 window[trans.cb] = undefined;
10133 delete window[trans.cb];
10140 handleResponse : function(o, trans){
10141 this.trans = false;
10142 this.destroyTrans(trans, true);
10145 result = trans.reader.readRecords(o);
10147 this.fireEvent("loadexception", this, o, trans.arg, e);
10148 trans.callback.call(trans.scope||window, null, trans.arg, false);
10151 this.fireEvent("load", this, o, trans.arg);
10152 trans.callback.call(trans.scope||window, result, trans.arg, true);
10156 handleFailure : function(trans){
10157 this.trans = false;
10158 this.destroyTrans(trans, false);
10159 this.fireEvent("loadexception", this, null, trans.arg);
10160 trans.callback.call(trans.scope||window, null, trans.arg, false);
10164 * Ext JS Library 1.1.1
10165 * Copyright(c) 2006-2007, Ext JS, LLC.
10167 * Originally Released Under LGPL - original licence link has changed is not relivant.
10170 * <script type="text/javascript">
10174 * @class Roo.data.JsonReader
10175 * @extends Roo.data.DataReader
10176 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10177 * based on mappings in a provided Roo.data.Record constructor.
10179 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10180 * in the reply previously.
10185 var RecordDef = Roo.data.Record.create([
10186 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10187 {name: 'occupation'} // This field will use "occupation" as the mapping.
10189 var myReader = new Roo.data.JsonReader({
10190 totalProperty: "results", // The property which contains the total dataset size (optional)
10191 root: "rows", // The property which contains an Array of row objects
10192 id: "id" // The property within each row object that provides an ID for the record (optional)
10196 * This would consume a JSON file like this:
10198 { 'results': 2, 'rows': [
10199 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10200 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10203 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10204 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10205 * paged from the remote server.
10206 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10207 * @cfg {String} root name of the property which contains the Array of row objects.
10208 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10210 * Create a new JsonReader
10211 * @param {Object} meta Metadata configuration options
10212 * @param {Object} recordType Either an Array of field definition objects,
10213 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10215 Roo.data.JsonReader = function(meta, recordType){
10218 // set some defaults:
10219 Roo.applyIf(meta, {
10220 totalProperty: 'total',
10221 successProperty : 'success',
10226 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10228 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10231 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10232 * Used by Store query builder to append _requestMeta to params.
10235 metaFromRemote : false,
10237 * This method is only used by a DataProxy which has retrieved data from a remote server.
10238 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10239 * @return {Object} data A data block which is used by an Roo.data.Store object as
10240 * a cache of Roo.data.Records.
10242 read : function(response){
10243 var json = response.responseText;
10245 var o = /* eval:var:o */ eval("("+json+")");
10247 throw {message: "JsonReader.read: Json object not found"};
10253 this.metaFromRemote = true;
10254 this.meta = o.metaData;
10255 this.recordType = Roo.data.Record.create(o.metaData.fields);
10256 this.onMetaChange(this.meta, this.recordType, o);
10258 return this.readRecords(o);
10261 // private function a store will implement
10262 onMetaChange : function(meta, recordType, o){
10269 simpleAccess: function(obj, subsc) {
10276 getJsonAccessor: function(){
10278 return function(expr) {
10280 return(re.test(expr))
10281 ? new Function("obj", "return obj." + expr)
10286 return Roo.emptyFn;
10291 * Create a data block containing Roo.data.Records from an XML document.
10292 * @param {Object} o An object which contains an Array of row objects in the property specified
10293 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10294 * which contains the total size of the dataset.
10295 * @return {Object} data A data block which is used by an Roo.data.Store object as
10296 * a cache of Roo.data.Records.
10298 readRecords : function(o){
10300 * After any data loads, the raw JSON data is available for further custom processing.
10304 var s = this.meta, Record = this.recordType,
10305 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10307 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10309 if(s.totalProperty) {
10310 this.getTotal = this.getJsonAccessor(s.totalProperty);
10312 if(s.successProperty) {
10313 this.getSuccess = this.getJsonAccessor(s.successProperty);
10315 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10317 var g = this.getJsonAccessor(s.id);
10318 this.getId = function(rec) {
10320 return (r === undefined || r === "") ? null : r;
10323 this.getId = function(){return null;};
10326 for(var jj = 0; jj < fl; jj++){
10328 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10329 this.ef[jj] = this.getJsonAccessor(map);
10333 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10334 if(s.totalProperty){
10335 var vt = parseInt(this.getTotal(o), 10);
10340 if(s.successProperty){
10341 var vs = this.getSuccess(o);
10342 if(vs === false || vs === 'false'){
10347 for(var i = 0; i < c; i++){
10350 var id = this.getId(n);
10351 for(var j = 0; j < fl; j++){
10353 var v = this.ef[j](n);
10355 Roo.log('missing convert for ' + f.name);
10359 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10361 var record = new Record(values, id);
10363 records[i] = record;
10369 totalRecords : totalRecords
10374 * Ext JS Library 1.1.1
10375 * Copyright(c) 2006-2007, Ext JS, LLC.
10377 * Originally Released Under LGPL - original licence link has changed is not relivant.
10380 * <script type="text/javascript">
10384 * @class Roo.data.ArrayReader
10385 * @extends Roo.data.DataReader
10386 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10387 * Each element of that Array represents a row of data fields. The
10388 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10389 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10393 var RecordDef = Roo.data.Record.create([
10394 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10395 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10397 var myReader = new Roo.data.ArrayReader({
10398 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10402 * This would consume an Array like this:
10404 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10406 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10408 * Create a new JsonReader
10409 * @param {Object} meta Metadata configuration options.
10410 * @param {Object} recordType Either an Array of field definition objects
10411 * as specified to {@link Roo.data.Record#create},
10412 * or an {@link Roo.data.Record} object
10413 * created using {@link Roo.data.Record#create}.
10415 Roo.data.ArrayReader = function(meta, recordType){
10416 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10419 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10421 * Create a data block containing Roo.data.Records from an XML document.
10422 * @param {Object} o An Array of row objects which represents the dataset.
10423 * @return {Object} data A data block which is used by an Roo.data.Store object as
10424 * a cache of Roo.data.Records.
10426 readRecords : function(o){
10427 var sid = this.meta ? this.meta.id : null;
10428 var recordType = this.recordType, fields = recordType.prototype.fields;
10431 for(var i = 0; i < root.length; i++){
10434 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10435 for(var j = 0, jlen = fields.length; j < jlen; j++){
10436 var f = fields.items[j];
10437 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10438 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10440 values[f.name] = v;
10442 var record = new recordType(values, id);
10444 records[records.length] = record;
10448 totalRecords : records.length
10457 * @class Roo.bootstrap.ComboBox
10458 * @extends Roo.bootstrap.TriggerField
10459 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10460 * @cfg {Boolean} append (true|false) default false
10461 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10462 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10463 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10464 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10465 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10467 * Create a new ComboBox.
10468 * @param {Object} config Configuration options
10470 Roo.bootstrap.ComboBox = function(config){
10471 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10475 * Fires when the dropdown list is expanded
10476 * @param {Roo.bootstrap.ComboBox} combo This combo box
10481 * Fires when the dropdown list is collapsed
10482 * @param {Roo.bootstrap.ComboBox} combo This combo box
10486 * @event beforeselect
10487 * Fires before a list item is selected. Return false to cancel the selection.
10488 * @param {Roo.bootstrap.ComboBox} combo This combo box
10489 * @param {Roo.data.Record} record The data record returned from the underlying store
10490 * @param {Number} index The index of the selected item in the dropdown list
10492 'beforeselect' : true,
10495 * Fires when a list item is selected
10496 * @param {Roo.bootstrap.ComboBox} combo This combo box
10497 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10498 * @param {Number} index The index of the selected item in the dropdown list
10502 * @event beforequery
10503 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10504 * The event object passed has these properties:
10505 * @param {Roo.bootstrap.ComboBox} combo This combo box
10506 * @param {String} query The query
10507 * @param {Boolean} forceAll true to force "all" query
10508 * @param {Boolean} cancel true to cancel the query
10509 * @param {Object} e The query event object
10511 'beforequery': true,
10514 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10515 * @param {Roo.bootstrap.ComboBox} combo This combo box
10520 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10521 * @param {Roo.bootstrap.ComboBox} combo This combo box
10522 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10527 * Fires when the remove value from the combobox array
10528 * @param {Roo.bootstrap.ComboBox} combo This combo box
10535 this.tickItems = [];
10537 this.selectedIndex = -1;
10538 if(this.mode == 'local'){
10539 if(config.queryDelay === undefined){
10540 this.queryDelay = 10;
10542 if(config.minChars === undefined){
10548 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10551 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10552 * rendering into an Roo.Editor, defaults to false)
10555 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10556 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10559 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10562 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10563 * the dropdown list (defaults to undefined, with no header element)
10567 * @cfg {String/Roo.Template} tpl The template to use to render the output
10571 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10573 listWidth: undefined,
10575 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10576 * mode = 'remote' or 'text' if mode = 'local')
10578 displayField: undefined,
10580 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10581 * mode = 'remote' or 'value' if mode = 'local').
10582 * Note: use of a valueField requires the user make a selection
10583 * in order for a value to be mapped.
10585 valueField: undefined,
10589 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10590 * field's data value (defaults to the underlying DOM element's name)
10592 hiddenName: undefined,
10594 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10598 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10600 selectedClass: 'active',
10603 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10607 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10608 * anchor positions (defaults to 'tl-bl')
10610 listAlign: 'tl-bl?',
10612 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10616 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10617 * query specified by the allQuery config option (defaults to 'query')
10619 triggerAction: 'query',
10621 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10622 * (defaults to 4, does not apply if editable = false)
10626 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10627 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10631 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10632 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10636 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10637 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10641 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10642 * when editable = true (defaults to false)
10644 selectOnFocus:false,
10646 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10648 queryParam: 'query',
10650 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10651 * when mode = 'remote' (defaults to 'Loading...')
10653 loadingText: 'Loading...',
10655 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10659 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10663 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10664 * traditional select (defaults to true)
10668 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10672 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10676 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10677 * listWidth has a higher value)
10681 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10682 * allow the user to set arbitrary text into the field (defaults to false)
10684 forceSelection:false,
10686 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10687 * if typeAhead = true (defaults to 250)
10689 typeAheadDelay : 250,
10691 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10692 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10694 valueNotFoundText : undefined,
10696 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10698 blockFocus : false,
10701 * @cfg {Boolean} disableClear Disable showing of clear button.
10703 disableClear : false,
10705 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10707 alwaysQuery : false,
10710 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10724 btnPosition : 'right',
10725 triggerList : true,
10726 showToggleBtn : true,
10727 // element that contains real text value.. (when hidden is used..)
10729 getAutoCreate : function()
10736 if(!this.tickable){
10737 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10742 * ComboBox with tickable selections
10745 var align = this.labelAlign || this.parentLabelAlign();
10748 cls : 'form-group roo-combobox-tickable' //input-group
10754 cls : 'tickable-buttons',
10759 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10766 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10773 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10780 Roo.each(buttons.cn, function(c){
10782 c.cls += ' btn-' + _this.size;
10785 if (_this.disabled) {
10796 cls: 'form-hidden-field'
10800 cls: 'select2-choices',
10804 cls: 'select2-search-field',
10816 cls: 'select2-container input-group select2-container-multi',
10821 // cls: 'typeahead typeahead-long dropdown-menu',
10822 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10827 if (align ==='left' && this.fieldLabel.length) {
10829 Roo.log("left and has label");
10835 cls : 'control-label col-sm-' + this.labelWidth,
10836 html : this.fieldLabel
10840 cls : "col-sm-" + (12 - this.labelWidth),
10847 } else if ( this.fieldLabel.length) {
10853 //cls : 'input-group-addon',
10854 html : this.fieldLabel
10864 Roo.log(" no label && no align");
10871 ['xs','sm','md','lg'].map(function(size){
10872 if (settings[size]) {
10873 cfg.cls += ' col-' + size + '-' + settings[size];
10882 initEvents: function()
10886 throw "can not find store for combo";
10888 this.store = Roo.factory(this.store, Roo.data);
10891 this.initTickableEvents();
10895 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10897 if(this.hiddenName){
10899 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10901 this.hiddenField.dom.value =
10902 this.hiddenValue !== undefined ? this.hiddenValue :
10903 this.value !== undefined ? this.value : '';
10905 // prevent input submission
10906 this.el.dom.removeAttribute('name');
10907 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10912 // this.el.dom.setAttribute('autocomplete', 'off');
10915 var cls = 'x-combo-list';
10917 //this.list = new Roo.Layer({
10918 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10924 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10925 _this.list.setWidth(lw);
10928 this.list.on('mouseover', this.onViewOver, this);
10929 this.list.on('mousemove', this.onViewMove, this);
10931 this.list.on('scroll', this.onViewScroll, this);
10934 this.list.swallowEvent('mousewheel');
10935 this.assetHeight = 0;
10938 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10939 this.assetHeight += this.header.getHeight();
10942 this.innerList = this.list.createChild({cls:cls+'-inner'});
10943 this.innerList.on('mouseover', this.onViewOver, this);
10944 this.innerList.on('mousemove', this.onViewMove, this);
10945 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10947 if(this.allowBlank && !this.pageSize && !this.disableClear){
10948 this.footer = this.list.createChild({cls:cls+'-ft'});
10949 this.pageTb = new Roo.Toolbar(this.footer);
10953 this.footer = this.list.createChild({cls:cls+'-ft'});
10954 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10955 {pageSize: this.pageSize});
10959 if (this.pageTb && this.allowBlank && !this.disableClear) {
10961 this.pageTb.add(new Roo.Toolbar.Fill(), {
10962 cls: 'x-btn-icon x-btn-clear',
10964 handler: function()
10967 _this.clearValue();
10968 _this.onSelect(false, -1);
10973 this.assetHeight += this.footer.getHeight();
10978 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10981 this.view = new Roo.View(this.list, this.tpl, {
10982 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10984 //this.view.wrapEl.setDisplayed(false);
10985 this.view.on('click', this.onViewClick, this);
10989 this.store.on('beforeload', this.onBeforeLoad, this);
10990 this.store.on('load', this.onLoad, this);
10991 this.store.on('loadexception', this.onLoadException, this);
10993 if(this.resizable){
10994 this.resizer = new Roo.Resizable(this.list, {
10995 pinned:true, handles:'se'
10997 this.resizer.on('resize', function(r, w, h){
10998 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10999 this.listWidth = w;
11000 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11001 this.restrictHeight();
11003 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11006 if(!this.editable){
11007 this.editable = true;
11008 this.setEditable(false);
11013 if (typeof(this.events.add.listeners) != 'undefined') {
11015 this.addicon = this.wrap.createChild(
11016 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11018 this.addicon.on('click', function(e) {
11019 this.fireEvent('add', this);
11022 if (typeof(this.events.edit.listeners) != 'undefined') {
11024 this.editicon = this.wrap.createChild(
11025 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11026 if (this.addicon) {
11027 this.editicon.setStyle('margin-left', '40px');
11029 this.editicon.on('click', function(e) {
11031 // we fire even if inothing is selected..
11032 this.fireEvent('edit', this, this.lastData );
11038 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11039 "up" : function(e){
11040 this.inKeyMode = true;
11044 "down" : function(e){
11045 if(!this.isExpanded()){
11046 this.onTriggerClick();
11048 this.inKeyMode = true;
11053 "enter" : function(e){
11054 // this.onViewClick();
11058 if(this.fireEvent("specialkey", this, e)){
11059 this.onViewClick(false);
11065 "esc" : function(e){
11069 "tab" : function(e){
11072 if(this.fireEvent("specialkey", this, e)){
11073 this.onViewClick(false);
11081 doRelay : function(foo, bar, hname){
11082 if(hname == 'down' || this.scope.isExpanded()){
11083 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11092 this.queryDelay = Math.max(this.queryDelay || 10,
11093 this.mode == 'local' ? 10 : 250);
11096 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11098 if(this.typeAhead){
11099 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11101 if(this.editable !== false){
11102 this.inputEl().on("keyup", this.onKeyUp, this);
11104 if(this.forceSelection){
11105 this.inputEl().on('blur', this.doForce, this);
11109 this.choices = this.el.select('ul.select2-choices', true).first();
11110 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11114 initTickableEvents: function()
11118 if(this.hiddenName){
11120 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11122 this.hiddenField.dom.value =
11123 this.hiddenValue !== undefined ? this.hiddenValue :
11124 this.value !== undefined ? this.value : '';
11126 // prevent input submission
11127 this.el.dom.removeAttribute('name');
11128 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11133 // this.list = this.el.select('ul.dropdown-menu',true).first();
11135 this.choices = this.el.select('ul.select2-choices', true).first();
11136 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11137 if(this.triggerList){
11138 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11141 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11142 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11144 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11145 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11147 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11148 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11150 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11151 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11152 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11155 this.cancelBtn.hide();
11160 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11161 _this.list.setWidth(lw);
11164 this.list.on('mouseover', this.onViewOver, this);
11165 this.list.on('mousemove', this.onViewMove, this);
11167 this.list.on('scroll', this.onViewScroll, this);
11170 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>';
11173 this.view = new Roo.View(this.list, this.tpl, {
11174 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11177 //this.view.wrapEl.setDisplayed(false);
11178 this.view.on('click', this.onViewClick, this);
11182 this.store.on('beforeload', this.onBeforeLoad, this);
11183 this.store.on('load', this.onLoad, this);
11184 this.store.on('loadexception', this.onLoadException, this);
11186 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11187 // "up" : function(e){
11188 // this.inKeyMode = true;
11189 // this.selectPrev();
11192 // "down" : function(e){
11193 // if(!this.isExpanded()){
11194 // this.onTriggerClick();
11196 // this.inKeyMode = true;
11197 // this.selectNext();
11201 // "enter" : function(e){
11202 //// this.onViewClick();
11204 // this.collapse();
11206 // if(this.fireEvent("specialkey", this, e)){
11207 // this.onViewClick(false);
11213 // "esc" : function(e){
11214 // this.collapse();
11217 // "tab" : function(e){
11218 // this.collapse();
11220 // if(this.fireEvent("specialkey", this, e)){
11221 // this.onViewClick(false);
11229 // doRelay : function(foo, bar, hname){
11230 // if(hname == 'down' || this.scope.isExpanded()){
11231 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11236 // forceKeyDown: true
11240 this.queryDelay = Math.max(this.queryDelay || 10,
11241 this.mode == 'local' ? 10 : 250);
11244 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11246 if(this.typeAhead){
11247 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11251 onDestroy : function(){
11253 this.view.setStore(null);
11254 this.view.el.removeAllListeners();
11255 this.view.el.remove();
11256 this.view.purgeListeners();
11259 this.list.dom.innerHTML = '';
11263 this.store.un('beforeload', this.onBeforeLoad, this);
11264 this.store.un('load', this.onLoad, this);
11265 this.store.un('loadexception', this.onLoadException, this);
11267 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11271 fireKey : function(e){
11272 if(e.isNavKeyPress() && !this.list.isVisible()){
11273 this.fireEvent("specialkey", this, e);
11278 onResize: function(w, h){
11279 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11281 // if(typeof w != 'number'){
11282 // // we do not handle it!?!?
11285 // var tw = this.trigger.getWidth();
11286 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11287 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11289 // this.inputEl().setWidth( this.adjustWidth('input', x));
11291 // //this.trigger.setStyle('left', x+'px');
11293 // if(this.list && this.listWidth === undefined){
11294 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11295 // this.list.setWidth(lw);
11296 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11304 * Allow or prevent the user from directly editing the field text. If false is passed,
11305 * the user will only be able to select from the items defined in the dropdown list. This method
11306 * is the runtime equivalent of setting the 'editable' config option at config time.
11307 * @param {Boolean} value True to allow the user to directly edit the field text
11309 setEditable : function(value){
11310 if(value == this.editable){
11313 this.editable = value;
11315 this.inputEl().dom.setAttribute('readOnly', true);
11316 this.inputEl().on('mousedown', this.onTriggerClick, this);
11317 this.inputEl().addClass('x-combo-noedit');
11319 this.inputEl().dom.setAttribute('readOnly', false);
11320 this.inputEl().un('mousedown', this.onTriggerClick, this);
11321 this.inputEl().removeClass('x-combo-noedit');
11327 onBeforeLoad : function(combo,opts){
11328 if(!this.hasFocus){
11332 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11334 this.restrictHeight();
11335 this.selectedIndex = -1;
11339 onLoad : function(){
11341 this.hasQuery = false;
11343 if(!this.hasFocus){
11347 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11348 this.loading.hide();
11351 if(this.store.getCount() > 0){
11353 // this.restrictHeight();
11354 if(this.lastQuery == this.allQuery){
11355 if(this.editable && !this.tickable){
11356 this.inputEl().dom.select();
11360 !this.selectByValue(this.value, true) &&
11361 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11362 this.store.lastOptions.add != true)
11364 this.select(0, true);
11367 if(this.autoFocus){
11370 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11371 this.taTask.delay(this.typeAheadDelay);
11375 this.onEmptyResults();
11381 onLoadException : function()
11383 this.hasQuery = false;
11385 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11386 this.loading.hide();
11390 Roo.log(this.store.reader.jsonData);
11391 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11393 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11399 onTypeAhead : function(){
11400 if(this.store.getCount() > 0){
11401 var r = this.store.getAt(0);
11402 var newValue = r.data[this.displayField];
11403 var len = newValue.length;
11404 var selStart = this.getRawValue().length;
11406 if(selStart != len){
11407 this.setRawValue(newValue);
11408 this.selectText(selStart, newValue.length);
11414 onSelect : function(record, index){
11416 if(this.fireEvent('beforeselect', this, record, index) !== false){
11418 this.setFromData(index > -1 ? record.data : false);
11421 this.fireEvent('select', this, record, index);
11426 * Returns the currently selected field value or empty string if no value is set.
11427 * @return {String} value The selected value
11429 getValue : function(){
11432 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11435 if(this.valueField){
11436 return typeof this.value != 'undefined' ? this.value : '';
11438 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11443 * Clears any text/value currently set in the field
11445 clearValue : function(){
11446 if(this.hiddenField){
11447 this.hiddenField.dom.value = '';
11450 this.setRawValue('');
11451 this.lastSelectionText = '';
11456 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11457 * will be displayed in the field. If the value does not match the data value of an existing item,
11458 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11459 * Otherwise the field will be blank (although the value will still be set).
11460 * @param {String} value The value to match
11462 setValue : function(v){
11469 if(this.valueField){
11470 var r = this.findRecord(this.valueField, v);
11472 text = r.data[this.displayField];
11473 }else if(this.valueNotFoundText !== undefined){
11474 text = this.valueNotFoundText;
11477 this.lastSelectionText = text;
11478 if(this.hiddenField){
11479 this.hiddenField.dom.value = v;
11481 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11485 * @property {Object} the last set data for the element
11490 * Sets the value of the field based on a object which is related to the record format for the store.
11491 * @param {Object} value the value to set as. or false on reset?
11493 setFromData : function(o){
11500 var dv = ''; // display value
11501 var vv = ''; // value value..
11503 if (this.displayField) {
11504 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11506 // this is an error condition!!!
11507 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11510 if(this.valueField){
11511 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11514 if(this.hiddenField){
11515 this.hiddenField.dom.value = vv;
11517 this.lastSelectionText = dv;
11518 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11522 // no hidden field.. - we store the value in 'value', but still display
11523 // display field!!!!
11524 this.lastSelectionText = dv;
11525 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11531 reset : function(){
11532 // overridden so that last data is reset..
11533 this.setValue(this.originalValue);
11534 this.clearInvalid();
11535 this.lastData = false;
11537 this.view.clearSelections();
11541 findRecord : function(prop, value){
11543 if(this.store.getCount() > 0){
11544 this.store.each(function(r){
11545 if(r.data[prop] == value){
11555 getName: function()
11557 // returns hidden if it's set..
11558 if (!this.rendered) {return ''};
11559 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11563 onViewMove : function(e, t){
11564 this.inKeyMode = false;
11568 onViewOver : function(e, t){
11569 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11572 var item = this.view.findItemFromChild(t);
11575 var index = this.view.indexOf(item);
11576 this.select(index, false);
11581 onViewClick : function(view, doFocus, el, e)
11583 var index = this.view.getSelectedIndexes()[0];
11585 var r = this.store.getAt(index);
11589 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11596 Roo.each(this.tickItems, function(v,k){
11598 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11599 _this.tickItems.splice(k, 1);
11609 this.tickItems.push(r.data);
11614 this.onSelect(r, index);
11616 if(doFocus !== false && !this.blockFocus){
11617 this.inputEl().focus();
11622 restrictHeight : function(){
11623 //this.innerList.dom.style.height = '';
11624 //var inner = this.innerList.dom;
11625 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11626 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11627 //this.list.beginUpdate();
11628 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11629 this.list.alignTo(this.inputEl(), this.listAlign);
11630 this.list.alignTo(this.inputEl(), this.listAlign);
11631 //this.list.endUpdate();
11635 onEmptyResults : function(){
11640 * Returns true if the dropdown list is expanded, else false.
11642 isExpanded : function(){
11643 return this.list.isVisible();
11647 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11648 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11649 * @param {String} value The data value of the item to select
11650 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11651 * selected item if it is not currently in view (defaults to true)
11652 * @return {Boolean} True if the value matched an item in the list, else false
11654 selectByValue : function(v, scrollIntoView){
11655 if(v !== undefined && v !== null){
11656 var r = this.findRecord(this.valueField || this.displayField, v);
11658 this.select(this.store.indexOf(r), scrollIntoView);
11666 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11667 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11668 * @param {Number} index The zero-based index of the list item to select
11669 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11670 * selected item if it is not currently in view (defaults to true)
11672 select : function(index, scrollIntoView){
11673 this.selectedIndex = index;
11674 this.view.select(index);
11675 if(scrollIntoView !== false){
11676 var el = this.view.getNode(index);
11677 if(el && !this.multiple && !this.tickable){
11678 this.list.scrollChildIntoView(el, false);
11684 selectNext : function(){
11685 var ct = this.store.getCount();
11687 if(this.selectedIndex == -1){
11689 }else if(this.selectedIndex < ct-1){
11690 this.select(this.selectedIndex+1);
11696 selectPrev : function(){
11697 var ct = this.store.getCount();
11699 if(this.selectedIndex == -1){
11701 }else if(this.selectedIndex != 0){
11702 this.select(this.selectedIndex-1);
11708 onKeyUp : function(e){
11709 if(this.editable !== false && !e.isSpecialKey()){
11710 this.lastKey = e.getKey();
11711 this.dqTask.delay(this.queryDelay);
11716 validateBlur : function(){
11717 return !this.list || !this.list.isVisible();
11721 initQuery : function(){
11722 this.doQuery(this.getRawValue());
11726 doForce : function(){
11727 if(this.inputEl().dom.value.length > 0){
11728 this.inputEl().dom.value =
11729 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11735 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11736 * query allowing the query action to be canceled if needed.
11737 * @param {String} query The SQL query to execute
11738 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11739 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11740 * saved in the current store (defaults to false)
11742 doQuery : function(q, forceAll){
11744 if(q === undefined || q === null){
11749 forceAll: forceAll,
11753 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11758 forceAll = qe.forceAll;
11759 if(forceAll === true || (q.length >= this.minChars)){
11761 this.hasQuery = true;
11763 if(this.lastQuery != q || this.alwaysQuery){
11764 this.lastQuery = q;
11765 if(this.mode == 'local'){
11766 this.selectedIndex = -1;
11768 this.store.clearFilter();
11770 this.store.filter(this.displayField, q);
11774 this.store.baseParams[this.queryParam] = q;
11776 var options = {params : this.getParams(q)};
11779 options.add = true;
11780 options.params.start = this.page * this.pageSize;
11783 this.store.load(options);
11785 * this code will make the page width larger, at the beginning, the list not align correctly,
11786 * we should expand the list on onLoad
11787 * so command out it
11792 this.selectedIndex = -1;
11797 this.loadNext = false;
11801 getParams : function(q){
11803 //p[this.queryParam] = q;
11807 p.limit = this.pageSize;
11813 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11815 collapse : function(){
11816 if(!this.isExpanded()){
11824 this.cancelBtn.hide();
11825 this.trigger.show();
11828 Roo.get(document).un('mousedown', this.collapseIf, this);
11829 Roo.get(document).un('mousewheel', this.collapseIf, this);
11830 if (!this.editable) {
11831 Roo.get(document).un('keydown', this.listKeyPress, this);
11833 this.fireEvent('collapse', this);
11837 collapseIf : function(e){
11838 var in_combo = e.within(this.el);
11839 var in_list = e.within(this.list);
11840 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11842 if (in_combo || in_list || is_list) {
11843 //e.stopPropagation();
11848 this.onTickableFooterButtonClick(e, false, false);
11856 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11858 expand : function(){
11860 if(this.isExpanded() || !this.hasFocus){
11864 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11865 this.list.setWidth(lw);
11872 this.restrictHeight();
11876 this.tickItems = Roo.apply([], this.item);
11879 this.cancelBtn.show();
11880 this.trigger.hide();
11884 Roo.get(document).on('mousedown', this.collapseIf, this);
11885 Roo.get(document).on('mousewheel', this.collapseIf, this);
11886 if (!this.editable) {
11887 Roo.get(document).on('keydown', this.listKeyPress, this);
11890 this.fireEvent('expand', this);
11894 // Implements the default empty TriggerField.onTriggerClick function
11895 onTriggerClick : function(e)
11897 Roo.log('trigger click');
11899 if(this.disabled || !this.triggerList){
11904 this.loadNext = false;
11906 if(this.isExpanded()){
11908 if (!this.blockFocus) {
11909 this.inputEl().focus();
11913 this.hasFocus = true;
11914 if(this.triggerAction == 'all') {
11915 this.doQuery(this.allQuery, true);
11917 this.doQuery(this.getRawValue());
11919 if (!this.blockFocus) {
11920 this.inputEl().focus();
11925 onTickableTriggerClick : function(e)
11932 this.loadNext = false;
11933 this.hasFocus = true;
11935 if(this.triggerAction == 'all') {
11936 this.doQuery(this.allQuery, true);
11938 this.doQuery(this.getRawValue());
11942 onSearchFieldClick : function(e)
11944 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11949 this.loadNext = false;
11950 this.hasFocus = true;
11952 if(this.triggerAction == 'all') {
11953 this.doQuery(this.allQuery, true);
11955 this.doQuery(this.getRawValue());
11959 listKeyPress : function(e)
11961 //Roo.log('listkeypress');
11962 // scroll to first matching element based on key pres..
11963 if (e.isSpecialKey()) {
11966 var k = String.fromCharCode(e.getKey()).toUpperCase();
11969 var csel = this.view.getSelectedNodes();
11970 var cselitem = false;
11972 var ix = this.view.indexOf(csel[0]);
11973 cselitem = this.store.getAt(ix);
11974 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11980 this.store.each(function(v) {
11982 // start at existing selection.
11983 if (cselitem.id == v.id) {
11989 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11990 match = this.store.indexOf(v);
11996 if (match === false) {
11997 return true; // no more action?
12000 this.view.select(match);
12001 var sn = Roo.get(this.view.getSelectedNodes()[0])
12002 sn.scrollIntoView(sn.dom.parentNode, false);
12005 onViewScroll : function(e, t){
12007 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){
12011 this.hasQuery = true;
12013 this.loading = this.list.select('.loading', true).first();
12015 if(this.loading === null){
12016 this.list.createChild({
12018 cls: 'loading select2-more-results select2-active',
12019 html: 'Loading more results...'
12022 this.loading = this.list.select('.loading', true).first();
12024 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12026 this.loading.hide();
12029 this.loading.show();
12034 this.loadNext = true;
12036 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12041 addItem : function(o)
12043 var dv = ''; // display value
12045 if (this.displayField) {
12046 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12048 // this is an error condition!!!
12049 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12056 var choice = this.choices.createChild({
12058 cls: 'select2-search-choice',
12067 cls: 'select2-search-choice-close',
12072 }, this.searchField);
12074 var close = choice.select('a.select2-search-choice-close', true).first()
12076 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12084 this.inputEl().dom.value = '';
12088 onRemoveItem : function(e, _self, o)
12090 e.preventDefault();
12091 var index = this.item.indexOf(o.data) * 1;
12094 Roo.log('not this item?!');
12098 this.item.splice(index, 1);
12103 this.fireEvent('remove', this, e);
12107 syncValue : function()
12109 if(!this.item.length){
12116 Roo.each(this.item, function(i){
12117 if(_this.valueField){
12118 value.push(i[_this.valueField]);
12125 this.value = value.join(',');
12127 if(this.hiddenField){
12128 this.hiddenField.dom.value = this.value;
12132 clearItem : function()
12134 if(!this.multiple){
12140 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12147 inputEl: function ()
12150 return this.searchField;
12152 return this.el.select('input.form-control',true).first();
12156 onTickableFooterButtonClick : function(e, btn, el)
12158 e.preventDefault();
12160 if(btn && btn.name == 'cancel'){
12161 this.tickItems = Roo.apply([], this.item);
12170 Roo.each(this.tickItems, function(o){
12178 validate : function()
12180 var v = this.getRawValue();
12183 v = this.getValue();
12186 if(this.disabled || this.validateValue(v)){
12187 this.clearInvalid();
12196 * @cfg {Boolean} grow
12200 * @cfg {Number} growMin
12204 * @cfg {Number} growMax
12214 * Ext JS Library 1.1.1
12215 * Copyright(c) 2006-2007, Ext JS, LLC.
12217 * Originally Released Under LGPL - original licence link has changed is not relivant.
12220 * <script type="text/javascript">
12225 * @extends Roo.util.Observable
12226 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12227 * This class also supports single and multi selection modes. <br>
12228 * Create a data model bound view:
12230 var store = new Roo.data.Store(...);
12232 var view = new Roo.View({
12234 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12236 singleSelect: true,
12237 selectedClass: "ydataview-selected",
12241 // listen for node click?
12242 view.on("click", function(vw, index, node, e){
12243 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12247 dataModel.load("foobar.xml");
12249 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12251 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12252 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12254 * Note: old style constructor is still suported (container, template, config)
12257 * Create a new View
12258 * @param {Object} config The config object
12261 Roo.View = function(config, depreciated_tpl, depreciated_config){
12263 this.parent = false;
12265 if (typeof(depreciated_tpl) == 'undefined') {
12266 // new way.. - universal constructor.
12267 Roo.apply(this, config);
12268 this.el = Roo.get(this.el);
12271 this.el = Roo.get(config);
12272 this.tpl = depreciated_tpl;
12273 Roo.apply(this, depreciated_config);
12275 this.wrapEl = this.el.wrap().wrap();
12276 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12279 if(typeof(this.tpl) == "string"){
12280 this.tpl = new Roo.Template(this.tpl);
12282 // support xtype ctors..
12283 this.tpl = new Roo.factory(this.tpl, Roo);
12287 this.tpl.compile();
12292 * @event beforeclick
12293 * Fires before a click is processed. Returns false to cancel the default action.
12294 * @param {Roo.View} this
12295 * @param {Number} index The index of the target node
12296 * @param {HTMLElement} node The target node
12297 * @param {Roo.EventObject} e The raw event object
12299 "beforeclick" : true,
12302 * Fires when a template node is clicked.
12303 * @param {Roo.View} this
12304 * @param {Number} index The index of the target node
12305 * @param {HTMLElement} node The target node
12306 * @param {Roo.EventObject} e The raw event object
12311 * Fires when a template node is double clicked.
12312 * @param {Roo.View} this
12313 * @param {Number} index The index of the target node
12314 * @param {HTMLElement} node The target node
12315 * @param {Roo.EventObject} e The raw event object
12319 * @event contextmenu
12320 * Fires when a template node is right clicked.
12321 * @param {Roo.View} this
12322 * @param {Number} index The index of the target node
12323 * @param {HTMLElement} node The target node
12324 * @param {Roo.EventObject} e The raw event object
12326 "contextmenu" : true,
12328 * @event selectionchange
12329 * Fires when the selected nodes change.
12330 * @param {Roo.View} this
12331 * @param {Array} selections Array of the selected nodes
12333 "selectionchange" : true,
12336 * @event beforeselect
12337 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12338 * @param {Roo.View} this
12339 * @param {HTMLElement} node The node to be selected
12340 * @param {Array} selections Array of currently selected nodes
12342 "beforeselect" : true,
12344 * @event preparedata
12345 * Fires on every row to render, to allow you to change the data.
12346 * @param {Roo.View} this
12347 * @param {Object} data to be rendered (change this)
12349 "preparedata" : true
12357 "click": this.onClick,
12358 "dblclick": this.onDblClick,
12359 "contextmenu": this.onContextMenu,
12363 this.selections = [];
12365 this.cmp = new Roo.CompositeElementLite([]);
12367 this.store = Roo.factory(this.store, Roo.data);
12368 this.setStore(this.store, true);
12371 if ( this.footer && this.footer.xtype) {
12373 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12375 this.footer.dataSource = this.store
12376 this.footer.container = fctr;
12377 this.footer = Roo.factory(this.footer, Roo);
12378 fctr.insertFirst(this.el);
12380 // this is a bit insane - as the paging toolbar seems to detach the el..
12381 // dom.parentNode.parentNode.parentNode
12382 // they get detached?
12386 Roo.View.superclass.constructor.call(this);
12391 Roo.extend(Roo.View, Roo.util.Observable, {
12394 * @cfg {Roo.data.Store} store Data store to load data from.
12399 * @cfg {String|Roo.Element} el The container element.
12404 * @cfg {String|Roo.Template} tpl The template used by this View
12408 * @cfg {String} dataName the named area of the template to use as the data area
12409 * Works with domtemplates roo-name="name"
12413 * @cfg {String} selectedClass The css class to add to selected nodes
12415 selectedClass : "x-view-selected",
12417 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12422 * @cfg {String} text to display on mask (default Loading)
12426 * @cfg {Boolean} multiSelect Allow multiple selection
12428 multiSelect : false,
12430 * @cfg {Boolean} singleSelect Allow single selection
12432 singleSelect: false,
12435 * @cfg {Boolean} toggleSelect - selecting
12437 toggleSelect : false,
12440 * @cfg {Boolean} tickable - selecting
12445 * Returns the element this view is bound to.
12446 * @return {Roo.Element}
12448 getEl : function(){
12449 return this.wrapEl;
12455 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12457 refresh : function(){
12458 //Roo.log('refresh');
12461 // if we are using something like 'domtemplate', then
12462 // the what gets used is:
12463 // t.applySubtemplate(NAME, data, wrapping data..)
12464 // the outer template then get' applied with
12465 // the store 'extra data'
12466 // and the body get's added to the
12467 // roo-name="data" node?
12468 // <span class='roo-tpl-{name}'></span> ?????
12472 this.clearSelections();
12473 this.el.update("");
12475 var records = this.store.getRange();
12476 if(records.length < 1) {
12478 // is this valid?? = should it render a template??
12480 this.el.update(this.emptyText);
12484 if (this.dataName) {
12485 this.el.update(t.apply(this.store.meta)); //????
12486 el = this.el.child('.roo-tpl-' + this.dataName);
12489 for(var i = 0, len = records.length; i < len; i++){
12490 var data = this.prepareData(records[i].data, i, records[i]);
12491 this.fireEvent("preparedata", this, data, i, records[i]);
12493 var d = Roo.apply({}, data);
12496 Roo.apply(d, {'roo-id' : Roo.id()});
12500 Roo.each(this.parent.item, function(item){
12501 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12504 Roo.apply(d, {'roo-data-checked' : 'checked'});
12508 html[html.length] = Roo.util.Format.trim(
12510 t.applySubtemplate(this.dataName, d, this.store.meta) :
12517 el.update(html.join(""));
12518 this.nodes = el.dom.childNodes;
12519 this.updateIndexes(0);
12524 * Function to override to reformat the data that is sent to
12525 * the template for each node.
12526 * DEPRICATED - use the preparedata event handler.
12527 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12528 * a JSON object for an UpdateManager bound view).
12530 prepareData : function(data, index, record)
12532 this.fireEvent("preparedata", this, data, index, record);
12536 onUpdate : function(ds, record){
12537 // Roo.log('on update');
12538 this.clearSelections();
12539 var index = this.store.indexOf(record);
12540 var n = this.nodes[index];
12541 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12542 n.parentNode.removeChild(n);
12543 this.updateIndexes(index, index);
12549 onAdd : function(ds, records, index)
12551 //Roo.log(['on Add', ds, records, index] );
12552 this.clearSelections();
12553 if(this.nodes.length == 0){
12557 var n = this.nodes[index];
12558 for(var i = 0, len = records.length; i < len; i++){
12559 var d = this.prepareData(records[i].data, i, records[i]);
12561 this.tpl.insertBefore(n, d);
12564 this.tpl.append(this.el, d);
12567 this.updateIndexes(index);
12570 onRemove : function(ds, record, index){
12571 // Roo.log('onRemove');
12572 this.clearSelections();
12573 var el = this.dataName ?
12574 this.el.child('.roo-tpl-' + this.dataName) :
12577 el.dom.removeChild(this.nodes[index]);
12578 this.updateIndexes(index);
12582 * Refresh an individual node.
12583 * @param {Number} index
12585 refreshNode : function(index){
12586 this.onUpdate(this.store, this.store.getAt(index));
12589 updateIndexes : function(startIndex, endIndex){
12590 var ns = this.nodes;
12591 startIndex = startIndex || 0;
12592 endIndex = endIndex || ns.length - 1;
12593 for(var i = startIndex; i <= endIndex; i++){
12594 ns[i].nodeIndex = i;
12599 * Changes the data store this view uses and refresh the view.
12600 * @param {Store} store
12602 setStore : function(store, initial){
12603 if(!initial && this.store){
12604 this.store.un("datachanged", this.refresh);
12605 this.store.un("add", this.onAdd);
12606 this.store.un("remove", this.onRemove);
12607 this.store.un("update", this.onUpdate);
12608 this.store.un("clear", this.refresh);
12609 this.store.un("beforeload", this.onBeforeLoad);
12610 this.store.un("load", this.onLoad);
12611 this.store.un("loadexception", this.onLoad);
12615 store.on("datachanged", this.refresh, this);
12616 store.on("add", this.onAdd, this);
12617 store.on("remove", this.onRemove, this);
12618 store.on("update", this.onUpdate, this);
12619 store.on("clear", this.refresh, this);
12620 store.on("beforeload", this.onBeforeLoad, this);
12621 store.on("load", this.onLoad, this);
12622 store.on("loadexception", this.onLoad, this);
12630 * onbeforeLoad - masks the loading area.
12633 onBeforeLoad : function(store,opts)
12635 //Roo.log('onBeforeLoad');
12637 this.el.update("");
12639 this.el.mask(this.mask ? this.mask : "Loading" );
12641 onLoad : function ()
12648 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12649 * @param {HTMLElement} node
12650 * @return {HTMLElement} The template node
12652 findItemFromChild : function(node){
12653 var el = this.dataName ?
12654 this.el.child('.roo-tpl-' + this.dataName,true) :
12657 if(!node || node.parentNode == el){
12660 var p = node.parentNode;
12661 while(p && p != el){
12662 if(p.parentNode == el){
12671 onClick : function(e){
12672 var item = this.findItemFromChild(e.getTarget());
12674 var index = this.indexOf(item);
12675 if(this.onItemClick(item, index, e) !== false){
12676 this.fireEvent("click", this, index, item, e);
12679 this.clearSelections();
12684 onContextMenu : function(e){
12685 var item = this.findItemFromChild(e.getTarget());
12687 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12692 onDblClick : function(e){
12693 var item = this.findItemFromChild(e.getTarget());
12695 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12699 onItemClick : function(item, index, e)
12701 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12704 if (this.toggleSelect) {
12705 var m = this.isSelected(item) ? 'unselect' : 'select';
12708 _t[m](item, true, false);
12711 if(this.multiSelect || this.singleSelect){
12712 if(this.multiSelect && e.shiftKey && this.lastSelection){
12713 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12715 this.select(item, this.multiSelect && e.ctrlKey);
12716 this.lastSelection = item;
12719 if(!this.tickable){
12720 e.preventDefault();
12728 * Get the number of selected nodes.
12731 getSelectionCount : function(){
12732 return this.selections.length;
12736 * Get the currently selected nodes.
12737 * @return {Array} An array of HTMLElements
12739 getSelectedNodes : function(){
12740 return this.selections;
12744 * Get the indexes of the selected nodes.
12747 getSelectedIndexes : function(){
12748 var indexes = [], s = this.selections;
12749 for(var i = 0, len = s.length; i < len; i++){
12750 indexes.push(s[i].nodeIndex);
12756 * Clear all selections
12757 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12759 clearSelections : function(suppressEvent){
12760 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12761 this.cmp.elements = this.selections;
12762 this.cmp.removeClass(this.selectedClass);
12763 this.selections = [];
12764 if(!suppressEvent){
12765 this.fireEvent("selectionchange", this, this.selections);
12771 * Returns true if the passed node is selected
12772 * @param {HTMLElement/Number} node The node or node index
12773 * @return {Boolean}
12775 isSelected : function(node){
12776 var s = this.selections;
12780 node = this.getNode(node);
12781 return s.indexOf(node) !== -1;
12786 * @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
12787 * @param {Boolean} keepExisting (optional) true to keep existing selections
12788 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12790 select : function(nodeInfo, keepExisting, suppressEvent){
12791 if(nodeInfo instanceof Array){
12793 this.clearSelections(true);
12795 for(var i = 0, len = nodeInfo.length; i < len; i++){
12796 this.select(nodeInfo[i], true, true);
12800 var node = this.getNode(nodeInfo);
12801 if(!node || this.isSelected(node)){
12802 return; // already selected.
12805 this.clearSelections(true);
12808 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12809 Roo.fly(node).addClass(this.selectedClass);
12810 this.selections.push(node);
12811 if(!suppressEvent){
12812 this.fireEvent("selectionchange", this, this.selections);
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 IGNORED (for campatibility with select)
12822 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12824 unselect : function(nodeInfo, keepExisting, suppressEvent)
12826 if(nodeInfo instanceof Array){
12827 Roo.each(this.selections, function(s) {
12828 this.unselect(s, nodeInfo);
12832 var node = this.getNode(nodeInfo);
12833 if(!node || !this.isSelected(node)){
12834 //Roo.log("not selected");
12835 return; // not selected.
12839 Roo.each(this.selections, function(s) {
12841 Roo.fly(node).removeClass(this.selectedClass);
12848 this.selections= ns;
12849 this.fireEvent("selectionchange", this, this.selections);
12853 * Gets a template node.
12854 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12855 * @return {HTMLElement} The node or null if it wasn't found
12857 getNode : function(nodeInfo){
12858 if(typeof nodeInfo == "string"){
12859 return document.getElementById(nodeInfo);
12860 }else if(typeof nodeInfo == "number"){
12861 return this.nodes[nodeInfo];
12867 * Gets a range template nodes.
12868 * @param {Number} startIndex
12869 * @param {Number} endIndex
12870 * @return {Array} An array of nodes
12872 getNodes : function(start, end){
12873 var ns = this.nodes;
12874 start = start || 0;
12875 end = typeof end == "undefined" ? ns.length - 1 : end;
12878 for(var i = start; i <= end; i++){
12882 for(var i = start; i >= end; i--){
12890 * Finds the index of the passed node
12891 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12892 * @return {Number} The index of the node or -1
12894 indexOf : function(node){
12895 node = this.getNode(node);
12896 if(typeof node.nodeIndex == "number"){
12897 return node.nodeIndex;
12899 var ns = this.nodes;
12900 for(var i = 0, len = ns.length; i < len; i++){
12911 * based on jquery fullcalendar
12915 Roo.bootstrap = Roo.bootstrap || {};
12917 * @class Roo.bootstrap.Calendar
12918 * @extends Roo.bootstrap.Component
12919 * Bootstrap Calendar class
12920 * @cfg {Boolean} loadMask (true|false) default false
12921 * @cfg {Object} header generate the user specific header of the calendar, default false
12924 * Create a new Container
12925 * @param {Object} config The config object
12930 Roo.bootstrap.Calendar = function(config){
12931 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12935 * Fires when a date is selected
12936 * @param {DatePicker} this
12937 * @param {Date} date The selected date
12941 * @event monthchange
12942 * Fires when the displayed month changes
12943 * @param {DatePicker} this
12944 * @param {Date} date The selected month
12946 'monthchange': true,
12948 * @event evententer
12949 * Fires when mouse over an event
12950 * @param {Calendar} this
12951 * @param {event} Event
12953 'evententer': true,
12955 * @event eventleave
12956 * Fires when the mouse leaves an
12957 * @param {Calendar} this
12960 'eventleave': true,
12962 * @event eventclick
12963 * Fires when the mouse click an
12964 * @param {Calendar} this
12973 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12976 * @cfg {Number} startDay
12977 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12985 getAutoCreate : function(){
12988 var fc_button = function(name, corner, style, content ) {
12989 return Roo.apply({},{
12991 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12993 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12996 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13007 style : 'width:100%',
13014 cls : 'fc-header-left',
13016 fc_button('prev', 'left', 'arrow', '‹' ),
13017 fc_button('next', 'right', 'arrow', '›' ),
13018 { tag: 'span', cls: 'fc-header-space' },
13019 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13027 cls : 'fc-header-center',
13031 cls: 'fc-header-title',
13034 html : 'month / year'
13042 cls : 'fc-header-right',
13044 /* fc_button('month', 'left', '', 'month' ),
13045 fc_button('week', '', '', 'week' ),
13046 fc_button('day', 'right', '', 'day' )
13058 header = this.header;
13061 var cal_heads = function() {
13063 // fixme - handle this.
13065 for (var i =0; i < Date.dayNames.length; i++) {
13066 var d = Date.dayNames[i];
13069 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13070 html : d.substring(0,3)
13074 ret[0].cls += ' fc-first';
13075 ret[6].cls += ' fc-last';
13078 var cal_cell = function(n) {
13081 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13086 cls: 'fc-day-number',
13090 cls: 'fc-day-content',
13094 style: 'position: relative;' // height: 17px;
13106 var cal_rows = function() {
13109 for (var r = 0; r < 6; r++) {
13116 for (var i =0; i < Date.dayNames.length; i++) {
13117 var d = Date.dayNames[i];
13118 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13121 row.cn[0].cls+=' fc-first';
13122 row.cn[0].cn[0].style = 'min-height:90px';
13123 row.cn[6].cls+=' fc-last';
13127 ret[0].cls += ' fc-first';
13128 ret[4].cls += ' fc-prev-last';
13129 ret[5].cls += ' fc-last';
13136 cls: 'fc-border-separate',
13137 style : 'width:100%',
13145 cls : 'fc-first fc-last',
13163 cls : 'fc-content',
13164 style : "position: relative;",
13167 cls : 'fc-view fc-view-month fc-grid',
13168 style : 'position: relative',
13169 unselectable : 'on',
13172 cls : 'fc-event-container',
13173 style : 'position:absolute;z-index:8;top:0;left:0;'
13191 initEvents : function()
13194 throw "can not find store for calendar";
13200 style: "text-align:center",
13204 style: "background-color:white;width:50%;margin:250 auto",
13208 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13219 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13221 var size = this.el.select('.fc-content', true).first().getSize();
13222 this.maskEl.setSize(size.width, size.height);
13223 this.maskEl.enableDisplayMode("block");
13224 if(!this.loadMask){
13225 this.maskEl.hide();
13228 this.store = Roo.factory(this.store, Roo.data);
13229 this.store.on('load', this.onLoad, this);
13230 this.store.on('beforeload', this.onBeforeLoad, this);
13234 this.cells = this.el.select('.fc-day',true);
13235 //Roo.log(this.cells);
13236 this.textNodes = this.el.query('.fc-day-number');
13237 this.cells.addClassOnOver('fc-state-hover');
13239 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13240 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13241 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13242 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13244 this.on('monthchange', this.onMonthChange, this);
13246 this.update(new Date().clearTime());
13249 resize : function() {
13250 var sz = this.el.getSize();
13252 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13253 this.el.select('.fc-day-content div',true).setHeight(34);
13258 showPrevMonth : function(e){
13259 this.update(this.activeDate.add("mo", -1));
13261 showToday : function(e){
13262 this.update(new Date().clearTime());
13265 showNextMonth : function(e){
13266 this.update(this.activeDate.add("mo", 1));
13270 showPrevYear : function(){
13271 this.update(this.activeDate.add("y", -1));
13275 showNextYear : function(){
13276 this.update(this.activeDate.add("y", 1));
13281 update : function(date)
13283 var vd = this.activeDate;
13284 this.activeDate = date;
13285 // if(vd && this.el){
13286 // var t = date.getTime();
13287 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13288 // Roo.log('using add remove');
13290 // this.fireEvent('monthchange', this, date);
13292 // this.cells.removeClass("fc-state-highlight");
13293 // this.cells.each(function(c){
13294 // if(c.dateValue == t){
13295 // c.addClass("fc-state-highlight");
13296 // setTimeout(function(){
13297 // try{c.dom.firstChild.focus();}catch(e){}
13307 var days = date.getDaysInMonth();
13309 var firstOfMonth = date.getFirstDateOfMonth();
13310 var startingPos = firstOfMonth.getDay()-this.startDay;
13312 if(startingPos < this.startDay){
13316 var pm = date.add(Date.MONTH, -1);
13317 var prevStart = pm.getDaysInMonth()-startingPos;
13319 this.cells = this.el.select('.fc-day',true);
13320 this.textNodes = this.el.query('.fc-day-number');
13321 this.cells.addClassOnOver('fc-state-hover');
13323 var cells = this.cells.elements;
13324 var textEls = this.textNodes;
13326 Roo.each(cells, function(cell){
13327 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13330 days += startingPos;
13332 // convert everything to numbers so it's fast
13333 var day = 86400000;
13334 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13337 //Roo.log(prevStart);
13339 var today = new Date().clearTime().getTime();
13340 var sel = date.clearTime().getTime();
13341 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13342 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13343 var ddMatch = this.disabledDatesRE;
13344 var ddText = this.disabledDatesText;
13345 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13346 var ddaysText = this.disabledDaysText;
13347 var format = this.format;
13349 var setCellClass = function(cal, cell){
13353 //Roo.log('set Cell Class');
13355 var t = d.getTime();
13359 cell.dateValue = t;
13361 cell.className += " fc-today";
13362 cell.className += " fc-state-highlight";
13363 cell.title = cal.todayText;
13366 // disable highlight in other month..
13367 //cell.className += " fc-state-highlight";
13372 cell.className = " fc-state-disabled";
13373 cell.title = cal.minText;
13377 cell.className = " fc-state-disabled";
13378 cell.title = cal.maxText;
13382 if(ddays.indexOf(d.getDay()) != -1){
13383 cell.title = ddaysText;
13384 cell.className = " fc-state-disabled";
13387 if(ddMatch && format){
13388 var fvalue = d.dateFormat(format);
13389 if(ddMatch.test(fvalue)){
13390 cell.title = ddText.replace("%0", fvalue);
13391 cell.className = " fc-state-disabled";
13395 if (!cell.initialClassName) {
13396 cell.initialClassName = cell.dom.className;
13399 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13404 for(; i < startingPos; i++) {
13405 textEls[i].innerHTML = (++prevStart);
13406 d.setDate(d.getDate()+1);
13408 cells[i].className = "fc-past fc-other-month";
13409 setCellClass(this, cells[i]);
13414 for(; i < days; i++){
13415 intDay = i - startingPos + 1;
13416 textEls[i].innerHTML = (intDay);
13417 d.setDate(d.getDate()+1);
13419 cells[i].className = ''; // "x-date-active";
13420 setCellClass(this, cells[i]);
13424 for(; i < 42; i++) {
13425 textEls[i].innerHTML = (++extraDays);
13426 d.setDate(d.getDate()+1);
13428 cells[i].className = "fc-future fc-other-month";
13429 setCellClass(this, cells[i]);
13432 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13434 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13436 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13437 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13439 if(totalRows != 6){
13440 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13441 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13444 this.fireEvent('monthchange', this, date);
13448 if(!this.internalRender){
13449 var main = this.el.dom.firstChild;
13450 var w = main.offsetWidth;
13451 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13452 Roo.fly(main).setWidth(w);
13453 this.internalRender = true;
13454 // opera does not respect the auto grow header center column
13455 // then, after it gets a width opera refuses to recalculate
13456 // without a second pass
13457 if(Roo.isOpera && !this.secondPass){
13458 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13459 this.secondPass = true;
13460 this.update.defer(10, this, [date]);
13467 findCell : function(dt) {
13468 dt = dt.clearTime().getTime();
13470 this.cells.each(function(c){
13471 //Roo.log("check " +c.dateValue + '?=' + dt);
13472 if(c.dateValue == dt){
13482 findCells : function(ev) {
13483 var s = ev.start.clone().clearTime().getTime();
13485 var e= ev.end.clone().clearTime().getTime();
13488 this.cells.each(function(c){
13489 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13491 if(c.dateValue > e){
13494 if(c.dateValue < s){
13503 // findBestRow: function(cells)
13507 // for (var i =0 ; i < cells.length;i++) {
13508 // ret = Math.max(cells[i].rows || 0,ret);
13515 addItem : function(ev)
13517 // look for vertical location slot in
13518 var cells = this.findCells(ev);
13520 // ev.row = this.findBestRow(cells);
13522 // work out the location.
13526 for(var i =0; i < cells.length; i++) {
13528 cells[i].row = cells[0].row;
13531 cells[i].row = cells[i].row + 1;
13541 if (crow.start.getY() == cells[i].getY()) {
13543 crow.end = cells[i];
13560 cells[0].events.push(ev);
13562 this.calevents.push(ev);
13565 clearEvents: function() {
13567 if(!this.calevents){
13571 Roo.each(this.cells.elements, function(c){
13577 Roo.each(this.calevents, function(e) {
13578 Roo.each(e.els, function(el) {
13579 el.un('mouseenter' ,this.onEventEnter, this);
13580 el.un('mouseleave' ,this.onEventLeave, this);
13585 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13591 renderEvents: function()
13595 this.cells.each(function(c) {
13604 if(c.row != c.events.length){
13605 r = 4 - (4 - (c.row - c.events.length));
13608 c.events = ev.slice(0, r);
13609 c.more = ev.slice(r);
13611 if(c.more.length && c.more.length == 1){
13612 c.events.push(c.more.pop());
13615 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13619 this.cells.each(function(c) {
13621 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13624 for (var e = 0; e < c.events.length; e++){
13625 var ev = c.events[e];
13626 var rows = ev.rows;
13628 for(var i = 0; i < rows.length; i++) {
13630 // how many rows should it span..
13633 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13634 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13636 unselectable : "on",
13639 cls: 'fc-event-inner',
13643 // cls: 'fc-event-time',
13644 // html : cells.length > 1 ? '' : ev.time
13648 cls: 'fc-event-title',
13649 html : String.format('{0}', ev.title)
13656 cls: 'ui-resizable-handle ui-resizable-e',
13657 html : '  '
13664 cfg.cls += ' fc-event-start';
13666 if ((i+1) == rows.length) {
13667 cfg.cls += ' fc-event-end';
13670 var ctr = _this.el.select('.fc-event-container',true).first();
13671 var cg = ctr.createChild(cfg);
13673 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13674 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13676 var r = (c.more.length) ? 1 : 0;
13677 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13678 cg.setWidth(ebox.right - sbox.x -2);
13680 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13681 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13682 cg.on('click', _this.onEventClick, _this, ev);
13693 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13694 style : 'position: absolute',
13695 unselectable : "on",
13698 cls: 'fc-event-inner',
13702 cls: 'fc-event-title',
13710 cls: 'ui-resizable-handle ui-resizable-e',
13711 html : '  '
13717 var ctr = _this.el.select('.fc-event-container',true).first();
13718 var cg = ctr.createChild(cfg);
13720 var sbox = c.select('.fc-day-content',true).first().getBox();
13721 var ebox = c.select('.fc-day-content',true).first().getBox();
13723 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13724 cg.setWidth(ebox.right - sbox.x -2);
13726 cg.on('click', _this.onMoreEventClick, _this, c.more);
13736 onEventEnter: function (e, el,event,d) {
13737 this.fireEvent('evententer', this, el, event);
13740 onEventLeave: function (e, el,event,d) {
13741 this.fireEvent('eventleave', this, el, event);
13744 onEventClick: function (e, el,event,d) {
13745 this.fireEvent('eventclick', this, el, event);
13748 onMonthChange: function () {
13752 onMoreEventClick: function(e, el, more)
13756 this.calpopover.placement = 'right';
13757 this.calpopover.setTitle('More');
13759 this.calpopover.setContent('');
13761 var ctr = this.calpopover.el.select('.popover-content', true).first();
13763 Roo.each(more, function(m){
13765 cls : 'fc-event-hori fc-event-draggable',
13768 var cg = ctr.createChild(cfg);
13770 cg.on('click', _this.onEventClick, _this, m);
13773 this.calpopover.show(el);
13778 onLoad: function ()
13780 this.calevents = [];
13783 if(this.store.getCount() > 0){
13784 this.store.data.each(function(d){
13787 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13788 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13789 time : d.data.start_time,
13790 title : d.data.title,
13791 description : d.data.description,
13792 venue : d.data.venue
13797 this.renderEvents();
13799 if(this.calevents.length && this.loadMask){
13800 this.maskEl.hide();
13804 onBeforeLoad: function()
13806 this.clearEvents();
13808 this.maskEl.show();
13822 * @class Roo.bootstrap.Popover
13823 * @extends Roo.bootstrap.Component
13824 * Bootstrap Popover class
13825 * @cfg {String} html contents of the popover (or false to use children..)
13826 * @cfg {String} title of popover (or false to hide)
13827 * @cfg {String} placement how it is placed
13828 * @cfg {String} trigger click || hover (or false to trigger manually)
13829 * @cfg {String} over what (parent or false to trigger manually.)
13830 * @cfg {Number} delay - delay before showing
13833 * Create a new Popover
13834 * @param {Object} config The config object
13837 Roo.bootstrap.Popover = function(config){
13838 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13841 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13843 title: 'Fill in a title',
13846 placement : 'right',
13847 trigger : 'hover', // hover
13853 can_build_overlaid : false,
13855 getChildContainer : function()
13857 return this.el.select('.popover-content',true).first();
13860 getAutoCreate : function(){
13861 Roo.log('make popover?');
13863 cls : 'popover roo-dynamic',
13864 style: 'display:block',
13870 cls : 'popover-inner',
13874 cls: 'popover-title',
13878 cls : 'popover-content',
13889 setTitle: function(str)
13891 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13893 setContent: function(str)
13895 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13897 // as it get's added to the bottom of the page.
13898 onRender : function(ct, position)
13900 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13902 var cfg = Roo.apply({}, this.getAutoCreate());
13906 cfg.cls += ' ' + this.cls;
13909 cfg.style = this.style;
13911 Roo.log("adding to ")
13912 this.el = Roo.get(document.body).createChild(cfg, position);
13918 initEvents : function()
13920 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13921 this.el.enableDisplayMode('block');
13923 if (this.over === false) {
13926 if (this.triggers === false) {
13929 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13930 var triggers = this.trigger ? this.trigger.split(' ') : [];
13931 Roo.each(triggers, function(trigger) {
13933 if (trigger == 'click') {
13934 on_el.on('click', this.toggle, this);
13935 } else if (trigger != 'manual') {
13936 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13937 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13939 on_el.on(eventIn ,this.enter, this);
13940 on_el.on(eventOut, this.leave, this);
13951 toggle : function () {
13952 this.hoverState == 'in' ? this.leave() : this.enter();
13955 enter : function () {
13958 clearTimeout(this.timeout);
13960 this.hoverState = 'in'
13962 if (!this.delay || !this.delay.show) {
13967 this.timeout = setTimeout(function () {
13968 if (_t.hoverState == 'in') {
13971 }, this.delay.show)
13973 leave : function() {
13974 clearTimeout(this.timeout);
13976 this.hoverState = 'out'
13978 if (!this.delay || !this.delay.hide) {
13983 this.timeout = setTimeout(function () {
13984 if (_t.hoverState == 'out') {
13987 }, this.delay.hide)
13990 show : function (on_el)
13993 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13996 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13997 if (this.html !== false) {
13998 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14000 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14001 if (!this.title.length) {
14002 this.el.select('.popover-title',true).hide();
14005 var placement = typeof this.placement == 'function' ?
14006 this.placement.call(this, this.el, on_el) :
14009 var autoToken = /\s?auto?\s?/i;
14010 var autoPlace = autoToken.test(placement);
14012 placement = placement.replace(autoToken, '') || 'top';
14016 //this.el.setXY([0,0]);
14018 this.el.dom.style.display='block';
14019 this.el.addClass(placement);
14021 //this.el.appendTo(on_el);
14023 var p = this.getPosition();
14024 var box = this.el.getBox();
14029 var align = Roo.bootstrap.Popover.alignment[placement]
14030 this.el.alignTo(on_el, align[0],align[1]);
14031 //var arrow = this.el.select('.arrow',true).first();
14032 //arrow.set(align[2],
14034 this.el.addClass('in');
14035 this.hoverState = null;
14037 if (this.el.hasClass('fade')) {
14044 this.el.setXY([0,0]);
14045 this.el.removeClass('in');
14052 Roo.bootstrap.Popover.alignment = {
14053 'left' : ['r-l', [-10,0], 'right'],
14054 'right' : ['l-r', [10,0], 'left'],
14055 'bottom' : ['t-b', [0,10], 'top'],
14056 'top' : [ 'b-t', [0,-10], 'bottom']
14067 * @class Roo.bootstrap.Progress
14068 * @extends Roo.bootstrap.Component
14069 * Bootstrap Progress class
14070 * @cfg {Boolean} striped striped of the progress bar
14071 * @cfg {Boolean} active animated of the progress bar
14075 * Create a new Progress
14076 * @param {Object} config The config object
14079 Roo.bootstrap.Progress = function(config){
14080 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14083 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14088 getAutoCreate : function(){
14096 cfg.cls += ' progress-striped';
14100 cfg.cls += ' active';
14119 * @class Roo.bootstrap.ProgressBar
14120 * @extends Roo.bootstrap.Component
14121 * Bootstrap ProgressBar class
14122 * @cfg {Number} aria_valuenow aria-value now
14123 * @cfg {Number} aria_valuemin aria-value min
14124 * @cfg {Number} aria_valuemax aria-value max
14125 * @cfg {String} label label for the progress bar
14126 * @cfg {String} panel (success | info | warning | danger )
14127 * @cfg {String} role role of the progress bar
14128 * @cfg {String} sr_only text
14132 * Create a new ProgressBar
14133 * @param {Object} config The config object
14136 Roo.bootstrap.ProgressBar = function(config){
14137 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14140 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14144 aria_valuemax : 100,
14150 getAutoCreate : function()
14155 cls: 'progress-bar',
14156 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14168 cfg.role = this.role;
14171 if(this.aria_valuenow){
14172 cfg['aria-valuenow'] = this.aria_valuenow;
14175 if(this.aria_valuemin){
14176 cfg['aria-valuemin'] = this.aria_valuemin;
14179 if(this.aria_valuemax){
14180 cfg['aria-valuemax'] = this.aria_valuemax;
14183 if(this.label && !this.sr_only){
14184 cfg.html = this.label;
14188 cfg.cls += ' progress-bar-' + this.panel;
14194 update : function(aria_valuenow)
14196 this.aria_valuenow = aria_valuenow;
14198 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14213 * @class Roo.bootstrap.TabGroup
14214 * @extends Roo.bootstrap.Column
14215 * Bootstrap Column class
14216 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14217 * @cfg {Boolean} carousel true to make the group behave like a carousel
14220 * Create a new TabGroup
14221 * @param {Object} config The config object
14224 Roo.bootstrap.TabGroup = function(config){
14225 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14227 this.navId = Roo.id();
14230 Roo.bootstrap.TabGroup.register(this);
14234 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14237 transition : false,
14239 getAutoCreate : function()
14241 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14243 cfg.cls += ' tab-content';
14245 if (this.carousel) {
14246 cfg.cls += ' carousel slide';
14248 cls : 'carousel-inner'
14255 getChildContainer : function()
14257 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14261 * register a Navigation item
14262 * @param {Roo.bootstrap.NavItem} the navitem to add
14264 register : function(item)
14266 this.tabs.push( item);
14267 item.navId = this.navId; // not really needed..
14271 getActivePanel : function()
14274 Roo.each(this.tabs, function(t) {
14284 getPanelByName : function(n)
14287 Roo.each(this.tabs, function(t) {
14288 if (t.tabId == n) {
14296 indexOfPanel : function(p)
14299 Roo.each(this.tabs, function(t,i) {
14300 if (t.tabId == p.tabId) {
14309 * show a specific panel
14310 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14311 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14313 showPanel : function (pan)
14316 if (typeof(pan) == 'number') {
14317 pan = this.tabs[pan];
14319 if (typeof(pan) == 'string') {
14320 pan = this.getPanelByName(pan);
14322 if (pan.tabId == this.getActivePanel().tabId) {
14325 var cur = this.getActivePanel();
14327 if (false === cur.fireEvent('beforedeactivate')) {
14331 if (this.carousel) {
14332 this.transition = true;
14333 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14334 var lr = dir == 'next' ? 'left' : 'right';
14335 pan.el.addClass(dir); // or prev
14336 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14337 cur.el.addClass(lr); // or right
14338 pan.el.addClass(lr);
14341 cur.el.on('transitionend', function() {
14342 Roo.log("trans end?");
14344 pan.el.removeClass([lr,dir]);
14345 pan.setActive(true);
14347 cur.el.removeClass([lr]);
14348 cur.setActive(false);
14350 _this.transition = false;
14352 }, this, { single: true } );
14356 cur.setActive(false);
14357 pan.setActive(true);
14361 showPanelNext : function()
14363 var i = this.indexOfPanel(this.getActivePanel());
14364 if (i > this.tabs.length) {
14367 this.showPanel(this.tabs[i+1]);
14369 showPanelPrev : function()
14371 var i = this.indexOfPanel(this.getActivePanel());
14375 this.showPanel(this.tabs[i-1]);
14386 Roo.apply(Roo.bootstrap.TabGroup, {
14390 * register a Navigation Group
14391 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14393 register : function(navgrp)
14395 this.groups[navgrp.navId] = navgrp;
14399 * fetch a Navigation Group based on the navigation ID
14400 * if one does not exist , it will get created.
14401 * @param {string} the navgroup to add
14402 * @returns {Roo.bootstrap.NavGroup} the navgroup
14404 get: function(navId) {
14405 if (typeof(this.groups[navId]) == 'undefined') {
14406 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14408 return this.groups[navId] ;
14423 * @class Roo.bootstrap.TabPanel
14424 * @extends Roo.bootstrap.Component
14425 * Bootstrap TabPanel class
14426 * @cfg {Boolean} active panel active
14427 * @cfg {String} html panel content
14428 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14429 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14433 * Create a new TabPanel
14434 * @param {Object} config The config object
14437 Roo.bootstrap.TabPanel = function(config){
14438 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14442 * Fires when the active status changes
14443 * @param {Roo.bootstrap.TabPanel} this
14444 * @param {Boolean} state the new state
14449 * @event beforedeactivate
14450 * Fires before a tab is de-activated - can be used to do validation on a form.
14451 * @param {Roo.bootstrap.TabPanel} this
14452 * @return {Boolean} false if there is an error
14455 'beforedeactivate': true
14458 this.tabId = this.tabId || Roo.id();
14462 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14469 getAutoCreate : function(){
14472 // item is needed for carousel - not sure if it has any effect otherwise
14473 cls: 'tab-pane item',
14474 html: this.html || ''
14478 cfg.cls += ' active';
14482 cfg.tabId = this.tabId;
14489 initEvents: function()
14491 Roo.log('-------- init events on tab panel ---------');
14493 var p = this.parent();
14494 this.navId = this.navId || p.navId;
14496 if (typeof(this.navId) != 'undefined') {
14497 // not really needed.. but just in case.. parent should be a NavGroup.
14498 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14499 Roo.log(['register', tg, this]);
14505 onRender : function(ct, position)
14507 // Roo.log("Call onRender: " + this.xtype);
14509 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14517 setActive: function(state)
14519 Roo.log("panel - set active " + this.tabId + "=" + state);
14521 this.active = state;
14523 this.el.removeClass('active');
14525 } else if (!this.el.hasClass('active')) {
14526 this.el.addClass('active');
14528 this.fireEvent('changed', this, state);
14545 * @class Roo.bootstrap.DateField
14546 * @extends Roo.bootstrap.Input
14547 * Bootstrap DateField class
14548 * @cfg {Number} weekStart default 0
14549 * @cfg {String} viewMode default empty, (months|years)
14550 * @cfg {String} minViewMode default empty, (months|years)
14551 * @cfg {Number} startDate default -Infinity
14552 * @cfg {Number} endDate default Infinity
14553 * @cfg {Boolean} todayHighlight default false
14554 * @cfg {Boolean} todayBtn default false
14555 * @cfg {Boolean} calendarWeeks default false
14556 * @cfg {Object} daysOfWeekDisabled default empty
14557 * @cfg {Boolean} singleMode default false (true | false)
14559 * @cfg {Boolean} keyboardNavigation default true
14560 * @cfg {String} language default en
14563 * Create a new DateField
14564 * @param {Object} config The config object
14567 Roo.bootstrap.DateField = function(config){
14568 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14572 * Fires when this field show.
14573 * @param {Roo.bootstrap.DateField} this
14574 * @param {Mixed} date The date value
14579 * Fires when this field hide.
14580 * @param {Roo.bootstrap.DateField} this
14581 * @param {Mixed} date The date value
14586 * Fires when select a date.
14587 * @param {Roo.bootstrap.DateField} this
14588 * @param {Mixed} date The date value
14594 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14597 * @cfg {String} format
14598 * The default date format string which can be overriden for localization support. The format must be
14599 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14603 * @cfg {String} altFormats
14604 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14605 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14607 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14615 todayHighlight : false,
14621 keyboardNavigation: true,
14623 calendarWeeks: false,
14625 startDate: -Infinity,
14629 daysOfWeekDisabled: [],
14633 singleMode : false,
14635 UTCDate: function()
14637 return new Date(Date.UTC.apply(Date, arguments));
14640 UTCToday: function()
14642 var today = new Date();
14643 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14646 getDate: function() {
14647 var d = this.getUTCDate();
14648 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14651 getUTCDate: function() {
14655 setDate: function(d) {
14656 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14659 setUTCDate: function(d) {
14661 this.setValue(this.formatDate(this.date));
14664 onRender: function(ct, position)
14667 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14669 this.language = this.language || 'en';
14670 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14671 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14673 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14674 this.format = this.format || 'm/d/y';
14675 this.isInline = false;
14676 this.isInput = true;
14677 this.component = this.el.select('.add-on', true).first() || false;
14678 this.component = (this.component && this.component.length === 0) ? false : this.component;
14679 this.hasInput = this.component && this.inputEL().length;
14681 if (typeof(this.minViewMode === 'string')) {
14682 switch (this.minViewMode) {
14684 this.minViewMode = 1;
14687 this.minViewMode = 2;
14690 this.minViewMode = 0;
14695 if (typeof(this.viewMode === 'string')) {
14696 switch (this.viewMode) {
14709 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14711 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14713 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14715 this.picker().on('mousedown', this.onMousedown, this);
14716 this.picker().on('click', this.onClick, this);
14718 this.picker().addClass('datepicker-dropdown');
14720 this.startViewMode = this.viewMode;
14722 if(this.singleMode){
14723 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14724 v.setVisibilityMode(Roo.Element.DISPLAY)
14728 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14729 v.setStyle('width', '189px');
14733 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14734 if(!this.calendarWeeks){
14739 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14740 v.attr('colspan', function(i, val){
14741 return parseInt(val) + 1;
14746 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14748 this.setStartDate(this.startDate);
14749 this.setEndDate(this.endDate);
14751 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14758 if(this.isInline) {
14763 picker : function()
14765 return this.pickerEl;
14766 // return this.el.select('.datepicker', true).first();
14769 fillDow: function()
14771 var dowCnt = this.weekStart;
14780 if(this.calendarWeeks){
14788 while (dowCnt < this.weekStart + 7) {
14792 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14796 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14799 fillMonths: function()
14802 var months = this.picker().select('>.datepicker-months td', true).first();
14804 months.dom.innerHTML = '';
14810 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14813 months.createChild(month);
14820 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;
14822 if (this.date < this.startDate) {
14823 this.viewDate = new Date(this.startDate);
14824 } else if (this.date > this.endDate) {
14825 this.viewDate = new Date(this.endDate);
14827 this.viewDate = new Date(this.date);
14835 var d = new Date(this.viewDate),
14836 year = d.getUTCFullYear(),
14837 month = d.getUTCMonth(),
14838 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14839 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14840 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14841 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14842 currentDate = this.date && this.date.valueOf(),
14843 today = this.UTCToday();
14845 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14847 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14849 // this.picker.select('>tfoot th.today').
14850 // .text(dates[this.language].today)
14851 // .toggle(this.todayBtn !== false);
14853 this.updateNavArrows();
14856 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14858 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14860 prevMonth.setUTCDate(day);
14862 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14864 var nextMonth = new Date(prevMonth);
14866 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14868 nextMonth = nextMonth.valueOf();
14870 var fillMonths = false;
14872 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14874 while(prevMonth.valueOf() < nextMonth) {
14877 if (prevMonth.getUTCDay() === this.weekStart) {
14879 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14887 if(this.calendarWeeks){
14888 // ISO 8601: First week contains first thursday.
14889 // ISO also states week starts on Monday, but we can be more abstract here.
14891 // Start of current week: based on weekstart/current date
14892 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14893 // Thursday of this week
14894 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14895 // First Thursday of year, year from thursday
14896 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14897 // Calendar week: ms between thursdays, div ms per day, div 7 days
14898 calWeek = (th - yth) / 864e5 / 7 + 1;
14900 fillMonths.cn.push({
14908 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14910 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14913 if (this.todayHighlight &&
14914 prevMonth.getUTCFullYear() == today.getFullYear() &&
14915 prevMonth.getUTCMonth() == today.getMonth() &&
14916 prevMonth.getUTCDate() == today.getDate()) {
14917 clsName += ' today';
14920 if (currentDate && prevMonth.valueOf() === currentDate) {
14921 clsName += ' active';
14924 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14925 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14926 clsName += ' disabled';
14929 fillMonths.cn.push({
14931 cls: 'day ' + clsName,
14932 html: prevMonth.getDate()
14935 prevMonth.setDate(prevMonth.getDate()+1);
14938 var currentYear = this.date && this.date.getUTCFullYear();
14939 var currentMonth = this.date && this.date.getUTCMonth();
14941 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14943 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14944 v.removeClass('active');
14946 if(currentYear === year && k === currentMonth){
14947 v.addClass('active');
14950 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14951 v.addClass('disabled');
14957 year = parseInt(year/10, 10) * 10;
14959 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14961 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14964 for (var i = -1; i < 11; i++) {
14965 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14967 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14975 showMode: function(dir)
14978 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14981 Roo.each(this.picker().select('>div',true).elements, function(v){
14982 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14985 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14990 if(this.isInline) return;
14992 this.picker().removeClass(['bottom', 'top']);
14994 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14996 * place to the top of element!
15000 this.picker().addClass('top');
15001 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15006 this.picker().addClass('bottom');
15008 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15011 parseDate : function(value)
15013 if(!value || value instanceof Date){
15016 var v = Date.parseDate(value, this.format);
15017 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15018 v = Date.parseDate(value, 'Y-m-d');
15020 if(!v && this.altFormats){
15021 if(!this.altFormatsArray){
15022 this.altFormatsArray = this.altFormats.split("|");
15024 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15025 v = Date.parseDate(value, this.altFormatsArray[i]);
15031 formatDate : function(date, fmt)
15033 return (!date || !(date instanceof Date)) ?
15034 date : date.dateFormat(fmt || this.format);
15037 onFocus : function()
15039 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15043 onBlur : function()
15045 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15047 var d = this.inputEl().getValue();
15056 this.picker().show();
15060 this.fireEvent('show', this, this.date);
15065 if(this.isInline) return;
15066 this.picker().hide();
15067 this.viewMode = this.startViewMode;
15070 this.fireEvent('hide', this, this.date);
15074 onMousedown: function(e)
15076 e.stopPropagation();
15077 e.preventDefault();
15082 Roo.bootstrap.DateField.superclass.keyup.call(this);
15086 setValue: function(v)
15089 // v can be a string or a date..
15092 var d = new Date(this.parseDate(v) ).clearTime();
15094 if(isNaN(d.getTime())){
15095 this.date = this.viewDate = '';
15096 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15100 v = this.formatDate(d);
15102 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15104 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15108 this.fireEvent('select', this, this.date);
15112 getValue: function()
15114 return this.formatDate(this.date);
15117 fireKey: function(e)
15119 if (!this.picker().isVisible()){
15120 if (e.keyCode == 27) // allow escape to hide and re-show picker
15125 var dateChanged = false,
15127 newDate, newViewDate;
15132 e.preventDefault();
15136 if (!this.keyboardNavigation) break;
15137 dir = e.keyCode == 37 ? -1 : 1;
15140 newDate = this.moveYear(this.date, dir);
15141 newViewDate = this.moveYear(this.viewDate, dir);
15142 } else if (e.shiftKey){
15143 newDate = this.moveMonth(this.date, dir);
15144 newViewDate = this.moveMonth(this.viewDate, dir);
15146 newDate = new Date(this.date);
15147 newDate.setUTCDate(this.date.getUTCDate() + dir);
15148 newViewDate = new Date(this.viewDate);
15149 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15151 if (this.dateWithinRange(newDate)){
15152 this.date = newDate;
15153 this.viewDate = newViewDate;
15154 this.setValue(this.formatDate(this.date));
15156 e.preventDefault();
15157 dateChanged = true;
15162 if (!this.keyboardNavigation) break;
15163 dir = e.keyCode == 38 ? -1 : 1;
15165 newDate = this.moveYear(this.date, dir);
15166 newViewDate = this.moveYear(this.viewDate, dir);
15167 } else if (e.shiftKey){
15168 newDate = this.moveMonth(this.date, dir);
15169 newViewDate = this.moveMonth(this.viewDate, dir);
15171 newDate = new Date(this.date);
15172 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15173 newViewDate = new Date(this.viewDate);
15174 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15176 if (this.dateWithinRange(newDate)){
15177 this.date = newDate;
15178 this.viewDate = newViewDate;
15179 this.setValue(this.formatDate(this.date));
15181 e.preventDefault();
15182 dateChanged = true;
15186 this.setValue(this.formatDate(this.date));
15188 e.preventDefault();
15191 this.setValue(this.formatDate(this.date));
15205 onClick: function(e)
15207 e.stopPropagation();
15208 e.preventDefault();
15210 var target = e.getTarget();
15212 if(target.nodeName.toLowerCase() === 'i'){
15213 target = Roo.get(target).dom.parentNode;
15216 var nodeName = target.nodeName;
15217 var className = target.className;
15218 var html = target.innerHTML;
15219 //Roo.log(nodeName);
15221 switch(nodeName.toLowerCase()) {
15223 switch(className) {
15229 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15230 switch(this.viewMode){
15232 this.viewDate = this.moveMonth(this.viewDate, dir);
15236 this.viewDate = this.moveYear(this.viewDate, dir);
15242 var date = new Date();
15243 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15245 this.setValue(this.formatDate(this.date));
15252 if (className.indexOf('disabled') < 0) {
15253 this.viewDate.setUTCDate(1);
15254 if (className.indexOf('month') > -1) {
15255 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15257 var year = parseInt(html, 10) || 0;
15258 this.viewDate.setUTCFullYear(year);
15262 if(this.singleMode){
15263 this.setValue(this.formatDate(this.viewDate));
15274 //Roo.log(className);
15275 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15276 var day = parseInt(html, 10) || 1;
15277 var year = this.viewDate.getUTCFullYear(),
15278 month = this.viewDate.getUTCMonth();
15280 if (className.indexOf('old') > -1) {
15287 } else if (className.indexOf('new') > -1) {
15295 //Roo.log([year,month,day]);
15296 this.date = this.UTCDate(year, month, day,0,0,0,0);
15297 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15299 //Roo.log(this.formatDate(this.date));
15300 this.setValue(this.formatDate(this.date));
15307 setStartDate: function(startDate)
15309 this.startDate = startDate || -Infinity;
15310 if (this.startDate !== -Infinity) {
15311 this.startDate = this.parseDate(this.startDate);
15314 this.updateNavArrows();
15317 setEndDate: function(endDate)
15319 this.endDate = endDate || Infinity;
15320 if (this.endDate !== Infinity) {
15321 this.endDate = this.parseDate(this.endDate);
15324 this.updateNavArrows();
15327 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15329 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15330 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15331 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15333 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15334 return parseInt(d, 10);
15337 this.updateNavArrows();
15340 updateNavArrows: function()
15342 if(this.singleMode){
15346 var d = new Date(this.viewDate),
15347 year = d.getUTCFullYear(),
15348 month = d.getUTCMonth();
15350 Roo.each(this.picker().select('.prev', true).elements, function(v){
15352 switch (this.viewMode) {
15355 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15361 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15368 Roo.each(this.picker().select('.next', true).elements, function(v){
15370 switch (this.viewMode) {
15373 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15379 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15387 moveMonth: function(date, dir)
15389 if (!dir) return date;
15390 var new_date = new Date(date.valueOf()),
15391 day = new_date.getUTCDate(),
15392 month = new_date.getUTCMonth(),
15393 mag = Math.abs(dir),
15395 dir = dir > 0 ? 1 : -1;
15398 // If going back one month, make sure month is not current month
15399 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15401 return new_date.getUTCMonth() == month;
15403 // If going forward one month, make sure month is as expected
15404 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15406 return new_date.getUTCMonth() != new_month;
15408 new_month = month + dir;
15409 new_date.setUTCMonth(new_month);
15410 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15411 if (new_month < 0 || new_month > 11)
15412 new_month = (new_month + 12) % 12;
15414 // For magnitudes >1, move one month at a time...
15415 for (var i=0; i<mag; i++)
15416 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15417 new_date = this.moveMonth(new_date, dir);
15418 // ...then reset the day, keeping it in the new month
15419 new_month = new_date.getUTCMonth();
15420 new_date.setUTCDate(day);
15422 return new_month != new_date.getUTCMonth();
15425 // Common date-resetting loop -- if date is beyond end of month, make it
15428 new_date.setUTCDate(--day);
15429 new_date.setUTCMonth(new_month);
15434 moveYear: function(date, dir)
15436 return this.moveMonth(date, dir*12);
15439 dateWithinRange: function(date)
15441 return date >= this.startDate && date <= this.endDate;
15447 this.picker().remove();
15452 Roo.apply(Roo.bootstrap.DateField, {
15463 html: '<i class="fa fa-arrow-left"/>'
15473 html: '<i class="fa fa-arrow-right"/>'
15515 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15516 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15517 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15518 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15519 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15532 navFnc: 'FullYear',
15537 navFnc: 'FullYear',
15542 Roo.apply(Roo.bootstrap.DateField, {
15546 cls: 'datepicker dropdown-menu roo-dynamic',
15550 cls: 'datepicker-days',
15554 cls: 'table-condensed',
15556 Roo.bootstrap.DateField.head,
15560 Roo.bootstrap.DateField.footer
15567 cls: 'datepicker-months',
15571 cls: 'table-condensed',
15573 Roo.bootstrap.DateField.head,
15574 Roo.bootstrap.DateField.content,
15575 Roo.bootstrap.DateField.footer
15582 cls: 'datepicker-years',
15586 cls: 'table-condensed',
15588 Roo.bootstrap.DateField.head,
15589 Roo.bootstrap.DateField.content,
15590 Roo.bootstrap.DateField.footer
15609 * @class Roo.bootstrap.TimeField
15610 * @extends Roo.bootstrap.Input
15611 * Bootstrap DateField class
15615 * Create a new TimeField
15616 * @param {Object} config The config object
15619 Roo.bootstrap.TimeField = function(config){
15620 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15624 * Fires when this field show.
15625 * @param {Roo.bootstrap.DateField} this
15626 * @param {Mixed} date The date value
15631 * Fires when this field hide.
15632 * @param {Roo.bootstrap.DateField} this
15633 * @param {Mixed} date The date value
15638 * Fires when select a date.
15639 * @param {Roo.bootstrap.DateField} this
15640 * @param {Mixed} date The date value
15646 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15649 * @cfg {String} format
15650 * The default time format string which can be overriden for localization support. The format must be
15651 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15655 onRender: function(ct, position)
15658 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15660 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15662 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15664 this.pop = this.picker().select('>.datepicker-time',true).first();
15665 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15667 this.picker().on('mousedown', this.onMousedown, this);
15668 this.picker().on('click', this.onClick, this);
15670 this.picker().addClass('datepicker-dropdown');
15675 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15676 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15677 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15678 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15679 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15680 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15684 fireKey: function(e){
15685 if (!this.picker().isVisible()){
15686 if (e.keyCode == 27) // allow escape to hide and re-show picker
15691 e.preventDefault();
15699 this.onTogglePeriod();
15702 this.onIncrementMinutes();
15705 this.onDecrementMinutes();
15714 onClick: function(e) {
15715 e.stopPropagation();
15716 e.preventDefault();
15719 picker : function()
15721 return this.el.select('.datepicker', true).first();
15724 fillTime: function()
15726 var time = this.pop.select('tbody', true).first();
15728 time.dom.innerHTML = '';
15743 cls: 'hours-up glyphicon glyphicon-chevron-up'
15763 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15784 cls: 'timepicker-hour',
15799 cls: 'timepicker-minute',
15814 cls: 'btn btn-primary period',
15836 cls: 'hours-down glyphicon glyphicon-chevron-down'
15856 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15874 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15881 var hours = this.time.getHours();
15882 var minutes = this.time.getMinutes();
15895 hours = hours - 12;
15899 hours = '0' + hours;
15903 minutes = '0' + minutes;
15906 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15907 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15908 this.pop.select('button', true).first().dom.innerHTML = period;
15914 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15916 var cls = ['bottom'];
15918 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15925 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15930 this.picker().addClass(cls.join('-'));
15934 Roo.each(cls, function(c){
15936 _this.picker().setTop(_this.inputEl().getHeight());
15940 _this.picker().setTop(0 - _this.picker().getHeight());
15945 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15949 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15956 onFocus : function()
15958 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15962 onBlur : function()
15964 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15970 this.picker().show();
15975 this.fireEvent('show', this, this.date);
15980 this.picker().hide();
15983 this.fireEvent('hide', this, this.date);
15986 setTime : function()
15989 this.setValue(this.time.format(this.format));
15991 this.fireEvent('select', this, this.date);
15996 onMousedown: function(e){
15997 e.stopPropagation();
15998 e.preventDefault();
16001 onIncrementHours: function()
16003 Roo.log('onIncrementHours');
16004 this.time = this.time.add(Date.HOUR, 1);
16009 onDecrementHours: function()
16011 Roo.log('onDecrementHours');
16012 this.time = this.time.add(Date.HOUR, -1);
16016 onIncrementMinutes: function()
16018 Roo.log('onIncrementMinutes');
16019 this.time = this.time.add(Date.MINUTE, 1);
16023 onDecrementMinutes: function()
16025 Roo.log('onDecrementMinutes');
16026 this.time = this.time.add(Date.MINUTE, -1);
16030 onTogglePeriod: function()
16032 Roo.log('onTogglePeriod');
16033 this.time = this.time.add(Date.HOUR, 12);
16040 Roo.apply(Roo.bootstrap.TimeField, {
16070 cls: 'btn btn-info ok',
16082 Roo.apply(Roo.bootstrap.TimeField, {
16086 cls: 'datepicker dropdown-menu',
16090 cls: 'datepicker-time',
16094 cls: 'table-condensed',
16096 Roo.bootstrap.TimeField.content,
16097 Roo.bootstrap.TimeField.footer
16116 * @class Roo.bootstrap.CheckBox
16117 * @extends Roo.bootstrap.Input
16118 * Bootstrap CheckBox class
16120 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16121 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16122 * @cfg {String} boxLabel The text that appears beside the checkbox
16123 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16124 * @cfg {Boolean} checked initnal the element
16125 * @cfg {Boolean} inline inline the element (default false)
16128 * Create a new CheckBox
16129 * @param {Object} config The config object
16132 Roo.bootstrap.CheckBox = function(config){
16133 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16138 * Fires when the element is checked or unchecked.
16139 * @param {Roo.bootstrap.CheckBox} this This input
16140 * @param {Boolean} checked The new checked value
16146 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16148 inputType: 'checkbox',
16156 getAutoCreate : function()
16158 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16164 cfg.cls = 'form-group ' + this.inputType //input-group
16167 cfg.cls += ' ' + this.inputType + '-inline';
16173 type : this.inputType,
16174 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16175 cls : 'roo-' + this.inputType, //'form-box',
16176 placeholder : this.placeholder || ''
16180 if (this.weight) { // Validity check?
16181 cfg.cls += " " + this.inputType + "-" + this.weight;
16184 if (this.disabled) {
16185 input.disabled=true;
16189 input.checked = this.checked;
16193 input.name = this.name;
16197 input.cls += ' input-' + this.size;
16201 ['xs','sm','md','lg'].map(function(size){
16202 if (settings[size]) {
16203 cfg.cls += ' col-' + size + '-' + settings[size];
16209 var inputblock = input;
16214 if (this.before || this.after) {
16217 cls : 'input-group',
16221 inputblock.cn.push({
16223 cls : 'input-group-addon',
16227 inputblock.cn.push(input);
16229 inputblock.cn.push({
16231 cls : 'input-group-addon',
16238 if (align ==='left' && this.fieldLabel.length) {
16239 Roo.log("left and has label");
16245 cls : 'control-label col-md-' + this.labelWidth,
16246 html : this.fieldLabel
16250 cls : "col-md-" + (12 - this.labelWidth),
16257 } else if ( this.fieldLabel.length) {
16262 tag: this.boxLabel ? 'span' : 'label',
16264 cls: 'control-label box-input-label',
16265 //cls : 'input-group-addon',
16266 html : this.fieldLabel
16276 Roo.log(" no label && no align");
16277 cfg.cn = [ inputblock ] ;
16282 var boxLabelCfg = {
16284 //'for': id, // box label is handled by onclick - so no for...
16286 html: this.boxLabel
16290 boxLabelCfg.tooltip = this.tooltip;
16293 cfg.cn.push(boxLabelCfg);
16303 * return the real input element.
16305 inputEl: function ()
16307 return this.el.select('input.roo-' + this.inputType,true).first();
16310 labelEl: function()
16312 return this.el.select('label.control-label',true).first();
16314 /* depricated... */
16318 return this.labelEl();
16321 initEvents : function()
16323 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16325 this.inputEl().on('click', this.onClick, this);
16326 if (this.boxLabel) {
16327 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16332 onClick : function()
16334 this.setChecked(!this.checked);
16337 setChecked : function(state,suppressEvent)
16339 if(this.inputType == 'radio'){
16341 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16342 e.dom.checked = false;
16345 this.inputEl().dom.checked = true;
16347 if(suppressEvent !== true){
16348 this.fireEvent('check', this, true);
16351 this.inputEl().dom.value = this.inputValue;
16356 this.checked = state;
16358 if(suppressEvent !== true){
16359 this.fireEvent('check', this, state);
16362 this.inputEl().dom.checked = state;
16364 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16368 getValue : function()
16370 if(this.inputType == 'radio'){
16371 return this.getGroupValue();
16374 return this.inputEl().getValue();
16378 getGroupValue : function()
16380 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16383 setValue : function(v,suppressEvent)
16385 if(this.inputType == 'radio'){
16386 this.setGroupValue(v, suppressEvent);
16390 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16393 setGroupValue : function(v, suppressEvent)
16395 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16396 e.dom.checked = false;
16398 if(e.dom.value == v){
16399 e.dom.checked = true;
16403 if(suppressEvent !== true){
16404 this.fireEvent('check', this, true);
16420 *<div class="radio">
16422 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
16423 Option one is this and that—be sure to include why it's great
16430 *<label class="radio-inline">fieldLabel</label>
16431 *<label class="radio-inline">
16432 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
16440 * @class Roo.bootstrap.Radio
16441 * @extends Roo.bootstrap.CheckBox
16442 * Bootstrap Radio class
16445 * Create a new Radio
16446 * @param {Object} config The config object
16449 Roo.bootstrap.Radio = function(config){
16450 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16454 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16456 inputType: 'radio',
16460 getAutoCreate : function()
16462 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16463 align = align || 'left'; // default...
16470 tag : this.inline ? 'span' : 'div',
16475 var inline = this.inline ? ' radio-inline' : '';
16479 // does not need for, as we wrap the input with it..
16481 cls : 'control-label box-label' + inline,
16487 cls : 'control-label' + inline,
16488 html : this.fieldLabel,
16489 style : 'cursor:default'
16498 type : this.inputType,
16499 //value : (!this.checked) ? this.valueOff : this.inputValue,
16500 value : this.inputValue,
16502 placeholder : this.placeholder || '' // ?? needed????
16505 if (this.weight) { // Validity check?
16506 input.cls += " radio-" + this.weight;
16508 if (this.disabled) {
16509 input.disabled=true;
16513 input.checked = this.checked;
16517 input.name = this.name;
16521 input.cls += ' input-' + this.size;
16524 //?? can span's inline have a width??
16527 ['xs','sm','md','lg'].map(function(size){
16528 if (settings[size]) {
16529 cfg.cls += ' col-' + size + '-' + settings[size];
16533 var inputblock = input;
16535 if (this.before || this.after) {
16538 cls : 'input-group',
16543 inputblock.cn.push({
16545 cls : 'input-group-addon',
16549 inputblock.cn.push(input);
16551 inputblock.cn.push({
16553 cls : 'input-group-addon',
16561 if (this.fieldLabel && this.fieldLabel.length) {
16562 cfg.cn.push(fieldLabel);
16565 // normal bootstrap puts the input inside the label.
16566 // however with our styled version - it has to go after the input.
16568 //lbl.cn.push(inputblock);
16572 cls: 'radio' + inline,
16579 cfg.cn.push( lblwrap);
16584 html: this.boxLabel
16593 initEvents : function()
16595 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16597 this.inputEl().on('click', this.onClick, this);
16598 if (this.boxLabel) {
16599 Roo.log('find label')
16600 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
16605 inputEl: function ()
16607 return this.el.select('input.roo-radio',true).first();
16609 onClick : function()
16612 this.setChecked(true);
16615 setChecked : function(state,suppressEvent)
16618 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16619 v.dom.checked = false;
16622 Roo.log(this.inputEl().dom);
16623 this.checked = state;
16624 this.inputEl().dom.checked = state;
16626 if(suppressEvent !== true){
16627 this.fireEvent('check', this, state);
16630 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16634 getGroupValue : function()
16637 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16638 if(v.dom.checked == true){
16639 value = v.dom.value;
16647 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16648 * @return {Mixed} value The field value
16650 getValue : function(){
16651 return this.getGroupValue();
16657 //<script type="text/javascript">
16660 * Based Ext JS Library 1.1.1
16661 * Copyright(c) 2006-2007, Ext JS, LLC.
16667 * @class Roo.HtmlEditorCore
16668 * @extends Roo.Component
16669 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16671 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16674 Roo.HtmlEditorCore = function(config){
16677 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16682 * @event initialize
16683 * Fires when the editor is fully initialized (including the iframe)
16684 * @param {Roo.HtmlEditorCore} this
16689 * Fires when the editor is first receives the focus. Any insertion must wait
16690 * until after this event.
16691 * @param {Roo.HtmlEditorCore} this
16695 * @event beforesync
16696 * Fires before the textarea is updated with content from the editor iframe. Return false
16697 * to cancel the sync.
16698 * @param {Roo.HtmlEditorCore} this
16699 * @param {String} html
16703 * @event beforepush
16704 * Fires before the iframe editor is updated with content from the textarea. Return false
16705 * to cancel the push.
16706 * @param {Roo.HtmlEditorCore} this
16707 * @param {String} html
16712 * Fires when the textarea is updated with content from the editor iframe.
16713 * @param {Roo.HtmlEditorCore} this
16714 * @param {String} html
16719 * Fires when the iframe editor is updated with content from the textarea.
16720 * @param {Roo.HtmlEditorCore} this
16721 * @param {String} html
16726 * @event editorevent
16727 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16728 * @param {Roo.HtmlEditorCore} this
16734 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16736 // defaults : white / black...
16737 this.applyBlacklists();
16744 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16748 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16754 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16759 * @cfg {Number} height (in pixels)
16763 * @cfg {Number} width (in pixels)
16768 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16771 stylesheets: false,
16776 // private properties
16777 validationEvent : false,
16779 initialized : false,
16781 sourceEditMode : false,
16782 onFocus : Roo.emptyFn,
16784 hideMode:'offsets',
16788 // blacklist + whitelisted elements..
16795 * Protected method that will not generally be called directly. It
16796 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16797 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16799 getDocMarkup : function(){
16803 // inherit styels from page...??
16804 if (this.stylesheets === false) {
16806 Roo.get(document.head).select('style').each(function(node) {
16807 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16810 Roo.get(document.head).select('link').each(function(node) {
16811 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16814 } else if (!this.stylesheets.length) {
16816 st = '<style type="text/css">' +
16817 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16823 st += '<style type="text/css">' +
16824 'IMG { cursor: pointer } ' +
16828 return '<html><head>' + st +
16829 //<style type="text/css">' +
16830 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16832 ' </head><body class="roo-htmleditor-body"></body></html>';
16836 onRender : function(ct, position)
16839 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16840 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16843 this.el.dom.style.border = '0 none';
16844 this.el.dom.setAttribute('tabIndex', -1);
16845 this.el.addClass('x-hidden hide');
16849 if(Roo.isIE){ // fix IE 1px bogus margin
16850 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16854 this.frameId = Roo.id();
16858 var iframe = this.owner.wrap.createChild({
16860 cls: 'form-control', // bootstrap..
16862 name: this.frameId,
16863 frameBorder : 'no',
16864 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16869 this.iframe = iframe.dom;
16871 this.assignDocWin();
16873 this.doc.designMode = 'on';
16876 this.doc.write(this.getDocMarkup());
16880 var task = { // must defer to wait for browser to be ready
16882 //console.log("run task?" + this.doc.readyState);
16883 this.assignDocWin();
16884 if(this.doc.body || this.doc.readyState == 'complete'){
16886 this.doc.designMode="on";
16890 Roo.TaskMgr.stop(task);
16891 this.initEditor.defer(10, this);
16898 Roo.TaskMgr.start(task);
16903 onResize : function(w, h)
16905 Roo.log('resize: ' +w + ',' + h );
16906 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16910 if(typeof w == 'number'){
16912 this.iframe.style.width = w + 'px';
16914 if(typeof h == 'number'){
16916 this.iframe.style.height = h + 'px';
16918 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16925 * Toggles the editor between standard and source edit mode.
16926 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16928 toggleSourceEdit : function(sourceEditMode){
16930 this.sourceEditMode = sourceEditMode === true;
16932 if(this.sourceEditMode){
16934 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16937 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16938 //this.iframe.className = '';
16941 //this.setSize(this.owner.wrap.getSize());
16942 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16949 * Protected method that will not generally be called directly. If you need/want
16950 * custom HTML cleanup, this is the method you should override.
16951 * @param {String} html The HTML to be cleaned
16952 * return {String} The cleaned HTML
16954 cleanHtml : function(html){
16955 html = String(html);
16956 if(html.length > 5){
16957 if(Roo.isSafari){ // strip safari nonsense
16958 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16961 if(html == ' '){
16968 * HTML Editor -> Textarea
16969 * Protected method that will not generally be called directly. Syncs the contents
16970 * of the editor iframe with the textarea.
16972 syncValue : function(){
16973 if(this.initialized){
16974 var bd = (this.doc.body || this.doc.documentElement);
16975 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16976 var html = bd.innerHTML;
16978 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16979 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16981 html = '<div style="'+m[0]+'">' + html + '</div>';
16984 html = this.cleanHtml(html);
16985 // fix up the special chars.. normaly like back quotes in word...
16986 // however we do not want to do this with chinese..
16987 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16988 var cc = b.charCodeAt();
16990 (cc >= 0x4E00 && cc < 0xA000 ) ||
16991 (cc >= 0x3400 && cc < 0x4E00 ) ||
16992 (cc >= 0xf900 && cc < 0xfb00 )
16998 if(this.owner.fireEvent('beforesync', this, html) !== false){
16999 this.el.dom.value = html;
17000 this.owner.fireEvent('sync', this, html);
17006 * Protected method that will not generally be called directly. Pushes the value of the textarea
17007 * into the iframe editor.
17009 pushValue : function(){
17010 if(this.initialized){
17011 var v = this.el.dom.value.trim();
17013 // if(v.length < 1){
17017 if(this.owner.fireEvent('beforepush', this, v) !== false){
17018 var d = (this.doc.body || this.doc.documentElement);
17020 this.cleanUpPaste();
17021 this.el.dom.value = d.innerHTML;
17022 this.owner.fireEvent('push', this, v);
17028 deferFocus : function(){
17029 this.focus.defer(10, this);
17033 focus : function(){
17034 if(this.win && !this.sourceEditMode){
17041 assignDocWin: function()
17043 var iframe = this.iframe;
17046 this.doc = iframe.contentWindow.document;
17047 this.win = iframe.contentWindow;
17049 // if (!Roo.get(this.frameId)) {
17052 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17053 // this.win = Roo.get(this.frameId).dom.contentWindow;
17055 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17059 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17060 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17065 initEditor : function(){
17066 //console.log("INIT EDITOR");
17067 this.assignDocWin();
17071 this.doc.designMode="on";
17073 this.doc.write(this.getDocMarkup());
17076 var dbody = (this.doc.body || this.doc.documentElement);
17077 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17078 // this copies styles from the containing element into thsi one..
17079 // not sure why we need all of this..
17080 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17082 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17083 //ss['background-attachment'] = 'fixed'; // w3c
17084 dbody.bgProperties = 'fixed'; // ie
17085 //Roo.DomHelper.applyStyles(dbody, ss);
17086 Roo.EventManager.on(this.doc, {
17087 //'mousedown': this.onEditorEvent,
17088 'mouseup': this.onEditorEvent,
17089 'dblclick': this.onEditorEvent,
17090 'click': this.onEditorEvent,
17091 'keyup': this.onEditorEvent,
17096 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17098 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17099 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17101 this.initialized = true;
17103 this.owner.fireEvent('initialize', this);
17108 onDestroy : function(){
17114 //for (var i =0; i < this.toolbars.length;i++) {
17115 // // fixme - ask toolbars for heights?
17116 // this.toolbars[i].onDestroy();
17119 //this.wrap.dom.innerHTML = '';
17120 //this.wrap.remove();
17125 onFirstFocus : function(){
17127 this.assignDocWin();
17130 this.activated = true;
17133 if(Roo.isGecko){ // prevent silly gecko errors
17135 var s = this.win.getSelection();
17136 if(!s.focusNode || s.focusNode.nodeType != 3){
17137 var r = s.getRangeAt(0);
17138 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17143 this.execCmd('useCSS', true);
17144 this.execCmd('styleWithCSS', false);
17147 this.owner.fireEvent('activate', this);
17151 adjustFont: function(btn){
17152 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17153 //if(Roo.isSafari){ // safari
17156 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17157 if(Roo.isSafari){ // safari
17158 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17159 v = (v < 10) ? 10 : v;
17160 v = (v > 48) ? 48 : v;
17161 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17166 v = Math.max(1, v+adjust);
17168 this.execCmd('FontSize', v );
17171 onEditorEvent : function(e){
17172 this.owner.fireEvent('editorevent', this, e);
17173 // this.updateToolbar();
17174 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17177 insertTag : function(tg)
17179 // could be a bit smarter... -> wrap the current selected tRoo..
17180 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17182 range = this.createRange(this.getSelection());
17183 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17184 wrappingNode.appendChild(range.extractContents());
17185 range.insertNode(wrappingNode);
17192 this.execCmd("formatblock", tg);
17196 insertText : function(txt)
17200 var range = this.createRange();
17201 range.deleteContents();
17202 //alert(Sender.getAttribute('label'));
17204 range.insertNode(this.doc.createTextNode(txt));
17210 * Executes a Midas editor command on the editor document and performs necessary focus and
17211 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17212 * @param {String} cmd The Midas command
17213 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17215 relayCmd : function(cmd, value){
17217 this.execCmd(cmd, value);
17218 this.owner.fireEvent('editorevent', this);
17219 //this.updateToolbar();
17220 this.owner.deferFocus();
17224 * Executes a Midas editor command directly on the editor document.
17225 * For visual commands, you should use {@link #relayCmd} instead.
17226 * <b>This should only be called after the editor is initialized.</b>
17227 * @param {String} cmd The Midas command
17228 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17230 execCmd : function(cmd, value){
17231 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17238 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17240 * @param {String} text | dom node..
17242 insertAtCursor : function(text)
17247 if(!this.activated){
17253 var r = this.doc.selection.createRange();
17264 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17268 // from jquery ui (MIT licenced)
17270 var win = this.win;
17272 if (win.getSelection && win.getSelection().getRangeAt) {
17273 range = win.getSelection().getRangeAt(0);
17274 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17275 range.insertNode(node);
17276 } else if (win.document.selection && win.document.selection.createRange) {
17277 // no firefox support
17278 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17279 win.document.selection.createRange().pasteHTML(txt);
17281 // no firefox support
17282 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17283 this.execCmd('InsertHTML', txt);
17292 mozKeyPress : function(e){
17294 var c = e.getCharCode(), cmd;
17297 c = String.fromCharCode(c).toLowerCase();
17311 this.cleanUpPaste.defer(100, this);
17319 e.preventDefault();
17327 fixKeys : function(){ // load time branching for fastest keydown performance
17329 return function(e){
17330 var k = e.getKey(), r;
17333 r = this.doc.selection.createRange();
17336 r.pasteHTML('    ');
17343 r = this.doc.selection.createRange();
17345 var target = r.parentElement();
17346 if(!target || target.tagName.toLowerCase() != 'li'){
17348 r.pasteHTML('<br />');
17354 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17355 this.cleanUpPaste.defer(100, this);
17361 }else if(Roo.isOpera){
17362 return function(e){
17363 var k = e.getKey();
17367 this.execCmd('InsertHTML','    ');
17370 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17371 this.cleanUpPaste.defer(100, this);
17376 }else if(Roo.isSafari){
17377 return function(e){
17378 var k = e.getKey();
17382 this.execCmd('InsertText','\t');
17386 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17387 this.cleanUpPaste.defer(100, this);
17395 getAllAncestors: function()
17397 var p = this.getSelectedNode();
17400 a.push(p); // push blank onto stack..
17401 p = this.getParentElement();
17405 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17409 a.push(this.doc.body);
17413 lastSelNode : false,
17416 getSelection : function()
17418 this.assignDocWin();
17419 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17422 getSelectedNode: function()
17424 // this may only work on Gecko!!!
17426 // should we cache this!!!!
17431 var range = this.createRange(this.getSelection()).cloneRange();
17434 var parent = range.parentElement();
17436 var testRange = range.duplicate();
17437 testRange.moveToElementText(parent);
17438 if (testRange.inRange(range)) {
17441 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17444 parent = parent.parentElement;
17449 // is ancestor a text element.
17450 var ac = range.commonAncestorContainer;
17451 if (ac.nodeType == 3) {
17452 ac = ac.parentNode;
17455 var ar = ac.childNodes;
17458 var other_nodes = [];
17459 var has_other_nodes = false;
17460 for (var i=0;i<ar.length;i++) {
17461 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17464 // fullly contained node.
17466 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17471 // probably selected..
17472 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17473 other_nodes.push(ar[i]);
17477 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17482 has_other_nodes = true;
17484 if (!nodes.length && other_nodes.length) {
17485 nodes= other_nodes;
17487 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17493 createRange: function(sel)
17495 // this has strange effects when using with
17496 // top toolbar - not sure if it's a great idea.
17497 //this.editor.contentWindow.focus();
17498 if (typeof sel != "undefined") {
17500 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17502 return this.doc.createRange();
17505 return this.doc.createRange();
17508 getParentElement: function()
17511 this.assignDocWin();
17512 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17514 var range = this.createRange(sel);
17517 var p = range.commonAncestorContainer;
17518 while (p.nodeType == 3) { // text node
17529 * Range intersection.. the hard stuff...
17533 * [ -- selected range --- ]
17537 * if end is before start or hits it. fail.
17538 * if start is after end or hits it fail.
17540 * if either hits (but other is outside. - then it's not
17546 // @see http://www.thismuchiknow.co.uk/?p=64.
17547 rangeIntersectsNode : function(range, node)
17549 var nodeRange = node.ownerDocument.createRange();
17551 nodeRange.selectNode(node);
17553 nodeRange.selectNodeContents(node);
17556 var rangeStartRange = range.cloneRange();
17557 rangeStartRange.collapse(true);
17559 var rangeEndRange = range.cloneRange();
17560 rangeEndRange.collapse(false);
17562 var nodeStartRange = nodeRange.cloneRange();
17563 nodeStartRange.collapse(true);
17565 var nodeEndRange = nodeRange.cloneRange();
17566 nodeEndRange.collapse(false);
17568 return rangeStartRange.compareBoundaryPoints(
17569 Range.START_TO_START, nodeEndRange) == -1 &&
17570 rangeEndRange.compareBoundaryPoints(
17571 Range.START_TO_START, nodeStartRange) == 1;
17575 rangeCompareNode : function(range, node)
17577 var nodeRange = node.ownerDocument.createRange();
17579 nodeRange.selectNode(node);
17581 nodeRange.selectNodeContents(node);
17585 range.collapse(true);
17587 nodeRange.collapse(true);
17589 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17590 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17592 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17594 var nodeIsBefore = ss == 1;
17595 var nodeIsAfter = ee == -1;
17597 if (nodeIsBefore && nodeIsAfter)
17599 if (!nodeIsBefore && nodeIsAfter)
17600 return 1; //right trailed.
17602 if (nodeIsBefore && !nodeIsAfter)
17603 return 2; // left trailed.
17608 // private? - in a new class?
17609 cleanUpPaste : function()
17611 // cleans up the whole document..
17612 Roo.log('cleanuppaste');
17614 this.cleanUpChildren(this.doc.body);
17615 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17616 if (clean != this.doc.body.innerHTML) {
17617 this.doc.body.innerHTML = clean;
17622 cleanWordChars : function(input) {// change the chars to hex code
17623 var he = Roo.HtmlEditorCore;
17625 var output = input;
17626 Roo.each(he.swapCodes, function(sw) {
17627 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17629 output = output.replace(swapper, sw[1]);
17636 cleanUpChildren : function (n)
17638 if (!n.childNodes.length) {
17641 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17642 this.cleanUpChild(n.childNodes[i]);
17649 cleanUpChild : function (node)
17652 //console.log(node);
17653 if (node.nodeName == "#text") {
17654 // clean up silly Windows -- stuff?
17657 if (node.nodeName == "#comment") {
17658 node.parentNode.removeChild(node);
17659 // clean up silly Windows -- stuff?
17662 var lcname = node.tagName.toLowerCase();
17663 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17664 // whitelist of tags..
17666 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17668 node.parentNode.removeChild(node);
17673 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17675 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17676 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17678 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17679 // remove_keep_children = true;
17682 if (remove_keep_children) {
17683 this.cleanUpChildren(node);
17684 // inserts everything just before this node...
17685 while (node.childNodes.length) {
17686 var cn = node.childNodes[0];
17687 node.removeChild(cn);
17688 node.parentNode.insertBefore(cn, node);
17690 node.parentNode.removeChild(node);
17694 if (!node.attributes || !node.attributes.length) {
17695 this.cleanUpChildren(node);
17699 function cleanAttr(n,v)
17702 if (v.match(/^\./) || v.match(/^\//)) {
17705 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17708 if (v.match(/^#/)) {
17711 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17712 node.removeAttribute(n);
17716 var cwhite = this.cwhite;
17717 var cblack = this.cblack;
17719 function cleanStyle(n,v)
17721 if (v.match(/expression/)) { //XSS?? should we even bother..
17722 node.removeAttribute(n);
17726 var parts = v.split(/;/);
17729 Roo.each(parts, function(p) {
17730 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17734 var l = p.split(':').shift().replace(/\s+/g,'');
17735 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17737 if ( cwhite.length && cblack.indexOf(l) > -1) {
17738 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17739 //node.removeAttribute(n);
17743 // only allow 'c whitelisted system attributes'
17744 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17745 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17746 //node.removeAttribute(n);
17756 if (clean.length) {
17757 node.setAttribute(n, clean.join(';'));
17759 node.removeAttribute(n);
17765 for (var i = node.attributes.length-1; i > -1 ; i--) {
17766 var a = node.attributes[i];
17769 if (a.name.toLowerCase().substr(0,2)=='on') {
17770 node.removeAttribute(a.name);
17773 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17774 node.removeAttribute(a.name);
17777 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17778 cleanAttr(a.name,a.value); // fixme..
17781 if (a.name == 'style') {
17782 cleanStyle(a.name,a.value);
17785 /// clean up MS crap..
17786 // tecnically this should be a list of valid class'es..
17789 if (a.name == 'class') {
17790 if (a.value.match(/^Mso/)) {
17791 node.className = '';
17794 if (a.value.match(/body/)) {
17795 node.className = '';
17806 this.cleanUpChildren(node);
17811 * Clean up MS wordisms...
17813 cleanWord : function(node)
17816 var cleanWordChildren = function()
17818 if (!node.childNodes.length) {
17821 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17822 _t.cleanWord(node.childNodes[i]);
17828 this.cleanWord(this.doc.body);
17831 if (node.nodeName == "#text") {
17832 // clean up silly Windows -- stuff?
17835 if (node.nodeName == "#comment") {
17836 node.parentNode.removeChild(node);
17837 // clean up silly Windows -- stuff?
17841 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17842 node.parentNode.removeChild(node);
17846 // remove - but keep children..
17847 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17848 while (node.childNodes.length) {
17849 var cn = node.childNodes[0];
17850 node.removeChild(cn);
17851 node.parentNode.insertBefore(cn, node);
17853 node.parentNode.removeChild(node);
17854 cleanWordChildren();
17858 if (node.className.length) {
17860 var cn = node.className.split(/\W+/);
17862 Roo.each(cn, function(cls) {
17863 if (cls.match(/Mso[a-zA-Z]+/)) {
17868 node.className = cna.length ? cna.join(' ') : '';
17870 node.removeAttribute("class");
17874 if (node.hasAttribute("lang")) {
17875 node.removeAttribute("lang");
17878 if (node.hasAttribute("style")) {
17880 var styles = node.getAttribute("style").split(";");
17882 Roo.each(styles, function(s) {
17883 if (!s.match(/:/)) {
17886 var kv = s.split(":");
17887 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17890 // what ever is left... we allow.
17893 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17894 if (!nstyle.length) {
17895 node.removeAttribute('style');
17899 cleanWordChildren();
17903 domToHTML : function(currentElement, depth, nopadtext) {
17905 depth = depth || 0;
17906 nopadtext = nopadtext || false;
17908 if (!currentElement) {
17909 return this.domToHTML(this.doc.body);
17912 //Roo.log(currentElement);
17914 var allText = false;
17915 var nodeName = currentElement.nodeName;
17916 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17918 if (nodeName == '#text') {
17920 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
17925 if (nodeName != 'BODY') {
17928 // Prints the node tagName, such as <A>, <IMG>, etc
17931 for(i = 0; i < currentElement.attributes.length;i++) {
17933 var aname = currentElement.attributes.item(i).name;
17934 if (!currentElement.attributes.item(i).value.length) {
17937 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17940 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17949 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17952 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17957 // Traverse the tree
17959 var currentElementChild = currentElement.childNodes.item(i);
17960 var allText = true;
17961 var innerHTML = '';
17963 while (currentElementChild) {
17964 // Formatting code (indent the tree so it looks nice on the screen)
17965 var nopad = nopadtext;
17966 if (lastnode == 'SPAN') {
17970 if (currentElementChild.nodeName == '#text') {
17971 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17972 toadd = nopadtext ? toadd : toadd.trim();
17973 if (!nopad && toadd.length > 80) {
17974 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17976 innerHTML += toadd;
17979 currentElementChild = currentElement.childNodes.item(i);
17985 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17987 // Recursively traverse the tree structure of the child node
17988 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17989 lastnode = currentElementChild.nodeName;
17991 currentElementChild=currentElement.childNodes.item(i);
17997 // The remaining code is mostly for formatting the tree
17998 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18003 ret+= "</"+tagName+">";
18009 applyBlacklists : function()
18011 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18012 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18016 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18017 if (b.indexOf(tag) > -1) {
18020 this.white.push(tag);
18024 Roo.each(w, function(tag) {
18025 if (b.indexOf(tag) > -1) {
18028 if (this.white.indexOf(tag) > -1) {
18031 this.white.push(tag);
18036 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18037 if (w.indexOf(tag) > -1) {
18040 this.black.push(tag);
18044 Roo.each(b, function(tag) {
18045 if (w.indexOf(tag) > -1) {
18048 if (this.black.indexOf(tag) > -1) {
18051 this.black.push(tag);
18056 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18057 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18061 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18062 if (b.indexOf(tag) > -1) {
18065 this.cwhite.push(tag);
18069 Roo.each(w, function(tag) {
18070 if (b.indexOf(tag) > -1) {
18073 if (this.cwhite.indexOf(tag) > -1) {
18076 this.cwhite.push(tag);
18081 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18082 if (w.indexOf(tag) > -1) {
18085 this.cblack.push(tag);
18089 Roo.each(b, function(tag) {
18090 if (w.indexOf(tag) > -1) {
18093 if (this.cblack.indexOf(tag) > -1) {
18096 this.cblack.push(tag);
18101 setStylesheets : function(stylesheets)
18103 if(typeof(stylesheets) == 'string'){
18104 Roo.get(this.iframe.contentDocument.head).createChild({
18106 rel : 'stylesheet',
18115 Roo.each(stylesheets, function(s) {
18120 Roo.get(_this.iframe.contentDocument.head).createChild({
18122 rel : 'stylesheet',
18131 removeStylesheets : function()
18135 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18140 // hide stuff that is not compatible
18154 * @event specialkey
18158 * @cfg {String} fieldClass @hide
18161 * @cfg {String} focusClass @hide
18164 * @cfg {String} autoCreate @hide
18167 * @cfg {String} inputType @hide
18170 * @cfg {String} invalidClass @hide
18173 * @cfg {String} invalidText @hide
18176 * @cfg {String} msgFx @hide
18179 * @cfg {String} validateOnBlur @hide
18183 Roo.HtmlEditorCore.white = [
18184 'area', 'br', 'img', 'input', 'hr', 'wbr',
18186 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18187 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18188 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18189 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18190 'table', 'ul', 'xmp',
18192 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18195 'dir', 'menu', 'ol', 'ul', 'dl',
18201 Roo.HtmlEditorCore.black = [
18202 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18204 'base', 'basefont', 'bgsound', 'blink', 'body',
18205 'frame', 'frameset', 'head', 'html', 'ilayer',
18206 'iframe', 'layer', 'link', 'meta', 'object',
18207 'script', 'style' ,'title', 'xml' // clean later..
18209 Roo.HtmlEditorCore.clean = [
18210 'script', 'style', 'title', 'xml'
18212 Roo.HtmlEditorCore.remove = [
18217 Roo.HtmlEditorCore.ablack = [
18221 Roo.HtmlEditorCore.aclean = [
18222 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18226 Roo.HtmlEditorCore.pwhite= [
18227 'http', 'https', 'mailto'
18230 // white listed style attributes.
18231 Roo.HtmlEditorCore.cwhite= [
18232 // 'text-align', /// default is to allow most things..
18238 // black listed style attributes.
18239 Roo.HtmlEditorCore.cblack= [
18240 // 'font-size' -- this can be set by the project
18244 Roo.HtmlEditorCore.swapCodes =[
18263 * @class Roo.bootstrap.HtmlEditor
18264 * @extends Roo.bootstrap.TextArea
18265 * Bootstrap HtmlEditor class
18268 * Create a new HtmlEditor
18269 * @param {Object} config The config object
18272 Roo.bootstrap.HtmlEditor = function(config){
18273 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18274 if (!this.toolbars) {
18275 this.toolbars = [];
18277 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18280 * @event initialize
18281 * Fires when the editor is fully initialized (including the iframe)
18282 * @param {HtmlEditor} this
18287 * Fires when the editor is first receives the focus. Any insertion must wait
18288 * until after this event.
18289 * @param {HtmlEditor} this
18293 * @event beforesync
18294 * Fires before the textarea is updated with content from the editor iframe. Return false
18295 * to cancel the sync.
18296 * @param {HtmlEditor} this
18297 * @param {String} html
18301 * @event beforepush
18302 * Fires before the iframe editor is updated with content from the textarea. Return false
18303 * to cancel the push.
18304 * @param {HtmlEditor} this
18305 * @param {String} html
18310 * Fires when the textarea is updated with content from the editor iframe.
18311 * @param {HtmlEditor} this
18312 * @param {String} html
18317 * Fires when the iframe editor is updated with content from the textarea.
18318 * @param {HtmlEditor} this
18319 * @param {String} html
18323 * @event editmodechange
18324 * Fires when the editor switches edit modes
18325 * @param {HtmlEditor} this
18326 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18328 editmodechange: true,
18330 * @event editorevent
18331 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18332 * @param {HtmlEditor} this
18336 * @event firstfocus
18337 * Fires when on first focus - needed by toolbars..
18338 * @param {HtmlEditor} this
18343 * Auto save the htmlEditor value as a file into Events
18344 * @param {HtmlEditor} this
18348 * @event savedpreview
18349 * preview the saved version of htmlEditor
18350 * @param {HtmlEditor} this
18357 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18361 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18366 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18371 * @cfg {Number} height (in pixels)
18375 * @cfg {Number} width (in pixels)
18380 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18383 stylesheets: false,
18388 // private properties
18389 validationEvent : false,
18391 initialized : false,
18394 onFocus : Roo.emptyFn,
18396 hideMode:'offsets',
18399 tbContainer : false,
18401 toolbarContainer :function() {
18402 return this.wrap.select('.x-html-editor-tb',true).first();
18406 * Protected method that will not generally be called directly. It
18407 * is called when the editor creates its toolbar. Override this method if you need to
18408 * add custom toolbar buttons.
18409 * @param {HtmlEditor} editor
18411 createToolbar : function(){
18413 Roo.log("create toolbars");
18415 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18416 this.toolbars[0].render(this.toolbarContainer());
18420 // if (!editor.toolbars || !editor.toolbars.length) {
18421 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18424 // for (var i =0 ; i < editor.toolbars.length;i++) {
18425 // editor.toolbars[i] = Roo.factory(
18426 // typeof(editor.toolbars[i]) == 'string' ?
18427 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18428 // Roo.bootstrap.HtmlEditor);
18429 // editor.toolbars[i].init(editor);
18435 onRender : function(ct, position)
18437 // Roo.log("Call onRender: " + this.xtype);
18439 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18441 this.wrap = this.inputEl().wrap({
18442 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18445 this.editorcore.onRender(ct, position);
18447 if (this.resizable) {
18448 this.resizeEl = new Roo.Resizable(this.wrap, {
18452 minHeight : this.height,
18453 height: this.height,
18454 handles : this.resizable,
18457 resize : function(r, w, h) {
18458 _t.onResize(w,h); // -something
18464 this.createToolbar(this);
18467 if(!this.width && this.resizable){
18468 this.setSize(this.wrap.getSize());
18470 if (this.resizeEl) {
18471 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18472 // should trigger onReize..
18478 onResize : function(w, h)
18480 Roo.log('resize: ' +w + ',' + h );
18481 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18485 if(this.inputEl() ){
18486 if(typeof w == 'number'){
18487 var aw = w - this.wrap.getFrameWidth('lr');
18488 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18491 if(typeof h == 'number'){
18492 var tbh = -11; // fixme it needs to tool bar size!
18493 for (var i =0; i < this.toolbars.length;i++) {
18494 // fixme - ask toolbars for heights?
18495 tbh += this.toolbars[i].el.getHeight();
18496 //if (this.toolbars[i].footer) {
18497 // tbh += this.toolbars[i].footer.el.getHeight();
18505 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18506 ah -= 5; // knock a few pixes off for look..
18507 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18511 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18512 this.editorcore.onResize(ew,eh);
18517 * Toggles the editor between standard and source edit mode.
18518 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18520 toggleSourceEdit : function(sourceEditMode)
18522 this.editorcore.toggleSourceEdit(sourceEditMode);
18524 if(this.editorcore.sourceEditMode){
18525 Roo.log('editor - showing textarea');
18528 // Roo.log(this.syncValue());
18530 this.inputEl().removeClass(['hide', 'x-hidden']);
18531 this.inputEl().dom.removeAttribute('tabIndex');
18532 this.inputEl().focus();
18534 Roo.log('editor - hiding textarea');
18536 // Roo.log(this.pushValue());
18539 this.inputEl().addClass(['hide', 'x-hidden']);
18540 this.inputEl().dom.setAttribute('tabIndex', -1);
18541 //this.deferFocus();
18544 if(this.resizable){
18545 this.setSize(this.wrap.getSize());
18548 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18551 // private (for BoxComponent)
18552 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18554 // private (for BoxComponent)
18555 getResizeEl : function(){
18559 // private (for BoxComponent)
18560 getPositionEl : function(){
18565 initEvents : function(){
18566 this.originalValue = this.getValue();
18570 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18573 // markInvalid : Roo.emptyFn,
18575 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18578 // clearInvalid : Roo.emptyFn,
18580 setValue : function(v){
18581 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18582 this.editorcore.pushValue();
18587 deferFocus : function(){
18588 this.focus.defer(10, this);
18592 focus : function(){
18593 this.editorcore.focus();
18599 onDestroy : function(){
18605 for (var i =0; i < this.toolbars.length;i++) {
18606 // fixme - ask toolbars for heights?
18607 this.toolbars[i].onDestroy();
18610 this.wrap.dom.innerHTML = '';
18611 this.wrap.remove();
18616 onFirstFocus : function(){
18617 //Roo.log("onFirstFocus");
18618 this.editorcore.onFirstFocus();
18619 for (var i =0; i < this.toolbars.length;i++) {
18620 this.toolbars[i].onFirstFocus();
18626 syncValue : function()
18628 this.editorcore.syncValue();
18631 pushValue : function()
18633 this.editorcore.pushValue();
18637 // hide stuff that is not compatible
18651 * @event specialkey
18655 * @cfg {String} fieldClass @hide
18658 * @cfg {String} focusClass @hide
18661 * @cfg {String} autoCreate @hide
18664 * @cfg {String} inputType @hide
18667 * @cfg {String} invalidClass @hide
18670 * @cfg {String} invalidText @hide
18673 * @cfg {String} msgFx @hide
18676 * @cfg {String} validateOnBlur @hide
18685 Roo.namespace('Roo.bootstrap.htmleditor');
18687 * @class Roo.bootstrap.HtmlEditorToolbar1
18692 new Roo.bootstrap.HtmlEditor({
18695 new Roo.bootstrap.HtmlEditorToolbar1({
18696 disable : { fonts: 1 , format: 1, ..., ... , ...],
18702 * @cfg {Object} disable List of elements to disable..
18703 * @cfg {Array} btns List of additional buttons.
18707 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18710 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18713 Roo.apply(this, config);
18715 // default disabled, based on 'good practice'..
18716 this.disable = this.disable || {};
18717 Roo.applyIf(this.disable, {
18720 specialElements : true
18722 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18724 this.editor = config.editor;
18725 this.editorcore = config.editor.editorcore;
18727 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18729 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18730 // dont call parent... till later.
18732 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18737 editorcore : false,
18742 "h1","h2","h3","h4","h5","h6",
18744 "abbr", "acronym", "address", "cite", "samp", "var",
18748 onRender : function(ct, position)
18750 // Roo.log("Call onRender: " + this.xtype);
18752 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18754 this.el.dom.style.marginBottom = '0';
18756 var editorcore = this.editorcore;
18757 var editor= this.editor;
18760 var btn = function(id,cmd , toggle, handler){
18762 var event = toggle ? 'toggle' : 'click';
18767 xns: Roo.bootstrap,
18770 enableToggle:toggle !== false,
18772 pressed : toggle ? false : null,
18775 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18776 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18785 xns: Roo.bootstrap,
18786 glyphicon : 'font',
18790 xns: Roo.bootstrap,
18794 Roo.each(this.formats, function(f) {
18795 style.menu.items.push({
18797 xns: Roo.bootstrap,
18798 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18803 editorcore.insertTag(this.tagname);
18810 children.push(style);
18813 btn('bold',false,true);
18814 btn('italic',false,true);
18815 btn('align-left', 'justifyleft',true);
18816 btn('align-center', 'justifycenter',true);
18817 btn('align-right' , 'justifyright',true);
18818 btn('link', false, false, function(btn) {
18819 //Roo.log("create link?");
18820 var url = prompt(this.createLinkText, this.defaultLinkValue);
18821 if(url && url != 'http:/'+'/'){
18822 this.editorcore.relayCmd('createlink', url);
18825 btn('list','insertunorderedlist',true);
18826 btn('pencil', false,true, function(btn){
18829 this.toggleSourceEdit(btn.pressed);
18835 xns: Roo.bootstrap,
18840 xns: Roo.bootstrap,
18845 cog.menu.items.push({
18847 xns: Roo.bootstrap,
18848 html : Clean styles,
18853 editorcore.insertTag(this.tagname);
18862 this.xtype = 'NavSimplebar';
18864 for(var i=0;i< children.length;i++) {
18866 this.buttons.add(this.addxtypeChild(children[i]));
18870 editor.on('editorevent', this.updateToolbar, this);
18872 onBtnClick : function(id)
18874 this.editorcore.relayCmd(id);
18875 this.editorcore.focus();
18879 * Protected method that will not generally be called directly. It triggers
18880 * a toolbar update by reading the markup state of the current selection in the editor.
18882 updateToolbar: function(){
18884 if(!this.editorcore.activated){
18885 this.editor.onFirstFocus(); // is this neeed?
18889 var btns = this.buttons;
18890 var doc = this.editorcore.doc;
18891 btns.get('bold').setActive(doc.queryCommandState('bold'));
18892 btns.get('italic').setActive(doc.queryCommandState('italic'));
18893 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18895 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18896 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18897 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18899 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18900 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18903 var ans = this.editorcore.getAllAncestors();
18904 if (this.formatCombo) {
18907 var store = this.formatCombo.store;
18908 this.formatCombo.setValue("");
18909 for (var i =0; i < ans.length;i++) {
18910 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18912 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18920 // hides menus... - so this cant be on a menu...
18921 Roo.bootstrap.MenuMgr.hideAll();
18923 Roo.bootstrap.MenuMgr.hideAll();
18924 //this.editorsyncValue();
18926 onFirstFocus: function() {
18927 this.buttons.each(function(item){
18931 toggleSourceEdit : function(sourceEditMode){
18934 if(sourceEditMode){
18935 Roo.log("disabling buttons");
18936 this.buttons.each( function(item){
18937 if(item.cmd != 'pencil'){
18943 Roo.log("enabling buttons");
18944 if(this.editorcore.initialized){
18945 this.buttons.each( function(item){
18951 Roo.log("calling toggole on editor");
18952 // tell the editor that it's been pressed..
18953 this.editor.toggleSourceEdit(sourceEditMode);
18963 * @class Roo.bootstrap.Table.AbstractSelectionModel
18964 * @extends Roo.util.Observable
18965 * Abstract base class for grid SelectionModels. It provides the interface that should be
18966 * implemented by descendant classes. This class should not be directly instantiated.
18969 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18970 this.locked = false;
18971 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18975 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18976 /** @ignore Called by the grid automatically. Do not call directly. */
18977 init : function(grid){
18983 * Locks the selections.
18986 this.locked = true;
18990 * Unlocks the selections.
18992 unlock : function(){
18993 this.locked = false;
18997 * Returns true if the selections are locked.
18998 * @return {Boolean}
19000 isLocked : function(){
19001 return this.locked;
19005 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19006 * @class Roo.bootstrap.Table.RowSelectionModel
19007 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19008 * It supports multiple selections and keyboard selection/navigation.
19010 * @param {Object} config
19013 Roo.bootstrap.Table.RowSelectionModel = function(config){
19014 Roo.apply(this, config);
19015 this.selections = new Roo.util.MixedCollection(false, function(o){
19020 this.lastActive = false;
19024 * @event selectionchange
19025 * Fires when the selection changes
19026 * @param {SelectionModel} this
19028 "selectionchange" : true,
19030 * @event afterselectionchange
19031 * Fires after the selection changes (eg. by key press or clicking)
19032 * @param {SelectionModel} this
19034 "afterselectionchange" : true,
19036 * @event beforerowselect
19037 * Fires when a row is selected being selected, return false to cancel.
19038 * @param {SelectionModel} this
19039 * @param {Number} rowIndex The selected index
19040 * @param {Boolean} keepExisting False if other selections will be cleared
19042 "beforerowselect" : true,
19045 * Fires when a row is selected.
19046 * @param {SelectionModel} this
19047 * @param {Number} rowIndex The selected index
19048 * @param {Roo.data.Record} r The record
19050 "rowselect" : true,
19052 * @event rowdeselect
19053 * Fires when a row is deselected.
19054 * @param {SelectionModel} this
19055 * @param {Number} rowIndex The selected index
19057 "rowdeselect" : true
19059 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19060 this.locked = false;
19063 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19065 * @cfg {Boolean} singleSelect
19066 * True to allow selection of only one row at a time (defaults to false)
19068 singleSelect : false,
19071 initEvents : function(){
19073 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19074 this.grid.on("mousedown", this.handleMouseDown, this);
19075 }else{ // allow click to work like normal
19076 this.grid.on("rowclick", this.handleDragableRowClick, this);
19079 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19080 "up" : function(e){
19082 this.selectPrevious(e.shiftKey);
19083 }else if(this.last !== false && this.lastActive !== false){
19084 var last = this.last;
19085 this.selectRange(this.last, this.lastActive-1);
19086 this.grid.getView().focusRow(this.lastActive);
19087 if(last !== false){
19091 this.selectFirstRow();
19093 this.fireEvent("afterselectionchange", this);
19095 "down" : function(e){
19097 this.selectNext(e.shiftKey);
19098 }else if(this.last !== false && this.lastActive !== false){
19099 var last = this.last;
19100 this.selectRange(this.last, this.lastActive+1);
19101 this.grid.getView().focusRow(this.lastActive);
19102 if(last !== false){
19106 this.selectFirstRow();
19108 this.fireEvent("afterselectionchange", this);
19113 var view = this.grid.view;
19114 view.on("refresh", this.onRefresh, this);
19115 view.on("rowupdated", this.onRowUpdated, this);
19116 view.on("rowremoved", this.onRemove, this);
19120 onRefresh : function(){
19121 var ds = this.grid.dataSource, i, v = this.grid.view;
19122 var s = this.selections;
19123 s.each(function(r){
19124 if((i = ds.indexOfId(r.id)) != -1){
19133 onRemove : function(v, index, r){
19134 this.selections.remove(r);
19138 onRowUpdated : function(v, index, r){
19139 if(this.isSelected(r)){
19140 v.onRowSelect(index);
19146 * @param {Array} records The records to select
19147 * @param {Boolean} keepExisting (optional) True to keep existing selections
19149 selectRecords : function(records, keepExisting){
19151 this.clearSelections();
19153 var ds = this.grid.dataSource;
19154 for(var i = 0, len = records.length; i < len; i++){
19155 this.selectRow(ds.indexOf(records[i]), true);
19160 * Gets the number of selected rows.
19163 getCount : function(){
19164 return this.selections.length;
19168 * Selects the first row in the grid.
19170 selectFirstRow : function(){
19175 * Select the last row.
19176 * @param {Boolean} keepExisting (optional) True to keep existing selections
19178 selectLastRow : function(keepExisting){
19179 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19183 * Selects the row immediately following the last selected row.
19184 * @param {Boolean} keepExisting (optional) True to keep existing selections
19186 selectNext : function(keepExisting){
19187 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19188 this.selectRow(this.last+1, keepExisting);
19189 this.grid.getView().focusRow(this.last);
19194 * Selects the row that precedes the last selected row.
19195 * @param {Boolean} keepExisting (optional) True to keep existing selections
19197 selectPrevious : function(keepExisting){
19199 this.selectRow(this.last-1, keepExisting);
19200 this.grid.getView().focusRow(this.last);
19205 * Returns the selected records
19206 * @return {Array} Array of selected records
19208 getSelections : function(){
19209 return [].concat(this.selections.items);
19213 * Returns the first selected record.
19216 getSelected : function(){
19217 return this.selections.itemAt(0);
19222 * Clears all selections.
19224 clearSelections : function(fast){
19225 if(this.locked) return;
19227 var ds = this.grid.dataSource;
19228 var s = this.selections;
19229 s.each(function(r){
19230 this.deselectRow(ds.indexOfId(r.id));
19234 this.selections.clear();
19241 * Selects all rows.
19243 selectAll : function(){
19244 if(this.locked) return;
19245 this.selections.clear();
19246 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19247 this.selectRow(i, true);
19252 * Returns True if there is a selection.
19253 * @return {Boolean}
19255 hasSelection : function(){
19256 return this.selections.length > 0;
19260 * Returns True if the specified row is selected.
19261 * @param {Number/Record} record The record or index of the record to check
19262 * @return {Boolean}
19264 isSelected : function(index){
19265 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19266 return (r && this.selections.key(r.id) ? true : false);
19270 * Returns True if the specified record id is selected.
19271 * @param {String} id The id of record to check
19272 * @return {Boolean}
19274 isIdSelected : function(id){
19275 return (this.selections.key(id) ? true : false);
19279 handleMouseDown : function(e, t){
19280 var view = this.grid.getView(), rowIndex;
19281 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19284 if(e.shiftKey && this.last !== false){
19285 var last = this.last;
19286 this.selectRange(last, rowIndex, e.ctrlKey);
19287 this.last = last; // reset the last
19288 view.focusRow(rowIndex);
19290 var isSelected = this.isSelected(rowIndex);
19291 if(e.button !== 0 && isSelected){
19292 view.focusRow(rowIndex);
19293 }else if(e.ctrlKey && isSelected){
19294 this.deselectRow(rowIndex);
19295 }else if(!isSelected){
19296 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19297 view.focusRow(rowIndex);
19300 this.fireEvent("afterselectionchange", this);
19303 handleDragableRowClick : function(grid, rowIndex, e)
19305 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19306 this.selectRow(rowIndex, false);
19307 grid.view.focusRow(rowIndex);
19308 this.fireEvent("afterselectionchange", this);
19313 * Selects multiple rows.
19314 * @param {Array} rows Array of the indexes of the row to select
19315 * @param {Boolean} keepExisting (optional) True to keep existing selections
19317 selectRows : function(rows, keepExisting){
19319 this.clearSelections();
19321 for(var i = 0, len = rows.length; i < len; i++){
19322 this.selectRow(rows[i], true);
19327 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19328 * @param {Number} startRow The index of the first row in the range
19329 * @param {Number} endRow The index of the last row in the range
19330 * @param {Boolean} keepExisting (optional) True to retain existing selections
19332 selectRange : function(startRow, endRow, keepExisting){
19333 if(this.locked) return;
19335 this.clearSelections();
19337 if(startRow <= endRow){
19338 for(var i = startRow; i <= endRow; i++){
19339 this.selectRow(i, true);
19342 for(var i = startRow; i >= endRow; i--){
19343 this.selectRow(i, true);
19349 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19350 * @param {Number} startRow The index of the first row in the range
19351 * @param {Number} endRow The index of the last row in the range
19353 deselectRange : function(startRow, endRow, preventViewNotify){
19354 if(this.locked) return;
19355 for(var i = startRow; i <= endRow; i++){
19356 this.deselectRow(i, preventViewNotify);
19362 * @param {Number} row The index of the row to select
19363 * @param {Boolean} keepExisting (optional) True to keep existing selections
19365 selectRow : function(index, keepExisting, preventViewNotify){
19366 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19367 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19368 if(!keepExisting || this.singleSelect){
19369 this.clearSelections();
19371 var r = this.grid.dataSource.getAt(index);
19372 this.selections.add(r);
19373 this.last = this.lastActive = index;
19374 if(!preventViewNotify){
19375 this.grid.getView().onRowSelect(index);
19377 this.fireEvent("rowselect", this, index, r);
19378 this.fireEvent("selectionchange", this);
19384 * @param {Number} row The index of the row to deselect
19386 deselectRow : function(index, preventViewNotify){
19387 if(this.locked) return;
19388 if(this.last == index){
19391 if(this.lastActive == index){
19392 this.lastActive = false;
19394 var r = this.grid.dataSource.getAt(index);
19395 this.selections.remove(r);
19396 if(!preventViewNotify){
19397 this.grid.getView().onRowDeselect(index);
19399 this.fireEvent("rowdeselect", this, index);
19400 this.fireEvent("selectionchange", this);
19404 restoreLast : function(){
19406 this.last = this._last;
19411 acceptsNav : function(row, col, cm){
19412 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19416 onEditorKey : function(field, e){
19417 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19422 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19424 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19426 }else if(k == e.ENTER && !e.ctrlKey){
19430 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19432 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19434 }else if(k == e.ESC){
19438 g.startEditing(newCell[0], newCell[1]);
19443 * Ext JS Library 1.1.1
19444 * Copyright(c) 2006-2007, Ext JS, LLC.
19446 * Originally Released Under LGPL - original licence link has changed is not relivant.
19449 * <script type="text/javascript">
19453 * @class Roo.bootstrap.PagingToolbar
19455 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19457 * Create a new PagingToolbar
19458 * @param {Object} config The config object
19460 Roo.bootstrap.PagingToolbar = function(config)
19462 // old args format still supported... - xtype is prefered..
19463 // created from xtype...
19464 var ds = config.dataSource;
19465 this.toolbarItems = [];
19466 if (config.items) {
19467 this.toolbarItems = config.items;
19468 // config.items = [];
19471 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19478 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19482 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19484 * @cfg {Roo.data.Store} dataSource
19485 * The underlying data store providing the paged data
19488 * @cfg {String/HTMLElement/Element} container
19489 * container The id or element that will contain the toolbar
19492 * @cfg {Boolean} displayInfo
19493 * True to display the displayMsg (defaults to false)
19496 * @cfg {Number} pageSize
19497 * The number of records to display per page (defaults to 20)
19501 * @cfg {String} displayMsg
19502 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19504 displayMsg : 'Displaying {0} - {1} of {2}',
19506 * @cfg {String} emptyMsg
19507 * The message to display when no records are found (defaults to "No data to display")
19509 emptyMsg : 'No data to display',
19511 * Customizable piece of the default paging text (defaults to "Page")
19514 beforePageText : "Page",
19516 * Customizable piece of the default paging text (defaults to "of %0")
19519 afterPageText : "of {0}",
19521 * Customizable piece of the default paging text (defaults to "First Page")
19524 firstText : "First Page",
19526 * Customizable piece of the default paging text (defaults to "Previous Page")
19529 prevText : "Previous Page",
19531 * Customizable piece of the default paging text (defaults to "Next Page")
19534 nextText : "Next Page",
19536 * Customizable piece of the default paging text (defaults to "Last Page")
19539 lastText : "Last Page",
19541 * Customizable piece of the default paging text (defaults to "Refresh")
19544 refreshText : "Refresh",
19548 onRender : function(ct, position)
19550 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19551 this.navgroup.parentId = this.id;
19552 this.navgroup.onRender(this.el, null);
19553 // add the buttons to the navgroup
19555 if(this.displayInfo){
19556 Roo.log(this.el.select('ul.navbar-nav',true).first());
19557 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19558 this.displayEl = this.el.select('.x-paging-info', true).first();
19559 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19560 // this.displayEl = navel.el.select('span',true).first();
19566 Roo.each(_this.buttons, function(e){
19567 Roo.factory(e).onRender(_this.el, null);
19571 Roo.each(_this.toolbarItems, function(e) {
19572 _this.navgroup.addItem(e);
19575 this.first = this.navgroup.addItem({
19576 tooltip: this.firstText,
19578 icon : 'fa fa-backward',
19580 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19583 this.prev = this.navgroup.addItem({
19584 tooltip: this.prevText,
19586 icon : 'fa fa-step-backward',
19588 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19590 //this.addSeparator();
19593 var field = this.navgroup.addItem( {
19595 cls : 'x-paging-position',
19597 html : this.beforePageText +
19598 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19599 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19602 this.field = field.el.select('input', true).first();
19603 this.field.on("keydown", this.onPagingKeydown, this);
19604 this.field.on("focus", function(){this.dom.select();});
19607 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19608 //this.field.setHeight(18);
19609 //this.addSeparator();
19610 this.next = this.navgroup.addItem({
19611 tooltip: this.nextText,
19613 html : ' <i class="fa fa-step-forward">',
19615 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19617 this.last = this.navgroup.addItem({
19618 tooltip: this.lastText,
19619 icon : 'fa fa-forward',
19622 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19624 //this.addSeparator();
19625 this.loading = this.navgroup.addItem({
19626 tooltip: this.refreshText,
19627 icon: 'fa fa-refresh',
19629 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19635 updateInfo : function(){
19636 if(this.displayEl){
19637 var count = this.ds.getCount();
19638 var msg = count == 0 ?
19642 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19644 this.displayEl.update(msg);
19649 onLoad : function(ds, r, o){
19650 this.cursor = o.params ? o.params.start : 0;
19651 var d = this.getPageData(),
19655 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19656 this.field.dom.value = ap;
19657 this.first.setDisabled(ap == 1);
19658 this.prev.setDisabled(ap == 1);
19659 this.next.setDisabled(ap == ps);
19660 this.last.setDisabled(ap == ps);
19661 this.loading.enable();
19666 getPageData : function(){
19667 var total = this.ds.getTotalCount();
19670 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19671 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19676 onLoadError : function(){
19677 this.loading.enable();
19681 onPagingKeydown : function(e){
19682 var k = e.getKey();
19683 var d = this.getPageData();
19685 var v = this.field.dom.value, pageNum;
19686 if(!v || isNaN(pageNum = parseInt(v, 10))){
19687 this.field.dom.value = d.activePage;
19690 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19691 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19694 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))
19696 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19697 this.field.dom.value = pageNum;
19698 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19701 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19703 var v = this.field.dom.value, pageNum;
19704 var increment = (e.shiftKey) ? 10 : 1;
19705 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19707 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19708 this.field.dom.value = d.activePage;
19711 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19713 this.field.dom.value = parseInt(v, 10) + increment;
19714 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19715 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19722 beforeLoad : function(){
19724 this.loading.disable();
19729 onClick : function(which){
19736 ds.load({params:{start: 0, limit: this.pageSize}});
19739 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19742 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19745 var total = ds.getTotalCount();
19746 var extra = total % this.pageSize;
19747 var lastStart = extra ? (total - extra) : total-this.pageSize;
19748 ds.load({params:{start: lastStart, limit: this.pageSize}});
19751 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19757 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19758 * @param {Roo.data.Store} store The data store to unbind
19760 unbind : function(ds){
19761 ds.un("beforeload", this.beforeLoad, this);
19762 ds.un("load", this.onLoad, this);
19763 ds.un("loadexception", this.onLoadError, this);
19764 ds.un("remove", this.updateInfo, this);
19765 ds.un("add", this.updateInfo, this);
19766 this.ds = undefined;
19770 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19771 * @param {Roo.data.Store} store The data store to bind
19773 bind : function(ds){
19774 ds.on("beforeload", this.beforeLoad, this);
19775 ds.on("load", this.onLoad, this);
19776 ds.on("loadexception", this.onLoadError, this);
19777 ds.on("remove", this.updateInfo, this);
19778 ds.on("add", this.updateInfo, this);
19789 * @class Roo.bootstrap.MessageBar
19790 * @extends Roo.bootstrap.Component
19791 * Bootstrap MessageBar class
19792 * @cfg {String} html contents of the MessageBar
19793 * @cfg {String} weight (info | success | warning | danger) default info
19794 * @cfg {String} beforeClass insert the bar before the given class
19795 * @cfg {Boolean} closable (true | false) default false
19796 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19799 * Create a new Element
19800 * @param {Object} config The config object
19803 Roo.bootstrap.MessageBar = function(config){
19804 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19807 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19813 beforeClass: 'bootstrap-sticky-wrap',
19815 getAutoCreate : function(){
19819 cls: 'alert alert-dismissable alert-' + this.weight,
19824 html: this.html || ''
19830 cfg.cls += ' alert-messages-fixed';
19844 onRender : function(ct, position)
19846 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19849 var cfg = Roo.apply({}, this.getAutoCreate());
19853 cfg.cls += ' ' + this.cls;
19856 cfg.style = this.style;
19858 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19860 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19863 this.el.select('>button.close').on('click', this.hide, this);
19869 if (!this.rendered) {
19875 this.fireEvent('show', this);
19881 if (!this.rendered) {
19887 this.fireEvent('hide', this);
19890 update : function()
19892 // var e = this.el.dom.firstChild;
19894 // if(this.closable){
19895 // e = e.nextSibling;
19898 // e.data = this.html || '';
19900 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19916 * @class Roo.bootstrap.Graph
19917 * @extends Roo.bootstrap.Component
19918 * Bootstrap Graph class
19922 @cfg {String} graphtype bar | vbar | pie
19923 @cfg {number} g_x coodinator | centre x (pie)
19924 @cfg {number} g_y coodinator | centre y (pie)
19925 @cfg {number} g_r radius (pie)
19926 @cfg {number} g_height height of the chart (respected by all elements in the set)
19927 @cfg {number} g_width width of the chart (respected by all elements in the set)
19928 @cfg {Object} title The title of the chart
19931 -opts (object) options for the chart
19933 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19934 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19936 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.
19937 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19939 o stretch (boolean)
19941 -opts (object) options for the pie
19944 o startAngle (number)
19945 o endAngle (number)
19949 * Create a new Input
19950 * @param {Object} config The config object
19953 Roo.bootstrap.Graph = function(config){
19954 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19960 * The img click event for the img.
19961 * @param {Roo.EventObject} e
19967 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19978 //g_colors: this.colors,
19985 getAutoCreate : function(){
19996 onRender : function(ct,position){
19997 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19998 this.raphael = Raphael(this.el.dom);
20000 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20001 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20002 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20003 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20005 r.text(160, 10, "Single Series Chart").attr(txtattr);
20006 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20007 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20008 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20010 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20011 r.barchart(330, 10, 300, 220, data1);
20012 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20013 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20016 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20017 // r.barchart(30, 30, 560, 250, xdata, {
20018 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20019 // axis : "0 0 1 1",
20020 // axisxlabels : xdata
20021 // //yvalues : cols,
20024 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20026 // this.load(null,xdata,{
20027 // axis : "0 0 1 1",
20028 // axisxlabels : xdata
20033 load : function(graphtype,xdata,opts){
20034 this.raphael.clear();
20036 graphtype = this.graphtype;
20041 var r = this.raphael,
20042 fin = function () {
20043 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20045 fout = function () {
20046 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20048 pfin = function() {
20049 this.sector.stop();
20050 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20053 this.label[0].stop();
20054 this.label[0].attr({ r: 7.5 });
20055 this.label[1].attr({ "font-weight": 800 });
20058 pfout = function() {
20059 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20062 this.label[0].animate({ r: 5 }, 500, "bounce");
20063 this.label[1].attr({ "font-weight": 400 });
20069 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20072 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20075 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20076 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20078 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20085 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20090 setTitle: function(o)
20095 initEvents: function() {
20098 this.el.on('click', this.onClick, this);
20102 onClick : function(e)
20104 Roo.log('img onclick');
20105 this.fireEvent('click', this, e);
20117 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20120 * @class Roo.bootstrap.dash.NumberBox
20121 * @extends Roo.bootstrap.Component
20122 * Bootstrap NumberBox class
20123 * @cfg {String} headline Box headline
20124 * @cfg {String} content Box content
20125 * @cfg {String} icon Box icon
20126 * @cfg {String} footer Footer text
20127 * @cfg {String} fhref Footer href
20130 * Create a new NumberBox
20131 * @param {Object} config The config object
20135 Roo.bootstrap.dash.NumberBox = function(config){
20136 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20140 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20149 getAutoCreate : function(){
20153 cls : 'small-box ',
20161 cls : 'roo-headline',
20162 html : this.headline
20166 cls : 'roo-content',
20167 html : this.content
20181 cls : 'ion ' + this.icon
20190 cls : 'small-box-footer',
20191 href : this.fhref || '#',
20195 cfg.cn.push(footer);
20202 onRender : function(ct,position){
20203 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20210 setHeadline: function (value)
20212 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20215 setFooter: function (value, href)
20217 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20220 this.el.select('a.small-box-footer',true).first().attr('href', href);
20225 setContent: function (value)
20227 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20230 initEvents: function()
20244 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20247 * @class Roo.bootstrap.dash.TabBox
20248 * @extends Roo.bootstrap.Component
20249 * Bootstrap TabBox class
20250 * @cfg {String} title Title of the TabBox
20251 * @cfg {String} icon Icon of the TabBox
20252 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20253 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20256 * Create a new TabBox
20257 * @param {Object} config The config object
20261 Roo.bootstrap.dash.TabBox = function(config){
20262 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20267 * When a pane is added
20268 * @param {Roo.bootstrap.dash.TabPane} pane
20272 * @event activatepane
20273 * When a pane is activated
20274 * @param {Roo.bootstrap.dash.TabPane} pane
20276 "activatepane" : true
20284 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20289 tabScrollable : false,
20291 getChildContainer : function()
20293 return this.el.select('.tab-content', true).first();
20296 getAutoCreate : function(){
20300 cls: 'pull-left header',
20308 cls: 'fa ' + this.icon
20314 cls: 'nav nav-tabs pull-right',
20320 if(this.tabScrollable){
20327 cls: 'nav nav-tabs pull-right',
20338 cls: 'nav-tabs-custom',
20343 cls: 'tab-content no-padding',
20351 initEvents : function()
20353 //Roo.log('add add pane handler');
20354 this.on('addpane', this.onAddPane, this);
20357 * Updates the box title
20358 * @param {String} html to set the title to.
20360 setTitle : function(value)
20362 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20364 onAddPane : function(pane)
20366 this.panes.push(pane);
20367 //Roo.log('addpane');
20369 // tabs are rendere left to right..
20370 if(!this.showtabs){
20374 var ctr = this.el.select('.nav-tabs', true).first();
20377 var existing = ctr.select('.nav-tab',true);
20378 var qty = existing.getCount();;
20381 var tab = ctr.createChild({
20383 cls : 'nav-tab' + (qty ? '' : ' active'),
20391 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20394 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20396 pane.el.addClass('active');
20401 onTabClick : function(ev,un,ob,pane)
20403 //Roo.log('tab - prev default');
20404 ev.preventDefault();
20407 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20408 pane.tab.addClass('active');
20409 //Roo.log(pane.title);
20410 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20411 // technically we should have a deactivate event.. but maybe add later.
20412 // and it should not de-activate the selected tab...
20413 this.fireEvent('activatepane', pane);
20414 pane.el.addClass('active');
20415 pane.fireEvent('activate');
20420 getActivePane : function()
20423 Roo.each(this.panes, function(p) {
20424 if(p.el.hasClass('active')){
20445 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20447 * @class Roo.bootstrap.TabPane
20448 * @extends Roo.bootstrap.Component
20449 * Bootstrap TabPane class
20450 * @cfg {Boolean} active (false | true) Default false
20451 * @cfg {String} title title of panel
20455 * Create a new TabPane
20456 * @param {Object} config The config object
20459 Roo.bootstrap.dash.TabPane = function(config){
20460 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20466 * When a pane is activated
20467 * @param {Roo.bootstrap.dash.TabPane} pane
20474 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20479 // the tabBox that this is attached to.
20482 getAutoCreate : function()
20490 cfg.cls += ' active';
20495 initEvents : function()
20497 //Roo.log('trigger add pane handler');
20498 this.parent().fireEvent('addpane', this)
20502 * Updates the tab title
20503 * @param {String} html to set the title to.
20505 setTitle: function(str)
20511 this.tab.select('a', true).first().dom.innerHTML = str;
20528 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20531 * @class Roo.bootstrap.menu.Menu
20532 * @extends Roo.bootstrap.Component
20533 * Bootstrap Menu class - container for Menu
20534 * @cfg {String} html Text of the menu
20535 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20536 * @cfg {String} icon Font awesome icon
20537 * @cfg {String} pos Menu align to (top | bottom) default bottom
20541 * Create a new Menu
20542 * @param {Object} config The config object
20546 Roo.bootstrap.menu.Menu = function(config){
20547 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20551 * @event beforeshow
20552 * Fires before this menu is displayed
20553 * @param {Roo.bootstrap.menu.Menu} this
20557 * @event beforehide
20558 * Fires before this menu is hidden
20559 * @param {Roo.bootstrap.menu.Menu} this
20564 * Fires after this menu is displayed
20565 * @param {Roo.bootstrap.menu.Menu} this
20570 * Fires after this menu is hidden
20571 * @param {Roo.bootstrap.menu.Menu} this
20576 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20577 * @param {Roo.bootstrap.menu.Menu} this
20578 * @param {Roo.EventObject} e
20585 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20589 weight : 'default',
20594 getChildContainer : function() {
20595 if(this.isSubMenu){
20599 return this.el.select('ul.dropdown-menu', true).first();
20602 getAutoCreate : function()
20607 cls : 'roo-menu-text',
20615 cls : 'fa ' + this.icon
20626 cls : 'dropdown-button btn btn-' + this.weight,
20631 cls : 'dropdown-toggle btn btn-' + this.weight,
20641 cls : 'dropdown-menu'
20647 if(this.pos == 'top'){
20648 cfg.cls += ' dropup';
20651 if(this.isSubMenu){
20654 cls : 'dropdown-menu'
20661 onRender : function(ct, position)
20663 this.isSubMenu = ct.hasClass('dropdown-submenu');
20665 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20668 initEvents : function()
20670 if(this.isSubMenu){
20674 this.hidden = true;
20676 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20677 this.triggerEl.on('click', this.onTriggerPress, this);
20679 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20680 this.buttonEl.on('click', this.onClick, this);
20686 if(this.isSubMenu){
20690 return this.el.select('ul.dropdown-menu', true).first();
20693 onClick : function(e)
20695 this.fireEvent("click", this, e);
20698 onTriggerPress : function(e)
20700 if (this.isVisible()) {
20707 isVisible : function(){
20708 return !this.hidden;
20713 this.fireEvent("beforeshow", this);
20715 this.hidden = false;
20716 this.el.addClass('open');
20718 Roo.get(document).on("mouseup", this.onMouseUp, this);
20720 this.fireEvent("show", this);
20727 this.fireEvent("beforehide", this);
20729 this.hidden = true;
20730 this.el.removeClass('open');
20732 Roo.get(document).un("mouseup", this.onMouseUp);
20734 this.fireEvent("hide", this);
20737 onMouseUp : function()
20751 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20754 * @class Roo.bootstrap.menu.Item
20755 * @extends Roo.bootstrap.Component
20756 * Bootstrap MenuItem class
20757 * @cfg {Boolean} submenu (true | false) default false
20758 * @cfg {String} html text of the item
20759 * @cfg {String} href the link
20760 * @cfg {Boolean} disable (true | false) default false
20761 * @cfg {Boolean} preventDefault (true | false) default true
20762 * @cfg {String} icon Font awesome icon
20763 * @cfg {String} pos Submenu align to (left | right) default right
20767 * Create a new Item
20768 * @param {Object} config The config object
20772 Roo.bootstrap.menu.Item = function(config){
20773 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20777 * Fires when the mouse is hovering over this menu
20778 * @param {Roo.bootstrap.menu.Item} this
20779 * @param {Roo.EventObject} e
20784 * Fires when the mouse exits this menu
20785 * @param {Roo.bootstrap.menu.Item} this
20786 * @param {Roo.EventObject} e
20792 * The raw click event for the entire grid.
20793 * @param {Roo.EventObject} e
20799 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20804 preventDefault: true,
20809 getAutoCreate : function()
20814 cls : 'roo-menu-item-text',
20822 cls : 'fa ' + this.icon
20831 href : this.href || '#',
20838 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20842 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20844 if(this.pos == 'left'){
20845 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20852 initEvents : function()
20854 this.el.on('mouseover', this.onMouseOver, this);
20855 this.el.on('mouseout', this.onMouseOut, this);
20857 this.el.select('a', true).first().on('click', this.onClick, this);
20861 onClick : function(e)
20863 if(this.preventDefault){
20864 e.preventDefault();
20867 this.fireEvent("click", this, e);
20870 onMouseOver : function(e)
20872 if(this.submenu && this.pos == 'left'){
20873 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20876 this.fireEvent("mouseover", this, e);
20879 onMouseOut : function(e)
20881 this.fireEvent("mouseout", this, e);
20893 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20896 * @class Roo.bootstrap.menu.Separator
20897 * @extends Roo.bootstrap.Component
20898 * Bootstrap Separator class
20901 * Create a new Separator
20902 * @param {Object} config The config object
20906 Roo.bootstrap.menu.Separator = function(config){
20907 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20910 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20912 getAutoCreate : function(){
20933 * @class Roo.bootstrap.Tooltip
20934 * Bootstrap Tooltip class
20935 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20936 * to determine which dom element triggers the tooltip.
20938 * It needs to add support for additional attributes like tooltip-position
20941 * Create a new Toolti
20942 * @param {Object} config The config object
20945 Roo.bootstrap.Tooltip = function(config){
20946 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20949 Roo.apply(Roo.bootstrap.Tooltip, {
20951 * @function init initialize tooltip monitoring.
20955 currentTip : false,
20956 currentRegion : false,
20962 Roo.get(document).on('mouseover', this.enter ,this);
20963 Roo.get(document).on('mouseout', this.leave, this);
20966 this.currentTip = new Roo.bootstrap.Tooltip();
20969 enter : function(ev)
20971 var dom = ev.getTarget();
20972 //Roo.log(['enter',dom]);
20973 var el = Roo.fly(dom);
20974 if (this.currentEl) {
20976 //Roo.log(this.currentEl);
20977 //Roo.log(this.currentEl.contains(dom));
20978 if (this.currentEl == el) {
20981 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20989 if (this.currentTip.el) {
20990 this.currentTip.el.hide(); // force hiding...
20993 if (!el.attr('tooltip')) { // parents who have tip?
20996 this.currentEl = el;
20997 this.currentTip.bind(el);
20998 this.currentRegion = Roo.lib.Region.getRegion(dom);
20999 this.currentTip.enter();
21002 leave : function(ev)
21004 var dom = ev.getTarget();
21005 //Roo.log(['leave',dom]);
21006 if (!this.currentEl) {
21011 if (dom != this.currentEl.dom) {
21014 var xy = ev.getXY();
21015 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21018 // only activate leave if mouse cursor is outside... bounding box..
21023 if (this.currentTip) {
21024 this.currentTip.leave();
21026 //Roo.log('clear currentEl');
21027 this.currentEl = false;
21032 'left' : ['r-l', [-2,0], 'right'],
21033 'right' : ['l-r', [2,0], 'left'],
21034 'bottom' : ['t-b', [0,2], 'top'],
21035 'top' : [ 'b-t', [0,-2], 'bottom']
21041 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21046 delay : null, // can be { show : 300 , hide: 500}
21050 hoverState : null, //???
21052 placement : 'bottom',
21054 getAutoCreate : function(){
21061 cls : 'tooltip-arrow'
21064 cls : 'tooltip-inner'
21071 bind : function(el)
21077 enter : function () {
21079 if (this.timeout != null) {
21080 clearTimeout(this.timeout);
21083 this.hoverState = 'in'
21084 //Roo.log("enter - show");
21085 if (!this.delay || !this.delay.show) {
21090 this.timeout = setTimeout(function () {
21091 if (_t.hoverState == 'in') {
21094 }, this.delay.show);
21098 clearTimeout(this.timeout);
21100 this.hoverState = 'out'
21101 if (!this.delay || !this.delay.hide) {
21107 this.timeout = setTimeout(function () {
21108 //Roo.log("leave - timeout");
21110 if (_t.hoverState == 'out') {
21112 Roo.bootstrap.Tooltip.currentEl = false;
21120 this.render(document.body);
21123 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21124 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21126 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21128 var placement = typeof this.placement == 'function' ?
21129 this.placement.call(this, this.el, on_el) :
21132 var autoToken = /\s?auto?\s?/i;
21133 var autoPlace = autoToken.test(placement);
21135 placement = placement.replace(autoToken, '') || 'top';
21139 //this.el.setXY([0,0]);
21141 //this.el.dom.style.display='block';
21142 this.el.addClass(placement);
21144 //this.el.appendTo(on_el);
21146 var p = this.getPosition();
21147 var box = this.el.getBox();
21152 var align = Roo.bootstrap.Tooltip.alignment[placement]
21153 this.el.alignTo(this.bindEl, align[0],align[1]);
21154 //var arrow = this.el.select('.arrow',true).first();
21155 //arrow.set(align[2],
21157 this.el.addClass('in fade');
21158 this.hoverState = null;
21160 if (this.el.hasClass('fade')) {
21171 //this.el.setXY([0,0]);
21172 this.el.removeClass('in');
21188 * @class Roo.bootstrap.LocationPicker
21189 * @extends Roo.bootstrap.Component
21190 * Bootstrap LocationPicker class
21191 * @cfg {Number} latitude Position when init default 0
21192 * @cfg {Number} longitude Position when init default 0
21193 * @cfg {Number} zoom default 15
21194 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21195 * @cfg {Boolean} mapTypeControl default false
21196 * @cfg {Boolean} disableDoubleClickZoom default false
21197 * @cfg {Boolean} scrollwheel default true
21198 * @cfg {Boolean} streetViewControl default false
21199 * @cfg {Number} radius default 0
21200 * @cfg {String} locationName
21201 * @cfg {Boolean} draggable default true
21202 * @cfg {Boolean} enableAutocomplete default false
21203 * @cfg {Boolean} enableReverseGeocode default true
21204 * @cfg {String} markerTitle
21207 * Create a new LocationPicker
21208 * @param {Object} config The config object
21212 Roo.bootstrap.LocationPicker = function(config){
21214 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21219 * Fires when the picker initialized.
21220 * @param {Roo.bootstrap.LocationPicker} this
21221 * @param {Google Location} location
21225 * @event positionchanged
21226 * Fires when the picker position changed.
21227 * @param {Roo.bootstrap.LocationPicker} this
21228 * @param {Google Location} location
21230 positionchanged : true,
21233 * Fires when the map resize.
21234 * @param {Roo.bootstrap.LocationPicker} this
21239 * Fires when the map show.
21240 * @param {Roo.bootstrap.LocationPicker} this
21245 * Fires when the map hide.
21246 * @param {Roo.bootstrap.LocationPicker} this
21253 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
21255 gMapContext: false,
21261 mapTypeControl: false,
21262 disableDoubleClickZoom: false,
21264 streetViewControl: false,
21268 enableAutocomplete: false,
21269 enableReverseGeocode: true,
21272 getAutoCreate: function()
21277 cls: 'roo-location-picker'
21283 initEvents: function(ct, position)
21285 if(!this.mapTypeId){
21286 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
21289 if(!this.el.getWidth() || this.isApplied()){
21293 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21298 initial: function()
21300 this.gMapContext = this.GMapContext();
21304 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
21305 _this.setPosition(_this.gMapContext.marker.position);
21308 this.setPosition(this.gMapContext.location);
21310 this.fireEvent('initial', this, this.gMapContext.location);
21313 isApplied: function()
21315 return this.getGmapContext() == false ? false : true;
21318 getGmapContext: function()
21320 return this.gMapContext
21323 GMapContext: function()
21325 var _map = new google.maps.Map(this.el.dom, this);
21326 var _marker = new google.maps.Marker({
21327 position: new google.maps.LatLng(this.latitude, this.longitude),
21329 title: this.markerTitle,
21330 draggable: this.draggable
21337 location: _marker.position,
21338 radius: this.radius,
21339 locationName: this.locationName,
21340 addressComponents: {
21341 formatted_address: null,
21342 addressLine1: null,
21343 addressLine2: null,
21345 streetNumber: null,
21349 stateOrProvince: null
21352 domContainer: this.el.dom,
21353 geodecoder: new google.maps.Geocoder()
21357 drawCircle: function(center, radius, options)
21359 if (this.gMapContext.circle != null) {
21360 this.gMapContext.circle.setMap(null);
21364 options = Roo.apply({}, options, {
21365 strokeColor: "#0000FF",
21366 strokeOpacity: .35,
21368 fillColor: "#0000FF",
21372 options.map = this.gMapContext.map;
21373 options.radius = radius;
21374 options.center = center;
21375 this.gMapContext.circle = new google.maps.Circle(options);
21376 return this.gMapContext.circle;
21382 setPosition: function(location)
21384 this.gMapContext.location = location;
21385 this.gMapContext.marker.setPosition(location);
21386 this.gMapContext.map.panTo(location);
21387 this.drawCircle(location, this.gMapContext.radius, {});
21391 if (this.gMapContext.settings.enableReverseGeocode) {
21392 this.gMapContext.geodecoder.geocode({
21393 latLng: this.gMapContext.location
21394 }, function(results, status) {
21396 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21397 _this.gMapContext.locationName = results[0].formatted_address;
21398 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21400 _this.fireEvent('positionchanged', this, location);
21407 this.fireEvent('positionchanged', this, location);
21412 google.maps.event.trigger(this.gMapContext.map, "resize");
21414 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
21416 this.fireEvent('resize', this);
21419 setPositionByLatLng: function(latitude, longitude)
21421 this.setPosition(new google.maps.LatLng(latitude, longitude));
21424 getCurrentPosition: function()
21427 latitude: this.gMapContext.location.lat(),
21428 longitude: this.gMapContext.location.lng()
21432 getAddressName: function()
21434 return this.gMapContext.locationName;
21437 getAddressComponents: function()
21439 return this.gMapContext.addressComponents;
21442 address_component_from_google_geocode: function(address_components)
21446 for (var i = 0; i < address_components.length; i++) {
21447 var component = address_components[i];
21448 if (component.types.indexOf("postal_code") >= 0) {
21449 result.postalCode = component.short_name;
21450 } else if (component.types.indexOf("street_number") >= 0) {
21451 result.streetNumber = component.short_name;
21452 } else if (component.types.indexOf("route") >= 0) {
21453 result.streetName = component.short_name;
21454 } else if (component.types.indexOf("neighborhood") >= 0) {
21455 result.city = component.short_name;
21456 } else if (component.types.indexOf("locality") >= 0) {
21457 result.city = component.short_name;
21458 } else if (component.types.indexOf("sublocality") >= 0) {
21459 result.district = component.short_name;
21460 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
21461 result.stateOrProvince = component.short_name;
21462 } else if (component.types.indexOf("country") >= 0) {
21463 result.country = component.short_name;
21467 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
21468 result.addressLine2 = "";
21472 setZoomLevel: function(zoom)
21474 this.gMapContext.map.setZoom(zoom);
21487 this.fireEvent('show', this);
21498 this.fireEvent('hide', this);
21510 * @class Roo.bootstrap.Alert
21511 * @extends Roo.bootstrap.Component
21512 * Bootstrap Alert class
21513 * @cfg {String} title The title of alert
21514 * @cfg {String} html The content of alert
21515 * @cfg {String} weight ( success | info | warning | danger )
21516 * @cfg {String} faicon font-awesomeicon
21519 * Create a new alert
21520 * @param {Object} config The config object
21524 Roo.bootstrap.Alert = function(config){
21525 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
21529 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
21536 getAutoCreate : function()
21545 cls : 'roo-alert-icon'
21550 cls : 'roo-alert-title',
21555 cls : 'roo-alert-text',
21562 cfg.cn[0].cls += ' fa ' + this.faicon;
21566 cfg.cls += ' alert-' + this.weight;
21572 initEvents: function()
21574 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21577 setTitle : function(str)
21579 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
21582 setText : function(str)
21584 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
21587 setWeight : function(weight)
21590 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
21593 this.weight = weight;
21595 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
21598 setIcon : function(icon)
21601 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
21606 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);