4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
33 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
36 allowDomMove : false, // to stop relocations in parent onRender...
46 * Initialize Events for the element
48 initEvents : function() { },
54 can_build_overlaid : true,
56 container_method : false,
63 // returns the parent component..
64 return Roo.ComponentMgr.get(this.parentId)
70 onRender : function(ct, position)
72 // Roo.log("Call onRender: " + this.xtype);
74 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
77 if (this.el.attr('xtype')) {
78 this.el.attr('xtypex', this.el.attr('xtype'));
79 this.el.dom.removeAttribute('xtype');
89 var cfg = Roo.apply({}, this.getAutoCreate());
92 // fill in the extra attributes
93 if (this.xattr && typeof(this.xattr) =='object') {
94 for (var i in this.xattr) {
95 cfg[i] = this.xattr[i];
100 cfg.dataId = this.dataId;
104 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
107 if (this.style) { // fixme needs to support more complex style data.
108 cfg.style = this.style;
112 cfg.name = this.name;
117 this.el = ct.createChild(cfg, position);
120 this.tooltipEl().attr('tooltip', this.tooltip);
123 if(this.tabIndex !== undefined){
124 this.el.dom.setAttribute('tabIndex', this.tabIndex);
131 * Fetch the element to add children to
132 * @return {Roo.Element} defaults to this.el
134 getChildContainer : function()
139 * Fetch the element to display the tooltip on.
140 * @return {Roo.Element} defaults to this.el
142 tooltipEl : function()
147 addxtype : function(tree,cntr)
151 cn = Roo.factory(tree);
153 cn.parentType = this.xtype; //??
154 cn.parentId = this.id;
156 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
157 if (typeof(cn.container_method) == 'string') {
158 cntr = cn.container_method;
162 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
164 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
166 var build_from_html = Roo.XComponent.build_from_html;
168 var is_body = (tree.xtype == 'Body') ;
170 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
172 var self_cntr_el = Roo.get(this[cntr](false));
174 // do not try and build conditional elements
175 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
179 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
180 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
181 return this.addxtypeChild(tree,cntr);
184 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
187 return this.addxtypeChild(Roo.apply({}, tree),cntr);
190 Roo.log('skipping render');
198 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
204 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
208 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
213 addxtypeChild : function (tree, cntr)
215 Roo.debug && Roo.log('addxtypeChild:' + cntr);
217 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
220 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
221 (typeof(tree['flexy:foreach']) != 'undefined');
225 skip_children = false;
226 // render the element if it's not BODY.
227 if (tree.xtype != 'Body') {
229 cn = Roo.factory(tree);
231 cn.parentType = this.xtype; //??
232 cn.parentId = this.id;
234 var build_from_html = Roo.XComponent.build_from_html;
237 // does the container contain child eleemnts with 'xtype' attributes.
238 // that match this xtype..
239 // note - when we render we create these as well..
240 // so we should check to see if body has xtype set.
241 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
243 var self_cntr_el = Roo.get(this[cntr](false));
244 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
247 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
248 // and are not displayed -this causes this to use up the wrong element when matching.
249 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
252 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
253 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
259 //echild.dom.removeAttribute('xtype');
261 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
262 Roo.debug && Roo.log(self_cntr_el);
263 Roo.debug && Roo.log(echild);
264 Roo.debug && Roo.log(cn);
270 // if object has flexy:if - then it may or may not be rendered.
271 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
272 // skip a flexy if element.
273 Roo.debug && Roo.log('skipping render');
274 Roo.debug && Roo.log(tree);
276 Roo.debug && Roo.log('skipping all children');
277 skip_children = true;
282 // actually if flexy:foreach is found, we really want to create
283 // multiple copies here...
285 //Roo.log(this[cntr]());
286 cn.render(this[cntr](true));
288 // then add the element..
296 if (typeof (tree.menu) != 'undefined') {
297 tree.menu.parentType = cn.xtype;
298 tree.menu.triggerEl = cn.el;
299 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
303 if (!tree.items || !tree.items.length) {
307 var items = tree.items;
310 //Roo.log(items.length);
312 if (!skip_children) {
313 for(var i =0;i < items.length;i++) {
314 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
336 * @class Roo.bootstrap.Body
337 * @extends Roo.bootstrap.Component
338 * Bootstrap Body class
342 * @param {Object} config The config object
345 Roo.bootstrap.Body = function(config){
346 Roo.bootstrap.Body.superclass.constructor.call(this, config);
347 this.el = Roo.get(document.body);
348 if (this.cls && this.cls.length) {
349 Roo.get(document.body).addClass(this.cls);
353 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
358 onRender : function(ct, position)
360 /* Roo.log("Roo.bootstrap.Body - onRender");
361 if (this.cls && this.cls.length) {
362 Roo.get(document.body).addClass(this.cls);
382 * @class Roo.bootstrap.ButtonGroup
383 * @extends Roo.bootstrap.Component
384 * Bootstrap ButtonGroup class
385 * @cfg {String} size lg | sm | xs (default empty normal)
386 * @cfg {String} align vertical | justified (default none)
387 * @cfg {String} direction up | down (default down)
388 * @cfg {Boolean} toolbar false | true
389 * @cfg {Boolean} btn true | false
394 * @param {Object} config The config object
397 Roo.bootstrap.ButtonGroup = function(config){
398 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
401 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
409 getAutoCreate : function(){
415 cfg.html = this.html || cfg.html;
426 if (['vertical','justified'].indexOf(this.align)!==-1) {
427 cfg.cls = 'btn-group-' + this.align;
429 if (this.align == 'justified') {
430 console.log(this.items);
434 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
435 cfg.cls += ' btn-group-' + this.size;
438 if (this.direction == 'up') {
439 cfg.cls += ' dropup' ;
455 * @class Roo.bootstrap.Button
456 * @extends Roo.bootstrap.Component
457 * Bootstrap Button class
458 * @cfg {String} html The button content
459 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
460 * @cfg {String} size ( lg | sm | xs)
461 * @cfg {String} tag ( a | input | submit)
462 * @cfg {String} href empty or href
463 * @cfg {Boolean} disabled default false;
464 * @cfg {Boolean} isClose default false;
465 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
466 * @cfg {String} badge text for badge
467 * @cfg {String} theme default
468 * @cfg {Boolean} inverse
469 * @cfg {Boolean} toggle
470 * @cfg {String} ontext text for on toggle state
471 * @cfg {String} offtext text for off toggle state
472 * @cfg {Boolean} defaulton
473 * @cfg {Boolean} preventDefault default true
474 * @cfg {Boolean} removeClass remove the standard class..
475 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
478 * Create a new button
479 * @param {Object} config The config object
483 Roo.bootstrap.Button = function(config){
484 Roo.bootstrap.Button.superclass.constructor.call(this, config);
489 * When a butotn is pressed
490 * @param {Roo.EventObject} e
495 * After the button has been toggles
496 * @param {Roo.EventObject} e
497 * @param {boolean} pressed (also available as button.pressed)
503 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
521 preventDefault: true,
530 getAutoCreate : function(){
538 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
539 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
544 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
546 if (this.toggle == true) {
549 cls: 'slider-frame roo-button',
554 'data-off-text':'OFF',
555 cls: 'slider-button',
561 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
562 cfg.cls += ' '+this.weight;
571 cfg["aria-hidden"] = true;
573 cfg.html = "×";
579 if (this.theme==='default') {
580 cfg.cls = 'btn roo-button';
582 //if (this.parentType != 'Navbar') {
583 this.weight = this.weight.length ? this.weight : 'default';
585 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
587 cfg.cls += ' btn-' + this.weight;
589 } else if (this.theme==='glow') {
592 cfg.cls = 'btn-glow roo-button';
594 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
596 cfg.cls += ' ' + this.weight;
602 this.cls += ' inverse';
607 cfg.cls += ' active';
611 cfg.disabled = 'disabled';
615 Roo.log('changing to ul' );
617 this.glyphicon = 'caret';
620 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
622 //gsRoo.log(this.parentType);
623 if (this.parentType === 'Navbar' && !this.parent().bar) {
624 Roo.log('changing to li?');
633 href : this.href || '#'
636 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
637 cfg.cls += ' dropdown';
644 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
646 if (this.glyphicon) {
647 cfg.html = ' ' + cfg.html;
652 cls: 'glyphicon glyphicon-' + this.glyphicon
662 // cfg.cls='btn roo-button';
666 var value = cfg.html;
671 cls: 'glyphicon glyphicon-' + this.glyphicon,
690 cfg.cls += ' dropdown';
691 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
694 if (cfg.tag !== 'a' && this.href !== '') {
695 throw "Tag must be a to set href.";
696 } else if (this.href.length > 0) {
697 cfg.href = this.href;
700 if(this.removeClass){
705 cfg.target = this.target;
710 initEvents: function() {
711 // Roo.log('init events?');
712 // Roo.log(this.el.dom);
715 if (typeof (this.menu) != 'undefined') {
716 this.menu.parentType = this.xtype;
717 this.menu.triggerEl = this.el;
718 this.addxtype(Roo.apply({}, this.menu));
722 if (this.el.hasClass('roo-button')) {
723 this.el.on('click', this.onClick, this);
725 this.el.select('.roo-button').on('click', this.onClick, this);
728 if(this.removeClass){
729 this.el.on('click', this.onClick, this);
732 this.el.enableDisplayMode();
735 onClick : function(e)
742 Roo.log('button on click ');
743 if(this.preventDefault){
746 if (this.pressed === true || this.pressed === false) {
747 this.pressed = !this.pressed;
748 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
749 this.fireEvent('toggle', this, e, this.pressed);
753 this.fireEvent('click', this, e);
757 * Enables this button
761 this.disabled = false;
762 this.el.removeClass('disabled');
766 * Disable this button
770 this.disabled = true;
771 this.el.addClass('disabled');
774 * sets the active state on/off,
775 * @param {Boolean} state (optional) Force a particular state
777 setActive : function(v) {
779 this.el[v ? 'addClass' : 'removeClass']('active');
782 * toggles the current active state
784 toggleActive : function()
786 var active = this.el.hasClass('active');
787 this.setActive(!active);
791 setText : function(str)
793 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
797 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
820 * @class Roo.bootstrap.Column
821 * @extends Roo.bootstrap.Component
822 * Bootstrap Column class
823 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
824 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
825 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
826 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
827 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
828 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
829 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
830 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
833 * @cfg {Boolean} hidden (true|false) hide the element
834 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
835 * @cfg {String} fa (ban|check|...) font awesome icon
836 * @cfg {Number} fasize (1|2|....) font awsome size
838 * @cfg {String} icon (info-sign|check|...) glyphicon name
840 * @cfg {String} html content of column.
843 * Create a new Column
844 * @param {Object} config The config object
847 Roo.bootstrap.Column = function(config){
848 Roo.bootstrap.Column.superclass.constructor.call(this, config);
851 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
869 getAutoCreate : function(){
870 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
878 ['xs','sm','md','lg'].map(function(size){
879 //Roo.log( size + ':' + settings[size]);
881 if (settings[size+'off'] !== false) {
882 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
885 if (settings[size] === false) {
888 Roo.log(settings[size]);
889 if (!settings[size]) { // 0 = hidden
890 cfg.cls += ' hidden-' + size;
893 cfg.cls += ' col-' + size + '-' + settings[size];
898 cfg.cls += ' hidden';
901 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
902 cfg.cls +=' alert alert-' + this.alert;
906 if (this.html.length) {
907 cfg.html = this.html;
911 if (this.fasize > 1) {
912 fasize = ' fa-' + this.fasize + 'x';
914 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
919 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
938 * @class Roo.bootstrap.Container
939 * @extends Roo.bootstrap.Component
940 * Bootstrap Container class
941 * @cfg {Boolean} jumbotron is it a jumbotron element
942 * @cfg {String} html content of element
943 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
944 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
945 * @cfg {String} header content of header (for panel)
946 * @cfg {String} footer content of footer (for panel)
947 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
948 * @cfg {String} tag (header|aside|section) type of HTML tag.
949 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
950 * @cfg {String} fa (ban|check|...) font awesome icon
951 * @cfg {String} icon (info-sign|check|...) glyphicon name
952 * @cfg {Boolean} hidden (true|false) hide the element
956 * Create a new Container
957 * @param {Object} config The config object
960 Roo.bootstrap.Container = function(config){
961 Roo.bootstrap.Container.superclass.constructor.call(this, config);
964 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
978 getChildContainer : function() {
984 if (this.panel.length) {
985 return this.el.select('.panel-body',true).first();
992 getAutoCreate : function(){
995 tag : this.tag || 'div',
999 if (this.jumbotron) {
1000 cfg.cls = 'jumbotron';
1005 // - this is applied by the parent..
1007 // cfg.cls = this.cls + '';
1010 if (this.sticky.length) {
1012 var bd = Roo.get(document.body);
1013 if (!bd.hasClass('bootstrap-sticky')) {
1014 bd.addClass('bootstrap-sticky');
1015 Roo.select('html',true).setStyle('height', '100%');
1018 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1022 if (this.well.length) {
1023 switch (this.well) {
1026 cfg.cls +=' well well-' +this.well;
1035 cfg.cls += ' hidden';
1039 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1040 cfg.cls +=' alert alert-' + this.alert;
1045 if (this.panel.length) {
1046 cfg.cls += ' panel panel-' + this.panel;
1048 if (this.header.length) {
1051 cls : 'panel-heading',
1054 cls : 'panel-title',
1067 if (this.footer.length) {
1069 cls : 'panel-footer',
1078 body.html = this.html || cfg.html;
1079 // prefix with the icons..
1081 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1084 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1089 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1090 cfg.cls = 'container';
1096 titleEl : function()
1098 if(!this.el || !this.panel.length || !this.header.length){
1102 return this.el.select('.panel-title',true).first();
1105 setTitle : function(v)
1107 var titleEl = this.titleEl();
1113 titleEl.dom.innerHTML = v;
1116 getTitle : function()
1119 var titleEl = this.titleEl();
1125 return titleEl.dom.innerHTML;
1129 this.el.removeClass('hidden');
1132 if (!this.el.hasClass('hidden')) {
1133 this.el.addClass('hidden');
1149 * @class Roo.bootstrap.Img
1150 * @extends Roo.bootstrap.Component
1151 * Bootstrap Img class
1152 * @cfg {Boolean} imgResponsive false | true
1153 * @cfg {String} border rounded | circle | thumbnail
1154 * @cfg {String} src image source
1155 * @cfg {String} alt image alternative text
1156 * @cfg {String} href a tag href
1157 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1160 * Create a new Input
1161 * @param {Object} config The config object
1164 Roo.bootstrap.Img = function(config){
1165 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1171 * The img click event for the img.
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1180 imgResponsive: true,
1186 getAutoCreate : function(){
1190 cls: (this.imgResponsive) ? 'img-responsive' : '',
1194 cfg.html = this.html || cfg.html;
1196 cfg.src = this.src || cfg.src;
1198 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1199 cfg.cls += ' img-' + this.border;
1216 a.target = this.target;
1222 return (this.href) ? a : cfg;
1225 initEvents: function() {
1228 this.el.on('click', this.onClick, this);
1232 onClick : function(e)
1234 Roo.log('img onclick');
1235 this.fireEvent('click', this, e);
1249 * @class Roo.bootstrap.Link
1250 * @extends Roo.bootstrap.Component
1251 * Bootstrap Link Class
1252 * @cfg {String} alt image alternative text
1253 * @cfg {String} href a tag href
1254 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1255 * @cfg {String} html the content of the link.
1256 * @cfg {String} anchor name for the anchor link
1258 * @cfg {Boolean} preventDefault (true | false) default false
1262 * Create a new Input
1263 * @param {Object} config The config object
1266 Roo.bootstrap.Link = function(config){
1267 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1273 * The img click event for the img.
1274 * @param {Roo.EventObject} e
1280 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1284 preventDefault: false,
1288 getAutoCreate : function()
1294 // anchor's do not require html/href...
1295 if (this.anchor === false) {
1296 cfg.html = this.html || 'html-missing';
1297 cfg.href = this.href || '#';
1299 cfg.name = this.anchor;
1300 if (this.html !== false) {
1301 cfg.html = this.html;
1303 if (this.href !== false) {
1304 cfg.href = this.href;
1308 if(this.alt !== false){
1313 if(this.target !== false) {
1314 cfg.target = this.target;
1320 initEvents: function() {
1322 if(!this.href || this.preventDefault){
1323 this.el.on('click', this.onClick, this);
1327 onClick : function(e)
1329 if(this.preventDefault){
1332 //Roo.log('img onclick');
1333 this.fireEvent('click', this, e);
1346 * @class Roo.bootstrap.Header
1347 * @extends Roo.bootstrap.Component
1348 * Bootstrap Header class
1349 * @cfg {String} html content of header
1350 * @cfg {Number} level (1|2|3|4|5|6) default 1
1353 * Create a new Header
1354 * @param {Object} config The config object
1358 Roo.bootstrap.Header = function(config){
1359 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1362 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1370 getAutoCreate : function(){
1375 tag: 'h' + (1 *this.level),
1376 html: this.html || ''
1388 * Ext JS Library 1.1.1
1389 * Copyright(c) 2006-2007, Ext JS, LLC.
1391 * Originally Released Under LGPL - original licence link has changed is not relivant.
1394 * <script type="text/javascript">
1398 * @class Roo.bootstrap.MenuMgr
1399 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1402 Roo.bootstrap.MenuMgr = function(){
1403 var menus, active, groups = {}, attached = false, lastShow = new Date();
1405 // private - called when first menu is created
1408 active = new Roo.util.MixedCollection();
1409 Roo.get(document).addKeyListener(27, function(){
1410 if(active.length > 0){
1418 if(active && active.length > 0){
1419 var c = active.clone();
1429 if(active.length < 1){
1430 Roo.get(document).un("mouseup", onMouseDown);
1438 var last = active.last();
1439 lastShow = new Date();
1442 Roo.get(document).on("mouseup", onMouseDown);
1447 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1448 m.parentMenu.activeChild = m;
1449 }else if(last && last.isVisible()){
1450 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1455 function onBeforeHide(m){
1457 m.activeChild.hide();
1459 if(m.autoHideTimer){
1460 clearTimeout(m.autoHideTimer);
1461 delete m.autoHideTimer;
1466 function onBeforeShow(m){
1467 var pm = m.parentMenu;
1468 if(!pm && !m.allowOtherMenus){
1470 }else if(pm && pm.activeChild && active != m){
1471 pm.activeChild.hide();
1476 function onMouseDown(e){
1477 Roo.log("on MouseDown");
1478 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1486 function onBeforeCheck(mi, state){
1488 var g = groups[mi.group];
1489 for(var i = 0, l = g.length; i < l; i++){
1491 g[i].setChecked(false);
1500 * Hides all menus that are currently visible
1502 hideAll : function(){
1507 register : function(menu){
1511 menus[menu.id] = menu;
1512 menu.on("beforehide", onBeforeHide);
1513 menu.on("hide", onHide);
1514 menu.on("beforeshow", onBeforeShow);
1515 menu.on("show", onShow);
1517 if(g && menu.events["checkchange"]){
1521 groups[g].push(menu);
1522 menu.on("checkchange", onCheck);
1527 * Returns a {@link Roo.menu.Menu} object
1528 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1529 * be used to generate and return a new Menu instance.
1531 get : function(menu){
1532 if(typeof menu == "string"){ // menu id
1534 }else if(menu.events){ // menu instance
1537 /*else if(typeof menu.length == 'number'){ // array of menu items?
1538 return new Roo.bootstrap.Menu({items:menu});
1539 }else{ // otherwise, must be a config
1540 return new Roo.bootstrap.Menu(menu);
1547 unregister : function(menu){
1548 delete menus[menu.id];
1549 menu.un("beforehide", onBeforeHide);
1550 menu.un("hide", onHide);
1551 menu.un("beforeshow", onBeforeShow);
1552 menu.un("show", onShow);
1554 if(g && menu.events["checkchange"]){
1555 groups[g].remove(menu);
1556 menu.un("checkchange", onCheck);
1561 registerCheckable : function(menuItem){
1562 var g = menuItem.group;
1567 groups[g].push(menuItem);
1568 menuItem.on("beforecheckchange", onBeforeCheck);
1573 unregisterCheckable : function(menuItem){
1574 var g = menuItem.group;
1576 groups[g].remove(menuItem);
1577 menuItem.un("beforecheckchange", onBeforeCheck);
1589 * @class Roo.bootstrap.Menu
1590 * @extends Roo.bootstrap.Component
1591 * Bootstrap Menu class - container for MenuItems
1592 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1596 * @param {Object} config The config object
1600 Roo.bootstrap.Menu = function(config){
1601 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1602 if (this.registerMenu) {
1603 Roo.bootstrap.MenuMgr.register(this);
1608 * Fires before this menu is displayed
1609 * @param {Roo.menu.Menu} this
1614 * Fires before this menu is hidden
1615 * @param {Roo.menu.Menu} this
1620 * Fires after this menu is displayed
1621 * @param {Roo.menu.Menu} this
1626 * Fires after this menu is hidden
1627 * @param {Roo.menu.Menu} this
1632 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1633 * @param {Roo.menu.Menu} this
1634 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1635 * @param {Roo.EventObject} e
1640 * Fires when the mouse is hovering over this menu
1641 * @param {Roo.menu.Menu} this
1642 * @param {Roo.EventObject} e
1643 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1648 * Fires when the mouse exits this menu
1649 * @param {Roo.menu.Menu} this
1650 * @param {Roo.EventObject} e
1651 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1656 * Fires when a menu item contained in this menu is clicked
1657 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1658 * @param {Roo.EventObject} e
1662 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1665 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1669 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1672 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1674 registerMenu : true,
1676 menuItems :false, // stores the menu items..
1682 getChildContainer : function() {
1686 getAutoCreate : function(){
1688 //if (['right'].indexOf(this.align)!==-1) {
1689 // cfg.cn[1].cls += ' pull-right'
1695 cls : 'dropdown-menu' ,
1696 style : 'z-index:1000'
1700 if (this.type === 'submenu') {
1701 cfg.cls = 'submenu active';
1703 if (this.type === 'treeview') {
1704 cfg.cls = 'treeview-menu';
1709 initEvents : function() {
1711 // Roo.log("ADD event");
1712 // Roo.log(this.triggerEl.dom);
1713 this.triggerEl.on('click', this.onTriggerPress, this);
1714 this.triggerEl.addClass('dropdown-toggle');
1715 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1717 this.el.on("mouseover", this.onMouseOver, this);
1718 this.el.on("mouseout", this.onMouseOut, this);
1722 findTargetItem : function(e){
1723 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1727 //Roo.log(t); Roo.log(t.id);
1729 //Roo.log(this.menuitems);
1730 return this.menuitems.get(t.id);
1732 //return this.items.get(t.menuItemId);
1737 onClick : function(e){
1738 Roo.log("menu.onClick");
1739 var t = this.findTargetItem(e);
1740 if(!t || t.isContainer){
1745 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1746 if(t == this.activeItem && t.shouldDeactivate(e)){
1747 this.activeItem.deactivate();
1748 delete this.activeItem;
1752 this.setActiveItem(t, true);
1760 Roo.log('pass click event');
1764 this.fireEvent("click", this, t, e);
1768 onMouseOver : function(e){
1769 var t = this.findTargetItem(e);
1772 // if(t.canActivate && !t.disabled){
1773 // this.setActiveItem(t, true);
1777 this.fireEvent("mouseover", this, e, t);
1779 isVisible : function(){
1780 return !this.hidden;
1782 onMouseOut : function(e){
1783 var t = this.findTargetItem(e);
1786 // if(t == this.activeItem && t.shouldDeactivate(e)){
1787 // this.activeItem.deactivate();
1788 // delete this.activeItem;
1791 this.fireEvent("mouseout", this, e, t);
1796 * Displays this menu relative to another element
1797 * @param {String/HTMLElement/Roo.Element} element The element to align to
1798 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1799 * the element (defaults to this.defaultAlign)
1800 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1802 show : function(el, pos, parentMenu){
1803 this.parentMenu = parentMenu;
1807 this.fireEvent("beforeshow", this);
1808 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1811 * Displays this menu at a specific xy position
1812 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1813 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1815 showAt : function(xy, parentMenu, /* private: */_e){
1816 this.parentMenu = parentMenu;
1821 this.fireEvent("beforeshow", this);
1823 //xy = this.el.adjustForConstraints(xy);
1825 //this.el.setXY(xy);
1827 this.hideMenuItems();
1828 this.hidden = false;
1829 this.triggerEl.addClass('open');
1831 this.fireEvent("show", this);
1837 this.doFocus.defer(50, this);
1841 doFocus : function(){
1843 this.focusEl.focus();
1848 * Hides this menu and optionally all parent menus
1849 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1851 hide : function(deep){
1853 this.hideMenuItems();
1854 if(this.el && this.isVisible()){
1855 this.fireEvent("beforehide", this);
1856 if(this.activeItem){
1857 this.activeItem.deactivate();
1858 this.activeItem = null;
1860 this.triggerEl.removeClass('open');;
1862 this.fireEvent("hide", this);
1864 if(deep === true && this.parentMenu){
1865 this.parentMenu.hide(true);
1869 onTriggerPress : function(e)
1872 Roo.log('trigger press');
1873 //Roo.log(e.getTarget());
1874 // Roo.log(this.triggerEl.dom);
1875 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1878 if (this.isVisible()) {
1882 this.show(this.triggerEl, false, false);
1891 hideMenuItems : function()
1893 //$(backdrop).remove()
1894 Roo.select('.open',true).each(function(aa) {
1896 aa.removeClass('open');
1897 //var parent = getParent($(this))
1898 //var relatedTarget = { relatedTarget: this }
1900 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1901 //if (e.isDefaultPrevented()) return
1902 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1905 addxtypeChild : function (tree, cntr) {
1906 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1908 this.menuitems.add(comp);
1929 * @class Roo.bootstrap.MenuItem
1930 * @extends Roo.bootstrap.Component
1931 * Bootstrap MenuItem class
1932 * @cfg {String} html the menu label
1933 * @cfg {String} href the link
1934 * @cfg {Boolean} preventDefault (true | false) default true
1935 * @cfg {Boolean} isContainer (true | false) default false
1939 * Create a new MenuItem
1940 * @param {Object} config The config object
1944 Roo.bootstrap.MenuItem = function(config){
1945 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1950 * The raw click event for the entire grid.
1951 * @param {Roo.EventObject} e
1957 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1961 preventDefault: true,
1962 isContainer : false,
1964 getAutoCreate : function(){
1966 if(this.isContainer){
1969 cls: 'dropdown-menu-item'
1975 cls: 'dropdown-menu-item',
1984 if (this.parent().type == 'treeview') {
1985 cfg.cls = 'treeview-menu';
1988 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1989 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1993 initEvents: function() {
1995 //this.el.select('a').on('click', this.onClick, this);
1998 onClick : function(e)
2000 Roo.log('item on click ');
2001 //if(this.preventDefault){
2002 // e.preventDefault();
2004 //this.parent().hideMenuItems();
2006 this.fireEvent('click', this, e);
2025 * @class Roo.bootstrap.MenuSeparator
2026 * @extends Roo.bootstrap.Component
2027 * Bootstrap MenuSeparator class
2030 * Create a new MenuItem
2031 * @param {Object} config The config object
2035 Roo.bootstrap.MenuSeparator = function(config){
2036 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2039 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2041 getAutoCreate : function(){
2060 * @class Roo.bootstrap.Modal
2061 * @extends Roo.bootstrap.Component
2062 * Bootstrap Modal class
2063 * @cfg {String} title Title of dialog
2064 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2065 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2066 * @cfg {Boolean} specificTitle default false
2067 * @cfg {Array} buttons Array of buttons or standard button set..
2068 * @cfg {String} buttonPosition (left|right|center) default right
2069 * @cfg {Boolean} animate default true
2070 * @cfg {Boolean} allow_close default true
2073 * Create a new Modal Dialog
2074 * @param {Object} config The config object
2077 Roo.bootstrap.Modal = function(config){
2078 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2083 * The raw btnclick event for the button
2084 * @param {Roo.EventObject} e
2088 this.buttons = this.buttons || [];
2091 this.tmpl = Roo.factory(this.tmpl);
2096 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2098 title : 'test dialog',
2108 specificTitle: false,
2110 buttonPosition: 'right',
2124 onRender : function(ct, position)
2126 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2129 var cfg = Roo.apply({}, this.getAutoCreate());
2132 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2134 //if (!cfg.name.length) {
2138 cfg.cls += ' ' + this.cls;
2141 cfg.style = this.style;
2143 this.el = Roo.get(document.body).createChild(cfg, position);
2145 //var type = this.el.dom.type;
2150 if(this.tabIndex !== undefined){
2151 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2155 this.bodyEl = this.el.select('.modal-body',true).first();
2156 this.closeEl = this.el.select('.modal-header .close', true).first();
2157 this.footerEl = this.el.select('.modal-footer',true).first();
2158 this.titleEl = this.el.select('.modal-title',true).first();
2162 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2163 this.maskEl.enableDisplayMode("block");
2165 //this.el.addClass("x-dlg-modal");
2167 if (this.buttons.length) {
2168 Roo.each(this.buttons, function(bb) {
2169 b = Roo.apply({}, bb);
2170 b.xns = b.xns || Roo.bootstrap;
2171 b.xtype = b.xtype || 'Button';
2172 if (typeof(b.listeners) == 'undefined') {
2173 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2176 var btn = Roo.factory(b);
2178 btn.onRender(this.el.select('.modal-footer div').first());
2182 // render the children.
2185 if(typeof(this.items) != 'undefined'){
2186 var items = this.items;
2189 for(var i =0;i < items.length;i++) {
2190 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2194 this.items = nitems;
2196 // where are these used - they used to be body/close/footer
2200 //this.el.addClass([this.fieldClass, this.cls]);
2203 getAutoCreate : function(){
2208 html : this.html || ''
2213 cls : 'modal-title',
2217 if(this.specificTitle){
2223 if (this.allow_close) {
2234 style : 'display: none',
2237 cls: "modal-dialog",
2240 cls : "modal-content",
2243 cls : 'modal-header',
2248 cls : 'modal-footer',
2252 cls: 'btn-' + this.buttonPosition
2269 modal.cls += ' fade';
2275 getChildContainer : function() {
2280 getButtonContainer : function() {
2281 return this.el.select('.modal-footer div',true).first();
2284 initEvents : function()
2286 if (this.allow_close) {
2287 this.closeEl.on('click', this.hide, this);
2293 if (!this.rendered) {
2297 this.el.setStyle('display', 'block');
2301 (function(){ _this.el.addClass('in'); }).defer(50);
2303 this.el.addClass('in');
2306 // not sure how we can show data in here..
2308 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2311 Roo.get(document.body).addClass("x-body-masked");
2312 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2314 this.el.setStyle('zIndex', '10001');
2316 this.fireEvent('show', this);
2323 Roo.get(document.body).removeClass("x-body-masked");
2324 this.el.removeClass('in');
2328 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2330 this.el.setStyle('display', 'none');
2333 this.fireEvent('hide', this);
2336 addButton : function(str, cb)
2340 var b = Roo.apply({}, { html : str } );
2341 b.xns = b.xns || Roo.bootstrap;
2342 b.xtype = b.xtype || 'Button';
2343 if (typeof(b.listeners) == 'undefined') {
2344 b.listeners = { click : cb.createDelegate(this) };
2347 var btn = Roo.factory(b);
2349 btn.onRender(this.el.select('.modal-footer div').first());
2355 setDefaultButton : function(btn)
2357 //this.el.select('.modal-footer').()
2359 resizeTo: function(w,h)
2363 setContentSize : function(w, h)
2367 onButtonClick: function(btn,e)
2370 this.fireEvent('btnclick', btn.name, e);
2373 * Set the title of the Dialog
2374 * @param {String} str new Title
2376 setTitle: function(str) {
2377 this.titleEl.dom.innerHTML = str;
2380 * Set the body of the Dialog
2381 * @param {String} str new Title
2383 setBody: function(str) {
2384 this.bodyEl.dom.innerHTML = str;
2387 * Set the body of the Dialog using the template
2388 * @param {Obj} data - apply this data to the template and replace the body contents.
2390 applyBody: function(obj)
2393 Roo.log("Error - using apply Body without a template");
2396 this.tmpl.overwrite(this.bodyEl, obj);
2402 Roo.apply(Roo.bootstrap.Modal, {
2404 * Button config that displays a single OK button
2413 * Button config that displays Yes and No buttons
2429 * Button config that displays OK and Cancel buttons
2444 * Button config that displays Yes, No and Cancel buttons
2467 * messagebox - can be used as a replace
2471 * @class Roo.MessageBox
2472 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2476 Roo.Msg.alert('Status', 'Changes saved successfully.');
2478 // Prompt for user data:
2479 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2481 // process text value...
2485 // Show a dialog using config options:
2487 title:'Save Changes?',
2488 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2489 buttons: Roo.Msg.YESNOCANCEL,
2496 Roo.bootstrap.MessageBox = function(){
2497 var dlg, opt, mask, waitTimer;
2498 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2499 var buttons, activeTextEl, bwidth;
2503 var handleButton = function(button){
2505 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2509 var handleHide = function(){
2511 dlg.el.removeClass(opt.cls);
2514 // Roo.TaskMgr.stop(waitTimer);
2515 // waitTimer = null;
2520 var updateButtons = function(b){
2523 buttons["ok"].hide();
2524 buttons["cancel"].hide();
2525 buttons["yes"].hide();
2526 buttons["no"].hide();
2527 //dlg.footer.dom.style.display = 'none';
2530 dlg.footerEl.dom.style.display = '';
2531 for(var k in buttons){
2532 if(typeof buttons[k] != "function"){
2535 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2536 width += buttons[k].el.getWidth()+15;
2546 var handleEsc = function(d, k, e){
2547 if(opt && opt.closable !== false){
2557 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2558 * @return {Roo.BasicDialog} The BasicDialog element
2560 getDialog : function(){
2562 dlg = new Roo.bootstrap.Modal( {
2565 //constraintoviewport:false,
2567 //collapsible : false,
2572 //buttonAlign:"center",
2573 closeClick : function(){
2574 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2577 handleButton("cancel");
2582 dlg.on("hide", handleHide);
2584 //dlg.addKeyListener(27, handleEsc);
2586 this.buttons = buttons;
2587 var bt = this.buttonText;
2588 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2589 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2590 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2591 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2593 bodyEl = dlg.bodyEl.createChild({
2595 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2596 '<textarea class="roo-mb-textarea"></textarea>' +
2597 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2599 msgEl = bodyEl.dom.firstChild;
2600 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2601 textboxEl.enableDisplayMode();
2602 textboxEl.addKeyListener([10,13], function(){
2603 if(dlg.isVisible() && opt && opt.buttons){
2606 }else if(opt.buttons.yes){
2607 handleButton("yes");
2611 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2612 textareaEl.enableDisplayMode();
2613 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2614 progressEl.enableDisplayMode();
2615 var pf = progressEl.dom.firstChild;
2617 pp = Roo.get(pf.firstChild);
2618 pp.setHeight(pf.offsetHeight);
2626 * Updates the message box body text
2627 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2628 * the XHTML-compliant non-breaking space character '&#160;')
2629 * @return {Roo.MessageBox} This message box
2631 updateText : function(text){
2632 if(!dlg.isVisible() && !opt.width){
2633 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2635 msgEl.innerHTML = text || ' ';
2637 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2638 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2640 Math.min(opt.width || cw , this.maxWidth),
2641 Math.max(opt.minWidth || this.minWidth, bwidth)
2644 activeTextEl.setWidth(w);
2646 if(dlg.isVisible()){
2647 dlg.fixedcenter = false;
2649 // to big, make it scroll. = But as usual stupid IE does not support
2652 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2653 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2654 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2656 bodyEl.dom.style.height = '';
2657 bodyEl.dom.style.overflowY = '';
2660 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2662 bodyEl.dom.style.overflowX = '';
2665 dlg.setContentSize(w, bodyEl.getHeight());
2666 if(dlg.isVisible()){
2667 dlg.fixedcenter = true;
2673 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2674 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2675 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2676 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2677 * @return {Roo.MessageBox} This message box
2679 updateProgress : function(value, text){
2681 this.updateText(text);
2683 if (pp) { // weird bug on my firefox - for some reason this is not defined
2684 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2690 * Returns true if the message box is currently displayed
2691 * @return {Boolean} True if the message box is visible, else false
2693 isVisible : function(){
2694 return dlg && dlg.isVisible();
2698 * Hides the message box if it is displayed
2701 if(this.isVisible()){
2707 * Displays a new message box, or reinitializes an existing message box, based on the config options
2708 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2709 * The following config object properties are supported:
2711 Property Type Description
2712 ---------- --------------- ------------------------------------------------------------------------------------
2713 animEl String/Element An id or Element from which the message box should animate as it opens and
2714 closes (defaults to undefined)
2715 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2716 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2717 closable Boolean False to hide the top-right close button (defaults to true). Note that
2718 progress and wait dialogs will ignore this property and always hide the
2719 close button as they can only be closed programmatically.
2720 cls String A custom CSS class to apply to the message box element
2721 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2722 displayed (defaults to 75)
2723 fn Function A callback function to execute after closing the dialog. The arguments to the
2724 function will be btn (the name of the button that was clicked, if applicable,
2725 e.g. "ok"), and text (the value of the active text field, if applicable).
2726 Progress and wait dialogs will ignore this option since they do not respond to
2727 user actions and can only be closed programmatically, so any required function
2728 should be called by the same code after it closes the dialog.
2729 icon String A CSS class that provides a background image to be used as an icon for
2730 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2731 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2732 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2733 modal Boolean False to allow user interaction with the page while the message box is
2734 displayed (defaults to true)
2735 msg String A string that will replace the existing message box body text (defaults
2736 to the XHTML-compliant non-breaking space character ' ')
2737 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2738 progress Boolean True to display a progress bar (defaults to false)
2739 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2740 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2741 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2742 title String The title text
2743 value String The string value to set into the active textbox element if displayed
2744 wait Boolean True to display a progress bar (defaults to false)
2745 width Number The width of the dialog in pixels
2752 msg: 'Please enter your address:',
2754 buttons: Roo.MessageBox.OKCANCEL,
2757 animEl: 'addAddressBtn'
2760 * @param {Object} config Configuration options
2761 * @return {Roo.MessageBox} This message box
2763 show : function(options)
2766 // this causes nightmares if you show one dialog after another
2767 // especially on callbacks..
2769 if(this.isVisible()){
2772 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2773 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2774 Roo.log("New Dialog Message:" + options.msg )
2775 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2776 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2779 var d = this.getDialog();
2781 d.setTitle(opt.title || " ");
2782 d.closeEl.setDisplayed(opt.closable !== false);
2783 activeTextEl = textboxEl;
2784 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2789 textareaEl.setHeight(typeof opt.multiline == "number" ?
2790 opt.multiline : this.defaultTextHeight);
2791 activeTextEl = textareaEl;
2800 progressEl.setDisplayed(opt.progress === true);
2801 this.updateProgress(0);
2802 activeTextEl.dom.value = opt.value || "";
2804 dlg.setDefaultButton(activeTextEl);
2806 var bs = opt.buttons;
2810 }else if(bs && bs.yes){
2811 db = buttons["yes"];
2813 dlg.setDefaultButton(db);
2815 bwidth = updateButtons(opt.buttons);
2816 this.updateText(opt.msg);
2818 d.el.addClass(opt.cls);
2820 d.proxyDrag = opt.proxyDrag === true;
2821 d.modal = opt.modal !== false;
2822 d.mask = opt.modal !== false ? mask : false;
2824 // force it to the end of the z-index stack so it gets a cursor in FF
2825 document.body.appendChild(dlg.el.dom);
2826 d.animateTarget = null;
2827 d.show(options.animEl);
2833 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2834 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2835 * and closing the message box when the process is complete.
2836 * @param {String} title The title bar text
2837 * @param {String} msg The message box body text
2838 * @return {Roo.MessageBox} This message box
2840 progress : function(title, msg){
2847 minWidth: this.minProgressWidth,
2854 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2855 * If a callback function is passed it will be called after the user clicks the button, and the
2856 * id of the button that was clicked will be passed as the only parameter to the callback
2857 * (could also be the top-right close button).
2858 * @param {String} title The title bar text
2859 * @param {String} msg The message box body text
2860 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2861 * @param {Object} scope (optional) The scope of the callback function
2862 * @return {Roo.MessageBox} This message box
2864 alert : function(title, msg, fn, scope){
2877 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2878 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2879 * You are responsible for closing the message box when the process is complete.
2880 * @param {String} msg The message box body text
2881 * @param {String} title (optional) The title bar text
2882 * @return {Roo.MessageBox} This message box
2884 wait : function(msg, title){
2895 waitTimer = Roo.TaskMgr.start({
2897 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2905 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2906 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2907 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2908 * @param {String} title The title bar text
2909 * @param {String} msg The message box body text
2910 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2911 * @param {Object} scope (optional) The scope of the callback function
2912 * @return {Roo.MessageBox} This message box
2914 confirm : function(title, msg, fn, scope){
2918 buttons: this.YESNO,
2927 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2928 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2929 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2930 * (could also be the top-right close button) and the text that was entered will be passed as the two
2931 * parameters to the callback.
2932 * @param {String} title The title bar text
2933 * @param {String} msg The message box body text
2934 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2935 * @param {Object} scope (optional) The scope of the callback function
2936 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2937 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2938 * @return {Roo.MessageBox} This message box
2940 prompt : function(title, msg, fn, scope, multiline){
2944 buttons: this.OKCANCEL,
2949 multiline: multiline,
2956 * Button config that displays a single OK button
2961 * Button config that displays Yes and No buttons
2964 YESNO : {yes:true, no:true},
2966 * Button config that displays OK and Cancel buttons
2969 OKCANCEL : {ok:true, cancel:true},
2971 * Button config that displays Yes, No and Cancel buttons
2974 YESNOCANCEL : {yes:true, no:true, cancel:true},
2977 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2980 defaultTextHeight : 75,
2982 * The maximum width in pixels of the message box (defaults to 600)
2987 * The minimum width in pixels of the message box (defaults to 100)
2992 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2993 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2996 minProgressWidth : 250,
2998 * An object containing the default button text strings that can be overriden for localized language support.
2999 * Supported properties are: ok, cancel, yes and no.
3000 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3013 * Shorthand for {@link Roo.MessageBox}
3015 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3016 Roo.Msg = Roo.Msg || Roo.MessageBox;
3025 * @class Roo.bootstrap.Navbar
3026 * @extends Roo.bootstrap.Component
3027 * Bootstrap Navbar class
3030 * Create a new Navbar
3031 * @param {Object} config The config object
3035 Roo.bootstrap.Navbar = function(config){
3036 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3040 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3049 getAutoCreate : function(){
3052 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3056 initEvents :function ()
3058 //Roo.log(this.el.select('.navbar-toggle',true));
3059 this.el.select('.navbar-toggle',true).on('click', function() {
3060 // Roo.log('click');
3061 this.el.select('.navbar-collapse',true).toggleClass('in');
3069 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3071 var size = this.el.getSize();
3072 this.maskEl.setSize(size.width, size.height);
3073 this.maskEl.enableDisplayMode("block");
3082 getChildContainer : function()
3084 if (this.el.select('.collapse').getCount()) {
3085 return this.el.select('.collapse',true).first();
3118 * @class Roo.bootstrap.NavSimplebar
3119 * @extends Roo.bootstrap.Navbar
3120 * Bootstrap Sidebar class
3122 * @cfg {Boolean} inverse is inverted color
3124 * @cfg {String} type (nav | pills | tabs)
3125 * @cfg {Boolean} arrangement stacked | justified
3126 * @cfg {String} align (left | right) alignment
3128 * @cfg {Boolean} main (true|false) main nav bar? default false
3129 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3131 * @cfg {String} tag (header|footer|nav|div) default is nav
3137 * Create a new Sidebar
3138 * @param {Object} config The config object
3142 Roo.bootstrap.NavSimplebar = function(config){
3143 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3146 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3162 getAutoCreate : function(){
3166 tag : this.tag || 'div',
3179 this.type = this.type || 'nav';
3180 if (['tabs','pills'].indexOf(this.type)!==-1) {
3181 cfg.cn[0].cls += ' nav-' + this.type
3185 if (this.type!=='nav') {
3186 Roo.log('nav type must be nav/tabs/pills')
3188 cfg.cn[0].cls += ' navbar-nav'
3194 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3195 cfg.cn[0].cls += ' nav-' + this.arrangement;
3199 if (this.align === 'right') {
3200 cfg.cn[0].cls += ' navbar-right';
3204 cfg.cls += ' navbar-inverse';
3231 * @class Roo.bootstrap.NavHeaderbar
3232 * @extends Roo.bootstrap.NavSimplebar
3233 * Bootstrap Sidebar class
3235 * @cfg {String} brand what is brand
3236 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3237 * @cfg {String} brand_href href of the brand
3238 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3239 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3240 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3241 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3244 * Create a new Sidebar
3245 * @param {Object} config The config object
3249 Roo.bootstrap.NavHeaderbar = function(config){
3250 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3254 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3261 desktopCenter : false,
3264 getAutoCreate : function(){
3267 tag: this.nav || 'nav',
3274 if (this.desktopCenter) {
3275 cn.push({cls : 'container', cn : []});
3282 cls: 'navbar-header',
3287 cls: 'navbar-toggle',
3288 'data-toggle': 'collapse',
3293 html: 'Toggle navigation'
3315 cls: 'collapse navbar-collapse',
3319 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3321 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3322 cfg.cls += ' navbar-' + this.position;
3324 // tag can override this..
3326 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3329 if (this.brand !== '') {
3332 href: this.brand_href ? this.brand_href : '#',
3333 cls: 'navbar-brand',
3341 cfg.cls += ' main-nav';
3349 getHeaderChildContainer : function()
3351 if (this.el.select('.navbar-header').getCount()) {
3352 return this.el.select('.navbar-header',true).first();
3355 return this.getChildContainer();
3359 initEvents : function()
3361 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3363 if (this.autohide) {
3368 Roo.get(document).on('scroll',function(e) {
3369 var ns = Roo.get(document).getScroll().top;
3370 var os = prevScroll;
3374 ft.removeClass('slideDown');
3375 ft.addClass('slideUp');
3378 ft.removeClass('slideUp');
3379 ft.addClass('slideDown');
3403 * @class Roo.bootstrap.NavSidebar
3404 * @extends Roo.bootstrap.Navbar
3405 * Bootstrap Sidebar class
3408 * Create a new Sidebar
3409 * @param {Object} config The config object
3413 Roo.bootstrap.NavSidebar = function(config){
3414 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3417 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3419 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3421 getAutoCreate : function(){
3426 cls: 'sidebar sidebar-nav'
3448 * @class Roo.bootstrap.NavGroup
3449 * @extends Roo.bootstrap.Component
3450 * Bootstrap NavGroup class
3451 * @cfg {String} align left | right
3452 * @cfg {Boolean} inverse false | true
3453 * @cfg {String} type (nav|pills|tab) default nav
3454 * @cfg {String} navId - reference Id for navbar.
3458 * Create a new nav group
3459 * @param {Object} config The config object
3462 Roo.bootstrap.NavGroup = function(config){
3463 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3466 Roo.bootstrap.NavGroup.register(this);
3470 * Fires when the active item changes
3471 * @param {Roo.bootstrap.NavGroup} this
3472 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3473 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3480 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3491 getAutoCreate : function()
3493 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3500 if (['tabs','pills'].indexOf(this.type)!==-1) {
3501 cfg.cls += ' nav-' + this.type
3503 if (this.type!=='nav') {
3504 Roo.log('nav type must be nav/tabs/pills')
3506 cfg.cls += ' navbar-nav'
3509 if (this.parent().sidebar) {
3512 cls: 'dashboard-menu sidebar-menu'
3518 if (this.form === true) {
3524 if (this.align === 'right') {
3525 cfg.cls += ' navbar-right';
3527 cfg.cls += ' navbar-left';
3531 if (this.align === 'right') {
3532 cfg.cls += ' navbar-right';
3536 cfg.cls += ' navbar-inverse';
3544 * sets the active Navigation item
3545 * @param {Roo.bootstrap.NavItem} the new current navitem
3547 setActiveItem : function(item)
3550 Roo.each(this.navItems, function(v){
3555 v.setActive(false, true);
3562 item.setActive(true, true);
3563 this.fireEvent('changed', this, item, prev);
3568 * gets the active Navigation item
3569 * @return {Roo.bootstrap.NavItem} the current navitem
3571 getActive : function()
3575 Roo.each(this.navItems, function(v){
3586 indexOfNav : function()
3590 Roo.each(this.navItems, function(v,i){
3601 * adds a Navigation item
3602 * @param {Roo.bootstrap.NavItem} the navitem to add
3604 addItem : function(cfg)
3606 var cn = new Roo.bootstrap.NavItem(cfg);
3608 cn.parentId = this.id;
3609 cn.onRender(this.el, null);
3613 * register a Navigation item
3614 * @param {Roo.bootstrap.NavItem} the navitem to add
3616 register : function(item)
3618 this.navItems.push( item);
3619 item.navId = this.navId;
3624 * clear all the Navigation item
3627 clearAll : function()
3630 this.el.dom.innerHTML = '';
3633 getNavItem: function(tabId)
3636 Roo.each(this.navItems, function(e) {
3637 if (e.tabId == tabId) {
3647 setActiveNext : function()
3649 var i = this.indexOfNav(this.getActive());
3650 if (i > this.navItems.length) {
3653 this.setActiveItem(this.navItems[i+1]);
3655 setActivePrev : function()
3657 var i = this.indexOfNav(this.getActive());
3661 this.setActiveItem(this.navItems[i-1]);
3663 clearWasActive : function(except) {
3664 Roo.each(this.navItems, function(e) {
3665 if (e.tabId != except.tabId && e.was_active) {
3666 e.was_active = false;
3673 getWasActive : function ()
3676 Roo.each(this.navItems, function(e) {
3691 Roo.apply(Roo.bootstrap.NavGroup, {
3695 * register a Navigation Group
3696 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3698 register : function(navgrp)
3700 this.groups[navgrp.navId] = navgrp;
3704 * fetch a Navigation Group based on the navigation ID
3705 * @param {string} the navgroup to add
3706 * @returns {Roo.bootstrap.NavGroup} the navgroup
3708 get: function(navId) {
3709 if (typeof(this.groups[navId]) == 'undefined') {
3711 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3713 return this.groups[navId] ;
3728 * @class Roo.bootstrap.NavItem
3729 * @extends Roo.bootstrap.Component
3730 * Bootstrap Navbar.NavItem class
3731 * @cfg {String} href link to
3732 * @cfg {String} html content of button
3733 * @cfg {String} badge text inside badge
3734 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3735 * @cfg {String} glyphicon name of glyphicon
3736 * @cfg {String} icon name of font awesome icon
3737 * @cfg {Boolean} active Is item active
3738 * @cfg {Boolean} disabled Is item disabled
3740 * @cfg {Boolean} preventDefault (true | false) default false
3741 * @cfg {String} tabId the tab that this item activates.
3742 * @cfg {String} tagtype (a|span) render as a href or span?
3745 * Create a new Navbar Item
3746 * @param {Object} config The config object
3748 Roo.bootstrap.NavItem = function(config){
3749 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3754 * The raw click event for the entire grid.
3755 * @param {Roo.EventObject} e
3760 * Fires when the active item active state changes
3761 * @param {Roo.bootstrap.NavItem} this
3762 * @param {boolean} state the new state
3770 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3778 preventDefault : false,
3785 getAutoCreate : function(){
3793 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3795 if (this.disabled) {
3796 cfg.cls += ' disabled';
3799 if (this.href || this.html || this.glyphicon || this.icon) {
3803 href : this.href || "#",
3804 html: this.html || ''
3809 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3812 if(this.glyphicon) {
3813 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3818 cfg.cn[0].html += " <span class='caret'></span>";
3822 if (this.badge !== '') {
3824 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3832 initEvents: function()
3834 if (typeof (this.menu) != 'undefined') {
3835 this.menu.parentType = this.xtype;
3836 this.menu.triggerEl = this.el;
3837 this.menu = this.addxtype(Roo.apply({}, this.menu));
3840 this.el.select('a',true).on('click', this.onClick, this);
3842 if(this.tagtype == 'span'){
3843 this.el.select('span',true).on('click', this.onClick, this);
3846 // at this point parent should be available..
3847 this.parent().register(this);
3850 onClick : function(e)
3852 if(this.preventDefault || this.href == '#'){
3856 if (this.disabled) {
3860 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3861 if (tg && tg.transition) {
3862 Roo.log("waiting for the transitionend");
3866 Roo.log("fire event clicked");
3867 if(this.fireEvent('click', this, e) === false){
3871 if(this.tagtype == 'span'){
3875 var p = this.parent();
3876 if (['tabs','pills'].indexOf(p.type)!==-1) {
3877 if (typeof(p.setActiveItem) !== 'undefined') {
3878 p.setActiveItem(this);
3881 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3882 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3883 // remove the collapsed menu expand...
3884 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3889 isActive: function () {
3892 setActive : function(state, fire, is_was_active)
3894 if (this.active && !state & this.navId) {
3895 this.was_active = true;
3896 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3898 nv.clearWasActive(this);
3902 this.active = state;
3905 this.el.removeClass('active');
3906 } else if (!this.el.hasClass('active')) {
3907 this.el.addClass('active');
3910 this.fireEvent('changed', this, state);
3913 // show a panel if it's registered and related..
3915 if (!this.navId || !this.tabId || !state || is_was_active) {
3919 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3923 var pan = tg.getPanelByName(this.tabId);
3927 // if we can not flip to new panel - go back to old nav highlight..
3928 if (false == tg.showPanel(pan)) {
3929 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3931 var onav = nv.getWasActive();
3933 onav.setActive(true, false, true);
3942 // this should not be here...
3943 setDisabled : function(state)
3945 this.disabled = state;
3947 this.el.removeClass('disabled');
3948 } else if (!this.el.hasClass('disabled')) {
3949 this.el.addClass('disabled');
3955 * Fetch the element to display the tooltip on.
3956 * @return {Roo.Element} defaults to this.el
3958 tooltipEl : function()
3960 return this.el.select('' + this.tagtype + '', true).first();
3971 * <span> icon </span>
3972 * <span> text </span>
3973 * <span>badge </span>
3977 * @class Roo.bootstrap.NavSidebarItem
3978 * @extends Roo.bootstrap.NavItem
3979 * Bootstrap Navbar.NavSidebarItem class
3981 * Create a new Navbar Button
3982 * @param {Object} config The config object
3984 Roo.bootstrap.NavSidebarItem = function(config){
3985 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3990 * The raw click event for the entire grid.
3991 * @param {Roo.EventObject} e
3996 * Fires when the active item active state changes
3997 * @param {Roo.bootstrap.NavSidebarItem} this
3998 * @param {boolean} state the new state
4006 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4009 getAutoCreate : function(){
4014 href : this.href || '#',
4026 html : this.html || ''
4031 cfg.cls += ' active';
4035 if (this.glyphicon || this.icon) {
4036 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4037 a.cn.push({ tag : 'i', cls : c }) ;
4042 if (this.badge !== '') {
4043 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4047 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4048 a.cls += 'dropdown-toggle treeview' ;
4072 * @class Roo.bootstrap.Row
4073 * @extends Roo.bootstrap.Component
4074 * Bootstrap Row class (contains columns...)
4078 * @param {Object} config The config object
4081 Roo.bootstrap.Row = function(config){
4082 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4085 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4087 getAutoCreate : function(){
4106 * @class Roo.bootstrap.Element
4107 * @extends Roo.bootstrap.Component
4108 * Bootstrap Element class
4109 * @cfg {String} html contents of the element
4110 * @cfg {String} tag tag of the element
4111 * @cfg {String} cls class of the element
4114 * Create a new Element
4115 * @param {Object} config The config object
4118 Roo.bootstrap.Element = function(config){
4119 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4122 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4129 getAutoCreate : function(){
4154 * @class Roo.bootstrap.Pagination
4155 * @extends Roo.bootstrap.Component
4156 * Bootstrap Pagination class
4157 * @cfg {String} size xs | sm | md | lg
4158 * @cfg {Boolean} inverse false | true
4161 * Create a new Pagination
4162 * @param {Object} config The config object
4165 Roo.bootstrap.Pagination = function(config){
4166 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4169 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4175 getAutoCreate : function(){
4181 cfg.cls += ' inverse';
4187 cfg.cls += " " + this.cls;
4205 * @class Roo.bootstrap.PaginationItem
4206 * @extends Roo.bootstrap.Component
4207 * Bootstrap PaginationItem class
4208 * @cfg {String} html text
4209 * @cfg {String} href the link
4210 * @cfg {Boolean} preventDefault (true | false) default true
4211 * @cfg {Boolean} active (true | false) default false
4212 * @cfg {Boolean} disabled default false
4216 * Create a new PaginationItem
4217 * @param {Object} config The config object
4221 Roo.bootstrap.PaginationItem = function(config){
4222 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4227 * The raw click event for the entire grid.
4228 * @param {Roo.EventObject} e
4234 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4238 preventDefault: true,
4243 getAutoCreate : function(){
4249 href : this.href ? this.href : '#',
4250 html : this.html ? this.html : ''
4260 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4264 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4270 initEvents: function() {
4272 this.el.on('click', this.onClick, this);
4275 onClick : function(e)
4277 Roo.log('PaginationItem on click ');
4278 if(this.preventDefault){
4286 this.fireEvent('click', this, e);
4302 * @class Roo.bootstrap.Slider
4303 * @extends Roo.bootstrap.Component
4304 * Bootstrap Slider class
4307 * Create a new Slider
4308 * @param {Object} config The config object
4311 Roo.bootstrap.Slider = function(config){
4312 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4315 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4317 getAutoCreate : function(){
4321 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4325 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4337 * Ext JS Library 1.1.1
4338 * Copyright(c) 2006-2007, Ext JS, LLC.
4340 * Originally Released Under LGPL - original licence link has changed is not relivant.
4343 * <script type="text/javascript">
4348 * @class Roo.grid.ColumnModel
4349 * @extends Roo.util.Observable
4350 * This is the default implementation of a ColumnModel used by the Grid. It defines
4351 * the columns in the grid.
4354 var colModel = new Roo.grid.ColumnModel([
4355 {header: "Ticker", width: 60, sortable: true, locked: true},
4356 {header: "Company Name", width: 150, sortable: true},
4357 {header: "Market Cap.", width: 100, sortable: true},
4358 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4359 {header: "Employees", width: 100, sortable: true, resizable: false}
4364 * The config options listed for this class are options which may appear in each
4365 * individual column definition.
4366 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4368 * @param {Object} config An Array of column config objects. See this class's
4369 * config objects for details.
4371 Roo.grid.ColumnModel = function(config){
4373 * The config passed into the constructor
4375 this.config = config;
4378 // if no id, create one
4379 // if the column does not have a dataIndex mapping,
4380 // map it to the order it is in the config
4381 for(var i = 0, len = config.length; i < len; i++){
4383 if(typeof c.dataIndex == "undefined"){
4386 if(typeof c.renderer == "string"){
4387 c.renderer = Roo.util.Format[c.renderer];
4389 if(typeof c.id == "undefined"){
4392 if(c.editor && c.editor.xtype){
4393 c.editor = Roo.factory(c.editor, Roo.grid);
4395 if(c.editor && c.editor.isFormField){
4396 c.editor = new Roo.grid.GridEditor(c.editor);
4398 this.lookup[c.id] = c;
4402 * The width of columns which have no width specified (defaults to 100)
4405 this.defaultWidth = 100;
4408 * Default sortable of columns which have no sortable specified (defaults to false)
4411 this.defaultSortable = false;
4415 * @event widthchange
4416 * Fires when the width of a column changes.
4417 * @param {ColumnModel} this
4418 * @param {Number} columnIndex The column index
4419 * @param {Number} newWidth The new width
4421 "widthchange": true,
4423 * @event headerchange
4424 * Fires when the text of a header changes.
4425 * @param {ColumnModel} this
4426 * @param {Number} columnIndex The column index
4427 * @param {Number} newText The new header text
4429 "headerchange": true,
4431 * @event hiddenchange
4432 * Fires when a column is hidden or "unhidden".
4433 * @param {ColumnModel} this
4434 * @param {Number} columnIndex The column index
4435 * @param {Boolean} hidden true if hidden, false otherwise
4437 "hiddenchange": true,
4439 * @event columnmoved
4440 * Fires when a column is moved.
4441 * @param {ColumnModel} this
4442 * @param {Number} oldIndex
4443 * @param {Number} newIndex
4445 "columnmoved" : true,
4447 * @event columlockchange
4448 * Fires when a column's locked state is changed
4449 * @param {ColumnModel} this
4450 * @param {Number} colIndex
4451 * @param {Boolean} locked true if locked
4453 "columnlockchange" : true
4455 Roo.grid.ColumnModel.superclass.constructor.call(this);
4457 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4459 * @cfg {String} header The header text to display in the Grid view.
4462 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4463 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4464 * specified, the column's index is used as an index into the Record's data Array.
4467 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4468 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4471 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4472 * Defaults to the value of the {@link #defaultSortable} property.
4473 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4476 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4479 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4482 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4485 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4488 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4489 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4490 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4491 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4494 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4497 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4500 * @cfg {String} cursor (Optional)
4503 * @cfg {String} tooltip (Optional)
4506 * Returns the id of the column at the specified index.
4507 * @param {Number} index The column index
4508 * @return {String} the id
4510 getColumnId : function(index){
4511 return this.config[index].id;
4515 * Returns the column for a specified id.
4516 * @param {String} id The column id
4517 * @return {Object} the column
4519 getColumnById : function(id){
4520 return this.lookup[id];
4525 * Returns the column for a specified dataIndex.
4526 * @param {String} dataIndex The column dataIndex
4527 * @return {Object|Boolean} the column or false if not found
4529 getColumnByDataIndex: function(dataIndex){
4530 var index = this.findColumnIndex(dataIndex);
4531 return index > -1 ? this.config[index] : false;
4535 * Returns the index for a specified column id.
4536 * @param {String} id The column id
4537 * @return {Number} the index, or -1 if not found
4539 getIndexById : function(id){
4540 for(var i = 0, len = this.config.length; i < len; i++){
4541 if(this.config[i].id == id){
4549 * Returns the index for a specified column dataIndex.
4550 * @param {String} dataIndex The column dataIndex
4551 * @return {Number} the index, or -1 if not found
4554 findColumnIndex : function(dataIndex){
4555 for(var i = 0, len = this.config.length; i < len; i++){
4556 if(this.config[i].dataIndex == dataIndex){
4564 moveColumn : function(oldIndex, newIndex){
4565 var c = this.config[oldIndex];
4566 this.config.splice(oldIndex, 1);
4567 this.config.splice(newIndex, 0, c);
4568 this.dataMap = null;
4569 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4572 isLocked : function(colIndex){
4573 return this.config[colIndex].locked === true;
4576 setLocked : function(colIndex, value, suppressEvent){
4577 if(this.isLocked(colIndex) == value){
4580 this.config[colIndex].locked = value;
4582 this.fireEvent("columnlockchange", this, colIndex, value);
4586 getTotalLockedWidth : function(){
4588 for(var i = 0; i < this.config.length; i++){
4589 if(this.isLocked(i) && !this.isHidden(i)){
4590 this.totalWidth += this.getColumnWidth(i);
4596 getLockedCount : function(){
4597 for(var i = 0, len = this.config.length; i < len; i++){
4598 if(!this.isLocked(i)){
4605 * Returns the number of columns.
4608 getColumnCount : function(visibleOnly){
4609 if(visibleOnly === true){
4611 for(var i = 0, len = this.config.length; i < len; i++){
4612 if(!this.isHidden(i)){
4618 return this.config.length;
4622 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4623 * @param {Function} fn
4624 * @param {Object} scope (optional)
4625 * @return {Array} result
4627 getColumnsBy : function(fn, scope){
4629 for(var i = 0, len = this.config.length; i < len; i++){
4630 var c = this.config[i];
4631 if(fn.call(scope||this, c, i) === true){
4639 * Returns true if the specified column is sortable.
4640 * @param {Number} col The column index
4643 isSortable : function(col){
4644 if(typeof this.config[col].sortable == "undefined"){
4645 return this.defaultSortable;
4647 return this.config[col].sortable;
4651 * Returns the rendering (formatting) function defined for the column.
4652 * @param {Number} col The column index.
4653 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4655 getRenderer : function(col){
4656 if(!this.config[col].renderer){
4657 return Roo.grid.ColumnModel.defaultRenderer;
4659 return this.config[col].renderer;
4663 * Sets the rendering (formatting) function for a column.
4664 * @param {Number} col The column index
4665 * @param {Function} fn The function to use to process the cell's raw data
4666 * to return HTML markup for the grid view. The render function is called with
4667 * the following parameters:<ul>
4668 * <li>Data value.</li>
4669 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4670 * <li>css A CSS style string to apply to the table cell.</li>
4671 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4672 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4673 * <li>Row index</li>
4674 * <li>Column index</li>
4675 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4677 setRenderer : function(col, fn){
4678 this.config[col].renderer = fn;
4682 * Returns the width for the specified column.
4683 * @param {Number} col The column index
4686 getColumnWidth : function(col){
4687 return this.config[col].width * 1 || this.defaultWidth;
4691 * Sets the width for a column.
4692 * @param {Number} col The column index
4693 * @param {Number} width The new width
4695 setColumnWidth : function(col, width, suppressEvent){
4696 this.config[col].width = width;
4697 this.totalWidth = null;
4699 this.fireEvent("widthchange", this, col, width);
4704 * Returns the total width of all columns.
4705 * @param {Boolean} includeHidden True to include hidden column widths
4708 getTotalWidth : function(includeHidden){
4709 if(!this.totalWidth){
4710 this.totalWidth = 0;
4711 for(var i = 0, len = this.config.length; i < len; i++){
4712 if(includeHidden || !this.isHidden(i)){
4713 this.totalWidth += this.getColumnWidth(i);
4717 return this.totalWidth;
4721 * Returns the header for the specified column.
4722 * @param {Number} col The column index
4725 getColumnHeader : function(col){
4726 return this.config[col].header;
4730 * Sets the header for a column.
4731 * @param {Number} col The column index
4732 * @param {String} header The new header
4734 setColumnHeader : function(col, header){
4735 this.config[col].header = header;
4736 this.fireEvent("headerchange", this, col, header);
4740 * Returns the tooltip for the specified column.
4741 * @param {Number} col The column index
4744 getColumnTooltip : function(col){
4745 return this.config[col].tooltip;
4748 * Sets the tooltip for a column.
4749 * @param {Number} col The column index
4750 * @param {String} tooltip The new tooltip
4752 setColumnTooltip : function(col, tooltip){
4753 this.config[col].tooltip = tooltip;
4757 * Returns the dataIndex for the specified column.
4758 * @param {Number} col The column index
4761 getDataIndex : function(col){
4762 return this.config[col].dataIndex;
4766 * Sets the dataIndex for a column.
4767 * @param {Number} col The column index
4768 * @param {Number} dataIndex The new dataIndex
4770 setDataIndex : function(col, dataIndex){
4771 this.config[col].dataIndex = dataIndex;
4777 * Returns true if the cell is editable.
4778 * @param {Number} colIndex The column index
4779 * @param {Number} rowIndex The row index
4782 isCellEditable : function(colIndex, rowIndex){
4783 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4787 * Returns the editor defined for the cell/column.
4788 * return false or null to disable editing.
4789 * @param {Number} colIndex The column index
4790 * @param {Number} rowIndex The row index
4793 getCellEditor : function(colIndex, rowIndex){
4794 return this.config[colIndex].editor;
4798 * Sets if a column is editable.
4799 * @param {Number} col The column index
4800 * @param {Boolean} editable True if the column is editable
4802 setEditable : function(col, editable){
4803 this.config[col].editable = editable;
4808 * Returns true if the column is hidden.
4809 * @param {Number} colIndex The column index
4812 isHidden : function(colIndex){
4813 return this.config[colIndex].hidden;
4818 * Returns true if the column width cannot be changed
4820 isFixed : function(colIndex){
4821 return this.config[colIndex].fixed;
4825 * Returns true if the column can be resized
4828 isResizable : function(colIndex){
4829 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4832 * Sets if a column is hidden.
4833 * @param {Number} colIndex The column index
4834 * @param {Boolean} hidden True if the column is hidden
4836 setHidden : function(colIndex, hidden){
4837 this.config[colIndex].hidden = hidden;
4838 this.totalWidth = null;
4839 this.fireEvent("hiddenchange", this, colIndex, hidden);
4843 * Sets the editor for a column.
4844 * @param {Number} col The column index
4845 * @param {Object} editor The editor object
4847 setEditor : function(col, editor){
4848 this.config[col].editor = editor;
4852 Roo.grid.ColumnModel.defaultRenderer = function(value){
4853 if(typeof value == "string" && value.length < 1){
4859 // Alias for backwards compatibility
4860 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4863 * Ext JS Library 1.1.1
4864 * Copyright(c) 2006-2007, Ext JS, LLC.
4866 * Originally Released Under LGPL - original licence link has changed is not relivant.
4869 * <script type="text/javascript">
4873 * @class Roo.LoadMask
4874 * A simple utility class for generically masking elements while loading data. If the element being masked has
4875 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4876 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4877 * element's UpdateManager load indicator and will be destroyed after the initial load.
4879 * Create a new LoadMask
4880 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4881 * @param {Object} config The config object
4883 Roo.LoadMask = function(el, config){
4884 this.el = Roo.get(el);
4885 Roo.apply(this, config);
4887 this.store.on('beforeload', this.onBeforeLoad, this);
4888 this.store.on('load', this.onLoad, this);
4889 this.store.on('loadexception', this.onLoadException, this);
4890 this.removeMask = false;
4892 var um = this.el.getUpdateManager();
4893 um.showLoadIndicator = false; // disable the default indicator
4894 um.on('beforeupdate', this.onBeforeLoad, this);
4895 um.on('update', this.onLoad, this);
4896 um.on('failure', this.onLoad, this);
4897 this.removeMask = true;
4901 Roo.LoadMask.prototype = {
4903 * @cfg {Boolean} removeMask
4904 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4905 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4909 * The text to display in a centered loading message box (defaults to 'Loading...')
4913 * @cfg {String} msgCls
4914 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4916 msgCls : 'x-mask-loading',
4919 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4925 * Disables the mask to prevent it from being displayed
4927 disable : function(){
4928 this.disabled = true;
4932 * Enables the mask so that it can be displayed
4934 enable : function(){
4935 this.disabled = false;
4938 onLoadException : function()
4942 if (typeof(arguments[3]) != 'undefined') {
4943 Roo.MessageBox.alert("Error loading",arguments[3]);
4947 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4948 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4957 this.el.unmask(this.removeMask);
4962 this.el.unmask(this.removeMask);
4966 onBeforeLoad : function(){
4968 this.el.mask(this.msg, this.msgCls);
4973 destroy : function(){
4975 this.store.un('beforeload', this.onBeforeLoad, this);
4976 this.store.un('load', this.onLoad, this);
4977 this.store.un('loadexception', this.onLoadException, this);
4979 var um = this.el.getUpdateManager();
4980 um.un('beforeupdate', this.onBeforeLoad, this);
4981 um.un('update', this.onLoad, this);
4982 um.un('failure', this.onLoad, this);
4993 * @class Roo.bootstrap.Table
4994 * @extends Roo.bootstrap.Component
4995 * Bootstrap Table class
4996 * @cfg {String} cls table class
4997 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4998 * @cfg {String} bgcolor Specifies the background color for a table
4999 * @cfg {Number} border Specifies whether the table cells should have borders or not
5000 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5001 * @cfg {Number} cellspacing Specifies the space between cells
5002 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5003 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5004 * @cfg {String} sortable Specifies that the table should be sortable
5005 * @cfg {String} summary Specifies a summary of the content of a table
5006 * @cfg {Number} width Specifies the width of a table
5007 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5009 * @cfg {boolean} striped Should the rows be alternative striped
5010 * @cfg {boolean} bordered Add borders to the table
5011 * @cfg {boolean} hover Add hover highlighting
5012 * @cfg {boolean} condensed Format condensed
5013 * @cfg {boolean} responsive Format condensed
5014 * @cfg {Boolean} loadMask (true|false) default false
5015 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5016 * @cfg {Boolean} thead (true|false) generate thead, default true
5017 * @cfg {Boolean} RowSelection (true|false) default false
5018 * @cfg {Boolean} CellSelection (true|false) default false
5019 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5023 * Create a new Table
5024 * @param {Object} config The config object
5027 Roo.bootstrap.Table = function(config){
5028 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5031 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5032 this.sm = this.selModel;
5033 this.sm.xmodule = this.xmodule || false;
5035 if (this.cm && typeof(this.cm.config) == 'undefined') {
5036 this.colModel = new Roo.grid.ColumnModel(this.cm);
5037 this.cm = this.colModel;
5038 this.cm.xmodule = this.xmodule || false;
5041 this.store= Roo.factory(this.store, Roo.data);
5042 this.ds = this.store;
5043 this.ds.xmodule = this.xmodule || false;
5046 if (this.footer && this.store) {
5047 this.footer.dataSource = this.ds;
5048 this.footer = Roo.factory(this.footer);
5055 * Fires when a cell is clicked
5056 * @param {Roo.bootstrap.Table} this
5057 * @param {Roo.Element} el
5058 * @param {Number} rowIndex
5059 * @param {Number} columnIndex
5060 * @param {Roo.EventObject} e
5064 * @event celldblclick
5065 * Fires when a cell is double clicked
5066 * @param {Roo.bootstrap.Table} this
5067 * @param {Roo.Element} el
5068 * @param {Number} rowIndex
5069 * @param {Number} columnIndex
5070 * @param {Roo.EventObject} e
5072 "celldblclick" : true,
5075 * Fires when a row is clicked
5076 * @param {Roo.bootstrap.Table} this
5077 * @param {Roo.Element} el
5078 * @param {Number} rowIndex
5079 * @param {Roo.EventObject} e
5083 * @event rowdblclick
5084 * Fires when a row is double clicked
5085 * @param {Roo.bootstrap.Table} this
5086 * @param {Roo.Element} el
5087 * @param {Number} rowIndex
5088 * @param {Roo.EventObject} e
5090 "rowdblclick" : true,
5093 * Fires when a mouseover occur
5094 * @param {Roo.bootstrap.Table} this
5095 * @param {Roo.Element} el
5096 * @param {Number} rowIndex
5097 * @param {Number} columnIndex
5098 * @param {Roo.EventObject} e
5103 * Fires when a mouseout occur
5104 * @param {Roo.bootstrap.Table} this
5105 * @param {Roo.Element} el
5106 * @param {Number} rowIndex
5107 * @param {Number} columnIndex
5108 * @param {Roo.EventObject} e
5113 * Fires when a row is rendered, so you can change add a style to it.
5114 * @param {Roo.bootstrap.Table} this
5115 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5119 * @event rowsrendered
5120 * Fires when all the rows have been rendered
5121 * @param {Roo.bootstrap.Table} this
5123 'rowsrendered' : true
5128 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5152 RowSelection : false,
5153 CellSelection : false,
5156 // Roo.Element - the tbody
5159 getAutoCreate : function(){
5160 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5169 cfg.cls += ' table-striped';
5173 cfg.cls += ' table-hover';
5175 if (this.bordered) {
5176 cfg.cls += ' table-bordered';
5178 if (this.condensed) {
5179 cfg.cls += ' table-condensed';
5181 if (this.responsive) {
5182 cfg.cls += ' table-responsive';
5186 cfg.cls+= ' ' +this.cls;
5189 // this lot should be simplifed...
5192 cfg.align=this.align;
5195 cfg.bgcolor=this.bgcolor;
5198 cfg.border=this.border;
5200 if (this.cellpadding) {
5201 cfg.cellpadding=this.cellpadding;
5203 if (this.cellspacing) {
5204 cfg.cellspacing=this.cellspacing;
5207 cfg.frame=this.frame;
5210 cfg.rules=this.rules;
5212 if (this.sortable) {
5213 cfg.sortable=this.sortable;
5216 cfg.summary=this.summary;
5219 cfg.width=this.width;
5222 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5225 if(this.store || this.cm){
5227 cfg.cn.push(this.renderHeader());
5230 cfg.cn.push(this.renderBody());
5233 cfg.cn.push(this.renderFooter());
5236 cfg.cls+= ' TableGrid';
5239 return { cn : [ cfg ] };
5242 initEvents : function()
5244 if(!this.store || !this.cm){
5248 //Roo.log('initEvents with ds!!!!');
5250 this.mainBody = this.el.select('tbody', true).first();
5255 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5256 e.on('click', _this.sort, _this);
5259 this.el.on("click", this.onClick, this);
5260 this.el.on("dblclick", this.onDblClick, this);
5262 // why is this done????? = it breaks dialogs??
5263 //this.parent().el.setStyle('position', 'relative');
5267 this.footer.parentId = this.id;
5268 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5271 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5273 this.store.on('load', this.onLoad, this);
5274 this.store.on('beforeload', this.onBeforeLoad, this);
5275 this.store.on('update', this.onUpdate, this);
5276 this.store.on('add', this.onAdd, this);
5280 onMouseover : function(e, el)
5282 var cell = Roo.get(el);
5288 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5289 cell = cell.findParent('td', false, true);
5292 var row = cell.findParent('tr', false, true);
5293 var cellIndex = cell.dom.cellIndex;
5294 var rowIndex = row.dom.rowIndex - 1; // start from 0
5296 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5300 onMouseout : function(e, el)
5302 var cell = Roo.get(el);
5308 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5309 cell = cell.findParent('td', false, true);
5312 var row = cell.findParent('tr', false, true);
5313 var cellIndex = cell.dom.cellIndex;
5314 var rowIndex = row.dom.rowIndex - 1; // start from 0
5316 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5320 onClick : function(e, el)
5322 var cell = Roo.get(el);
5324 if(!cell || (!this.CellSelection && !this.RowSelection)){
5328 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5329 cell = cell.findParent('td', false, true);
5332 if(!cell || typeof(cell) == 'undefined'){
5336 var row = cell.findParent('tr', false, true);
5338 if(!row || typeof(row) == 'undefined'){
5342 var cellIndex = cell.dom.cellIndex;
5343 var rowIndex = this.getRowIndex(row);
5345 if(this.CellSelection){
5346 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5349 if(this.RowSelection){
5350 this.fireEvent('rowclick', this, row, rowIndex, e);
5356 onDblClick : function(e,el)
5358 var cell = Roo.get(el);
5360 if(!cell || (!this.CellSelection && !this.RowSelection)){
5364 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5365 cell = cell.findParent('td', false, true);
5368 if(!cell || typeof(cell) == 'undefined'){
5372 var row = cell.findParent('tr', false, true);
5374 if(!row || typeof(row) == 'undefined'){
5378 var cellIndex = cell.dom.cellIndex;
5379 var rowIndex = this.getRowIndex(row);
5381 if(this.CellSelection){
5382 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5385 if(this.RowSelection){
5386 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5390 sort : function(e,el)
5392 var col = Roo.get(el);
5394 if(!col.hasClass('sortable')){
5398 var sort = col.attr('sort');
5401 if(col.hasClass('glyphicon-arrow-up')){
5405 this.store.sortInfo = {field : sort, direction : dir};
5408 Roo.log("calling footer first");
5409 this.footer.onClick('first');
5412 this.store.load({ params : { start : 0 } });
5416 renderHeader : function()
5425 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5427 var config = cm.config[i];
5432 html: cm.getColumnHeader(i)
5435 if(typeof(config.tooltip) != 'undefined'){
5436 c.tooltip = config.tooltip;
5439 if(typeof(config.hidden) != 'undefined' && config.hidden){
5440 c.style += ' display:none;';
5443 if(typeof(config.dataIndex) != 'undefined'){
5444 c.sort = config.dataIndex;
5447 if(typeof(config.sortable) != 'undefined' && config.sortable){
5451 if(typeof(config.align) != 'undefined' && config.align.length){
5452 c.style += ' text-align:' + config.align + ';';
5455 if(typeof(config.width) != 'undefined'){
5456 c.style += ' width:' + config.width + 'px;';
5465 renderBody : function()
5475 colspan : this.cm.getColumnCount()
5485 renderFooter : function()
5495 colspan : this.cm.getColumnCount()
5509 Roo.log('ds onload');
5514 var ds = this.store;
5516 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5517 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5519 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5520 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5523 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5524 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5528 var tbody = this.mainBody;
5530 if(ds.getCount() > 0){
5531 ds.data.each(function(d,rowIndex){
5532 var row = this.renderRow(cm, ds, rowIndex);
5534 tbody.createChild(row);
5538 if(row.cellObjects.length){
5539 Roo.each(row.cellObjects, function(r){
5540 _this.renderCellObject(r);
5547 Roo.each(this.el.select('tbody td', true).elements, function(e){
5548 e.on('mouseover', _this.onMouseover, _this);
5551 Roo.each(this.el.select('tbody td', true).elements, function(e){
5552 e.on('mouseout', _this.onMouseout, _this);
5554 this.fireEvent('rowsrendered', this);
5555 //if(this.loadMask){
5556 // this.maskEl.hide();
5561 onUpdate : function(ds,record)
5563 this.refreshRow(record);
5566 onRemove : function(ds, record, index, isUpdate){
5567 if(isUpdate !== true){
5568 this.fireEvent("beforerowremoved", this, index, record);
5570 var bt = this.mainBody.dom;
5572 var rows = this.el.select('tbody > tr', true).elements;
5574 if(typeof(rows[index]) != 'undefined'){
5575 bt.removeChild(rows[index].dom);
5578 // if(bt.rows[index]){
5579 // bt.removeChild(bt.rows[index]);
5582 if(isUpdate !== true){
5583 //this.stripeRows(index);
5584 //this.syncRowHeights(index, index);
5586 this.fireEvent("rowremoved", this, index, record);
5590 onAdd : function(ds, records, rowIndex)
5592 //Roo.log('on Add called');
5593 // - note this does not handle multiple adding very well..
5594 var bt = this.mainBody.dom;
5595 for (var i =0 ; i < records.length;i++) {
5596 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5597 //Roo.log(records[i]);
5598 //Roo.log(this.store.getAt(rowIndex+i));
5599 this.insertRow(this.store, rowIndex + i, false);
5606 refreshRow : function(record){
5607 var ds = this.store, index;
5608 if(typeof record == 'number'){
5610 record = ds.getAt(index);
5612 index = ds.indexOf(record);
5614 this.insertRow(ds, index, true);
5615 this.onRemove(ds, record, index+1, true);
5616 //this.syncRowHeights(index, index);
5618 this.fireEvent("rowupdated", this, index, record);
5621 insertRow : function(dm, rowIndex, isUpdate){
5624 this.fireEvent("beforerowsinserted", this, rowIndex);
5626 //var s = this.getScrollState();
5627 var row = this.renderRow(this.cm, this.store, rowIndex);
5628 // insert before rowIndex..
5629 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5633 if(row.cellObjects.length){
5634 Roo.each(row.cellObjects, function(r){
5635 _this.renderCellObject(r);
5640 this.fireEvent("rowsinserted", this, rowIndex);
5641 //this.syncRowHeights(firstRow, lastRow);
5642 //this.stripeRows(firstRow);
5649 getRowDom : function(rowIndex)
5651 var rows = this.el.select('tbody > tr', true).elements;
5653 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5656 // returns the object tree for a tr..
5659 renderRow : function(cm, ds, rowIndex)
5662 var d = ds.getAt(rowIndex);
5669 var cellObjects = [];
5671 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5672 var config = cm.config[i];
5674 var renderer = cm.getRenderer(i);
5678 if(typeof(renderer) !== 'undefined'){
5679 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5681 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5682 // and are rendered into the cells after the row is rendered - using the id for the element.
5684 if(typeof(value) === 'object'){
5694 rowIndex : rowIndex,
5699 this.fireEvent('rowclass', this, rowcfg);
5703 cls : rowcfg.rowClass,
5705 html: (typeof(value) === 'object') ? '' : value
5712 if(typeof(config.hidden) != 'undefined' && config.hidden){
5713 td.style += ' display:none;';
5716 if(typeof(config.align) != 'undefined' && config.align.length){
5717 td.style += ' text-align:' + config.align + ';';
5720 if(typeof(config.width) != 'undefined'){
5721 td.style += ' width:' + config.width + 'px;';
5724 if(typeof(config.cursor) != 'undefined'){
5725 td.style += ' cursor:' + config.cursor + ';';
5732 row.cellObjects = cellObjects;
5740 onBeforeLoad : function()
5742 //Roo.log('ds onBeforeLoad');
5746 //if(this.loadMask){
5747 // this.maskEl.show();
5755 this.el.select('tbody', true).first().dom.innerHTML = '';
5758 * Show or hide a row.
5759 * @param {Number} rowIndex to show or hide
5760 * @param {Boolean} state hide
5762 setRowVisibility : function(rowIndex, state)
5764 var bt = this.mainBody.dom;
5766 var rows = this.el.select('tbody > tr', true).elements;
5768 if(typeof(rows[rowIndex]) == 'undefined'){
5771 rows[rowIndex].dom.style.display = state ? '' : 'none';
5775 getSelectionModel : function(){
5777 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5779 return this.selModel;
5782 * Render the Roo.bootstrap object from renderder
5784 renderCellObject : function(r)
5788 var t = r.cfg.render(r.container);
5791 Roo.each(r.cfg.cn, function(c){
5793 container: t.getChildContainer(),
5796 _this.renderCellObject(child);
5801 getRowIndex : function(row)
5805 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5828 * @class Roo.bootstrap.TableCell
5829 * @extends Roo.bootstrap.Component
5830 * Bootstrap TableCell class
5831 * @cfg {String} html cell contain text
5832 * @cfg {String} cls cell class
5833 * @cfg {String} tag cell tag (td|th) default td
5834 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5835 * @cfg {String} align Aligns the content in a cell
5836 * @cfg {String} axis Categorizes cells
5837 * @cfg {String} bgcolor Specifies the background color of a cell
5838 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5839 * @cfg {Number} colspan Specifies the number of columns a cell should span
5840 * @cfg {String} headers Specifies one or more header cells a cell is related to
5841 * @cfg {Number} height Sets the height of a cell
5842 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5843 * @cfg {Number} rowspan Sets the number of rows a cell should span
5844 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5845 * @cfg {String} valign Vertical aligns the content in a cell
5846 * @cfg {Number} width Specifies the width of a cell
5849 * Create a new TableCell
5850 * @param {Object} config The config object
5853 Roo.bootstrap.TableCell = function(config){
5854 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5857 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5877 getAutoCreate : function(){
5878 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5898 cfg.align=this.align
5904 cfg.bgcolor=this.bgcolor
5907 cfg.charoff=this.charoff
5910 cfg.colspan=this.colspan
5913 cfg.headers=this.headers
5916 cfg.height=this.height
5919 cfg.nowrap=this.nowrap
5922 cfg.rowspan=this.rowspan
5925 cfg.scope=this.scope
5928 cfg.valign=this.valign
5931 cfg.width=this.width
5950 * @class Roo.bootstrap.TableRow
5951 * @extends Roo.bootstrap.Component
5952 * Bootstrap TableRow class
5953 * @cfg {String} cls row class
5954 * @cfg {String} align Aligns the content in a table row
5955 * @cfg {String} bgcolor Specifies a background color for a table row
5956 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5957 * @cfg {String} valign Vertical aligns the content in a table row
5960 * Create a new TableRow
5961 * @param {Object} config The config object
5964 Roo.bootstrap.TableRow = function(config){
5965 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5968 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5976 getAutoCreate : function(){
5977 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5987 cfg.align = this.align;
5990 cfg.bgcolor = this.bgcolor;
5993 cfg.charoff = this.charoff;
5996 cfg.valign = this.valign;
6014 * @class Roo.bootstrap.TableBody
6015 * @extends Roo.bootstrap.Component
6016 * Bootstrap TableBody class
6017 * @cfg {String} cls element class
6018 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6019 * @cfg {String} align Aligns the content inside the element
6020 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6021 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6024 * Create a new TableBody
6025 * @param {Object} config The config object
6028 Roo.bootstrap.TableBody = function(config){
6029 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6032 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6040 getAutoCreate : function(){
6041 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6055 cfg.align = this.align;
6058 cfg.charoff = this.charoff;
6061 cfg.valign = this.valign;
6068 // initEvents : function()
6075 // this.store = Roo.factory(this.store, Roo.data);
6076 // this.store.on('load', this.onLoad, this);
6078 // this.store.load();
6082 // onLoad: function ()
6084 // this.fireEvent('load', this);
6094 * Ext JS Library 1.1.1
6095 * Copyright(c) 2006-2007, Ext JS, LLC.
6097 * Originally Released Under LGPL - original licence link has changed is not relivant.
6100 * <script type="text/javascript">
6103 // as we use this in bootstrap.
6104 Roo.namespace('Roo.form');
6106 * @class Roo.form.Action
6107 * Internal Class used to handle form actions
6109 * @param {Roo.form.BasicForm} el The form element or its id
6110 * @param {Object} config Configuration options
6115 // define the action interface
6116 Roo.form.Action = function(form, options){
6118 this.options = options || {};
6121 * Client Validation Failed
6124 Roo.form.Action.CLIENT_INVALID = 'client';
6126 * Server Validation Failed
6129 Roo.form.Action.SERVER_INVALID = 'server';
6131 * Connect to Server Failed
6134 Roo.form.Action.CONNECT_FAILURE = 'connect';
6136 * Reading Data from Server Failed
6139 Roo.form.Action.LOAD_FAILURE = 'load';
6141 Roo.form.Action.prototype = {
6143 failureType : undefined,
6144 response : undefined,
6148 run : function(options){
6153 success : function(response){
6158 handleResponse : function(response){
6162 // default connection failure
6163 failure : function(response){
6165 this.response = response;
6166 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6167 this.form.afterAction(this, false);
6170 processResponse : function(response){
6171 this.response = response;
6172 if(!response.responseText){
6175 this.result = this.handleResponse(response);
6179 // utility functions used internally
6180 getUrl : function(appendParams){
6181 var url = this.options.url || this.form.url || this.form.el.dom.action;
6183 var p = this.getParams();
6185 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6191 getMethod : function(){
6192 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6195 getParams : function(){
6196 var bp = this.form.baseParams;
6197 var p = this.options.params;
6199 if(typeof p == "object"){
6200 p = Roo.urlEncode(Roo.applyIf(p, bp));
6201 }else if(typeof p == 'string' && bp){
6202 p += '&' + Roo.urlEncode(bp);
6205 p = Roo.urlEncode(bp);
6210 createCallback : function(){
6212 success: this.success,
6213 failure: this.failure,
6215 timeout: (this.form.timeout*1000),
6216 upload: this.form.fileUpload ? this.success : undefined
6221 Roo.form.Action.Submit = function(form, options){
6222 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6225 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6228 haveProgress : false,
6229 uploadComplete : false,
6231 // uploadProgress indicator.
6232 uploadProgress : function()
6234 if (!this.form.progressUrl) {
6238 if (!this.haveProgress) {
6239 Roo.MessageBox.progress("Uploading", "Uploading");
6241 if (this.uploadComplete) {
6242 Roo.MessageBox.hide();
6246 this.haveProgress = true;
6248 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6250 var c = new Roo.data.Connection();
6252 url : this.form.progressUrl,
6257 success : function(req){
6258 //console.log(data);
6262 rdata = Roo.decode(req.responseText)
6264 Roo.log("Invalid data from server..");
6268 if (!rdata || !rdata.success) {
6270 Roo.MessageBox.alert(Roo.encode(rdata));
6273 var data = rdata.data;
6275 if (this.uploadComplete) {
6276 Roo.MessageBox.hide();
6281 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6282 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6285 this.uploadProgress.defer(2000,this);
6288 failure: function(data) {
6289 Roo.log('progress url failed ');
6300 // run get Values on the form, so it syncs any secondary forms.
6301 this.form.getValues();
6303 var o = this.options;
6304 var method = this.getMethod();
6305 var isPost = method == 'POST';
6306 if(o.clientValidation === false || this.form.isValid()){
6308 if (this.form.progressUrl) {
6309 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6310 (new Date() * 1) + '' + Math.random());
6315 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6316 form:this.form.el.dom,
6317 url:this.getUrl(!isPost),
6319 params:isPost ? this.getParams() : null,
6320 isUpload: this.form.fileUpload
6323 this.uploadProgress();
6325 }else if (o.clientValidation !== false){ // client validation failed
6326 this.failureType = Roo.form.Action.CLIENT_INVALID;
6327 this.form.afterAction(this, false);
6331 success : function(response)
6333 this.uploadComplete= true;
6334 if (this.haveProgress) {
6335 Roo.MessageBox.hide();
6339 var result = this.processResponse(response);
6340 if(result === true || result.success){
6341 this.form.afterAction(this, true);
6345 this.form.markInvalid(result.errors);
6346 this.failureType = Roo.form.Action.SERVER_INVALID;
6348 this.form.afterAction(this, false);
6350 failure : function(response)
6352 this.uploadComplete= true;
6353 if (this.haveProgress) {
6354 Roo.MessageBox.hide();
6357 this.response = response;
6358 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6359 this.form.afterAction(this, false);
6362 handleResponse : function(response){
6363 if(this.form.errorReader){
6364 var rs = this.form.errorReader.read(response);
6367 for(var i = 0, len = rs.records.length; i < len; i++) {
6368 var r = rs.records[i];
6372 if(errors.length < 1){
6376 success : rs.success,
6382 ret = Roo.decode(response.responseText);
6386 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6396 Roo.form.Action.Load = function(form, options){
6397 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6398 this.reader = this.form.reader;
6401 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6406 Roo.Ajax.request(Roo.apply(
6407 this.createCallback(), {
6408 method:this.getMethod(),
6409 url:this.getUrl(false),
6410 params:this.getParams()
6414 success : function(response){
6416 var result = this.processResponse(response);
6417 if(result === true || !result.success || !result.data){
6418 this.failureType = Roo.form.Action.LOAD_FAILURE;
6419 this.form.afterAction(this, false);
6422 this.form.clearInvalid();
6423 this.form.setValues(result.data);
6424 this.form.afterAction(this, true);
6427 handleResponse : function(response){
6428 if(this.form.reader){
6429 var rs = this.form.reader.read(response);
6430 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6432 success : rs.success,
6436 return Roo.decode(response.responseText);
6440 Roo.form.Action.ACTION_TYPES = {
6441 'load' : Roo.form.Action.Load,
6442 'submit' : Roo.form.Action.Submit
6451 * @class Roo.bootstrap.Form
6452 * @extends Roo.bootstrap.Component
6453 * Bootstrap Form class
6454 * @cfg {String} method GET | POST (default POST)
6455 * @cfg {String} labelAlign top | left (default top)
6456 * @cfg {String} align left | right - for navbars
6457 * @cfg {Boolean} loadMask load mask when submit (default true)
6462 * @param {Object} config The config object
6466 Roo.bootstrap.Form = function(config){
6467 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6470 * @event clientvalidation
6471 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6472 * @param {Form} this
6473 * @param {Boolean} valid true if the form has passed client-side validation
6475 clientvalidation: true,
6477 * @event beforeaction
6478 * Fires before any action is performed. Return false to cancel the action.
6479 * @param {Form} this
6480 * @param {Action} action The action to be performed
6484 * @event actionfailed
6485 * Fires when an action fails.
6486 * @param {Form} this
6487 * @param {Action} action The action that failed
6489 actionfailed : true,
6491 * @event actioncomplete
6492 * Fires when an action is completed.
6493 * @param {Form} this
6494 * @param {Action} action The action that completed
6496 actioncomplete : true
6501 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6504 * @cfg {String} method
6505 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6510 * The URL to use for form actions if one isn't supplied in the action options.
6513 * @cfg {Boolean} fileUpload
6514 * Set to true if this form is a file upload.
6518 * @cfg {Object} baseParams
6519 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6523 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6527 * @cfg {Sting} align (left|right) for navbar forms
6532 activeAction : null,
6535 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6536 * element by passing it or its id or mask the form itself by passing in true.
6539 waitMsgTarget : false,
6543 getAutoCreate : function(){
6547 method : this.method || 'POST',
6548 id : this.id || Roo.id(),
6551 if (this.parent().xtype.match(/^Nav/)) {
6552 cfg.cls = 'navbar-form navbar-' + this.align;
6556 if (this.labelAlign == 'left' ) {
6557 cfg.cls += ' form-horizontal';
6563 initEvents : function()
6565 this.el.on('submit', this.onSubmit, this);
6566 // this was added as random key presses on the form where triggering form submit.
6567 this.el.on('keypress', function(e) {
6568 if (e.getCharCode() != 13) {
6571 // we might need to allow it for textareas.. and some other items.
6572 // check e.getTarget().
6574 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6578 Roo.log("keypress blocked");
6586 onSubmit : function(e){
6591 * Returns true if client-side validation on the form is successful.
6594 isValid : function(){
6595 var items = this.getItems();
6597 items.each(function(f){
6606 * Returns true if any fields in this form have changed since their original load.
6609 isDirty : function(){
6611 var items = this.getItems();
6612 items.each(function(f){
6622 * Performs a predefined action (submit or load) or custom actions you define on this form.
6623 * @param {String} actionName The name of the action type
6624 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6625 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6626 * accept other config options):
6628 Property Type Description
6629 ---------------- --------------- ----------------------------------------------------------------------------------
6630 url String The url for the action (defaults to the form's url)
6631 method String The form method to use (defaults to the form's method, or POST if not defined)
6632 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6633 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6634 validate the form on the client (defaults to false)
6636 * @return {BasicForm} this
6638 doAction : function(action, options){
6639 if(typeof action == 'string'){
6640 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6642 if(this.fireEvent('beforeaction', this, action) !== false){
6643 this.beforeAction(action);
6644 action.run.defer(100, action);
6650 beforeAction : function(action){
6651 var o = action.options;
6654 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6656 // not really supported yet.. ??
6658 //if(this.waitMsgTarget === true){
6659 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6660 //}else if(this.waitMsgTarget){
6661 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6662 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6664 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6670 afterAction : function(action, success){
6671 this.activeAction = null;
6672 var o = action.options;
6674 //if(this.waitMsgTarget === true){
6676 //}else if(this.waitMsgTarget){
6677 // this.waitMsgTarget.unmask();
6679 // Roo.MessageBox.updateProgress(1);
6680 // Roo.MessageBox.hide();
6687 Roo.callback(o.success, o.scope, [this, action]);
6688 this.fireEvent('actioncomplete', this, action);
6692 // failure condition..
6693 // we have a scenario where updates need confirming.
6694 // eg. if a locking scenario exists..
6695 // we look for { errors : { needs_confirm : true }} in the response.
6697 (typeof(action.result) != 'undefined') &&
6698 (typeof(action.result.errors) != 'undefined') &&
6699 (typeof(action.result.errors.needs_confirm) != 'undefined')
6702 Roo.log("not supported yet");
6705 Roo.MessageBox.confirm(
6706 "Change requires confirmation",
6707 action.result.errorMsg,
6712 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6722 Roo.callback(o.failure, o.scope, [this, action]);
6723 // show an error message if no failed handler is set..
6724 if (!this.hasListener('actionfailed')) {
6725 Roo.log("need to add dialog support");
6727 Roo.MessageBox.alert("Error",
6728 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6729 action.result.errorMsg :
6730 "Saving Failed, please check your entries or try again"
6735 this.fireEvent('actionfailed', this, action);
6740 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6741 * @param {String} id The value to search for
6744 findField : function(id){
6745 var items = this.getItems();
6746 var field = items.get(id);
6748 items.each(function(f){
6749 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6756 return field || null;
6759 * Mark fields in this form invalid in bulk.
6760 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6761 * @return {BasicForm} this
6763 markInvalid : function(errors){
6764 if(errors instanceof Array){
6765 for(var i = 0, len = errors.length; i < len; i++){
6766 var fieldError = errors[i];
6767 var f = this.findField(fieldError.id);
6769 f.markInvalid(fieldError.msg);
6775 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6776 field.markInvalid(errors[id]);
6780 //Roo.each(this.childForms || [], function (f) {
6781 // f.markInvalid(errors);
6788 * Set values for fields in this form in bulk.
6789 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6790 * @return {BasicForm} this
6792 setValues : function(values){
6793 if(values instanceof Array){ // array of objects
6794 for(var i = 0, len = values.length; i < len; i++){
6796 var f = this.findField(v.id);
6798 f.setValue(v.value);
6799 if(this.trackResetOnLoad){
6800 f.originalValue = f.getValue();
6804 }else{ // object hash
6807 if(typeof values[id] != 'function' && (field = this.findField(id))){
6809 if (field.setFromData &&
6811 field.displayField &&
6812 // combos' with local stores can
6813 // be queried via setValue()
6814 // to set their value..
6815 (field.store && !field.store.isLocal)
6819 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6820 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6821 field.setFromData(sd);
6824 field.setValue(values[id]);
6828 if(this.trackResetOnLoad){
6829 field.originalValue = field.getValue();
6835 //Roo.each(this.childForms || [], function (f) {
6836 // f.setValues(values);
6843 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6844 * they are returned as an array.
6845 * @param {Boolean} asString
6848 getValues : function(asString){
6849 //if (this.childForms) {
6850 // copy values from the child forms
6851 // Roo.each(this.childForms, function (f) {
6852 // this.setValues(f.getValues());
6858 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6859 if(asString === true){
6862 return Roo.urlDecode(fs);
6866 * Returns the fields in this form as an object with key/value pairs.
6867 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6870 getFieldValues : function(with_hidden)
6872 var items = this.getItems();
6874 items.each(function(f){
6878 var v = f.getValue();
6879 if (f.inputType =='radio') {
6880 if (typeof(ret[f.getName()]) == 'undefined') {
6881 ret[f.getName()] = ''; // empty..
6884 if (!f.el.dom.checked) {
6892 // not sure if this supported any more..
6893 if ((typeof(v) == 'object') && f.getRawValue) {
6894 v = f.getRawValue() ; // dates..
6896 // combo boxes where name != hiddenName...
6897 if (f.name != f.getName()) {
6898 ret[f.name] = f.getRawValue();
6900 ret[f.getName()] = v;
6907 * Clears all invalid messages in this form.
6908 * @return {BasicForm} this
6910 clearInvalid : function(){
6911 var items = this.getItems();
6913 items.each(function(f){
6924 * @return {BasicForm} this
6927 var items = this.getItems();
6928 items.each(function(f){
6932 Roo.each(this.childForms || [], function (f) {
6939 getItems : function()
6941 var r=new Roo.util.MixedCollection(false, function(o){
6942 return o.id || (o.id = Roo.id());
6944 var iter = function(el) {
6951 Roo.each(el.items,function(e) {
6971 * Ext JS Library 1.1.1
6972 * Copyright(c) 2006-2007, Ext JS, LLC.
6974 * Originally Released Under LGPL - original licence link has changed is not relivant.
6977 * <script type="text/javascript">
6980 * @class Roo.form.VTypes
6981 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6984 Roo.form.VTypes = function(){
6985 // closure these in so they are only created once.
6986 var alpha = /^[a-zA-Z_]+$/;
6987 var alphanum = /^[a-zA-Z0-9_]+$/;
6988 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6989 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6991 // All these messages and functions are configurable
6994 * The function used to validate email addresses
6995 * @param {String} value The email address
6997 'email' : function(v){
6998 return email.test(v);
7001 * The error text to display when the email validation function returns false
7004 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7006 * The keystroke filter mask to be applied on email input
7009 'emailMask' : /[a-z0-9_\.\-@]/i,
7012 * The function used to validate URLs
7013 * @param {String} value The URL
7015 'url' : function(v){
7019 * The error text to display when the url validation function returns false
7022 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7025 * The function used to validate alpha values
7026 * @param {String} value The value
7028 'alpha' : function(v){
7029 return alpha.test(v);
7032 * The error text to display when the alpha validation function returns false
7035 'alphaText' : 'This field should only contain letters and _',
7037 * The keystroke filter mask to be applied on alpha input
7040 'alphaMask' : /[a-z_]/i,
7043 * The function used to validate alphanumeric values
7044 * @param {String} value The value
7046 'alphanum' : function(v){
7047 return alphanum.test(v);
7050 * The error text to display when the alphanumeric validation function returns false
7053 'alphanumText' : 'This field should only contain letters, numbers and _',
7055 * The keystroke filter mask to be applied on alphanumeric input
7058 'alphanumMask' : /[a-z0-9_]/i
7068 * @class Roo.bootstrap.Input
7069 * @extends Roo.bootstrap.Component
7070 * Bootstrap Input class
7071 * @cfg {Boolean} disabled is it disabled
7072 * @cfg {String} fieldLabel - the label associated
7073 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7074 * @cfg {String} name name of the input
7075 * @cfg {string} fieldLabel - the label associated
7076 * @cfg {string} inputType - input / file submit ...
7077 * @cfg {string} placeholder - placeholder to put in text.
7078 * @cfg {string} before - input group add on before
7079 * @cfg {string} after - input group add on after
7080 * @cfg {string} size - (lg|sm) or leave empty..
7081 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7082 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7083 * @cfg {Number} md colspan out of 12 for computer-sized screens
7084 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7085 * @cfg {string} value default value of the input
7086 * @cfg {Number} labelWidth set the width of label (0-12)
7087 * @cfg {String} labelAlign (top|left)
7088 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7089 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7091 * @cfg {String} align (left|center|right) Default left
7096 * Create a new Input
7097 * @param {Object} config The config object
7100 Roo.bootstrap.Input = function(config){
7101 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7106 * Fires when this field receives input focus.
7107 * @param {Roo.form.Field} this
7112 * Fires when this field loses input focus.
7113 * @param {Roo.form.Field} this
7118 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7119 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7120 * @param {Roo.form.Field} this
7121 * @param {Roo.EventObject} e The event object
7126 * Fires just before the field blurs if the field value has changed.
7127 * @param {Roo.form.Field} this
7128 * @param {Mixed} newValue The new value
7129 * @param {Mixed} oldValue The original value
7134 * Fires after the field has been marked as invalid.
7135 * @param {Roo.form.Field} this
7136 * @param {String} msg The validation message
7141 * Fires after the field has been validated with no errors.
7142 * @param {Roo.form.Field} this
7147 * Fires after the key up
7148 * @param {Roo.form.Field} this
7149 * @param {Roo.EventObject} e The event Object
7155 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7157 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7158 automatic validation (defaults to "keyup").
7160 validationEvent : "keyup",
7162 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7164 validateOnBlur : true,
7166 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7168 validationDelay : 250,
7170 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7172 focusClass : "x-form-focus", // not needed???
7176 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7178 invalidClass : "has-warning",
7181 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7183 validClass : "has-success",
7186 * @cfg {Boolean} hasFeedback (true|false) default true
7191 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7193 invalidFeedbackClass : "glyphicon-warning-sign",
7196 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7198 validFeedbackClass : "glyphicon-ok",
7201 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7203 selectOnFocus : false,
7206 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7210 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7215 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7217 disableKeyFilter : false,
7220 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7224 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7228 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7230 blankText : "This field is required",
7233 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7237 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7239 maxLength : Number.MAX_VALUE,
7241 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7243 minLengthText : "The minimum length for this field is {0}",
7245 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7247 maxLengthText : "The maximum length for this field is {0}",
7251 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7252 * If available, this function will be called only after the basic validators all return true, and will be passed the
7253 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7257 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7258 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7259 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7263 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7267 autocomplete: false,
7286 formatedValue : false,
7288 parentLabelAlign : function()
7291 while (parent.parent()) {
7292 parent = parent.parent();
7293 if (typeof(parent.labelAlign) !='undefined') {
7294 return parent.labelAlign;
7301 getAutoCreate : function(){
7303 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7309 if(this.inputType != 'hidden'){
7310 cfg.cls = 'form-group' //input-group
7316 type : this.inputType,
7318 cls : 'form-control',
7319 placeholder : this.placeholder || '',
7320 autocomplete : this.autocomplete || 'new-password'
7325 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7328 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7329 input.maxLength = this.maxLength;
7332 if (this.disabled) {
7333 input.disabled=true;
7336 if (this.readOnly) {
7337 input.readonly=true;
7341 input.name = this.name;
7344 input.cls += ' input-' + this.size;
7347 ['xs','sm','md','lg'].map(function(size){
7348 if (settings[size]) {
7349 cfg.cls += ' col-' + size + '-' + settings[size];
7353 var inputblock = input;
7355 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7359 cls: 'glyphicon form-control-feedback'
7363 cls : 'has-feedback',
7371 // var inputblock = input;
7373 if (this.before || this.after) {
7376 cls : 'input-group',
7380 if (this.before && typeof(this.before) == 'string') {
7382 inputblock.cn.push({
7384 cls : 'roo-input-before input-group-addon',
7388 if (this.before && typeof(this.before) == 'object') {
7389 this.before = Roo.factory(this.before);
7390 Roo.log(this.before);
7391 inputblock.cn.push({
7393 cls : 'roo-input-before input-group-' +
7394 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7398 inputblock.cn.push(input);
7400 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7401 inputblock.cls += ' has-feedback';
7402 inputblock.cn.push(feedback);
7405 if (this.after && typeof(this.after) == 'string') {
7406 inputblock.cn.push({
7408 cls : 'roo-input-after input-group-addon',
7412 if (this.after && typeof(this.after) == 'object') {
7413 this.after = Roo.factory(this.after);
7414 Roo.log(this.after);
7415 inputblock.cn.push({
7417 cls : 'roo-input-after input-group-' +
7418 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7423 if (align ==='left' && this.fieldLabel.length) {
7424 Roo.log("left and has label");
7430 cls : 'control-label col-sm-' + this.labelWidth,
7431 html : this.fieldLabel
7435 cls : "col-sm-" + (12 - this.labelWidth),
7442 } else if ( this.fieldLabel.length) {
7448 //cls : 'input-group-addon',
7449 html : this.fieldLabel
7459 Roo.log(" no label && no align");
7468 Roo.log('input-parentType: ' + this.parentType);
7470 if (this.parentType === 'Navbar' && this.parent().bar) {
7471 cfg.cls += ' navbar-form';
7479 * return the real input element.
7481 inputEl: function ()
7483 return this.el.select('input.form-control',true).first();
7486 tooltipEl : function()
7488 return this.inputEl();
7491 setDisabled : function(v)
7493 var i = this.inputEl().dom;
7495 i.removeAttribute('disabled');
7499 i.setAttribute('disabled','true');
7501 initEvents : function()
7504 this.inputEl().on("keydown" , this.fireKey, this);
7505 this.inputEl().on("focus", this.onFocus, this);
7506 this.inputEl().on("blur", this.onBlur, this);
7508 this.inputEl().relayEvent('keyup', this);
7510 // reference to original value for reset
7511 this.originalValue = this.getValue();
7512 //Roo.form.TextField.superclass.initEvents.call(this);
7513 if(this.validationEvent == 'keyup'){
7514 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7515 this.inputEl().on('keyup', this.filterValidation, this);
7517 else if(this.validationEvent !== false){
7518 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7521 if(this.selectOnFocus){
7522 this.on("focus", this.preFocus, this);
7525 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7526 this.inputEl().on("keypress", this.filterKeys, this);
7529 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7530 this.el.on("click", this.autoSize, this);
7533 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7534 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7537 if (typeof(this.before) == 'object') {
7538 this.before.render(this.el.select('.roo-input-before',true).first());
7540 if (typeof(this.after) == 'object') {
7541 this.after.render(this.el.select('.roo-input-after',true).first());
7546 filterValidation : function(e){
7547 if(!e.isNavKeyPress()){
7548 this.validationTask.delay(this.validationDelay);
7552 * Validates the field value
7553 * @return {Boolean} True if the value is valid, else false
7555 validate : function(){
7556 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7557 if(this.disabled || this.validateValue(this.getRawValue())){
7568 * Validates a value according to the field's validation rules and marks the field as invalid
7569 * if the validation fails
7570 * @param {Mixed} value The value to validate
7571 * @return {Boolean} True if the value is valid, else false
7573 validateValue : function(value){
7574 if(value.length < 1) { // if it's blank
7575 if(this.allowBlank){
7581 if(value.length < this.minLength){
7584 if(value.length > this.maxLength){
7588 var vt = Roo.form.VTypes;
7589 if(!vt[this.vtype](value, this)){
7593 if(typeof this.validator == "function"){
7594 var msg = this.validator(value);
7600 if(this.regex && !this.regex.test(value)){
7610 fireKey : function(e){
7611 //Roo.log('field ' + e.getKey());
7612 if(e.isNavKeyPress()){
7613 this.fireEvent("specialkey", this, e);
7616 focus : function (selectText){
7618 this.inputEl().focus();
7619 if(selectText === true){
7620 this.inputEl().dom.select();
7626 onFocus : function(){
7627 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7628 // this.el.addClass(this.focusClass);
7631 this.hasFocus = true;
7632 this.startValue = this.getValue();
7633 this.fireEvent("focus", this);
7637 beforeBlur : Roo.emptyFn,
7641 onBlur : function(){
7643 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7644 //this.el.removeClass(this.focusClass);
7646 this.hasFocus = false;
7647 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7650 var v = this.getValue();
7651 if(String(v) !== String(this.startValue)){
7652 this.fireEvent('change', this, v, this.startValue);
7654 this.fireEvent("blur", this);
7658 * Resets the current field value to the originally loaded value and clears any validation messages
7661 this.setValue(this.originalValue);
7665 * Returns the name of the field
7666 * @return {Mixed} name The name field
7668 getName: function(){
7672 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7673 * @return {Mixed} value The field value
7675 getValue : function(){
7677 var v = this.inputEl().getValue();
7682 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7683 * @return {Mixed} value The field value
7685 getRawValue : function(){
7686 var v = this.inputEl().getValue();
7692 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7693 * @param {Mixed} value The value to set
7695 setRawValue : function(v){
7696 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7699 selectText : function(start, end){
7700 var v = this.getRawValue();
7702 start = start === undefined ? 0 : start;
7703 end = end === undefined ? v.length : end;
7704 var d = this.inputEl().dom;
7705 if(d.setSelectionRange){
7706 d.setSelectionRange(start, end);
7707 }else if(d.createTextRange){
7708 var range = d.createTextRange();
7709 range.moveStart("character", start);
7710 range.moveEnd("character", v.length-end);
7717 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7718 * @param {Mixed} value The value to set
7720 setValue : function(v){
7723 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7729 processValue : function(value){
7730 if(this.stripCharsRe){
7731 var newValue = value.replace(this.stripCharsRe, '');
7732 if(newValue !== value){
7733 this.setRawValue(newValue);
7740 preFocus : function(){
7742 if(this.selectOnFocus){
7743 this.inputEl().dom.select();
7746 filterKeys : function(e){
7748 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7751 var c = e.getCharCode(), cc = String.fromCharCode(c);
7752 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7755 if(!this.maskRe.test(cc)){
7760 * Clear any invalid styles/messages for this field
7762 clearInvalid : function(){
7764 if(!this.el || this.preventMark){ // not rendered
7767 this.el.removeClass(this.invalidClass);
7769 this.fireEvent('valid', this);
7773 * Mark this field as valid
7775 markValid : function(){
7776 if(!this.el || this.preventMark){ // not rendered
7780 this.el.removeClass([this.invalidClass, this.validClass]);
7782 if(this.disabled || this.allowBlank){
7786 this.el.addClass(this.validClass);
7788 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7790 var feedback = this.el.select('.form-control-feedback', true).first();
7793 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7794 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7799 this.fireEvent('valid', this);
7803 * Mark this field as invalid
7804 * @param {String} msg The validation message
7806 markInvalid : function(msg){
7807 if(!this.el || this.preventMark){ // not rendered
7811 this.el.removeClass([this.invalidClass, this.validClass]);
7813 if(this.disabled || this.allowBlank){
7817 this.el.addClass(this.invalidClass);
7819 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7821 var feedback = this.el.select('.form-control-feedback', true).first();
7824 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7826 if(this.getValue().length){
7827 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7834 this.fireEvent('invalid', this, msg);
7837 SafariOnKeyDown : function(event)
7839 // this is a workaround for a password hang bug on chrome/ webkit.
7841 var isSelectAll = false;
7843 if(this.inputEl().dom.selectionEnd > 0){
7844 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7846 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7847 event.preventDefault();
7852 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7854 event.preventDefault();
7855 // this is very hacky as keydown always get's upper case.
7857 var cc = String.fromCharCode(event.getCharCode());
7858 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7862 adjustWidth : function(tag, w){
7863 tag = tag.toLowerCase();
7864 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7865 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7869 if(tag == 'textarea'){
7872 }else if(Roo.isOpera){
7876 if(tag == 'textarea'){
7895 * @class Roo.bootstrap.TextArea
7896 * @extends Roo.bootstrap.Input
7897 * Bootstrap TextArea class
7898 * @cfg {Number} cols Specifies the visible width of a text area
7899 * @cfg {Number} rows Specifies the visible number of lines in a text area
7900 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7901 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7902 * @cfg {string} html text
7905 * Create a new TextArea
7906 * @param {Object} config The config object
7909 Roo.bootstrap.TextArea = function(config){
7910 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7914 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7924 getAutoCreate : function(){
7926 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7937 value : this.value || '',
7938 html: this.html || '',
7939 cls : 'form-control',
7940 placeholder : this.placeholder || ''
7944 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7945 input.maxLength = this.maxLength;
7949 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7953 input.cols = this.cols;
7956 if (this.readOnly) {
7957 input.readonly = true;
7961 input.name = this.name;
7965 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7969 ['xs','sm','md','lg'].map(function(size){
7970 if (settings[size]) {
7971 cfg.cls += ' col-' + size + '-' + settings[size];
7975 var inputblock = input;
7977 if(this.hasFeedback && !this.allowBlank){
7981 cls: 'glyphicon form-control-feedback'
7985 cls : 'has-feedback',
7994 if (this.before || this.after) {
7997 cls : 'input-group',
8001 inputblock.cn.push({
8003 cls : 'input-group-addon',
8008 inputblock.cn.push(input);
8010 if(this.hasFeedback && !this.allowBlank){
8011 inputblock.cls += ' has-feedback';
8012 inputblock.cn.push(feedback);
8016 inputblock.cn.push({
8018 cls : 'input-group-addon',
8025 if (align ==='left' && this.fieldLabel.length) {
8026 Roo.log("left and has label");
8032 cls : 'control-label col-sm-' + this.labelWidth,
8033 html : this.fieldLabel
8037 cls : "col-sm-" + (12 - this.labelWidth),
8044 } else if ( this.fieldLabel.length) {
8050 //cls : 'input-group-addon',
8051 html : this.fieldLabel
8061 Roo.log(" no label && no align");
8071 if (this.disabled) {
8072 input.disabled=true;
8079 * return the real textarea element.
8081 inputEl: function ()
8083 return this.el.select('textarea.form-control',true).first();
8091 * trigger field - base class for combo..
8096 * @class Roo.bootstrap.TriggerField
8097 * @extends Roo.bootstrap.Input
8098 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8099 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8100 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8101 * for which you can provide a custom implementation. For example:
8103 var trigger = new Roo.bootstrap.TriggerField();
8104 trigger.onTriggerClick = myTriggerFn;
8105 trigger.applyTo('my-field');
8108 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8109 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8110 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8111 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8112 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8115 * Create a new TriggerField.
8116 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8117 * to the base TextField)
8119 Roo.bootstrap.TriggerField = function(config){
8120 this.mimicing = false;
8121 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8124 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8126 * @cfg {String} triggerClass A CSS class to apply to the trigger
8129 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8133 /** @cfg {Boolean} grow @hide */
8134 /** @cfg {Number} growMin @hide */
8135 /** @cfg {Number} growMax @hide */
8141 autoSize: Roo.emptyFn,
8148 actionMode : 'wrap',
8153 getAutoCreate : function(){
8155 var align = this.labelAlign || this.parentLabelAlign();
8160 cls: 'form-group' //input-group
8167 type : this.inputType,
8168 cls : 'form-control',
8169 autocomplete: 'new-password',
8170 placeholder : this.placeholder || ''
8174 input.name = this.name;
8177 input.cls += ' input-' + this.size;
8180 if (this.disabled) {
8181 input.disabled=true;
8184 var inputblock = input;
8186 if(this.hasFeedback && !this.allowBlank){
8190 cls: 'glyphicon form-control-feedback'
8194 cls : 'has-feedback',
8202 if (this.before || this.after) {
8205 cls : 'input-group',
8209 inputblock.cn.push({
8211 cls : 'input-group-addon',
8216 inputblock.cn.push(input);
8218 if(this.hasFeedback && !this.allowBlank){
8219 inputblock.cls += ' has-feedback';
8220 inputblock.cn.push(feedback);
8224 inputblock.cn.push({
8226 cls : 'input-group-addon',
8239 cls: 'form-hidden-field'
8247 Roo.log('multiple');
8255 cls: 'form-hidden-field'
8259 cls: 'select2-choices',
8263 cls: 'select2-search-field',
8276 cls: 'select2-container input-group',
8281 // cls: 'typeahead typeahead-long dropdown-menu',
8282 // style: 'display:none'
8287 if(!this.multiple && this.showToggleBtn){
8293 if (this.caret != false) {
8296 cls: 'fa fa-' + this.caret
8303 cls : 'input-group-addon btn dropdown-toggle',
8308 cls: 'combobox-clear',
8322 combobox.cls += ' select2-container-multi';
8325 if (align ==='left' && this.fieldLabel.length) {
8327 Roo.log("left and has label");
8333 cls : 'control-label col-sm-' + this.labelWidth,
8334 html : this.fieldLabel
8338 cls : "col-sm-" + (12 - this.labelWidth),
8345 } else if ( this.fieldLabel.length) {
8351 //cls : 'input-group-addon',
8352 html : this.fieldLabel
8362 Roo.log(" no label && no align");
8369 ['xs','sm','md','lg'].map(function(size){
8370 if (settings[size]) {
8371 cfg.cls += ' col-' + size + '-' + settings[size];
8382 onResize : function(w, h){
8383 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8384 // if(typeof w == 'number'){
8385 // var x = w - this.trigger.getWidth();
8386 // this.inputEl().setWidth(this.adjustWidth('input', x));
8387 // this.trigger.setStyle('left', x+'px');
8392 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8395 getResizeEl : function(){
8396 return this.inputEl();
8400 getPositionEl : function(){
8401 return this.inputEl();
8405 alignErrorIcon : function(){
8406 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8410 initEvents : function(){
8414 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8415 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8416 if(!this.multiple && this.showToggleBtn){
8417 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8418 if(this.hideTrigger){
8419 this.trigger.setDisplayed(false);
8421 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8425 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8428 //this.trigger.addClassOnOver('x-form-trigger-over');
8429 //this.trigger.addClassOnClick('x-form-trigger-click');
8432 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8436 createList : function()
8438 this.list = Roo.get(document.body).createChild({
8440 cls: 'typeahead typeahead-long dropdown-menu',
8441 style: 'display:none'
8444 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8449 initTrigger : function(){
8454 onDestroy : function(){
8456 this.trigger.removeAllListeners();
8457 // this.trigger.remove();
8460 // this.wrap.remove();
8462 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8466 onFocus : function(){
8467 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8470 this.wrap.addClass('x-trigger-wrap-focus');
8471 this.mimicing = true;
8472 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8473 if(this.monitorTab){
8474 this.el.on("keydown", this.checkTab, this);
8481 checkTab : function(e){
8482 if(e.getKey() == e.TAB){
8488 onBlur : function(){
8493 mimicBlur : function(e, t){
8495 if(!this.wrap.contains(t) && this.validateBlur()){
8502 triggerBlur : function(){
8503 this.mimicing = false;
8504 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8505 if(this.monitorTab){
8506 this.el.un("keydown", this.checkTab, this);
8508 //this.wrap.removeClass('x-trigger-wrap-focus');
8509 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8513 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8514 validateBlur : function(e, t){
8519 onDisable : function(){
8520 this.inputEl().dom.disabled = true;
8521 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8523 // this.wrap.addClass('x-item-disabled');
8528 onEnable : function(){
8529 this.inputEl().dom.disabled = false;
8530 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8532 // this.el.removeClass('x-item-disabled');
8537 onShow : function(){
8538 var ae = this.getActionEl();
8541 ae.dom.style.display = '';
8542 ae.dom.style.visibility = 'visible';
8548 onHide : function(){
8549 var ae = this.getActionEl();
8550 ae.dom.style.display = 'none';
8554 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8555 * by an implementing function.
8557 * @param {EventObject} e
8559 onTriggerClick : Roo.emptyFn
8563 * Ext JS Library 1.1.1
8564 * Copyright(c) 2006-2007, Ext JS, LLC.
8566 * Originally Released Under LGPL - original licence link has changed is not relivant.
8569 * <script type="text/javascript">
8574 * @class Roo.data.SortTypes
8576 * Defines the default sorting (casting?) comparison functions used when sorting data.
8578 Roo.data.SortTypes = {
8580 * Default sort that does nothing
8581 * @param {Mixed} s The value being converted
8582 * @return {Mixed} The comparison value
8589 * The regular expression used to strip tags
8593 stripTagsRE : /<\/?[^>]+>/gi,
8596 * Strips all HTML tags to sort on text only
8597 * @param {Mixed} s The value being converted
8598 * @return {String} The comparison value
8600 asText : function(s){
8601 return String(s).replace(this.stripTagsRE, "");
8605 * Strips all HTML tags to sort on text only - Case insensitive
8606 * @param {Mixed} s The value being converted
8607 * @return {String} The comparison value
8609 asUCText : function(s){
8610 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8614 * Case insensitive string
8615 * @param {Mixed} s The value being converted
8616 * @return {String} The comparison value
8618 asUCString : function(s) {
8619 return String(s).toUpperCase();
8624 * @param {Mixed} s The value being converted
8625 * @return {Number} The comparison value
8627 asDate : function(s) {
8631 if(s instanceof Date){
8634 return Date.parse(String(s));
8639 * @param {Mixed} s The value being converted
8640 * @return {Float} The comparison value
8642 asFloat : function(s) {
8643 var val = parseFloat(String(s).replace(/,/g, ""));
8644 if(isNaN(val)) val = 0;
8650 * @param {Mixed} s The value being converted
8651 * @return {Number} The comparison value
8653 asInt : function(s) {
8654 var val = parseInt(String(s).replace(/,/g, ""));
8655 if(isNaN(val)) val = 0;
8660 * Ext JS Library 1.1.1
8661 * Copyright(c) 2006-2007, Ext JS, LLC.
8663 * Originally Released Under LGPL - original licence link has changed is not relivant.
8666 * <script type="text/javascript">
8670 * @class Roo.data.Record
8671 * Instances of this class encapsulate both record <em>definition</em> information, and record
8672 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8673 * to access Records cached in an {@link Roo.data.Store} object.<br>
8675 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8676 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8679 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8681 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8682 * {@link #create}. The parameters are the same.
8683 * @param {Array} data An associative Array of data values keyed by the field name.
8684 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8685 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8686 * not specified an integer id is generated.
8688 Roo.data.Record = function(data, id){
8689 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8694 * Generate a constructor for a specific record layout.
8695 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8696 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8697 * Each field definition object may contain the following properties: <ul>
8698 * <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,
8699 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8700 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8701 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8702 * is being used, then this is a string containing the javascript expression to reference the data relative to
8703 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8704 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8705 * this may be omitted.</p></li>
8706 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8707 * <ul><li>auto (Default, implies no conversion)</li>
8712 * <li>date</li></ul></p></li>
8713 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8714 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8715 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8716 * by the Reader into an object that will be stored in the Record. It is passed the
8717 * following parameters:<ul>
8718 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8720 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8722 * <br>usage:<br><pre><code>
8723 var TopicRecord = Roo.data.Record.create(
8724 {name: 'title', mapping: 'topic_title'},
8725 {name: 'author', mapping: 'username'},
8726 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8727 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8728 {name: 'lastPoster', mapping: 'user2'},
8729 {name: 'excerpt', mapping: 'post_text'}
8732 var myNewRecord = new TopicRecord({
8733 title: 'Do my job please',
8736 lastPost: new Date(),
8737 lastPoster: 'Animal',
8738 excerpt: 'No way dude!'
8740 myStore.add(myNewRecord);
8745 Roo.data.Record.create = function(o){
8747 f.superclass.constructor.apply(this, arguments);
8749 Roo.extend(f, Roo.data.Record);
8750 var p = f.prototype;
8751 p.fields = new Roo.util.MixedCollection(false, function(field){
8754 for(var i = 0, len = o.length; i < len; i++){
8755 p.fields.add(new Roo.data.Field(o[i]));
8757 f.getField = function(name){
8758 return p.fields.get(name);
8763 Roo.data.Record.AUTO_ID = 1000;
8764 Roo.data.Record.EDIT = 'edit';
8765 Roo.data.Record.REJECT = 'reject';
8766 Roo.data.Record.COMMIT = 'commit';
8768 Roo.data.Record.prototype = {
8770 * Readonly flag - true if this record has been modified.
8779 join : function(store){
8784 * Set the named field to the specified value.
8785 * @param {String} name The name of the field to set.
8786 * @param {Object} value The value to set the field to.
8788 set : function(name, value){
8789 if(this.data[name] == value){
8796 if(typeof this.modified[name] == 'undefined'){
8797 this.modified[name] = this.data[name];
8799 this.data[name] = value;
8800 if(!this.editing && this.store){
8801 this.store.afterEdit(this);
8806 * Get the value of the named field.
8807 * @param {String} name The name of the field to get the value of.
8808 * @return {Object} The value of the field.
8810 get : function(name){
8811 return this.data[name];
8815 beginEdit : function(){
8816 this.editing = true;
8821 cancelEdit : function(){
8822 this.editing = false;
8823 delete this.modified;
8827 endEdit : function(){
8828 this.editing = false;
8829 if(this.dirty && this.store){
8830 this.store.afterEdit(this);
8835 * Usually called by the {@link Roo.data.Store} which owns the Record.
8836 * Rejects all changes made to the Record since either creation, or the last commit operation.
8837 * Modified fields are reverted to their original values.
8839 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8840 * of reject operations.
8842 reject : function(){
8843 var m = this.modified;
8845 if(typeof m[n] != "function"){
8846 this.data[n] = m[n];
8850 delete this.modified;
8851 this.editing = false;
8853 this.store.afterReject(this);
8858 * Usually called by the {@link Roo.data.Store} which owns the Record.
8859 * Commits all changes made to the Record since either creation, or the last commit operation.
8861 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8862 * of commit operations.
8864 commit : function(){
8866 delete this.modified;
8867 this.editing = false;
8869 this.store.afterCommit(this);
8874 hasError : function(){
8875 return this.error != null;
8879 clearError : function(){
8884 * Creates a copy of this record.
8885 * @param {String} id (optional) A new record id if you don't want to use this record's id
8888 copy : function(newId) {
8889 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8893 * Ext JS Library 1.1.1
8894 * Copyright(c) 2006-2007, Ext JS, LLC.
8896 * Originally Released Under LGPL - original licence link has changed is not relivant.
8899 * <script type="text/javascript">
8905 * @class Roo.data.Store
8906 * @extends Roo.util.Observable
8907 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8908 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8910 * 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
8911 * has no knowledge of the format of the data returned by the Proxy.<br>
8913 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8914 * instances from the data object. These records are cached and made available through accessor functions.
8916 * Creates a new Store.
8917 * @param {Object} config A config object containing the objects needed for the Store to access data,
8918 * and read the data into Records.
8920 Roo.data.Store = function(config){
8921 this.data = new Roo.util.MixedCollection(false);
8922 this.data.getKey = function(o){
8925 this.baseParams = {};
8932 "multisort" : "_multisort"
8935 if(config && config.data){
8936 this.inlineData = config.data;
8940 Roo.apply(this, config);
8942 if(this.reader){ // reader passed
8943 this.reader = Roo.factory(this.reader, Roo.data);
8944 this.reader.xmodule = this.xmodule || false;
8945 if(!this.recordType){
8946 this.recordType = this.reader.recordType;
8948 if(this.reader.onMetaChange){
8949 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8953 if(this.recordType){
8954 this.fields = this.recordType.prototype.fields;
8960 * @event datachanged
8961 * Fires when the data cache has changed, and a widget which is using this Store
8962 * as a Record cache should refresh its view.
8963 * @param {Store} this
8968 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8969 * @param {Store} this
8970 * @param {Object} meta The JSON metadata
8975 * Fires when Records have been added to the Store
8976 * @param {Store} this
8977 * @param {Roo.data.Record[]} records The array of Records added
8978 * @param {Number} index The index at which the record(s) were added
8983 * Fires when a Record has been removed from the Store
8984 * @param {Store} this
8985 * @param {Roo.data.Record} record The Record that was removed
8986 * @param {Number} index The index at which the record was removed
8991 * Fires when a Record has been updated
8992 * @param {Store} this
8993 * @param {Roo.data.Record} record The Record that was updated
8994 * @param {String} operation The update operation being performed. Value may be one of:
8996 Roo.data.Record.EDIT
8997 Roo.data.Record.REJECT
8998 Roo.data.Record.COMMIT
9004 * Fires when the data cache has been cleared.
9005 * @param {Store} this
9010 * Fires before a request is made for a new data object. If the beforeload handler returns false
9011 * the load action will be canceled.
9012 * @param {Store} this
9013 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9017 * @event beforeloadadd
9018 * Fires after a new set of Records has been loaded.
9019 * @param {Store} this
9020 * @param {Roo.data.Record[]} records The Records that were loaded
9021 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9023 beforeloadadd : true,
9026 * Fires after a new set of Records has been loaded, before they are added to the store.
9027 * @param {Store} this
9028 * @param {Roo.data.Record[]} records The Records that were loaded
9029 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9030 * @params {Object} return from reader
9034 * @event loadexception
9035 * Fires if an exception occurs in the Proxy during loading.
9036 * Called with the signature of the Proxy's "loadexception" event.
9037 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9040 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9041 * @param {Object} load options
9042 * @param {Object} jsonData from your request (normally this contains the Exception)
9044 loadexception : true
9048 this.proxy = Roo.factory(this.proxy, Roo.data);
9049 this.proxy.xmodule = this.xmodule || false;
9050 this.relayEvents(this.proxy, ["loadexception"]);
9052 this.sortToggle = {};
9053 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9055 Roo.data.Store.superclass.constructor.call(this);
9057 if(this.inlineData){
9058 this.loadData(this.inlineData);
9059 delete this.inlineData;
9063 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9065 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9066 * without a remote query - used by combo/forms at present.
9070 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9073 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9076 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9077 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9080 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9081 * on any HTTP request
9084 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9087 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9091 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9092 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9097 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9098 * loaded or when a record is removed. (defaults to false).
9100 pruneModifiedRecords : false,
9106 * Add Records to the Store and fires the add event.
9107 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9109 add : function(records){
9110 records = [].concat(records);
9111 for(var i = 0, len = records.length; i < len; i++){
9112 records[i].join(this);
9114 var index = this.data.length;
9115 this.data.addAll(records);
9116 this.fireEvent("add", this, records, index);
9120 * Remove a Record from the Store and fires the remove event.
9121 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9123 remove : function(record){
9124 var index = this.data.indexOf(record);
9125 this.data.removeAt(index);
9126 if(this.pruneModifiedRecords){
9127 this.modified.remove(record);
9129 this.fireEvent("remove", this, record, index);
9133 * Remove all Records from the Store and fires the clear event.
9135 removeAll : function(){
9137 if(this.pruneModifiedRecords){
9140 this.fireEvent("clear", this);
9144 * Inserts Records to the Store at the given index and fires the add event.
9145 * @param {Number} index The start index at which to insert the passed Records.
9146 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9148 insert : function(index, records){
9149 records = [].concat(records);
9150 for(var i = 0, len = records.length; i < len; i++){
9151 this.data.insert(index, records[i]);
9152 records[i].join(this);
9154 this.fireEvent("add", this, records, index);
9158 * Get the index within the cache of the passed Record.
9159 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9160 * @return {Number} The index of the passed Record. Returns -1 if not found.
9162 indexOf : function(record){
9163 return this.data.indexOf(record);
9167 * Get the index within the cache of the Record with the passed id.
9168 * @param {String} id The id of the Record to find.
9169 * @return {Number} The index of the Record. Returns -1 if not found.
9171 indexOfId : function(id){
9172 return this.data.indexOfKey(id);
9176 * Get the Record with the specified id.
9177 * @param {String} id The id of the Record to find.
9178 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9180 getById : function(id){
9181 return this.data.key(id);
9185 * Get the Record at the specified index.
9186 * @param {Number} index The index of the Record to find.
9187 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9189 getAt : function(index){
9190 return this.data.itemAt(index);
9194 * Returns a range of Records between specified indices.
9195 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9196 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9197 * @return {Roo.data.Record[]} An array of Records
9199 getRange : function(start, end){
9200 return this.data.getRange(start, end);
9204 storeOptions : function(o){
9205 o = Roo.apply({}, o);
9208 this.lastOptions = o;
9212 * Loads the Record cache from the configured Proxy using the configured Reader.
9214 * If using remote paging, then the first load call must specify the <em>start</em>
9215 * and <em>limit</em> properties in the options.params property to establish the initial
9216 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9218 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9219 * and this call will return before the new data has been loaded. Perform any post-processing
9220 * in a callback function, or in a "load" event handler.</strong>
9222 * @param {Object} options An object containing properties which control loading options:<ul>
9223 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9224 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9225 * passed the following arguments:<ul>
9226 * <li>r : Roo.data.Record[]</li>
9227 * <li>options: Options object from the load call</li>
9228 * <li>success: Boolean success indicator</li></ul></li>
9229 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9230 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9233 load : function(options){
9234 options = options || {};
9235 if(this.fireEvent("beforeload", this, options) !== false){
9236 this.storeOptions(options);
9237 var p = Roo.apply(options.params || {}, this.baseParams);
9238 // if meta was not loaded from remote source.. try requesting it.
9239 if (!this.reader.metaFromRemote) {
9242 if(this.sortInfo && this.remoteSort){
9243 var pn = this.paramNames;
9244 p[pn["sort"]] = this.sortInfo.field;
9245 p[pn["dir"]] = this.sortInfo.direction;
9247 if (this.multiSort) {
9248 var pn = this.paramNames;
9249 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9252 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9257 * Reloads the Record cache from the configured Proxy using the configured Reader and
9258 * the options from the last load operation performed.
9259 * @param {Object} options (optional) An object containing properties which may override the options
9260 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9261 * the most recently used options are reused).
9263 reload : function(options){
9264 this.load(Roo.applyIf(options||{}, this.lastOptions));
9268 // Called as a callback by the Reader during a load operation.
9269 loadRecords : function(o, options, success){
9270 if(!o || success === false){
9271 if(success !== false){
9272 this.fireEvent("load", this, [], options, o);
9274 if(options.callback){
9275 options.callback.call(options.scope || this, [], options, false);
9279 // if data returned failure - throw an exception.
9280 if (o.success === false) {
9281 // show a message if no listener is registered.
9282 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9283 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9285 // loadmask wil be hooked into this..
9286 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9289 var r = o.records, t = o.totalRecords || r.length;
9291 this.fireEvent("beforeloadadd", this, r, options, o);
9293 if(!options || options.add !== true){
9294 if(this.pruneModifiedRecords){
9297 for(var i = 0, len = r.length; i < len; i++){
9301 this.data = this.snapshot;
9302 delete this.snapshot;
9305 this.data.addAll(r);
9306 this.totalLength = t;
9308 this.fireEvent("datachanged", this);
9310 this.totalLength = Math.max(t, this.data.length+r.length);
9313 this.fireEvent("load", this, r, options, o);
9314 if(options.callback){
9315 options.callback.call(options.scope || this, r, options, true);
9321 * Loads data from a passed data block. A Reader which understands the format of the data
9322 * must have been configured in the constructor.
9323 * @param {Object} data The data block from which to read the Records. The format of the data expected
9324 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9325 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9327 loadData : function(o, append){
9328 var r = this.reader.readRecords(o);
9329 this.loadRecords(r, {add: append}, true);
9333 * Gets the number of cached records.
9335 * <em>If using paging, this may not be the total size of the dataset. If the data object
9336 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9337 * the data set size</em>
9339 getCount : function(){
9340 return this.data.length || 0;
9344 * Gets the total number of records in the dataset as returned by the server.
9346 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9347 * the dataset size</em>
9349 getTotalCount : function(){
9350 return this.totalLength || 0;
9354 * Returns the sort state of the Store as an object with two properties:
9356 field {String} The name of the field by which the Records are sorted
9357 direction {String} The sort order, "ASC" or "DESC"
9360 getSortState : function(){
9361 return this.sortInfo;
9365 applySort : function(){
9366 if(this.sortInfo && !this.remoteSort){
9367 var s = this.sortInfo, f = s.field;
9368 var st = this.fields.get(f).sortType;
9369 var fn = function(r1, r2){
9370 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9371 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9373 this.data.sort(s.direction, fn);
9374 if(this.snapshot && this.snapshot != this.data){
9375 this.snapshot.sort(s.direction, fn);
9381 * Sets the default sort column and order to be used by the next load operation.
9382 * @param {String} fieldName The name of the field to sort by.
9383 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9385 setDefaultSort : function(field, dir){
9386 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9391 * If remote sorting is used, the sort is performed on the server, and the cache is
9392 * reloaded. If local sorting is used, the cache is sorted internally.
9393 * @param {String} fieldName The name of the field to sort by.
9394 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9396 sort : function(fieldName, dir){
9397 var f = this.fields.get(fieldName);
9399 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9401 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9402 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9407 this.sortToggle[f.name] = dir;
9408 this.sortInfo = {field: f.name, direction: dir};
9409 if(!this.remoteSort){
9411 this.fireEvent("datachanged", this);
9413 this.load(this.lastOptions);
9418 * Calls the specified function for each of the Records in the cache.
9419 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9420 * Returning <em>false</em> aborts and exits the iteration.
9421 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9423 each : function(fn, scope){
9424 this.data.each(fn, scope);
9428 * Gets all records modified since the last commit. Modified records are persisted across load operations
9429 * (e.g., during paging).
9430 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9432 getModifiedRecords : function(){
9433 return this.modified;
9437 createFilterFn : function(property, value, anyMatch){
9438 if(!value.exec){ // not a regex
9439 value = String(value);
9440 if(value.length == 0){
9443 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9446 return value.test(r.data[property]);
9451 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9452 * @param {String} property A field on your records
9453 * @param {Number} start The record index to start at (defaults to 0)
9454 * @param {Number} end The last record index to include (defaults to length - 1)
9455 * @return {Number} The sum
9457 sum : function(property, start, end){
9458 var rs = this.data.items, v = 0;
9460 end = (end || end === 0) ? end : rs.length-1;
9462 for(var i = start; i <= end; i++){
9463 v += (rs[i].data[property] || 0);
9469 * Filter the records by a specified property.
9470 * @param {String} field A field on your records
9471 * @param {String/RegExp} value Either a string that the field
9472 * should start with or a RegExp to test against the field
9473 * @param {Boolean} anyMatch True to match any part not just the beginning
9475 filter : function(property, value, anyMatch){
9476 var fn = this.createFilterFn(property, value, anyMatch);
9477 return fn ? this.filterBy(fn) : this.clearFilter();
9481 * Filter by a function. The specified function will be called with each
9482 * record in this data source. If the function returns true the record is included,
9483 * otherwise it is filtered.
9484 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9485 * @param {Object} scope (optional) The scope of the function (defaults to this)
9487 filterBy : function(fn, scope){
9488 this.snapshot = this.snapshot || this.data;
9489 this.data = this.queryBy(fn, scope||this);
9490 this.fireEvent("datachanged", this);
9494 * Query the records by a specified property.
9495 * @param {String} field A field on your records
9496 * @param {String/RegExp} value Either a string that the field
9497 * should start with or a RegExp to test against the field
9498 * @param {Boolean} anyMatch True to match any part not just the beginning
9499 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9501 query : function(property, value, anyMatch){
9502 var fn = this.createFilterFn(property, value, anyMatch);
9503 return fn ? this.queryBy(fn) : this.data.clone();
9507 * Query by a function. The specified function will be called with each
9508 * record in this data source. If the function returns true the record is included
9510 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9511 * @param {Object} scope (optional) The scope of the function (defaults to this)
9512 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9514 queryBy : function(fn, scope){
9515 var data = this.snapshot || this.data;
9516 return data.filterBy(fn, scope||this);
9520 * Collects unique values for a particular dataIndex from this store.
9521 * @param {String} dataIndex The property to collect
9522 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9523 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9524 * @return {Array} An array of the unique values
9526 collect : function(dataIndex, allowNull, bypassFilter){
9527 var d = (bypassFilter === true && this.snapshot) ?
9528 this.snapshot.items : this.data.items;
9529 var v, sv, r = [], l = {};
9530 for(var i = 0, len = d.length; i < len; i++){
9531 v = d[i].data[dataIndex];
9533 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9542 * Revert to a view of the Record cache with no filtering applied.
9543 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9545 clearFilter : function(suppressEvent){
9546 if(this.snapshot && this.snapshot != this.data){
9547 this.data = this.snapshot;
9548 delete this.snapshot;
9549 if(suppressEvent !== true){
9550 this.fireEvent("datachanged", this);
9556 afterEdit : function(record){
9557 if(this.modified.indexOf(record) == -1){
9558 this.modified.push(record);
9560 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9564 afterReject : function(record){
9565 this.modified.remove(record);
9566 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9570 afterCommit : function(record){
9571 this.modified.remove(record);
9572 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9576 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9577 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9579 commitChanges : function(){
9580 var m = this.modified.slice(0);
9582 for(var i = 0, len = m.length; i < len; i++){
9588 * Cancel outstanding changes on all changed records.
9590 rejectChanges : function(){
9591 var m = this.modified.slice(0);
9593 for(var i = 0, len = m.length; i < len; i++){
9598 onMetaChange : function(meta, rtype, o){
9599 this.recordType = rtype;
9600 this.fields = rtype.prototype.fields;
9601 delete this.snapshot;
9602 this.sortInfo = meta.sortInfo || this.sortInfo;
9604 this.fireEvent('metachange', this, this.reader.meta);
9607 moveIndex : function(data, type)
9609 var index = this.indexOf(data);
9611 var newIndex = index + type;
9615 this.insert(newIndex, data);
9620 * Ext JS Library 1.1.1
9621 * Copyright(c) 2006-2007, Ext JS, LLC.
9623 * Originally Released Under LGPL - original licence link has changed is not relivant.
9626 * <script type="text/javascript">
9630 * @class Roo.data.SimpleStore
9631 * @extends Roo.data.Store
9632 * Small helper class to make creating Stores from Array data easier.
9633 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9634 * @cfg {Array} fields An array of field definition objects, or field name strings.
9635 * @cfg {Array} data The multi-dimensional array of data
9637 * @param {Object} config
9639 Roo.data.SimpleStore = function(config){
9640 Roo.data.SimpleStore.superclass.constructor.call(this, {
9642 reader: new Roo.data.ArrayReader({
9645 Roo.data.Record.create(config.fields)
9647 proxy : new Roo.data.MemoryProxy(config.data)
9651 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9653 * Ext JS Library 1.1.1
9654 * Copyright(c) 2006-2007, Ext JS, LLC.
9656 * Originally Released Under LGPL - original licence link has changed is not relivant.
9659 * <script type="text/javascript">
9664 * @extends Roo.data.Store
9665 * @class Roo.data.JsonStore
9666 * Small helper class to make creating Stores for JSON data easier. <br/>
9668 var store = new Roo.data.JsonStore({
9669 url: 'get-images.php',
9671 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9674 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9675 * JsonReader and HttpProxy (unless inline data is provided).</b>
9676 * @cfg {Array} fields An array of field definition objects, or field name strings.
9678 * @param {Object} config
9680 Roo.data.JsonStore = function(c){
9681 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9682 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9683 reader: new Roo.data.JsonReader(c, c.fields)
9686 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9688 * Ext JS Library 1.1.1
9689 * Copyright(c) 2006-2007, Ext JS, LLC.
9691 * Originally Released Under LGPL - original licence link has changed is not relivant.
9694 * <script type="text/javascript">
9698 Roo.data.Field = function(config){
9699 if(typeof config == "string"){
9700 config = {name: config};
9702 Roo.apply(this, config);
9708 var st = Roo.data.SortTypes;
9709 // named sortTypes are supported, here we look them up
9710 if(typeof this.sortType == "string"){
9711 this.sortType = st[this.sortType];
9714 // set default sortType for strings and dates
9718 this.sortType = st.asUCString;
9721 this.sortType = st.asDate;
9724 this.sortType = st.none;
9729 var stripRe = /[\$,%]/g;
9731 // prebuilt conversion function for this field, instead of
9732 // switching every time we're reading a value
9734 var cv, dateFormat = this.dateFormat;
9739 cv = function(v){ return v; };
9742 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9746 return v !== undefined && v !== null && v !== '' ?
9747 parseInt(String(v).replace(stripRe, ""), 10) : '';
9752 return v !== undefined && v !== null && v !== '' ?
9753 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9758 cv = function(v){ return v === true || v === "true" || v == 1; };
9765 if(v instanceof Date){
9769 if(dateFormat == "timestamp"){
9770 return new Date(v*1000);
9772 return Date.parseDate(v, dateFormat);
9774 var parsed = Date.parse(v);
9775 return parsed ? new Date(parsed) : null;
9784 Roo.data.Field.prototype = {
9792 * Ext JS Library 1.1.1
9793 * Copyright(c) 2006-2007, Ext JS, LLC.
9795 * Originally Released Under LGPL - original licence link has changed is not relivant.
9798 * <script type="text/javascript">
9801 // Base class for reading structured data from a data source. This class is intended to be
9802 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9805 * @class Roo.data.DataReader
9806 * Base class for reading structured data from a data source. This class is intended to be
9807 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9810 Roo.data.DataReader = function(meta, recordType){
9814 this.recordType = recordType instanceof Array ?
9815 Roo.data.Record.create(recordType) : recordType;
9818 Roo.data.DataReader.prototype = {
9820 * Create an empty record
9821 * @param {Object} data (optional) - overlay some values
9822 * @return {Roo.data.Record} record created.
9824 newRow : function(d) {
9826 this.recordType.prototype.fields.each(function(c) {
9828 case 'int' : da[c.name] = 0; break;
9829 case 'date' : da[c.name] = new Date(); break;
9830 case 'float' : da[c.name] = 0.0; break;
9831 case 'boolean' : da[c.name] = false; break;
9832 default : da[c.name] = ""; break;
9836 return new this.recordType(Roo.apply(da, d));
9841 * Ext JS Library 1.1.1
9842 * Copyright(c) 2006-2007, Ext JS, LLC.
9844 * Originally Released Under LGPL - original licence link has changed is not relivant.
9847 * <script type="text/javascript">
9851 * @class Roo.data.DataProxy
9852 * @extends Roo.data.Observable
9853 * This class is an abstract base class for implementations which provide retrieval of
9854 * unformatted data objects.<br>
9856 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9857 * (of the appropriate type which knows how to parse the data object) to provide a block of
9858 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9860 * Custom implementations must implement the load method as described in
9861 * {@link Roo.data.HttpProxy#load}.
9863 Roo.data.DataProxy = function(){
9867 * Fires before a network request is made to retrieve a data object.
9868 * @param {Object} This DataProxy object.
9869 * @param {Object} params The params parameter to the load function.
9874 * Fires before the load method's callback is called.
9875 * @param {Object} This DataProxy object.
9876 * @param {Object} o The data object.
9877 * @param {Object} arg The callback argument object passed to the load function.
9881 * @event loadexception
9882 * Fires if an Exception occurs during data retrieval.
9883 * @param {Object} This DataProxy object.
9884 * @param {Object} o The data object.
9885 * @param {Object} arg The callback argument object passed to the load function.
9886 * @param {Object} e The Exception.
9888 loadexception : true
9890 Roo.data.DataProxy.superclass.constructor.call(this);
9893 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9896 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9900 * Ext JS Library 1.1.1
9901 * Copyright(c) 2006-2007, Ext JS, LLC.
9903 * Originally Released Under LGPL - original licence link has changed is not relivant.
9906 * <script type="text/javascript">
9909 * @class Roo.data.MemoryProxy
9910 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9911 * to the Reader when its load method is called.
9913 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9915 Roo.data.MemoryProxy = function(data){
9919 Roo.data.MemoryProxy.superclass.constructor.call(this);
9923 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9925 * Load data from the requested source (in this case an in-memory
9926 * data object passed to the constructor), read the data object into
9927 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9928 * process that block using the passed callback.
9929 * @param {Object} params This parameter is not used by the MemoryProxy class.
9930 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9931 * object into a block of Roo.data.Records.
9932 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9933 * The function must be passed <ul>
9934 * <li>The Record block object</li>
9935 * <li>The "arg" argument from the load function</li>
9936 * <li>A boolean success indicator</li>
9938 * @param {Object} scope The scope in which to call the callback
9939 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9941 load : function(params, reader, callback, scope, arg){
9942 params = params || {};
9945 result = reader.readRecords(this.data);
9947 this.fireEvent("loadexception", this, arg, null, e);
9948 callback.call(scope, null, arg, false);
9951 callback.call(scope, result, arg, true);
9955 update : function(params, records){
9960 * Ext JS Library 1.1.1
9961 * Copyright(c) 2006-2007, Ext JS, LLC.
9963 * Originally Released Under LGPL - original licence link has changed is not relivant.
9966 * <script type="text/javascript">
9969 * @class Roo.data.HttpProxy
9970 * @extends Roo.data.DataProxy
9971 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9972 * configured to reference a certain URL.<br><br>
9974 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9975 * from which the running page was served.<br><br>
9977 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9979 * Be aware that to enable the browser to parse an XML document, the server must set
9980 * the Content-Type header in the HTTP response to "text/xml".
9982 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9983 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9984 * will be used to make the request.
9986 Roo.data.HttpProxy = function(conn){
9987 Roo.data.HttpProxy.superclass.constructor.call(this);
9988 // is conn a conn config or a real conn?
9990 this.useAjax = !conn || !conn.events;
9994 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9995 // thse are take from connection...
9998 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10001 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10002 * extra parameters to each request made by this object. (defaults to undefined)
10005 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10006 * to each request made by this object. (defaults to undefined)
10009 * @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)
10012 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10015 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10021 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10025 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10026 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10027 * a finer-grained basis than the DataProxy events.
10029 getConnection : function(){
10030 return this.useAjax ? Roo.Ajax : this.conn;
10034 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10035 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10036 * process that block using the passed callback.
10037 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10038 * for the request to the remote server.
10039 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10040 * object into a block of Roo.data.Records.
10041 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10042 * The function must be passed <ul>
10043 * <li>The Record block object</li>
10044 * <li>The "arg" argument from the load function</li>
10045 * <li>A boolean success indicator</li>
10047 * @param {Object} scope The scope in which to call the callback
10048 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10050 load : function(params, reader, callback, scope, arg){
10051 if(this.fireEvent("beforeload", this, params) !== false){
10053 params : params || {},
10055 callback : callback,
10060 callback : this.loadResponse,
10064 Roo.applyIf(o, this.conn);
10065 if(this.activeRequest){
10066 Roo.Ajax.abort(this.activeRequest);
10068 this.activeRequest = Roo.Ajax.request(o);
10070 this.conn.request(o);
10073 callback.call(scope||this, null, arg, false);
10078 loadResponse : function(o, success, response){
10079 delete this.activeRequest;
10081 this.fireEvent("loadexception", this, o, response);
10082 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10087 result = o.reader.read(response);
10089 this.fireEvent("loadexception", this, o, response, e);
10090 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10094 this.fireEvent("load", this, o, o.request.arg);
10095 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10099 update : function(dataSet){
10104 updateResponse : function(dataSet){
10109 * Ext JS Library 1.1.1
10110 * Copyright(c) 2006-2007, Ext JS, LLC.
10112 * Originally Released Under LGPL - original licence link has changed is not relivant.
10115 * <script type="text/javascript">
10119 * @class Roo.data.ScriptTagProxy
10120 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10121 * other than the originating domain of the running page.<br><br>
10123 * <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
10124 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10126 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10127 * source code that is used as the source inside a <script> tag.<br><br>
10129 * In order for the browser to process the returned data, the server must wrap the data object
10130 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10131 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10132 * depending on whether the callback name was passed:
10135 boolean scriptTag = false;
10136 String cb = request.getParameter("callback");
10139 response.setContentType("text/javascript");
10141 response.setContentType("application/x-json");
10143 Writer out = response.getWriter();
10145 out.write(cb + "(");
10147 out.print(dataBlock.toJsonString());
10154 * @param {Object} config A configuration object.
10156 Roo.data.ScriptTagProxy = function(config){
10157 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10158 Roo.apply(this, config);
10159 this.head = document.getElementsByTagName("head")[0];
10162 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10164 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10166 * @cfg {String} url The URL from which to request the data object.
10169 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10173 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10174 * the server the name of the callback function set up by the load call to process the returned data object.
10175 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10176 * javascript output which calls this named function passing the data object as its only parameter.
10178 callbackParam : "callback",
10180 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10181 * name to the request.
10186 * Load data from the configured URL, read the data object into
10187 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10188 * process that block using the passed callback.
10189 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10190 * for the request to the remote server.
10191 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10192 * object into a block of Roo.data.Records.
10193 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10194 * The function must be passed <ul>
10195 * <li>The Record block object</li>
10196 * <li>The "arg" argument from the load function</li>
10197 * <li>A boolean success indicator</li>
10199 * @param {Object} scope The scope in which to call the callback
10200 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10202 load : function(params, reader, callback, scope, arg){
10203 if(this.fireEvent("beforeload", this, params) !== false){
10205 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10207 var url = this.url;
10208 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10210 url += "&_dc=" + (new Date().getTime());
10212 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10215 cb : "stcCallback"+transId,
10216 scriptId : "stcScript"+transId,
10220 callback : callback,
10226 window[trans.cb] = function(o){
10227 conn.handleResponse(o, trans);
10230 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10232 if(this.autoAbort !== false){
10236 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10238 var script = document.createElement("script");
10239 script.setAttribute("src", url);
10240 script.setAttribute("type", "text/javascript");
10241 script.setAttribute("id", trans.scriptId);
10242 this.head.appendChild(script);
10244 this.trans = trans;
10246 callback.call(scope||this, null, arg, false);
10251 isLoading : function(){
10252 return this.trans ? true : false;
10256 * Abort the current server request.
10258 abort : function(){
10259 if(this.isLoading()){
10260 this.destroyTrans(this.trans);
10265 destroyTrans : function(trans, isLoaded){
10266 this.head.removeChild(document.getElementById(trans.scriptId));
10267 clearTimeout(trans.timeoutId);
10269 window[trans.cb] = undefined;
10271 delete window[trans.cb];
10274 // if hasn't been loaded, wait for load to remove it to prevent script error
10275 window[trans.cb] = function(){
10276 window[trans.cb] = undefined;
10278 delete window[trans.cb];
10285 handleResponse : function(o, trans){
10286 this.trans = false;
10287 this.destroyTrans(trans, true);
10290 result = trans.reader.readRecords(o);
10292 this.fireEvent("loadexception", this, o, trans.arg, e);
10293 trans.callback.call(trans.scope||window, null, trans.arg, false);
10296 this.fireEvent("load", this, o, trans.arg);
10297 trans.callback.call(trans.scope||window, result, trans.arg, true);
10301 handleFailure : function(trans){
10302 this.trans = false;
10303 this.destroyTrans(trans, false);
10304 this.fireEvent("loadexception", this, null, trans.arg);
10305 trans.callback.call(trans.scope||window, null, trans.arg, false);
10309 * Ext JS Library 1.1.1
10310 * Copyright(c) 2006-2007, Ext JS, LLC.
10312 * Originally Released Under LGPL - original licence link has changed is not relivant.
10315 * <script type="text/javascript">
10319 * @class Roo.data.JsonReader
10320 * @extends Roo.data.DataReader
10321 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10322 * based on mappings in a provided Roo.data.Record constructor.
10324 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10325 * in the reply previously.
10330 var RecordDef = Roo.data.Record.create([
10331 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10332 {name: 'occupation'} // This field will use "occupation" as the mapping.
10334 var myReader = new Roo.data.JsonReader({
10335 totalProperty: "results", // The property which contains the total dataset size (optional)
10336 root: "rows", // The property which contains an Array of row objects
10337 id: "id" // The property within each row object that provides an ID for the record (optional)
10341 * This would consume a JSON file like this:
10343 { 'results': 2, 'rows': [
10344 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10345 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10348 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10349 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10350 * paged from the remote server.
10351 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10352 * @cfg {String} root name of the property which contains the Array of row objects.
10353 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10355 * Create a new JsonReader
10356 * @param {Object} meta Metadata configuration options
10357 * @param {Object} recordType Either an Array of field definition objects,
10358 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10360 Roo.data.JsonReader = function(meta, recordType){
10363 // set some defaults:
10364 Roo.applyIf(meta, {
10365 totalProperty: 'total',
10366 successProperty : 'success',
10371 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10373 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10376 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10377 * Used by Store query builder to append _requestMeta to params.
10380 metaFromRemote : false,
10382 * This method is only used by a DataProxy which has retrieved data from a remote server.
10383 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10384 * @return {Object} data A data block which is used by an Roo.data.Store object as
10385 * a cache of Roo.data.Records.
10387 read : function(response){
10388 var json = response.responseText;
10390 var o = /* eval:var:o */ eval("("+json+")");
10392 throw {message: "JsonReader.read: Json object not found"};
10398 this.metaFromRemote = true;
10399 this.meta = o.metaData;
10400 this.recordType = Roo.data.Record.create(o.metaData.fields);
10401 this.onMetaChange(this.meta, this.recordType, o);
10403 return this.readRecords(o);
10406 // private function a store will implement
10407 onMetaChange : function(meta, recordType, o){
10414 simpleAccess: function(obj, subsc) {
10421 getJsonAccessor: function(){
10423 return function(expr) {
10425 return(re.test(expr))
10426 ? new Function("obj", "return obj." + expr)
10431 return Roo.emptyFn;
10436 * Create a data block containing Roo.data.Records from an XML document.
10437 * @param {Object} o An object which contains an Array of row objects in the property specified
10438 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10439 * which contains the total size of the dataset.
10440 * @return {Object} data A data block which is used by an Roo.data.Store object as
10441 * a cache of Roo.data.Records.
10443 readRecords : function(o){
10445 * After any data loads, the raw JSON data is available for further custom processing.
10449 var s = this.meta, Record = this.recordType,
10450 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10452 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10454 if(s.totalProperty) {
10455 this.getTotal = this.getJsonAccessor(s.totalProperty);
10457 if(s.successProperty) {
10458 this.getSuccess = this.getJsonAccessor(s.successProperty);
10460 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10462 var g = this.getJsonAccessor(s.id);
10463 this.getId = function(rec) {
10465 return (r === undefined || r === "") ? null : r;
10468 this.getId = function(){return null;};
10471 for(var jj = 0; jj < fl; jj++){
10473 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10474 this.ef[jj] = this.getJsonAccessor(map);
10478 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10479 if(s.totalProperty){
10480 var vt = parseInt(this.getTotal(o), 10);
10485 if(s.successProperty){
10486 var vs = this.getSuccess(o);
10487 if(vs === false || vs === 'false'){
10492 for(var i = 0; i < c; i++){
10495 var id = this.getId(n);
10496 for(var j = 0; j < fl; j++){
10498 var v = this.ef[j](n);
10500 Roo.log('missing convert for ' + f.name);
10504 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10506 var record = new Record(values, id);
10508 records[i] = record;
10514 totalRecords : totalRecords
10519 * Ext JS Library 1.1.1
10520 * Copyright(c) 2006-2007, Ext JS, LLC.
10522 * Originally Released Under LGPL - original licence link has changed is not relivant.
10525 * <script type="text/javascript">
10529 * @class Roo.data.ArrayReader
10530 * @extends Roo.data.DataReader
10531 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10532 * Each element of that Array represents a row of data fields. The
10533 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10534 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10538 var RecordDef = Roo.data.Record.create([
10539 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10540 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10542 var myReader = new Roo.data.ArrayReader({
10543 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10547 * This would consume an Array like this:
10549 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10551 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10553 * Create a new JsonReader
10554 * @param {Object} meta Metadata configuration options.
10555 * @param {Object} recordType Either an Array of field definition objects
10556 * as specified to {@link Roo.data.Record#create},
10557 * or an {@link Roo.data.Record} object
10558 * created using {@link Roo.data.Record#create}.
10560 Roo.data.ArrayReader = function(meta, recordType){
10561 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10564 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10566 * Create a data block containing Roo.data.Records from an XML document.
10567 * @param {Object} o An Array of row objects which represents the dataset.
10568 * @return {Object} data A data block which is used by an Roo.data.Store object as
10569 * a cache of Roo.data.Records.
10571 readRecords : function(o){
10572 var sid = this.meta ? this.meta.id : null;
10573 var recordType = this.recordType, fields = recordType.prototype.fields;
10576 for(var i = 0; i < root.length; i++){
10579 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10580 for(var j = 0, jlen = fields.length; j < jlen; j++){
10581 var f = fields.items[j];
10582 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10583 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10585 values[f.name] = v;
10587 var record = new recordType(values, id);
10589 records[records.length] = record;
10593 totalRecords : records.length
10602 * @class Roo.bootstrap.ComboBox
10603 * @extends Roo.bootstrap.TriggerField
10604 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10605 * @cfg {Boolean} append (true|false) default false
10606 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10607 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10608 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10609 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10610 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10612 * Create a new ComboBox.
10613 * @param {Object} config Configuration options
10615 Roo.bootstrap.ComboBox = function(config){
10616 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10620 * Fires when the dropdown list is expanded
10621 * @param {Roo.bootstrap.ComboBox} combo This combo box
10626 * Fires when the dropdown list is collapsed
10627 * @param {Roo.bootstrap.ComboBox} combo This combo box
10631 * @event beforeselect
10632 * Fires before a list item is selected. Return false to cancel the selection.
10633 * @param {Roo.bootstrap.ComboBox} combo This combo box
10634 * @param {Roo.data.Record} record The data record returned from the underlying store
10635 * @param {Number} index The index of the selected item in the dropdown list
10637 'beforeselect' : true,
10640 * Fires when a list item is selected
10641 * @param {Roo.bootstrap.ComboBox} combo This combo box
10642 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10643 * @param {Number} index The index of the selected item in the dropdown list
10647 * @event beforequery
10648 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10649 * The event object passed has these properties:
10650 * @param {Roo.bootstrap.ComboBox} combo This combo box
10651 * @param {String} query The query
10652 * @param {Boolean} forceAll true to force "all" query
10653 * @param {Boolean} cancel true to cancel the query
10654 * @param {Object} e The query event object
10656 'beforequery': true,
10659 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10660 * @param {Roo.bootstrap.ComboBox} combo This combo box
10665 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10666 * @param {Roo.bootstrap.ComboBox} combo This combo box
10667 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10672 * Fires when the remove value from the combobox array
10673 * @param {Roo.bootstrap.ComboBox} combo This combo box
10680 this.tickItems = [];
10682 this.selectedIndex = -1;
10683 if(this.mode == 'local'){
10684 if(config.queryDelay === undefined){
10685 this.queryDelay = 10;
10687 if(config.minChars === undefined){
10693 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10696 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10697 * rendering into an Roo.Editor, defaults to false)
10700 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10701 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10704 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10707 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10708 * the dropdown list (defaults to undefined, with no header element)
10712 * @cfg {String/Roo.Template} tpl The template to use to render the output
10716 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10718 listWidth: undefined,
10720 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10721 * mode = 'remote' or 'text' if mode = 'local')
10723 displayField: undefined,
10725 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10726 * mode = 'remote' or 'value' if mode = 'local').
10727 * Note: use of a valueField requires the user make a selection
10728 * in order for a value to be mapped.
10730 valueField: undefined,
10734 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10735 * field's data value (defaults to the underlying DOM element's name)
10737 hiddenName: undefined,
10739 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10743 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10745 selectedClass: 'active',
10748 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10752 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10753 * anchor positions (defaults to 'tl-bl')
10755 listAlign: 'tl-bl?',
10757 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10761 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10762 * query specified by the allQuery config option (defaults to 'query')
10764 triggerAction: 'query',
10766 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10767 * (defaults to 4, does not apply if editable = false)
10771 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10772 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10776 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10777 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10781 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10782 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10786 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10787 * when editable = true (defaults to false)
10789 selectOnFocus:false,
10791 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10793 queryParam: 'query',
10795 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10796 * when mode = 'remote' (defaults to 'Loading...')
10798 loadingText: 'Loading...',
10800 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10804 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10808 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10809 * traditional select (defaults to true)
10813 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10817 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10821 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10822 * listWidth has a higher value)
10826 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10827 * allow the user to set arbitrary text into the field (defaults to false)
10829 forceSelection:false,
10831 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10832 * if typeAhead = true (defaults to 250)
10834 typeAheadDelay : 250,
10836 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10837 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10839 valueNotFoundText : undefined,
10841 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10843 blockFocus : false,
10846 * @cfg {Boolean} disableClear Disable showing of clear button.
10848 disableClear : false,
10850 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10852 alwaysQuery : false,
10855 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10860 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10862 invalidClass : "has-warning",
10865 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10867 validClass : "has-success",
10879 btnPosition : 'right',
10880 triggerList : true,
10881 showToggleBtn : true,
10882 // element that contains real text value.. (when hidden is used..)
10884 getAutoCreate : function()
10891 if(!this.tickable){
10892 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10897 * ComboBox with tickable selections
10900 var align = this.labelAlign || this.parentLabelAlign();
10903 cls : 'form-group roo-combobox-tickable' //input-group
10909 cls : 'tickable-buttons',
10914 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10921 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10928 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10935 Roo.each(buttons.cn, function(c){
10937 c.cls += ' btn-' + _this.size;
10940 if (_this.disabled) {
10951 cls: 'form-hidden-field'
10955 cls: 'select2-choices',
10959 cls: 'select2-search-field',
10971 cls: 'select2-container input-group select2-container-multi',
10976 // cls: 'typeahead typeahead-long dropdown-menu',
10977 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10982 if(this.hasFeedback && !this.allowBlank){
10986 cls: 'glyphicon form-control-feedback'
10989 combobox.cn.push(feedback);
10992 if (align ==='left' && this.fieldLabel.length) {
10994 Roo.log("left and has label");
11000 cls : 'control-label col-sm-' + this.labelWidth,
11001 html : this.fieldLabel
11005 cls : "col-sm-" + (12 - this.labelWidth),
11012 } else if ( this.fieldLabel.length) {
11018 //cls : 'input-group-addon',
11019 html : this.fieldLabel
11029 Roo.log(" no label && no align");
11036 ['xs','sm','md','lg'].map(function(size){
11037 if (settings[size]) {
11038 cfg.cls += ' col-' + size + '-' + settings[size];
11047 initEvents: function()
11051 throw "can not find store for combo";
11053 this.store = Roo.factory(this.store, Roo.data);
11056 this.initTickableEvents();
11060 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11062 if(this.hiddenName){
11064 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11066 this.hiddenField.dom.value =
11067 this.hiddenValue !== undefined ? this.hiddenValue :
11068 this.value !== undefined ? this.value : '';
11070 // prevent input submission
11071 this.el.dom.removeAttribute('name');
11072 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11077 // this.el.dom.setAttribute('autocomplete', 'off');
11080 var cls = 'x-combo-list';
11082 //this.list = new Roo.Layer({
11083 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11089 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11090 _this.list.setWidth(lw);
11093 this.list.on('mouseover', this.onViewOver, this);
11094 this.list.on('mousemove', this.onViewMove, this);
11096 this.list.on('scroll', this.onViewScroll, this);
11099 this.list.swallowEvent('mousewheel');
11100 this.assetHeight = 0;
11103 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11104 this.assetHeight += this.header.getHeight();
11107 this.innerList = this.list.createChild({cls:cls+'-inner'});
11108 this.innerList.on('mouseover', this.onViewOver, this);
11109 this.innerList.on('mousemove', this.onViewMove, this);
11110 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11112 if(this.allowBlank && !this.pageSize && !this.disableClear){
11113 this.footer = this.list.createChild({cls:cls+'-ft'});
11114 this.pageTb = new Roo.Toolbar(this.footer);
11118 this.footer = this.list.createChild({cls:cls+'-ft'});
11119 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11120 {pageSize: this.pageSize});
11124 if (this.pageTb && this.allowBlank && !this.disableClear) {
11126 this.pageTb.add(new Roo.Toolbar.Fill(), {
11127 cls: 'x-btn-icon x-btn-clear',
11129 handler: function()
11132 _this.clearValue();
11133 _this.onSelect(false, -1);
11138 this.assetHeight += this.footer.getHeight();
11143 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11146 this.view = new Roo.View(this.list, this.tpl, {
11147 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11149 //this.view.wrapEl.setDisplayed(false);
11150 this.view.on('click', this.onViewClick, this);
11154 this.store.on('beforeload', this.onBeforeLoad, this);
11155 this.store.on('load', this.onLoad, this);
11156 this.store.on('loadexception', this.onLoadException, this);
11158 if(this.resizable){
11159 this.resizer = new Roo.Resizable(this.list, {
11160 pinned:true, handles:'se'
11162 this.resizer.on('resize', function(r, w, h){
11163 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11164 this.listWidth = w;
11165 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11166 this.restrictHeight();
11168 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11171 if(!this.editable){
11172 this.editable = true;
11173 this.setEditable(false);
11178 if (typeof(this.events.add.listeners) != 'undefined') {
11180 this.addicon = this.wrap.createChild(
11181 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11183 this.addicon.on('click', function(e) {
11184 this.fireEvent('add', this);
11187 if (typeof(this.events.edit.listeners) != 'undefined') {
11189 this.editicon = this.wrap.createChild(
11190 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11191 if (this.addicon) {
11192 this.editicon.setStyle('margin-left', '40px');
11194 this.editicon.on('click', function(e) {
11196 // we fire even if inothing is selected..
11197 this.fireEvent('edit', this, this.lastData );
11203 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11204 "up" : function(e){
11205 this.inKeyMode = true;
11209 "down" : function(e){
11210 if(!this.isExpanded()){
11211 this.onTriggerClick();
11213 this.inKeyMode = true;
11218 "enter" : function(e){
11219 // this.onViewClick();
11223 if(this.fireEvent("specialkey", this, e)){
11224 this.onViewClick(false);
11230 "esc" : function(e){
11234 "tab" : function(e){
11237 if(this.fireEvent("specialkey", this, e)){
11238 this.onViewClick(false);
11246 doRelay : function(foo, bar, hname){
11247 if(hname == 'down' || this.scope.isExpanded()){
11248 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11257 this.queryDelay = Math.max(this.queryDelay || 10,
11258 this.mode == 'local' ? 10 : 250);
11261 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11263 if(this.typeAhead){
11264 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11266 if(this.editable !== false){
11267 this.inputEl().on("keyup", this.onKeyUp, this);
11269 if(this.forceSelection){
11270 this.inputEl().on('blur', this.doForce, this);
11274 this.choices = this.el.select('ul.select2-choices', true).first();
11275 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11279 initTickableEvents: function()
11283 if(this.hiddenName){
11285 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11287 this.hiddenField.dom.value =
11288 this.hiddenValue !== undefined ? this.hiddenValue :
11289 this.value !== undefined ? this.value : '';
11291 // prevent input submission
11292 this.el.dom.removeAttribute('name');
11293 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11298 // this.list = this.el.select('ul.dropdown-menu',true).first();
11300 this.choices = this.el.select('ul.select2-choices', true).first();
11301 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11302 if(this.triggerList){
11303 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11306 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11307 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11309 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11310 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11312 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11313 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11315 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11316 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11317 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11320 this.cancelBtn.hide();
11325 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11326 _this.list.setWidth(lw);
11329 this.list.on('mouseover', this.onViewOver, this);
11330 this.list.on('mousemove', this.onViewMove, this);
11332 this.list.on('scroll', this.onViewScroll, this);
11335 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>';
11338 this.view = new Roo.View(this.list, this.tpl, {
11339 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11342 //this.view.wrapEl.setDisplayed(false);
11343 this.view.on('click', this.onViewClick, this);
11347 this.store.on('beforeload', this.onBeforeLoad, this);
11348 this.store.on('load', this.onLoad, this);
11349 this.store.on('loadexception', this.onLoadException, this);
11351 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11352 // "up" : function(e){
11353 // this.inKeyMode = true;
11354 // this.selectPrev();
11357 // "down" : function(e){
11358 // if(!this.isExpanded()){
11359 // this.onTriggerClick();
11361 // this.inKeyMode = true;
11362 // this.selectNext();
11366 // "enter" : function(e){
11367 //// this.onViewClick();
11369 // this.collapse();
11371 // if(this.fireEvent("specialkey", this, e)){
11372 // this.onViewClick(false);
11378 // "esc" : function(e){
11379 // this.collapse();
11382 // "tab" : function(e){
11383 // this.collapse();
11385 // if(this.fireEvent("specialkey", this, e)){
11386 // this.onViewClick(false);
11394 // doRelay : function(foo, bar, hname){
11395 // if(hname == 'down' || this.scope.isExpanded()){
11396 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11401 // forceKeyDown: true
11405 this.queryDelay = Math.max(this.queryDelay || 10,
11406 this.mode == 'local' ? 10 : 250);
11409 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11411 if(this.typeAhead){
11412 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11417 onDestroy : function(){
11419 this.view.setStore(null);
11420 this.view.el.removeAllListeners();
11421 this.view.el.remove();
11422 this.view.purgeListeners();
11425 this.list.dom.innerHTML = '';
11429 this.store.un('beforeload', this.onBeforeLoad, this);
11430 this.store.un('load', this.onLoad, this);
11431 this.store.un('loadexception', this.onLoadException, this);
11433 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11437 fireKey : function(e){
11438 if(e.isNavKeyPress() && !this.list.isVisible()){
11439 this.fireEvent("specialkey", this, e);
11444 onResize: function(w, h){
11445 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11447 // if(typeof w != 'number'){
11448 // // we do not handle it!?!?
11451 // var tw = this.trigger.getWidth();
11452 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11453 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11455 // this.inputEl().setWidth( this.adjustWidth('input', x));
11457 // //this.trigger.setStyle('left', x+'px');
11459 // if(this.list && this.listWidth === undefined){
11460 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11461 // this.list.setWidth(lw);
11462 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11470 * Allow or prevent the user from directly editing the field text. If false is passed,
11471 * the user will only be able to select from the items defined in the dropdown list. This method
11472 * is the runtime equivalent of setting the 'editable' config option at config time.
11473 * @param {Boolean} value True to allow the user to directly edit the field text
11475 setEditable : function(value){
11476 if(value == this.editable){
11479 this.editable = value;
11481 this.inputEl().dom.setAttribute('readOnly', true);
11482 this.inputEl().on('mousedown', this.onTriggerClick, this);
11483 this.inputEl().addClass('x-combo-noedit');
11485 this.inputEl().dom.setAttribute('readOnly', false);
11486 this.inputEl().un('mousedown', this.onTriggerClick, this);
11487 this.inputEl().removeClass('x-combo-noedit');
11493 onBeforeLoad : function(combo,opts){
11494 if(!this.hasFocus){
11498 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11500 this.restrictHeight();
11501 this.selectedIndex = -1;
11505 onLoad : function(){
11507 this.hasQuery = false;
11509 if(!this.hasFocus){
11513 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11514 this.loading.hide();
11517 if(this.store.getCount() > 0){
11519 // this.restrictHeight();
11520 if(this.lastQuery == this.allQuery){
11521 if(this.editable && !this.tickable){
11522 this.inputEl().dom.select();
11526 !this.selectByValue(this.value, true) &&
11527 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11528 this.store.lastOptions.add != true)
11530 this.select(0, true);
11533 if(this.autoFocus){
11536 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11537 this.taTask.delay(this.typeAheadDelay);
11541 this.onEmptyResults();
11547 onLoadException : function()
11549 this.hasQuery = false;
11551 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11552 this.loading.hide();
11556 Roo.log(this.store.reader.jsonData);
11557 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11559 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11565 onTypeAhead : function(){
11566 if(this.store.getCount() > 0){
11567 var r = this.store.getAt(0);
11568 var newValue = r.data[this.displayField];
11569 var len = newValue.length;
11570 var selStart = this.getRawValue().length;
11572 if(selStart != len){
11573 this.setRawValue(newValue);
11574 this.selectText(selStart, newValue.length);
11580 onSelect : function(record, index){
11582 if(this.fireEvent('beforeselect', this, record, index) !== false){
11584 this.setFromData(index > -1 ? record.data : false);
11587 this.fireEvent('select', this, record, index);
11592 * Returns the currently selected field value or empty string if no value is set.
11593 * @return {String} value The selected value
11595 getValue : function(){
11598 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11601 if(this.valueField){
11602 return typeof this.value != 'undefined' ? this.value : '';
11604 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11609 * Clears any text/value currently set in the field
11611 clearValue : function(){
11612 if(this.hiddenField){
11613 this.hiddenField.dom.value = '';
11616 this.setRawValue('');
11617 this.lastSelectionText = '';
11618 this.lastData = false;
11623 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11624 * will be displayed in the field. If the value does not match the data value of an existing item,
11625 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11626 * Otherwise the field will be blank (although the value will still be set).
11627 * @param {String} value The value to match
11629 setValue : function(v){
11636 if(this.valueField){
11637 var r = this.findRecord(this.valueField, v);
11639 text = r.data[this.displayField];
11640 }else if(this.valueNotFoundText !== undefined){
11641 text = this.valueNotFoundText;
11644 this.lastSelectionText = text;
11645 if(this.hiddenField){
11646 this.hiddenField.dom.value = v;
11648 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11652 * @property {Object} the last set data for the element
11657 * Sets the value of the field based on a object which is related to the record format for the store.
11658 * @param {Object} value the value to set as. or false on reset?
11660 setFromData : function(o){
11667 var dv = ''; // display value
11668 var vv = ''; // value value..
11670 if (this.displayField) {
11671 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11673 // this is an error condition!!!
11674 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11677 if(this.valueField){
11678 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11681 if(this.hiddenField){
11682 this.hiddenField.dom.value = vv;
11684 this.lastSelectionText = dv;
11685 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11689 // no hidden field.. - we store the value in 'value', but still display
11690 // display field!!!!
11691 this.lastSelectionText = dv;
11692 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11698 reset : function(){
11699 // overridden so that last data is reset..
11700 this.setValue(this.originalValue);
11701 this.clearInvalid();
11702 this.lastData = false;
11704 this.view.clearSelections();
11708 findRecord : function(prop, value){
11710 if(this.store.getCount() > 0){
11711 this.store.each(function(r){
11712 if(r.data[prop] == value){
11722 getName: function()
11724 // returns hidden if it's set..
11725 if (!this.rendered) {return ''};
11726 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11730 onViewMove : function(e, t){
11731 this.inKeyMode = false;
11735 onViewOver : function(e, t){
11736 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11739 var item = this.view.findItemFromChild(t);
11742 var index = this.view.indexOf(item);
11743 this.select(index, false);
11748 onViewClick : function(view, doFocus, el, e)
11750 var index = this.view.getSelectedIndexes()[0];
11752 var r = this.store.getAt(index);
11756 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11763 Roo.each(this.tickItems, function(v,k){
11765 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11766 _this.tickItems.splice(k, 1);
11776 this.tickItems.push(r.data);
11781 this.onSelect(r, index);
11783 if(doFocus !== false && !this.blockFocus){
11784 this.inputEl().focus();
11789 restrictHeight : function(){
11790 //this.innerList.dom.style.height = '';
11791 //var inner = this.innerList.dom;
11792 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11793 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11794 //this.list.beginUpdate();
11795 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11796 this.list.alignTo(this.inputEl(), this.listAlign);
11797 this.list.alignTo(this.inputEl(), this.listAlign);
11798 //this.list.endUpdate();
11802 onEmptyResults : function(){
11807 * Returns true if the dropdown list is expanded, else false.
11809 isExpanded : function(){
11810 return this.list.isVisible();
11814 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11815 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11816 * @param {String} value The data value of the item to select
11817 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11818 * selected item if it is not currently in view (defaults to true)
11819 * @return {Boolean} True if the value matched an item in the list, else false
11821 selectByValue : function(v, scrollIntoView){
11822 if(v !== undefined && v !== null){
11823 var r = this.findRecord(this.valueField || this.displayField, v);
11825 this.select(this.store.indexOf(r), scrollIntoView);
11833 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11834 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11835 * @param {Number} index The zero-based index of the list item to select
11836 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11837 * selected item if it is not currently in view (defaults to true)
11839 select : function(index, scrollIntoView){
11840 this.selectedIndex = index;
11841 this.view.select(index);
11842 if(scrollIntoView !== false){
11843 var el = this.view.getNode(index);
11844 if(el && !this.multiple && !this.tickable){
11845 this.list.scrollChildIntoView(el, false);
11851 selectNext : function(){
11852 var ct = this.store.getCount();
11854 if(this.selectedIndex == -1){
11856 }else if(this.selectedIndex < ct-1){
11857 this.select(this.selectedIndex+1);
11863 selectPrev : function(){
11864 var ct = this.store.getCount();
11866 if(this.selectedIndex == -1){
11868 }else if(this.selectedIndex != 0){
11869 this.select(this.selectedIndex-1);
11875 onKeyUp : function(e){
11876 if(this.editable !== false && !e.isSpecialKey()){
11877 this.lastKey = e.getKey();
11878 this.dqTask.delay(this.queryDelay);
11883 validateBlur : function(){
11884 return !this.list || !this.list.isVisible();
11888 initQuery : function(){
11889 this.doQuery(this.getRawValue());
11893 doForce : function(){
11894 if(this.inputEl().dom.value.length > 0){
11895 this.inputEl().dom.value =
11896 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11902 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11903 * query allowing the query action to be canceled if needed.
11904 * @param {String} query The SQL query to execute
11905 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11906 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11907 * saved in the current store (defaults to false)
11909 doQuery : function(q, forceAll){
11911 if(q === undefined || q === null){
11916 forceAll: forceAll,
11920 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11925 forceAll = qe.forceAll;
11926 if(forceAll === true || (q.length >= this.minChars)){
11928 this.hasQuery = true;
11930 if(this.lastQuery != q || this.alwaysQuery){
11931 this.lastQuery = q;
11932 if(this.mode == 'local'){
11933 this.selectedIndex = -1;
11935 this.store.clearFilter();
11937 this.store.filter(this.displayField, q);
11941 this.store.baseParams[this.queryParam] = q;
11943 var options = {params : this.getParams(q)};
11946 options.add = true;
11947 options.params.start = this.page * this.pageSize;
11950 this.store.load(options);
11952 * this code will make the page width larger, at the beginning, the list not align correctly,
11953 * we should expand the list on onLoad
11954 * so command out it
11959 this.selectedIndex = -1;
11964 this.loadNext = false;
11968 getParams : function(q){
11970 //p[this.queryParam] = q;
11974 p.limit = this.pageSize;
11980 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11982 collapse : function(){
11983 if(!this.isExpanded()){
11990 this.hasFocus = false;
11992 this.cancelBtn.hide();
11993 this.trigger.show();
11996 Roo.get(document).un('mousedown', this.collapseIf, this);
11997 Roo.get(document).un('mousewheel', this.collapseIf, this);
11998 if (!this.editable) {
11999 Roo.get(document).un('keydown', this.listKeyPress, this);
12001 this.fireEvent('collapse', this);
12005 collapseIf : function(e){
12006 var in_combo = e.within(this.el);
12007 var in_list = e.within(this.list);
12008 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12010 if (in_combo || in_list || is_list) {
12011 //e.stopPropagation();
12016 this.onTickableFooterButtonClick(e, false, false);
12024 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12026 expand : function(){
12028 if(this.isExpanded() || !this.hasFocus){
12032 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12033 this.list.setWidth(lw);
12040 this.restrictHeight();
12044 this.tickItems = Roo.apply([], this.item);
12047 this.cancelBtn.show();
12048 this.trigger.hide();
12052 Roo.get(document).on('mousedown', this.collapseIf, this);
12053 Roo.get(document).on('mousewheel', this.collapseIf, this);
12054 if (!this.editable) {
12055 Roo.get(document).on('keydown', this.listKeyPress, this);
12058 this.fireEvent('expand', this);
12062 // Implements the default empty TriggerField.onTriggerClick function
12063 onTriggerClick : function(e)
12065 Roo.log('trigger click');
12067 if(this.disabled || !this.triggerList){
12072 this.loadNext = false;
12074 if(this.isExpanded()){
12076 if (!this.blockFocus) {
12077 this.inputEl().focus();
12081 this.hasFocus = true;
12082 if(this.triggerAction == 'all') {
12083 this.doQuery(this.allQuery, true);
12085 this.doQuery(this.getRawValue());
12087 if (!this.blockFocus) {
12088 this.inputEl().focus();
12093 onTickableTriggerClick : function(e)
12100 this.loadNext = false;
12101 this.hasFocus = true;
12103 if(this.triggerAction == 'all') {
12104 this.doQuery(this.allQuery, true);
12106 this.doQuery(this.getRawValue());
12110 onSearchFieldClick : function(e)
12112 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12113 this.onTickableFooterButtonClick(e, false, false);
12117 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12122 this.loadNext = false;
12123 this.hasFocus = true;
12125 if(this.triggerAction == 'all') {
12126 this.doQuery(this.allQuery, true);
12128 this.doQuery(this.getRawValue());
12132 listKeyPress : function(e)
12134 //Roo.log('listkeypress');
12135 // scroll to first matching element based on key pres..
12136 if (e.isSpecialKey()) {
12139 var k = String.fromCharCode(e.getKey()).toUpperCase();
12142 var csel = this.view.getSelectedNodes();
12143 var cselitem = false;
12145 var ix = this.view.indexOf(csel[0]);
12146 cselitem = this.store.getAt(ix);
12147 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12153 this.store.each(function(v) {
12155 // start at existing selection.
12156 if (cselitem.id == v.id) {
12162 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12163 match = this.store.indexOf(v);
12169 if (match === false) {
12170 return true; // no more action?
12173 this.view.select(match);
12174 var sn = Roo.get(this.view.getSelectedNodes()[0])
12175 sn.scrollIntoView(sn.dom.parentNode, false);
12178 onViewScroll : function(e, t){
12180 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){
12184 this.hasQuery = true;
12186 this.loading = this.list.select('.loading', true).first();
12188 if(this.loading === null){
12189 this.list.createChild({
12191 cls: 'loading select2-more-results select2-active',
12192 html: 'Loading more results...'
12195 this.loading = this.list.select('.loading', true).first();
12197 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12199 this.loading.hide();
12202 this.loading.show();
12207 this.loadNext = true;
12209 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12214 addItem : function(o)
12216 var dv = ''; // display value
12218 if (this.displayField) {
12219 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12221 // this is an error condition!!!
12222 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12229 var choice = this.choices.createChild({
12231 cls: 'select2-search-choice',
12240 cls: 'select2-search-choice-close',
12245 }, this.searchField);
12247 var close = choice.select('a.select2-search-choice-close', true).first()
12249 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12257 this.inputEl().dom.value = '';
12262 onRemoveItem : function(e, _self, o)
12264 e.preventDefault();
12266 this.lastItem = Roo.apply([], this.item);
12268 var index = this.item.indexOf(o.data) * 1;
12271 Roo.log('not this item?!');
12275 this.item.splice(index, 1);
12280 this.fireEvent('remove', this, e);
12286 syncValue : function()
12288 if(!this.item.length){
12295 Roo.each(this.item, function(i){
12296 if(_this.valueField){
12297 value.push(i[_this.valueField]);
12304 this.value = value.join(',');
12306 if(this.hiddenField){
12307 this.hiddenField.dom.value = this.value;
12311 clearItem : function()
12313 if(!this.multiple){
12319 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12328 inputEl: function ()
12331 return this.searchField;
12333 return this.el.select('input.form-control',true).first();
12337 onTickableFooterButtonClick : function(e, btn, el)
12339 e.preventDefault();
12341 this.lastItem = Roo.apply([], this.item);
12343 if(btn && btn.name == 'cancel'){
12344 this.tickItems = Roo.apply([], this.item);
12353 Roo.each(this.tickItems, function(o){
12361 validate : function()
12363 var v = this.getRawValue();
12366 v = this.getValue();
12369 if(this.disabled || this.allowBlank || v.length){
12374 this.markInvalid();
12381 * @cfg {Boolean} grow
12385 * @cfg {Number} growMin
12389 * @cfg {Number} growMax
12399 * Ext JS Library 1.1.1
12400 * Copyright(c) 2006-2007, Ext JS, LLC.
12402 * Originally Released Under LGPL - original licence link has changed is not relivant.
12405 * <script type="text/javascript">
12410 * @extends Roo.util.Observable
12411 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12412 * This class also supports single and multi selection modes. <br>
12413 * Create a data model bound view:
12415 var store = new Roo.data.Store(...);
12417 var view = new Roo.View({
12419 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12421 singleSelect: true,
12422 selectedClass: "ydataview-selected",
12426 // listen for node click?
12427 view.on("click", function(vw, index, node, e){
12428 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12432 dataModel.load("foobar.xml");
12434 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12436 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12437 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12439 * Note: old style constructor is still suported (container, template, config)
12442 * Create a new View
12443 * @param {Object} config The config object
12446 Roo.View = function(config, depreciated_tpl, depreciated_config){
12448 this.parent = false;
12450 if (typeof(depreciated_tpl) == 'undefined') {
12451 // new way.. - universal constructor.
12452 Roo.apply(this, config);
12453 this.el = Roo.get(this.el);
12456 this.el = Roo.get(config);
12457 this.tpl = depreciated_tpl;
12458 Roo.apply(this, depreciated_config);
12460 this.wrapEl = this.el.wrap().wrap();
12461 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12464 if(typeof(this.tpl) == "string"){
12465 this.tpl = new Roo.Template(this.tpl);
12467 // support xtype ctors..
12468 this.tpl = new Roo.factory(this.tpl, Roo);
12472 this.tpl.compile();
12477 * @event beforeclick
12478 * Fires before a click is processed. Returns false to cancel the default action.
12479 * @param {Roo.View} this
12480 * @param {Number} index The index of the target node
12481 * @param {HTMLElement} node The target node
12482 * @param {Roo.EventObject} e The raw event object
12484 "beforeclick" : true,
12487 * Fires when a template node is clicked.
12488 * @param {Roo.View} this
12489 * @param {Number} index The index of the target node
12490 * @param {HTMLElement} node The target node
12491 * @param {Roo.EventObject} e The raw event object
12496 * Fires when a template node is double clicked.
12497 * @param {Roo.View} this
12498 * @param {Number} index The index of the target node
12499 * @param {HTMLElement} node The target node
12500 * @param {Roo.EventObject} e The raw event object
12504 * @event contextmenu
12505 * Fires when a template node is right clicked.
12506 * @param {Roo.View} this
12507 * @param {Number} index The index of the target node
12508 * @param {HTMLElement} node The target node
12509 * @param {Roo.EventObject} e The raw event object
12511 "contextmenu" : true,
12513 * @event selectionchange
12514 * Fires when the selected nodes change.
12515 * @param {Roo.View} this
12516 * @param {Array} selections Array of the selected nodes
12518 "selectionchange" : true,
12521 * @event beforeselect
12522 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12523 * @param {Roo.View} this
12524 * @param {HTMLElement} node The node to be selected
12525 * @param {Array} selections Array of currently selected nodes
12527 "beforeselect" : true,
12529 * @event preparedata
12530 * Fires on every row to render, to allow you to change the data.
12531 * @param {Roo.View} this
12532 * @param {Object} data to be rendered (change this)
12534 "preparedata" : true
12542 "click": this.onClick,
12543 "dblclick": this.onDblClick,
12544 "contextmenu": this.onContextMenu,
12548 this.selections = [];
12550 this.cmp = new Roo.CompositeElementLite([]);
12552 this.store = Roo.factory(this.store, Roo.data);
12553 this.setStore(this.store, true);
12556 if ( this.footer && this.footer.xtype) {
12558 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12560 this.footer.dataSource = this.store
12561 this.footer.container = fctr;
12562 this.footer = Roo.factory(this.footer, Roo);
12563 fctr.insertFirst(this.el);
12565 // this is a bit insane - as the paging toolbar seems to detach the el..
12566 // dom.parentNode.parentNode.parentNode
12567 // they get detached?
12571 Roo.View.superclass.constructor.call(this);
12576 Roo.extend(Roo.View, Roo.util.Observable, {
12579 * @cfg {Roo.data.Store} store Data store to load data from.
12584 * @cfg {String|Roo.Element} el The container element.
12589 * @cfg {String|Roo.Template} tpl The template used by this View
12593 * @cfg {String} dataName the named area of the template to use as the data area
12594 * Works with domtemplates roo-name="name"
12598 * @cfg {String} selectedClass The css class to add to selected nodes
12600 selectedClass : "x-view-selected",
12602 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12607 * @cfg {String} text to display on mask (default Loading)
12611 * @cfg {Boolean} multiSelect Allow multiple selection
12613 multiSelect : false,
12615 * @cfg {Boolean} singleSelect Allow single selection
12617 singleSelect: false,
12620 * @cfg {Boolean} toggleSelect - selecting
12622 toggleSelect : false,
12625 * @cfg {Boolean} tickable - selecting
12630 * Returns the element this view is bound to.
12631 * @return {Roo.Element}
12633 getEl : function(){
12634 return this.wrapEl;
12640 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12642 refresh : function(){
12643 //Roo.log('refresh');
12646 // if we are using something like 'domtemplate', then
12647 // the what gets used is:
12648 // t.applySubtemplate(NAME, data, wrapping data..)
12649 // the outer template then get' applied with
12650 // the store 'extra data'
12651 // and the body get's added to the
12652 // roo-name="data" node?
12653 // <span class='roo-tpl-{name}'></span> ?????
12657 this.clearSelections();
12658 this.el.update("");
12660 var records = this.store.getRange();
12661 if(records.length < 1) {
12663 // is this valid?? = should it render a template??
12665 this.el.update(this.emptyText);
12669 if (this.dataName) {
12670 this.el.update(t.apply(this.store.meta)); //????
12671 el = this.el.child('.roo-tpl-' + this.dataName);
12674 for(var i = 0, len = records.length; i < len; i++){
12675 var data = this.prepareData(records[i].data, i, records[i]);
12676 this.fireEvent("preparedata", this, data, i, records[i]);
12678 var d = Roo.apply({}, data);
12681 Roo.apply(d, {'roo-id' : Roo.id()});
12685 Roo.each(this.parent.item, function(item){
12686 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12689 Roo.apply(d, {'roo-data-checked' : 'checked'});
12693 html[html.length] = Roo.util.Format.trim(
12695 t.applySubtemplate(this.dataName, d, this.store.meta) :
12702 el.update(html.join(""));
12703 this.nodes = el.dom.childNodes;
12704 this.updateIndexes(0);
12709 * Function to override to reformat the data that is sent to
12710 * the template for each node.
12711 * DEPRICATED - use the preparedata event handler.
12712 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12713 * a JSON object for an UpdateManager bound view).
12715 prepareData : function(data, index, record)
12717 this.fireEvent("preparedata", this, data, index, record);
12721 onUpdate : function(ds, record){
12722 // Roo.log('on update');
12723 this.clearSelections();
12724 var index = this.store.indexOf(record);
12725 var n = this.nodes[index];
12726 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12727 n.parentNode.removeChild(n);
12728 this.updateIndexes(index, index);
12734 onAdd : function(ds, records, index)
12736 //Roo.log(['on Add', ds, records, index] );
12737 this.clearSelections();
12738 if(this.nodes.length == 0){
12742 var n = this.nodes[index];
12743 for(var i = 0, len = records.length; i < len; i++){
12744 var d = this.prepareData(records[i].data, i, records[i]);
12746 this.tpl.insertBefore(n, d);
12749 this.tpl.append(this.el, d);
12752 this.updateIndexes(index);
12755 onRemove : function(ds, record, index){
12756 // Roo.log('onRemove');
12757 this.clearSelections();
12758 var el = this.dataName ?
12759 this.el.child('.roo-tpl-' + this.dataName) :
12762 el.dom.removeChild(this.nodes[index]);
12763 this.updateIndexes(index);
12767 * Refresh an individual node.
12768 * @param {Number} index
12770 refreshNode : function(index){
12771 this.onUpdate(this.store, this.store.getAt(index));
12774 updateIndexes : function(startIndex, endIndex){
12775 var ns = this.nodes;
12776 startIndex = startIndex || 0;
12777 endIndex = endIndex || ns.length - 1;
12778 for(var i = startIndex; i <= endIndex; i++){
12779 ns[i].nodeIndex = i;
12784 * Changes the data store this view uses and refresh the view.
12785 * @param {Store} store
12787 setStore : function(store, initial){
12788 if(!initial && this.store){
12789 this.store.un("datachanged", this.refresh);
12790 this.store.un("add", this.onAdd);
12791 this.store.un("remove", this.onRemove);
12792 this.store.un("update", this.onUpdate);
12793 this.store.un("clear", this.refresh);
12794 this.store.un("beforeload", this.onBeforeLoad);
12795 this.store.un("load", this.onLoad);
12796 this.store.un("loadexception", this.onLoad);
12800 store.on("datachanged", this.refresh, this);
12801 store.on("add", this.onAdd, this);
12802 store.on("remove", this.onRemove, this);
12803 store.on("update", this.onUpdate, this);
12804 store.on("clear", this.refresh, this);
12805 store.on("beforeload", this.onBeforeLoad, this);
12806 store.on("load", this.onLoad, this);
12807 store.on("loadexception", this.onLoad, this);
12815 * onbeforeLoad - masks the loading area.
12818 onBeforeLoad : function(store,opts)
12820 //Roo.log('onBeforeLoad');
12822 this.el.update("");
12824 this.el.mask(this.mask ? this.mask : "Loading" );
12826 onLoad : function ()
12833 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12834 * @param {HTMLElement} node
12835 * @return {HTMLElement} The template node
12837 findItemFromChild : function(node){
12838 var el = this.dataName ?
12839 this.el.child('.roo-tpl-' + this.dataName,true) :
12842 if(!node || node.parentNode == el){
12845 var p = node.parentNode;
12846 while(p && p != el){
12847 if(p.parentNode == el){
12856 onClick : function(e){
12857 var item = this.findItemFromChild(e.getTarget());
12859 var index = this.indexOf(item);
12860 if(this.onItemClick(item, index, e) !== false){
12861 this.fireEvent("click", this, index, item, e);
12864 this.clearSelections();
12869 onContextMenu : function(e){
12870 var item = this.findItemFromChild(e.getTarget());
12872 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12877 onDblClick : function(e){
12878 var item = this.findItemFromChild(e.getTarget());
12880 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12884 onItemClick : function(item, index, e)
12886 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12889 if (this.toggleSelect) {
12890 var m = this.isSelected(item) ? 'unselect' : 'select';
12893 _t[m](item, true, false);
12896 if(this.multiSelect || this.singleSelect){
12897 if(this.multiSelect && e.shiftKey && this.lastSelection){
12898 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12900 this.select(item, this.multiSelect && e.ctrlKey);
12901 this.lastSelection = item;
12904 if(!this.tickable){
12905 e.preventDefault();
12913 * Get the number of selected nodes.
12916 getSelectionCount : function(){
12917 return this.selections.length;
12921 * Get the currently selected nodes.
12922 * @return {Array} An array of HTMLElements
12924 getSelectedNodes : function(){
12925 return this.selections;
12929 * Get the indexes of the selected nodes.
12932 getSelectedIndexes : function(){
12933 var indexes = [], s = this.selections;
12934 for(var i = 0, len = s.length; i < len; i++){
12935 indexes.push(s[i].nodeIndex);
12941 * Clear all selections
12942 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12944 clearSelections : function(suppressEvent){
12945 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12946 this.cmp.elements = this.selections;
12947 this.cmp.removeClass(this.selectedClass);
12948 this.selections = [];
12949 if(!suppressEvent){
12950 this.fireEvent("selectionchange", this, this.selections);
12956 * Returns true if the passed node is selected
12957 * @param {HTMLElement/Number} node The node or node index
12958 * @return {Boolean}
12960 isSelected : function(node){
12961 var s = this.selections;
12965 node = this.getNode(node);
12966 return s.indexOf(node) !== -1;
12971 * @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
12972 * @param {Boolean} keepExisting (optional) true to keep existing selections
12973 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12975 select : function(nodeInfo, keepExisting, suppressEvent){
12976 if(nodeInfo instanceof Array){
12978 this.clearSelections(true);
12980 for(var i = 0, len = nodeInfo.length; i < len; i++){
12981 this.select(nodeInfo[i], true, true);
12985 var node = this.getNode(nodeInfo);
12986 if(!node || this.isSelected(node)){
12987 return; // already selected.
12990 this.clearSelections(true);
12993 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12994 Roo.fly(node).addClass(this.selectedClass);
12995 this.selections.push(node);
12996 if(!suppressEvent){
12997 this.fireEvent("selectionchange", this, this.selections);
13005 * @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
13006 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13007 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13009 unselect : function(nodeInfo, keepExisting, suppressEvent)
13011 if(nodeInfo instanceof Array){
13012 Roo.each(this.selections, function(s) {
13013 this.unselect(s, nodeInfo);
13017 var node = this.getNode(nodeInfo);
13018 if(!node || !this.isSelected(node)){
13019 //Roo.log("not selected");
13020 return; // not selected.
13024 Roo.each(this.selections, function(s) {
13026 Roo.fly(node).removeClass(this.selectedClass);
13033 this.selections= ns;
13034 this.fireEvent("selectionchange", this, this.selections);
13038 * Gets a template node.
13039 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13040 * @return {HTMLElement} The node or null if it wasn't found
13042 getNode : function(nodeInfo){
13043 if(typeof nodeInfo == "string"){
13044 return document.getElementById(nodeInfo);
13045 }else if(typeof nodeInfo == "number"){
13046 return this.nodes[nodeInfo];
13052 * Gets a range template nodes.
13053 * @param {Number} startIndex
13054 * @param {Number} endIndex
13055 * @return {Array} An array of nodes
13057 getNodes : function(start, end){
13058 var ns = this.nodes;
13059 start = start || 0;
13060 end = typeof end == "undefined" ? ns.length - 1 : end;
13063 for(var i = start; i <= end; i++){
13067 for(var i = start; i >= end; i--){
13075 * Finds the index of the passed node
13076 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13077 * @return {Number} The index of the node or -1
13079 indexOf : function(node){
13080 node = this.getNode(node);
13081 if(typeof node.nodeIndex == "number"){
13082 return node.nodeIndex;
13084 var ns = this.nodes;
13085 for(var i = 0, len = ns.length; i < len; i++){
13096 * based on jquery fullcalendar
13100 Roo.bootstrap = Roo.bootstrap || {};
13102 * @class Roo.bootstrap.Calendar
13103 * @extends Roo.bootstrap.Component
13104 * Bootstrap Calendar class
13105 * @cfg {Boolean} loadMask (true|false) default false
13106 * @cfg {Object} header generate the user specific header of the calendar, default false
13109 * Create a new Container
13110 * @param {Object} config The config object
13115 Roo.bootstrap.Calendar = function(config){
13116 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13120 * Fires when a date is selected
13121 * @param {DatePicker} this
13122 * @param {Date} date The selected date
13126 * @event monthchange
13127 * Fires when the displayed month changes
13128 * @param {DatePicker} this
13129 * @param {Date} date The selected month
13131 'monthchange': true,
13133 * @event evententer
13134 * Fires when mouse over an event
13135 * @param {Calendar} this
13136 * @param {event} Event
13138 'evententer': true,
13140 * @event eventleave
13141 * Fires when the mouse leaves an
13142 * @param {Calendar} this
13145 'eventleave': true,
13147 * @event eventclick
13148 * Fires when the mouse click an
13149 * @param {Calendar} this
13158 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13161 * @cfg {Number} startDay
13162 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13170 getAutoCreate : function(){
13173 var fc_button = function(name, corner, style, content ) {
13174 return Roo.apply({},{
13176 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13178 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13181 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13192 style : 'width:100%',
13199 cls : 'fc-header-left',
13201 fc_button('prev', 'left', 'arrow', '‹' ),
13202 fc_button('next', 'right', 'arrow', '›' ),
13203 { tag: 'span', cls: 'fc-header-space' },
13204 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13212 cls : 'fc-header-center',
13216 cls: 'fc-header-title',
13219 html : 'month / year'
13227 cls : 'fc-header-right',
13229 /* fc_button('month', 'left', '', 'month' ),
13230 fc_button('week', '', '', 'week' ),
13231 fc_button('day', 'right', '', 'day' )
13243 header = this.header;
13246 var cal_heads = function() {
13248 // fixme - handle this.
13250 for (var i =0; i < Date.dayNames.length; i++) {
13251 var d = Date.dayNames[i];
13254 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13255 html : d.substring(0,3)
13259 ret[0].cls += ' fc-first';
13260 ret[6].cls += ' fc-last';
13263 var cal_cell = function(n) {
13266 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13271 cls: 'fc-day-number',
13275 cls: 'fc-day-content',
13279 style: 'position: relative;' // height: 17px;
13291 var cal_rows = function() {
13294 for (var r = 0; r < 6; r++) {
13301 for (var i =0; i < Date.dayNames.length; i++) {
13302 var d = Date.dayNames[i];
13303 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13306 row.cn[0].cls+=' fc-first';
13307 row.cn[0].cn[0].style = 'min-height:90px';
13308 row.cn[6].cls+=' fc-last';
13312 ret[0].cls += ' fc-first';
13313 ret[4].cls += ' fc-prev-last';
13314 ret[5].cls += ' fc-last';
13321 cls: 'fc-border-separate',
13322 style : 'width:100%',
13330 cls : 'fc-first fc-last',
13348 cls : 'fc-content',
13349 style : "position: relative;",
13352 cls : 'fc-view fc-view-month fc-grid',
13353 style : 'position: relative',
13354 unselectable : 'on',
13357 cls : 'fc-event-container',
13358 style : 'position:absolute;z-index:8;top:0;left:0;'
13376 initEvents : function()
13379 throw "can not find store for calendar";
13385 style: "text-align:center",
13389 style: "background-color:white;width:50%;margin:250 auto",
13393 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13404 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13406 var size = this.el.select('.fc-content', true).first().getSize();
13407 this.maskEl.setSize(size.width, size.height);
13408 this.maskEl.enableDisplayMode("block");
13409 if(!this.loadMask){
13410 this.maskEl.hide();
13413 this.store = Roo.factory(this.store, Roo.data);
13414 this.store.on('load', this.onLoad, this);
13415 this.store.on('beforeload', this.onBeforeLoad, this);
13419 this.cells = this.el.select('.fc-day',true);
13420 //Roo.log(this.cells);
13421 this.textNodes = this.el.query('.fc-day-number');
13422 this.cells.addClassOnOver('fc-state-hover');
13424 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13425 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13426 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13427 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13429 this.on('monthchange', this.onMonthChange, this);
13431 this.update(new Date().clearTime());
13434 resize : function() {
13435 var sz = this.el.getSize();
13437 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13438 this.el.select('.fc-day-content div',true).setHeight(34);
13443 showPrevMonth : function(e){
13444 this.update(this.activeDate.add("mo", -1));
13446 showToday : function(e){
13447 this.update(new Date().clearTime());
13450 showNextMonth : function(e){
13451 this.update(this.activeDate.add("mo", 1));
13455 showPrevYear : function(){
13456 this.update(this.activeDate.add("y", -1));
13460 showNextYear : function(){
13461 this.update(this.activeDate.add("y", 1));
13466 update : function(date)
13468 var vd = this.activeDate;
13469 this.activeDate = date;
13470 // if(vd && this.el){
13471 // var t = date.getTime();
13472 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13473 // Roo.log('using add remove');
13475 // this.fireEvent('monthchange', this, date);
13477 // this.cells.removeClass("fc-state-highlight");
13478 // this.cells.each(function(c){
13479 // if(c.dateValue == t){
13480 // c.addClass("fc-state-highlight");
13481 // setTimeout(function(){
13482 // try{c.dom.firstChild.focus();}catch(e){}
13492 var days = date.getDaysInMonth();
13494 var firstOfMonth = date.getFirstDateOfMonth();
13495 var startingPos = firstOfMonth.getDay()-this.startDay;
13497 if(startingPos < this.startDay){
13501 var pm = date.add(Date.MONTH, -1);
13502 var prevStart = pm.getDaysInMonth()-startingPos;
13504 this.cells = this.el.select('.fc-day',true);
13505 this.textNodes = this.el.query('.fc-day-number');
13506 this.cells.addClassOnOver('fc-state-hover');
13508 var cells = this.cells.elements;
13509 var textEls = this.textNodes;
13511 Roo.each(cells, function(cell){
13512 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13515 days += startingPos;
13517 // convert everything to numbers so it's fast
13518 var day = 86400000;
13519 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13522 //Roo.log(prevStart);
13524 var today = new Date().clearTime().getTime();
13525 var sel = date.clearTime().getTime();
13526 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13527 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13528 var ddMatch = this.disabledDatesRE;
13529 var ddText = this.disabledDatesText;
13530 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13531 var ddaysText = this.disabledDaysText;
13532 var format = this.format;
13534 var setCellClass = function(cal, cell){
13538 //Roo.log('set Cell Class');
13540 var t = d.getTime();
13544 cell.dateValue = t;
13546 cell.className += " fc-today";
13547 cell.className += " fc-state-highlight";
13548 cell.title = cal.todayText;
13551 // disable highlight in other month..
13552 //cell.className += " fc-state-highlight";
13557 cell.className = " fc-state-disabled";
13558 cell.title = cal.minText;
13562 cell.className = " fc-state-disabled";
13563 cell.title = cal.maxText;
13567 if(ddays.indexOf(d.getDay()) != -1){
13568 cell.title = ddaysText;
13569 cell.className = " fc-state-disabled";
13572 if(ddMatch && format){
13573 var fvalue = d.dateFormat(format);
13574 if(ddMatch.test(fvalue)){
13575 cell.title = ddText.replace("%0", fvalue);
13576 cell.className = " fc-state-disabled";
13580 if (!cell.initialClassName) {
13581 cell.initialClassName = cell.dom.className;
13584 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13589 for(; i < startingPos; i++) {
13590 textEls[i].innerHTML = (++prevStart);
13591 d.setDate(d.getDate()+1);
13593 cells[i].className = "fc-past fc-other-month";
13594 setCellClass(this, cells[i]);
13599 for(; i < days; i++){
13600 intDay = i - startingPos + 1;
13601 textEls[i].innerHTML = (intDay);
13602 d.setDate(d.getDate()+1);
13604 cells[i].className = ''; // "x-date-active";
13605 setCellClass(this, cells[i]);
13609 for(; i < 42; i++) {
13610 textEls[i].innerHTML = (++extraDays);
13611 d.setDate(d.getDate()+1);
13613 cells[i].className = "fc-future fc-other-month";
13614 setCellClass(this, cells[i]);
13617 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13619 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13621 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13622 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13624 if(totalRows != 6){
13625 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13626 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13629 this.fireEvent('monthchange', this, date);
13633 if(!this.internalRender){
13634 var main = this.el.dom.firstChild;
13635 var w = main.offsetWidth;
13636 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13637 Roo.fly(main).setWidth(w);
13638 this.internalRender = true;
13639 // opera does not respect the auto grow header center column
13640 // then, after it gets a width opera refuses to recalculate
13641 // without a second pass
13642 if(Roo.isOpera && !this.secondPass){
13643 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13644 this.secondPass = true;
13645 this.update.defer(10, this, [date]);
13652 findCell : function(dt) {
13653 dt = dt.clearTime().getTime();
13655 this.cells.each(function(c){
13656 //Roo.log("check " +c.dateValue + '?=' + dt);
13657 if(c.dateValue == dt){
13667 findCells : function(ev) {
13668 var s = ev.start.clone().clearTime().getTime();
13670 var e= ev.end.clone().clearTime().getTime();
13673 this.cells.each(function(c){
13674 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13676 if(c.dateValue > e){
13679 if(c.dateValue < s){
13688 // findBestRow: function(cells)
13692 // for (var i =0 ; i < cells.length;i++) {
13693 // ret = Math.max(cells[i].rows || 0,ret);
13700 addItem : function(ev)
13702 // look for vertical location slot in
13703 var cells = this.findCells(ev);
13705 // ev.row = this.findBestRow(cells);
13707 // work out the location.
13711 for(var i =0; i < cells.length; i++) {
13713 cells[i].row = cells[0].row;
13716 cells[i].row = cells[i].row + 1;
13726 if (crow.start.getY() == cells[i].getY()) {
13728 crow.end = cells[i];
13745 cells[0].events.push(ev);
13747 this.calevents.push(ev);
13750 clearEvents: function() {
13752 if(!this.calevents){
13756 Roo.each(this.cells.elements, function(c){
13762 Roo.each(this.calevents, function(e) {
13763 Roo.each(e.els, function(el) {
13764 el.un('mouseenter' ,this.onEventEnter, this);
13765 el.un('mouseleave' ,this.onEventLeave, this);
13770 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13776 renderEvents: function()
13780 this.cells.each(function(c) {
13789 if(c.row != c.events.length){
13790 r = 4 - (4 - (c.row - c.events.length));
13793 c.events = ev.slice(0, r);
13794 c.more = ev.slice(r);
13796 if(c.more.length && c.more.length == 1){
13797 c.events.push(c.more.pop());
13800 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13804 this.cells.each(function(c) {
13806 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13809 for (var e = 0; e < c.events.length; e++){
13810 var ev = c.events[e];
13811 var rows = ev.rows;
13813 for(var i = 0; i < rows.length; i++) {
13815 // how many rows should it span..
13818 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13819 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13821 unselectable : "on",
13824 cls: 'fc-event-inner',
13828 // cls: 'fc-event-time',
13829 // html : cells.length > 1 ? '' : ev.time
13833 cls: 'fc-event-title',
13834 html : String.format('{0}', ev.title)
13841 cls: 'ui-resizable-handle ui-resizable-e',
13842 html : '  '
13849 cfg.cls += ' fc-event-start';
13851 if ((i+1) == rows.length) {
13852 cfg.cls += ' fc-event-end';
13855 var ctr = _this.el.select('.fc-event-container',true).first();
13856 var cg = ctr.createChild(cfg);
13858 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13859 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13861 var r = (c.more.length) ? 1 : 0;
13862 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13863 cg.setWidth(ebox.right - sbox.x -2);
13865 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13866 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13867 cg.on('click', _this.onEventClick, _this, ev);
13878 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13879 style : 'position: absolute',
13880 unselectable : "on",
13883 cls: 'fc-event-inner',
13887 cls: 'fc-event-title',
13895 cls: 'ui-resizable-handle ui-resizable-e',
13896 html : '  '
13902 var ctr = _this.el.select('.fc-event-container',true).first();
13903 var cg = ctr.createChild(cfg);
13905 var sbox = c.select('.fc-day-content',true).first().getBox();
13906 var ebox = c.select('.fc-day-content',true).first().getBox();
13908 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13909 cg.setWidth(ebox.right - sbox.x -2);
13911 cg.on('click', _this.onMoreEventClick, _this, c.more);
13921 onEventEnter: function (e, el,event,d) {
13922 this.fireEvent('evententer', this, el, event);
13925 onEventLeave: function (e, el,event,d) {
13926 this.fireEvent('eventleave', this, el, event);
13929 onEventClick: function (e, el,event,d) {
13930 this.fireEvent('eventclick', this, el, event);
13933 onMonthChange: function () {
13937 onMoreEventClick: function(e, el, more)
13941 this.calpopover.placement = 'right';
13942 this.calpopover.setTitle('More');
13944 this.calpopover.setContent('');
13946 var ctr = this.calpopover.el.select('.popover-content', true).first();
13948 Roo.each(more, function(m){
13950 cls : 'fc-event-hori fc-event-draggable',
13953 var cg = ctr.createChild(cfg);
13955 cg.on('click', _this.onEventClick, _this, m);
13958 this.calpopover.show(el);
13963 onLoad: function ()
13965 this.calevents = [];
13968 if(this.store.getCount() > 0){
13969 this.store.data.each(function(d){
13972 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13973 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13974 time : d.data.start_time,
13975 title : d.data.title,
13976 description : d.data.description,
13977 venue : d.data.venue
13982 this.renderEvents();
13984 if(this.calevents.length && this.loadMask){
13985 this.maskEl.hide();
13989 onBeforeLoad: function()
13991 this.clearEvents();
13993 this.maskEl.show();
14007 * @class Roo.bootstrap.Popover
14008 * @extends Roo.bootstrap.Component
14009 * Bootstrap Popover class
14010 * @cfg {String} html contents of the popover (or false to use children..)
14011 * @cfg {String} title of popover (or false to hide)
14012 * @cfg {String} placement how it is placed
14013 * @cfg {String} trigger click || hover (or false to trigger manually)
14014 * @cfg {String} over what (parent or false to trigger manually.)
14015 * @cfg {Number} delay - delay before showing
14018 * Create a new Popover
14019 * @param {Object} config The config object
14022 Roo.bootstrap.Popover = function(config){
14023 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14026 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14028 title: 'Fill in a title',
14031 placement : 'right',
14032 trigger : 'hover', // hover
14038 can_build_overlaid : false,
14040 getChildContainer : function()
14042 return this.el.select('.popover-content',true).first();
14045 getAutoCreate : function(){
14046 Roo.log('make popover?');
14048 cls : 'popover roo-dynamic',
14049 style: 'display:block',
14055 cls : 'popover-inner',
14059 cls: 'popover-title',
14063 cls : 'popover-content',
14074 setTitle: function(str)
14076 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14078 setContent: function(str)
14080 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14082 // as it get's added to the bottom of the page.
14083 onRender : function(ct, position)
14085 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14087 var cfg = Roo.apply({}, this.getAutoCreate());
14091 cfg.cls += ' ' + this.cls;
14094 cfg.style = this.style;
14096 Roo.log("adding to ")
14097 this.el = Roo.get(document.body).createChild(cfg, position);
14103 initEvents : function()
14105 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14106 this.el.enableDisplayMode('block');
14108 if (this.over === false) {
14111 if (this.triggers === false) {
14114 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14115 var triggers = this.trigger ? this.trigger.split(' ') : [];
14116 Roo.each(triggers, function(trigger) {
14118 if (trigger == 'click') {
14119 on_el.on('click', this.toggle, this);
14120 } else if (trigger != 'manual') {
14121 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14122 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14124 on_el.on(eventIn ,this.enter, this);
14125 on_el.on(eventOut, this.leave, this);
14136 toggle : function () {
14137 this.hoverState == 'in' ? this.leave() : this.enter();
14140 enter : function () {
14143 clearTimeout(this.timeout);
14145 this.hoverState = 'in';
14147 if (!this.delay || !this.delay.show) {
14152 this.timeout = setTimeout(function () {
14153 if (_t.hoverState == 'in') {
14156 }, this.delay.show)
14158 leave : function() {
14159 clearTimeout(this.timeout);
14161 this.hoverState = 'out';
14163 if (!this.delay || !this.delay.hide) {
14168 this.timeout = setTimeout(function () {
14169 if (_t.hoverState == 'out') {
14172 }, this.delay.hide)
14175 show : function (on_el)
14178 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14181 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14182 if (this.html !== false) {
14183 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14185 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14186 if (!this.title.length) {
14187 this.el.select('.popover-title',true).hide();
14190 var placement = typeof this.placement == 'function' ?
14191 this.placement.call(this, this.el, on_el) :
14194 var autoToken = /\s?auto?\s?/i;
14195 var autoPlace = autoToken.test(placement);
14197 placement = placement.replace(autoToken, '') || 'top';
14201 //this.el.setXY([0,0]);
14203 this.el.dom.style.display='block';
14204 this.el.addClass(placement);
14206 //this.el.appendTo(on_el);
14208 var p = this.getPosition();
14209 var box = this.el.getBox();
14214 var align = Roo.bootstrap.Popover.alignment[placement];
14215 this.el.alignTo(on_el, align[0],align[1]);
14216 //var arrow = this.el.select('.arrow',true).first();
14217 //arrow.set(align[2],
14219 this.el.addClass('in');
14220 this.hoverState = null;
14222 if (this.el.hasClass('fade')) {
14229 this.el.setXY([0,0]);
14230 this.el.removeClass('in');
14237 Roo.bootstrap.Popover.alignment = {
14238 'left' : ['r-l', [-10,0], 'right'],
14239 'right' : ['l-r', [10,0], 'left'],
14240 'bottom' : ['t-b', [0,10], 'top'],
14241 'top' : [ 'b-t', [0,-10], 'bottom']
14252 * @class Roo.bootstrap.Progress
14253 * @extends Roo.bootstrap.Component
14254 * Bootstrap Progress class
14255 * @cfg {Boolean} striped striped of the progress bar
14256 * @cfg {Boolean} active animated of the progress bar
14260 * Create a new Progress
14261 * @param {Object} config The config object
14264 Roo.bootstrap.Progress = function(config){
14265 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14268 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14273 getAutoCreate : function(){
14281 cfg.cls += ' progress-striped';
14285 cfg.cls += ' active';
14304 * @class Roo.bootstrap.ProgressBar
14305 * @extends Roo.bootstrap.Component
14306 * Bootstrap ProgressBar class
14307 * @cfg {Number} aria_valuenow aria-value now
14308 * @cfg {Number} aria_valuemin aria-value min
14309 * @cfg {Number} aria_valuemax aria-value max
14310 * @cfg {String} label label for the progress bar
14311 * @cfg {String} panel (success | info | warning | danger )
14312 * @cfg {String} role role of the progress bar
14313 * @cfg {String} sr_only text
14317 * Create a new ProgressBar
14318 * @param {Object} config The config object
14321 Roo.bootstrap.ProgressBar = function(config){
14322 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14325 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14329 aria_valuemax : 100,
14335 getAutoCreate : function()
14340 cls: 'progress-bar',
14341 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14353 cfg.role = this.role;
14356 if(this.aria_valuenow){
14357 cfg['aria-valuenow'] = this.aria_valuenow;
14360 if(this.aria_valuemin){
14361 cfg['aria-valuemin'] = this.aria_valuemin;
14364 if(this.aria_valuemax){
14365 cfg['aria-valuemax'] = this.aria_valuemax;
14368 if(this.label && !this.sr_only){
14369 cfg.html = this.label;
14373 cfg.cls += ' progress-bar-' + this.panel;
14379 update : function(aria_valuenow)
14381 this.aria_valuenow = aria_valuenow;
14383 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14398 * @class Roo.bootstrap.TabGroup
14399 * @extends Roo.bootstrap.Column
14400 * Bootstrap Column class
14401 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14402 * @cfg {Boolean} carousel true to make the group behave like a carousel
14405 * Create a new TabGroup
14406 * @param {Object} config The config object
14409 Roo.bootstrap.TabGroup = function(config){
14410 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14412 this.navId = Roo.id();
14415 Roo.bootstrap.TabGroup.register(this);
14419 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14422 transition : false,
14424 getAutoCreate : function()
14426 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14428 cfg.cls += ' tab-content';
14430 if (this.carousel) {
14431 cfg.cls += ' carousel slide';
14433 cls : 'carousel-inner'
14440 getChildContainer : function()
14442 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14446 * register a Navigation item
14447 * @param {Roo.bootstrap.NavItem} the navitem to add
14449 register : function(item)
14451 this.tabs.push( item);
14452 item.navId = this.navId; // not really needed..
14456 getActivePanel : function()
14459 Roo.each(this.tabs, function(t) {
14469 getPanelByName : function(n)
14472 Roo.each(this.tabs, function(t) {
14473 if (t.tabId == n) {
14481 indexOfPanel : function(p)
14484 Roo.each(this.tabs, function(t,i) {
14485 if (t.tabId == p.tabId) {
14494 * show a specific panel
14495 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14496 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14498 showPanel : function (pan)
14501 if (typeof(pan) == 'number') {
14502 pan = this.tabs[pan];
14504 if (typeof(pan) == 'string') {
14505 pan = this.getPanelByName(pan);
14507 if (pan.tabId == this.getActivePanel().tabId) {
14510 var cur = this.getActivePanel();
14512 if (false === cur.fireEvent('beforedeactivate')) {
14516 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14518 this.transition = true;
14519 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14520 var lr = dir == 'next' ? 'left' : 'right';
14521 pan.el.addClass(dir); // or prev
14522 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14523 cur.el.addClass(lr); // or right
14524 pan.el.addClass(lr);
14527 cur.el.on('transitionend', function() {
14528 Roo.log("trans end?");
14530 pan.el.removeClass([lr,dir]);
14531 pan.setActive(true);
14533 cur.el.removeClass([lr]);
14534 cur.setActive(false);
14536 _this.transition = false;
14538 }, this, { single: true } );
14542 cur.setActive(false);
14543 pan.setActive(true);
14547 showPanelNext : function()
14549 var i = this.indexOfPanel(this.getActivePanel());
14550 if (i > this.tabs.length) {
14553 this.showPanel(this.tabs[i+1]);
14555 showPanelPrev : function()
14557 var i = this.indexOfPanel(this.getActivePanel());
14561 this.showPanel(this.tabs[i-1]);
14572 Roo.apply(Roo.bootstrap.TabGroup, {
14576 * register a Navigation Group
14577 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14579 register : function(navgrp)
14581 this.groups[navgrp.navId] = navgrp;
14585 * fetch a Navigation Group based on the navigation ID
14586 * if one does not exist , it will get created.
14587 * @param {string} the navgroup to add
14588 * @returns {Roo.bootstrap.NavGroup} the navgroup
14590 get: function(navId) {
14591 if (typeof(this.groups[navId]) == 'undefined') {
14592 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14594 return this.groups[navId] ;
14609 * @class Roo.bootstrap.TabPanel
14610 * @extends Roo.bootstrap.Component
14611 * Bootstrap TabPanel class
14612 * @cfg {Boolean} active panel active
14613 * @cfg {String} html panel content
14614 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14615 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14619 * Create a new TabPanel
14620 * @param {Object} config The config object
14623 Roo.bootstrap.TabPanel = function(config){
14624 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14628 * Fires when the active status changes
14629 * @param {Roo.bootstrap.TabPanel} this
14630 * @param {Boolean} state the new state
14635 * @event beforedeactivate
14636 * Fires before a tab is de-activated - can be used to do validation on a form.
14637 * @param {Roo.bootstrap.TabPanel} this
14638 * @return {Boolean} false if there is an error
14641 'beforedeactivate': true
14644 this.tabId = this.tabId || Roo.id();
14648 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14655 getAutoCreate : function(){
14658 // item is needed for carousel - not sure if it has any effect otherwise
14659 cls: 'tab-pane item',
14660 html: this.html || ''
14664 cfg.cls += ' active';
14668 cfg.tabId = this.tabId;
14675 initEvents: function()
14677 Roo.log('-------- init events on tab panel ---------');
14679 var p = this.parent();
14680 this.navId = this.navId || p.navId;
14682 if (typeof(this.navId) != 'undefined') {
14683 // not really needed.. but just in case.. parent should be a NavGroup.
14684 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14685 Roo.log(['register', tg, this]);
14691 onRender : function(ct, position)
14693 // Roo.log("Call onRender: " + this.xtype);
14695 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14703 setActive: function(state)
14705 Roo.log("panel - set active " + this.tabId + "=" + state);
14707 this.active = state;
14709 this.el.removeClass('active');
14711 } else if (!this.el.hasClass('active')) {
14712 this.el.addClass('active');
14714 this.fireEvent('changed', this, state);
14731 * @class Roo.bootstrap.DateField
14732 * @extends Roo.bootstrap.Input
14733 * Bootstrap DateField class
14734 * @cfg {Number} weekStart default 0
14735 * @cfg {String} viewMode default empty, (months|years)
14736 * @cfg {String} minViewMode default empty, (months|years)
14737 * @cfg {Number} startDate default -Infinity
14738 * @cfg {Number} endDate default Infinity
14739 * @cfg {Boolean} todayHighlight default false
14740 * @cfg {Boolean} todayBtn default false
14741 * @cfg {Boolean} calendarWeeks default false
14742 * @cfg {Object} daysOfWeekDisabled default empty
14743 * @cfg {Boolean} singleMode default false (true | false)
14745 * @cfg {Boolean} keyboardNavigation default true
14746 * @cfg {String} language default en
14749 * Create a new DateField
14750 * @param {Object} config The config object
14753 Roo.bootstrap.DateField = function(config){
14754 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14758 * Fires when this field show.
14759 * @param {Roo.bootstrap.DateField} this
14760 * @param {Mixed} date The date value
14765 * Fires when this field hide.
14766 * @param {Roo.bootstrap.DateField} this
14767 * @param {Mixed} date The date value
14772 * Fires when select a date.
14773 * @param {Roo.bootstrap.DateField} this
14774 * @param {Mixed} date The date value
14780 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14783 * @cfg {String} format
14784 * The default date format string which can be overriden for localization support. The format must be
14785 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14789 * @cfg {String} altFormats
14790 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14791 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14793 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14801 todayHighlight : false,
14807 keyboardNavigation: true,
14809 calendarWeeks: false,
14811 startDate: -Infinity,
14815 daysOfWeekDisabled: [],
14819 singleMode : false,
14821 UTCDate: function()
14823 return new Date(Date.UTC.apply(Date, arguments));
14826 UTCToday: function()
14828 var today = new Date();
14829 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14832 getDate: function() {
14833 var d = this.getUTCDate();
14834 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14837 getUTCDate: function() {
14841 setDate: function(d) {
14842 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14845 setUTCDate: function(d) {
14847 this.setValue(this.formatDate(this.date));
14850 onRender: function(ct, position)
14853 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14855 this.language = this.language || 'en';
14856 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14857 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14859 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14860 this.format = this.format || 'm/d/y';
14861 this.isInline = false;
14862 this.isInput = true;
14863 this.component = this.el.select('.add-on', true).first() || false;
14864 this.component = (this.component && this.component.length === 0) ? false : this.component;
14865 this.hasInput = this.component && this.inputEL().length;
14867 if (typeof(this.minViewMode === 'string')) {
14868 switch (this.minViewMode) {
14870 this.minViewMode = 1;
14873 this.minViewMode = 2;
14876 this.minViewMode = 0;
14881 if (typeof(this.viewMode === 'string')) {
14882 switch (this.viewMode) {
14895 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14897 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14899 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14901 this.picker().on('mousedown', this.onMousedown, this);
14902 this.picker().on('click', this.onClick, this);
14904 this.picker().addClass('datepicker-dropdown');
14906 this.startViewMode = this.viewMode;
14908 if(this.singleMode){
14909 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14910 v.setVisibilityMode(Roo.Element.DISPLAY)
14914 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14915 v.setStyle('width', '189px');
14919 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14920 if(!this.calendarWeeks){
14925 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14926 v.attr('colspan', function(i, val){
14927 return parseInt(val) + 1;
14932 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14934 this.setStartDate(this.startDate);
14935 this.setEndDate(this.endDate);
14937 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14944 if(this.isInline) {
14949 picker : function()
14951 return this.pickerEl;
14952 // return this.el.select('.datepicker', true).first();
14955 fillDow: function()
14957 var dowCnt = this.weekStart;
14966 if(this.calendarWeeks){
14974 while (dowCnt < this.weekStart + 7) {
14978 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14982 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14985 fillMonths: function()
14988 var months = this.picker().select('>.datepicker-months td', true).first();
14990 months.dom.innerHTML = '';
14996 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14999 months.createChild(month);
15006 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;
15008 if (this.date < this.startDate) {
15009 this.viewDate = new Date(this.startDate);
15010 } else if (this.date > this.endDate) {
15011 this.viewDate = new Date(this.endDate);
15013 this.viewDate = new Date(this.date);
15021 var d = new Date(this.viewDate),
15022 year = d.getUTCFullYear(),
15023 month = d.getUTCMonth(),
15024 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15025 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15026 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15027 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15028 currentDate = this.date && this.date.valueOf(),
15029 today = this.UTCToday();
15031 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15033 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15035 // this.picker.select('>tfoot th.today').
15036 // .text(dates[this.language].today)
15037 // .toggle(this.todayBtn !== false);
15039 this.updateNavArrows();
15042 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15044 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15046 prevMonth.setUTCDate(day);
15048 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15050 var nextMonth = new Date(prevMonth);
15052 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15054 nextMonth = nextMonth.valueOf();
15056 var fillMonths = false;
15058 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15060 while(prevMonth.valueOf() < nextMonth) {
15063 if (prevMonth.getUTCDay() === this.weekStart) {
15065 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15073 if(this.calendarWeeks){
15074 // ISO 8601: First week contains first thursday.
15075 // ISO also states week starts on Monday, but we can be more abstract here.
15077 // Start of current week: based on weekstart/current date
15078 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15079 // Thursday of this week
15080 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15081 // First Thursday of year, year from thursday
15082 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15083 // Calendar week: ms between thursdays, div ms per day, div 7 days
15084 calWeek = (th - yth) / 864e5 / 7 + 1;
15086 fillMonths.cn.push({
15094 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15096 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15099 if (this.todayHighlight &&
15100 prevMonth.getUTCFullYear() == today.getFullYear() &&
15101 prevMonth.getUTCMonth() == today.getMonth() &&
15102 prevMonth.getUTCDate() == today.getDate()) {
15103 clsName += ' today';
15106 if (currentDate && prevMonth.valueOf() === currentDate) {
15107 clsName += ' active';
15110 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15111 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15112 clsName += ' disabled';
15115 fillMonths.cn.push({
15117 cls: 'day ' + clsName,
15118 html: prevMonth.getDate()
15121 prevMonth.setDate(prevMonth.getDate()+1);
15124 var currentYear = this.date && this.date.getUTCFullYear();
15125 var currentMonth = this.date && this.date.getUTCMonth();
15127 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15129 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15130 v.removeClass('active');
15132 if(currentYear === year && k === currentMonth){
15133 v.addClass('active');
15136 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15137 v.addClass('disabled');
15143 year = parseInt(year/10, 10) * 10;
15145 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15147 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15150 for (var i = -1; i < 11; i++) {
15151 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15153 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15161 showMode: function(dir)
15164 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15167 Roo.each(this.picker().select('>div',true).elements, function(v){
15168 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15171 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15176 if(this.isInline) return;
15178 this.picker().removeClass(['bottom', 'top']);
15180 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15182 * place to the top of element!
15186 this.picker().addClass('top');
15187 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15192 this.picker().addClass('bottom');
15194 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15197 parseDate : function(value)
15199 if(!value || value instanceof Date){
15202 var v = Date.parseDate(value, this.format);
15203 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15204 v = Date.parseDate(value, 'Y-m-d');
15206 if(!v && this.altFormats){
15207 if(!this.altFormatsArray){
15208 this.altFormatsArray = this.altFormats.split("|");
15210 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15211 v = Date.parseDate(value, this.altFormatsArray[i]);
15217 formatDate : function(date, fmt)
15219 return (!date || !(date instanceof Date)) ?
15220 date : date.dateFormat(fmt || this.format);
15223 onFocus : function()
15225 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15229 onBlur : function()
15231 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15233 var d = this.inputEl().getValue();
15242 this.picker().show();
15246 this.fireEvent('show', this, this.date);
15251 if(this.isInline) return;
15252 this.picker().hide();
15253 this.viewMode = this.startViewMode;
15256 this.fireEvent('hide', this, this.date);
15260 onMousedown: function(e)
15262 e.stopPropagation();
15263 e.preventDefault();
15268 Roo.bootstrap.DateField.superclass.keyup.call(this);
15272 setValue: function(v)
15275 // v can be a string or a date..
15278 var d = new Date(this.parseDate(v) ).clearTime();
15280 if(isNaN(d.getTime())){
15281 this.date = this.viewDate = '';
15282 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15286 v = this.formatDate(d);
15288 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15290 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15294 this.fireEvent('select', this, this.date);
15298 getValue: function()
15300 return this.formatDate(this.date);
15303 fireKey: function(e)
15305 if (!this.picker().isVisible()){
15306 if (e.keyCode == 27) // allow escape to hide and re-show picker
15311 var dateChanged = false,
15313 newDate, newViewDate;
15318 e.preventDefault();
15322 if (!this.keyboardNavigation) break;
15323 dir = e.keyCode == 37 ? -1 : 1;
15326 newDate = this.moveYear(this.date, dir);
15327 newViewDate = this.moveYear(this.viewDate, dir);
15328 } else if (e.shiftKey){
15329 newDate = this.moveMonth(this.date, dir);
15330 newViewDate = this.moveMonth(this.viewDate, dir);
15332 newDate = new Date(this.date);
15333 newDate.setUTCDate(this.date.getUTCDate() + dir);
15334 newViewDate = new Date(this.viewDate);
15335 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15337 if (this.dateWithinRange(newDate)){
15338 this.date = newDate;
15339 this.viewDate = newViewDate;
15340 this.setValue(this.formatDate(this.date));
15342 e.preventDefault();
15343 dateChanged = true;
15348 if (!this.keyboardNavigation) break;
15349 dir = e.keyCode == 38 ? -1 : 1;
15351 newDate = this.moveYear(this.date, dir);
15352 newViewDate = this.moveYear(this.viewDate, dir);
15353 } else if (e.shiftKey){
15354 newDate = this.moveMonth(this.date, dir);
15355 newViewDate = this.moveMonth(this.viewDate, dir);
15357 newDate = new Date(this.date);
15358 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15359 newViewDate = new Date(this.viewDate);
15360 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15362 if (this.dateWithinRange(newDate)){
15363 this.date = newDate;
15364 this.viewDate = newViewDate;
15365 this.setValue(this.formatDate(this.date));
15367 e.preventDefault();
15368 dateChanged = true;
15372 this.setValue(this.formatDate(this.date));
15374 e.preventDefault();
15377 this.setValue(this.formatDate(this.date));
15391 onClick: function(e)
15393 e.stopPropagation();
15394 e.preventDefault();
15396 var target = e.getTarget();
15398 if(target.nodeName.toLowerCase() === 'i'){
15399 target = Roo.get(target).dom.parentNode;
15402 var nodeName = target.nodeName;
15403 var className = target.className;
15404 var html = target.innerHTML;
15405 //Roo.log(nodeName);
15407 switch(nodeName.toLowerCase()) {
15409 switch(className) {
15415 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15416 switch(this.viewMode){
15418 this.viewDate = this.moveMonth(this.viewDate, dir);
15422 this.viewDate = this.moveYear(this.viewDate, dir);
15428 var date = new Date();
15429 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15431 this.setValue(this.formatDate(this.date));
15438 if (className.indexOf('disabled') < 0) {
15439 this.viewDate.setUTCDate(1);
15440 if (className.indexOf('month') > -1) {
15441 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15443 var year = parseInt(html, 10) || 0;
15444 this.viewDate.setUTCFullYear(year);
15448 if(this.singleMode){
15449 this.setValue(this.formatDate(this.viewDate));
15460 //Roo.log(className);
15461 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15462 var day = parseInt(html, 10) || 1;
15463 var year = this.viewDate.getUTCFullYear(),
15464 month = this.viewDate.getUTCMonth();
15466 if (className.indexOf('old') > -1) {
15473 } else if (className.indexOf('new') > -1) {
15481 //Roo.log([year,month,day]);
15482 this.date = this.UTCDate(year, month, day,0,0,0,0);
15483 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15485 //Roo.log(this.formatDate(this.date));
15486 this.setValue(this.formatDate(this.date));
15493 setStartDate: function(startDate)
15495 this.startDate = startDate || -Infinity;
15496 if (this.startDate !== -Infinity) {
15497 this.startDate = this.parseDate(this.startDate);
15500 this.updateNavArrows();
15503 setEndDate: function(endDate)
15505 this.endDate = endDate || Infinity;
15506 if (this.endDate !== Infinity) {
15507 this.endDate = this.parseDate(this.endDate);
15510 this.updateNavArrows();
15513 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15515 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15516 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15517 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15519 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15520 return parseInt(d, 10);
15523 this.updateNavArrows();
15526 updateNavArrows: function()
15528 if(this.singleMode){
15532 var d = new Date(this.viewDate),
15533 year = d.getUTCFullYear(),
15534 month = d.getUTCMonth();
15536 Roo.each(this.picker().select('.prev', true).elements, function(v){
15538 switch (this.viewMode) {
15541 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15547 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15554 Roo.each(this.picker().select('.next', true).elements, function(v){
15556 switch (this.viewMode) {
15559 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15565 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15573 moveMonth: function(date, dir)
15575 if (!dir) return date;
15576 var new_date = new Date(date.valueOf()),
15577 day = new_date.getUTCDate(),
15578 month = new_date.getUTCMonth(),
15579 mag = Math.abs(dir),
15581 dir = dir > 0 ? 1 : -1;
15584 // If going back one month, make sure month is not current month
15585 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15587 return new_date.getUTCMonth() == month;
15589 // If going forward one month, make sure month is as expected
15590 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15592 return new_date.getUTCMonth() != new_month;
15594 new_month = month + dir;
15595 new_date.setUTCMonth(new_month);
15596 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15597 if (new_month < 0 || new_month > 11)
15598 new_month = (new_month + 12) % 12;
15600 // For magnitudes >1, move one month at a time...
15601 for (var i=0; i<mag; i++)
15602 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15603 new_date = this.moveMonth(new_date, dir);
15604 // ...then reset the day, keeping it in the new month
15605 new_month = new_date.getUTCMonth();
15606 new_date.setUTCDate(day);
15608 return new_month != new_date.getUTCMonth();
15611 // Common date-resetting loop -- if date is beyond end of month, make it
15614 new_date.setUTCDate(--day);
15615 new_date.setUTCMonth(new_month);
15620 moveYear: function(date, dir)
15622 return this.moveMonth(date, dir*12);
15625 dateWithinRange: function(date)
15627 return date >= this.startDate && date <= this.endDate;
15633 this.picker().remove();
15638 Roo.apply(Roo.bootstrap.DateField, {
15649 html: '<i class="fa fa-arrow-left"/>'
15659 html: '<i class="fa fa-arrow-right"/>'
15701 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15702 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15703 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15704 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15705 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15718 navFnc: 'FullYear',
15723 navFnc: 'FullYear',
15728 Roo.apply(Roo.bootstrap.DateField, {
15732 cls: 'datepicker dropdown-menu roo-dynamic',
15736 cls: 'datepicker-days',
15740 cls: 'table-condensed',
15742 Roo.bootstrap.DateField.head,
15746 Roo.bootstrap.DateField.footer
15753 cls: 'datepicker-months',
15757 cls: 'table-condensed',
15759 Roo.bootstrap.DateField.head,
15760 Roo.bootstrap.DateField.content,
15761 Roo.bootstrap.DateField.footer
15768 cls: 'datepicker-years',
15772 cls: 'table-condensed',
15774 Roo.bootstrap.DateField.head,
15775 Roo.bootstrap.DateField.content,
15776 Roo.bootstrap.DateField.footer
15795 * @class Roo.bootstrap.TimeField
15796 * @extends Roo.bootstrap.Input
15797 * Bootstrap DateField class
15801 * Create a new TimeField
15802 * @param {Object} config The config object
15805 Roo.bootstrap.TimeField = function(config){
15806 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15810 * Fires when this field show.
15811 * @param {Roo.bootstrap.DateField} thisthis
15812 * @param {Mixed} date The date value
15817 * Fires when this field hide.
15818 * @param {Roo.bootstrap.DateField} this
15819 * @param {Mixed} date The date value
15824 * Fires when select a date.
15825 * @param {Roo.bootstrap.DateField} this
15826 * @param {Mixed} date The date value
15832 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15835 * @cfg {String} format
15836 * The default time format string which can be overriden for localization support. The format must be
15837 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15841 onRender: function(ct, position)
15844 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15846 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15848 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15850 this.pop = this.picker().select('>.datepicker-time',true).first();
15851 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15853 this.picker().on('mousedown', this.onMousedown, this);
15854 this.picker().on('click', this.onClick, this);
15856 this.picker().addClass('datepicker-dropdown');
15861 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15862 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15863 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15864 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15865 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15866 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15870 fireKey: function(e){
15871 if (!this.picker().isVisible()){
15872 if (e.keyCode == 27) { // allow escape to hide and re-show picker
15878 e.preventDefault();
15886 this.onTogglePeriod();
15889 this.onIncrementMinutes();
15892 this.onDecrementMinutes();
15901 onClick: function(e) {
15902 e.stopPropagation();
15903 e.preventDefault();
15906 picker : function()
15908 return this.el.select('.datepicker', true).first();
15911 fillTime: function()
15913 var time = this.pop.select('tbody', true).first();
15915 time.dom.innerHTML = '';
15930 cls: 'hours-up glyphicon glyphicon-chevron-up'
15950 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15971 cls: 'timepicker-hour',
15986 cls: 'timepicker-minute',
16001 cls: 'btn btn-primary period',
16023 cls: 'hours-down glyphicon glyphicon-chevron-down'
16043 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16061 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16068 var hours = this.time.getHours();
16069 var minutes = this.time.getMinutes();
16082 hours = hours - 12;
16086 hours = '0' + hours;
16090 minutes = '0' + minutes;
16093 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16094 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16095 this.pop.select('button', true).first().dom.innerHTML = period;
16101 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16103 var cls = ['bottom'];
16105 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16112 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16117 this.picker().addClass(cls.join('-'));
16121 Roo.each(cls, function(c){
16123 _this.picker().setTop(_this.inputEl().getHeight());
16127 _this.picker().setTop(0 - _this.picker().getHeight());
16132 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16136 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16143 onFocus : function()
16145 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16149 onBlur : function()
16151 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16157 this.picker().show();
16162 this.fireEvent('show', this, this.date);
16167 this.picker().hide();
16170 this.fireEvent('hide', this, this.date);
16173 setTime : function()
16176 this.setValue(this.time.format(this.format));
16178 this.fireEvent('select', this, this.date);
16183 onMousedown: function(e){
16184 e.stopPropagation();
16185 e.preventDefault();
16188 onIncrementHours: function()
16190 Roo.log('onIncrementHours');
16191 this.time = this.time.add(Date.HOUR, 1);
16196 onDecrementHours: function()
16198 Roo.log('onDecrementHours');
16199 this.time = this.time.add(Date.HOUR, -1);
16203 onIncrementMinutes: function()
16205 Roo.log('onIncrementMinutes');
16206 this.time = this.time.add(Date.MINUTE, 1);
16210 onDecrementMinutes: function()
16212 Roo.log('onDecrementMinutes');
16213 this.time = this.time.add(Date.MINUTE, -1);
16217 onTogglePeriod: function()
16219 Roo.log('onTogglePeriod');
16220 this.time = this.time.add(Date.HOUR, 12);
16227 Roo.apply(Roo.bootstrap.TimeField, {
16257 cls: 'btn btn-info ok',
16269 Roo.apply(Roo.bootstrap.TimeField, {
16273 cls: 'datepicker dropdown-menu',
16277 cls: 'datepicker-time',
16281 cls: 'table-condensed',
16283 Roo.bootstrap.TimeField.content,
16284 Roo.bootstrap.TimeField.footer
16303 * @class Roo.bootstrap.MonthField
16304 * @extends Roo.bootstrap.Input
16305 * Bootstrap MonthField class
16307 * @cfg {String} language default en
16310 * Create a new MonthField
16311 * @param {Object} config The config object
16314 Roo.bootstrap.MonthField = function(config){
16315 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16320 * Fires when this field show.
16321 * @param {Roo.bootstrap.MonthField} this
16322 * @param {Mixed} date The date value
16327 * Fires when this field hide.
16328 * @param {Roo.bootstrap.MonthField} this
16329 * @param {Mixed} date The date value
16334 * Fires when select a date.
16335 * @param {Roo.bootstrap.MonthField} this
16336 * @param {String} oldvalue The old value
16337 * @param {String} newvalue The new value
16343 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16345 onRender: function(ct, position)
16348 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16350 this.language = this.language || 'en';
16351 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16352 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16354 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16355 this.isInline = false;
16356 this.isInput = true;
16357 this.component = this.el.select('.add-on', true).first() || false;
16358 this.component = (this.component && this.component.length === 0) ? false : this.component;
16359 this.hasInput = this.component && this.inputEL().length;
16361 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16363 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16365 this.picker().on('mousedown', this.onMousedown, this);
16366 this.picker().on('click', this.onClick, this);
16368 this.picker().addClass('datepicker-dropdown');
16370 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16371 v.setStyle('width', '189px');
16378 if(this.isInline) {
16384 setValue: function(v, suppressEvent)
16386 var o = this.getValue();
16388 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16392 if(suppressEvent !== true){
16393 this.fireEvent('select', this, o, v);
16398 getValue: function()
16403 onClick: function(e)
16405 e.stopPropagation();
16406 e.preventDefault();
16408 var target = e.getTarget();
16410 if(target.nodeName.toLowerCase() === 'i'){
16411 target = Roo.get(target).dom.parentNode;
16414 var nodeName = target.nodeName;
16415 var className = target.className;
16416 var html = target.innerHTML;
16418 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16422 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16424 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16430 picker : function()
16432 return this.pickerEl;
16435 fillMonths: function()
16438 var months = this.picker().select('>.datepicker-months td', true).first();
16440 months.dom.innerHTML = '';
16446 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16449 months.createChild(month);
16458 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16459 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16462 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16463 e.removeClass('active');
16465 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16466 e.addClass('active');
16473 if(this.isInline) return;
16475 this.picker().removeClass(['bottom', 'top']);
16477 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16479 * place to the top of element!
16483 this.picker().addClass('top');
16484 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16489 this.picker().addClass('bottom');
16491 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16494 onFocus : function()
16496 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16500 onBlur : function()
16502 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16504 var d = this.inputEl().getValue();
16513 this.picker().show();
16514 this.picker().select('>.datepicker-months', true).first().show();
16518 this.fireEvent('show', this, this.date);
16523 if(this.isInline) return;
16524 this.picker().hide();
16525 this.fireEvent('hide', this, this.date);
16529 onMousedown: function(e)
16531 e.stopPropagation();
16532 e.preventDefault();
16537 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16541 fireKey: function(e)
16543 if (!this.picker().isVisible()){
16544 if (e.keyCode == 27) // allow escape to hide and re-show picker
16554 e.preventDefault();
16558 dir = e.keyCode == 37 ? -1 : 1;
16560 this.vIndex = this.vIndex + dir;
16562 if(this.vIndex < 0){
16566 if(this.vIndex > 11){
16570 if(isNaN(this.vIndex)){
16574 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16580 dir = e.keyCode == 38 ? -1 : 1;
16582 this.vIndex = this.vIndex + dir * 4;
16584 if(this.vIndex < 0){
16588 if(this.vIndex > 11){
16592 if(isNaN(this.vIndex)){
16596 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16601 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16602 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16606 e.preventDefault();
16609 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16610 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16626 this.picker().remove();
16631 Roo.apply(Roo.bootstrap.MonthField, {
16650 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16651 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16656 Roo.apply(Roo.bootstrap.MonthField, {
16660 cls: 'datepicker dropdown-menu roo-dynamic',
16664 cls: 'datepicker-months',
16668 cls: 'table-condensed',
16670 Roo.bootstrap.DateField.content
16690 * @class Roo.bootstrap.CheckBox
16691 * @extends Roo.bootstrap.Input
16692 * Bootstrap CheckBox class
16694 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16695 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16696 * @cfg {String} boxLabel The text that appears beside the checkbox
16697 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16698 * @cfg {Boolean} checked initnal the element
16699 * @cfg {Boolean} inline inline the element (default false)
16700 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16703 * Create a new CheckBox
16704 * @param {Object} config The config object
16707 Roo.bootstrap.CheckBox = function(config){
16708 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16713 * Fires when the element is checked or unchecked.
16714 * @param {Roo.bootstrap.CheckBox} this This input
16715 * @param {Boolean} checked The new checked value
16722 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16724 inputType: 'checkbox',
16732 getAutoCreate : function()
16734 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16740 cfg.cls = 'form-group ' + this.inputType; //input-group
16743 cfg.cls += ' ' + this.inputType + '-inline';
16749 type : this.inputType,
16750 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16751 cls : 'roo-' + this.inputType, //'form-box',
16752 placeholder : this.placeholder || ''
16756 if (this.weight) { // Validity check?
16757 cfg.cls += " " + this.inputType + "-" + this.weight;
16760 if (this.disabled) {
16761 input.disabled=true;
16765 input.checked = this.checked;
16769 input.name = this.name;
16773 input.cls += ' input-' + this.size;
16778 ['xs','sm','md','lg'].map(function(size){
16779 if (settings[size]) {
16780 cfg.cls += ' col-' + size + '-' + settings[size];
16784 var inputblock = input;
16786 if (this.before || this.after) {
16789 cls : 'input-group',
16794 inputblock.cn.push({
16796 cls : 'input-group-addon',
16801 inputblock.cn.push(input);
16804 inputblock.cn.push({
16806 cls : 'input-group-addon',
16813 if (align ==='left' && this.fieldLabel.length) {
16814 Roo.log("left and has label");
16820 cls : 'control-label col-md-' + this.labelWidth,
16821 html : this.fieldLabel
16825 cls : "col-md-" + (12 - this.labelWidth),
16832 } else if ( this.fieldLabel.length) {
16837 tag: this.boxLabel ? 'span' : 'label',
16839 cls: 'control-label box-input-label',
16840 //cls : 'input-group-addon',
16841 html : this.fieldLabel
16851 Roo.log(" no label && no align");
16852 cfg.cn = [ inputblock ] ;
16857 var boxLabelCfg = {
16859 //'for': id, // box label is handled by onclick - so no for...
16861 html: this.boxLabel
16865 boxLabelCfg.tooltip = this.tooltip;
16868 cfg.cn.push(boxLabelCfg);
16878 * return the real input element.
16880 inputEl: function ()
16882 return this.el.select('input.roo-' + this.inputType,true).first();
16885 labelEl: function()
16887 return this.el.select('label.control-label',true).first();
16889 /* depricated... */
16893 return this.labelEl();
16896 initEvents : function()
16898 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16900 this.inputEl().on('click', this.onClick, this);
16902 if (this.boxLabel) {
16903 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16906 this.startValue = this.getValue();
16909 Roo.bootstrap.CheckBox.register(this);
16913 onClick : function()
16915 this.setChecked(!this.checked);
16918 setChecked : function(state,suppressEvent)
16920 this.startValue = this.getValue();
16922 if(this.inputType == 'radio'){
16924 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16925 e.dom.checked = false;
16928 this.inputEl().dom.checked = true;
16930 this.inputEl().dom.value = this.inputValue;
16932 if(suppressEvent !== true){
16933 this.fireEvent('check', this, true);
16941 this.checked = state;
16943 this.inputEl().dom.checked = state;
16945 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16947 if(suppressEvent !== true){
16948 this.fireEvent('check', this, state);
16954 getValue : function()
16956 if(this.inputType == 'radio'){
16957 return this.getGroupValue();
16960 return this.inputEl().getValue();
16964 getGroupValue : function()
16966 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16970 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16973 setValue : function(v,suppressEvent)
16975 if(this.inputType == 'radio'){
16976 this.setGroupValue(v, suppressEvent);
16980 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16985 setGroupValue : function(v, suppressEvent)
16987 this.startValue = this.getValue();
16989 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16990 e.dom.checked = false;
16992 if(e.dom.value == v){
16993 e.dom.checked = true;
16997 if(suppressEvent !== true){
16998 this.fireEvent('check', this, true);
17006 validate : function()
17010 (this.inputType == 'radio' && this.validateRadio()) ||
17011 (this.inputType == 'checkbox' && this.validateCheckbox())
17017 this.markInvalid();
17021 validateRadio : function()
17025 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17026 if(!e.dom.checked){
17038 validateCheckbox : function()
17041 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17044 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17052 for(var i in group){
17057 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17064 * Mark this field as valid
17066 markValid : function()
17070 this.fireEvent('valid', this);
17072 if(this.inputType == 'radio'){
17073 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17074 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17075 e.findParent('.form-group', false, true).addClass(_this.validClass);
17082 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17083 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17087 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17093 for(var i in group){
17094 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17095 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17100 * Mark this field as invalid
17101 * @param {String} msg The validation message
17103 markInvalid : function(msg)
17107 this.fireEvent('invalid', this, msg);
17109 if(this.inputType == 'radio'){
17110 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17111 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17112 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17119 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17120 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17124 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17130 for(var i in group){
17131 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17132 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17139 Roo.apply(Roo.bootstrap.CheckBox, {
17144 * register a CheckBox Group
17145 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17147 register : function(checkbox)
17149 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17150 this.groups[checkbox.groupId] = {};
17153 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17157 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17161 * fetch a CheckBox Group based on the group ID
17162 * @param {string} the group ID
17163 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17165 get: function(groupId) {
17166 if (typeof(this.groups[groupId]) == 'undefined') {
17170 return this.groups[groupId] ;
17182 *<div class="radio">
17184 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17185 Option one is this and that—be sure to include why it's great
17192 *<label class="radio-inline">fieldLabel</label>
17193 *<label class="radio-inline">
17194 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17202 * @class Roo.bootstrap.Radio
17203 * @extends Roo.bootstrap.CheckBox
17204 * Bootstrap Radio class
17207 * Create a new Radio
17208 * @param {Object} config The config object
17211 Roo.bootstrap.Radio = function(config){
17212 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17216 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17218 inputType: 'radio',
17222 getAutoCreate : function()
17224 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17225 align = align || 'left'; // default...
17232 tag : this.inline ? 'span' : 'div',
17237 var inline = this.inline ? ' radio-inline' : '';
17241 // does not need for, as we wrap the input with it..
17243 cls : 'control-label box-label' + inline,
17246 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17250 //cls : 'control-label' + inline,
17251 html : this.fieldLabel,
17252 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17261 type : this.inputType,
17262 //value : (!this.checked) ? this.valueOff : this.inputValue,
17263 value : this.inputValue,
17265 placeholder : this.placeholder || '' // ?? needed????
17268 if (this.weight) { // Validity check?
17269 input.cls += " radio-" + this.weight;
17271 if (this.disabled) {
17272 input.disabled=true;
17276 input.checked = this.checked;
17280 input.name = this.name;
17284 input.cls += ' input-' + this.size;
17287 //?? can span's inline have a width??
17290 ['xs','sm','md','lg'].map(function(size){
17291 if (settings[size]) {
17292 cfg.cls += ' col-' + size + '-' + settings[size];
17296 var inputblock = input;
17298 if (this.before || this.after) {
17301 cls : 'input-group',
17306 inputblock.cn.push({
17308 cls : 'input-group-addon',
17312 inputblock.cn.push(input);
17314 inputblock.cn.push({
17316 cls : 'input-group-addon',
17324 if (this.fieldLabel && this.fieldLabel.length) {
17325 cfg.cn.push(fieldLabel);
17328 // normal bootstrap puts the input inside the label.
17329 // however with our styled version - it has to go after the input.
17331 //lbl.cn.push(inputblock);
17335 cls: 'radio' + inline,
17342 cfg.cn.push( lblwrap);
17347 html: this.boxLabel
17356 initEvents : function()
17358 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17360 this.inputEl().on('click', this.onClick, this);
17361 if (this.boxLabel) {
17362 Roo.log('find label')
17363 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17368 inputEl: function ()
17370 return this.el.select('input.roo-radio',true).first();
17372 onClick : function()
17375 this.setChecked(true);
17378 setChecked : function(state,suppressEvent)
17381 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17382 v.dom.checked = false;
17385 Roo.log(this.inputEl().dom);
17386 this.checked = state;
17387 this.inputEl().dom.checked = state;
17389 if(suppressEvent !== true){
17390 this.fireEvent('check', this, state);
17393 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17397 getGroupValue : function()
17400 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17401 if(v.dom.checked == true){
17402 value = v.dom.value;
17410 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17411 * @return {Mixed} value The field value
17413 getValue : function(){
17414 return this.getGroupValue();
17420 //<script type="text/javascript">
17423 * Based Ext JS Library 1.1.1
17424 * Copyright(c) 2006-2007, Ext JS, LLC.
17430 * @class Roo.HtmlEditorCore
17431 * @extends Roo.Component
17432 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17434 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17437 Roo.HtmlEditorCore = function(config){
17440 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17445 * @event initialize
17446 * Fires when the editor is fully initialized (including the iframe)
17447 * @param {Roo.HtmlEditorCore} this
17452 * Fires when the editor is first receives the focus. Any insertion must wait
17453 * until after this event.
17454 * @param {Roo.HtmlEditorCore} this
17458 * @event beforesync
17459 * Fires before the textarea is updated with content from the editor iframe. Return false
17460 * to cancel the sync.
17461 * @param {Roo.HtmlEditorCore} this
17462 * @param {String} html
17466 * @event beforepush
17467 * Fires before the iframe editor is updated with content from the textarea. Return false
17468 * to cancel the push.
17469 * @param {Roo.HtmlEditorCore} this
17470 * @param {String} html
17475 * Fires when the textarea is updated with content from the editor iframe.
17476 * @param {Roo.HtmlEditorCore} this
17477 * @param {String} html
17482 * Fires when the iframe editor is updated with content from the textarea.
17483 * @param {Roo.HtmlEditorCore} this
17484 * @param {String} html
17489 * @event editorevent
17490 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17491 * @param {Roo.HtmlEditorCore} this
17497 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17499 // defaults : white / black...
17500 this.applyBlacklists();
17507 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17511 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17517 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17522 * @cfg {Number} height (in pixels)
17526 * @cfg {Number} width (in pixels)
17531 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17534 stylesheets: false,
17539 // private properties
17540 validationEvent : false,
17542 initialized : false,
17544 sourceEditMode : false,
17545 onFocus : Roo.emptyFn,
17547 hideMode:'offsets',
17551 // blacklist + whitelisted elements..
17558 * Protected method that will not generally be called directly. It
17559 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17560 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17562 getDocMarkup : function(){
17566 // inherit styels from page...??
17567 if (this.stylesheets === false) {
17569 Roo.get(document.head).select('style').each(function(node) {
17570 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17573 Roo.get(document.head).select('link').each(function(node) {
17574 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17577 } else if (!this.stylesheets.length) {
17579 st = '<style type="text/css">' +
17580 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17586 st += '<style type="text/css">' +
17587 'IMG { cursor: pointer } ' +
17591 return '<html><head>' + st +
17592 //<style type="text/css">' +
17593 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17595 ' </head><body class="roo-htmleditor-body"></body></html>';
17599 onRender : function(ct, position)
17602 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17603 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17606 this.el.dom.style.border = '0 none';
17607 this.el.dom.setAttribute('tabIndex', -1);
17608 this.el.addClass('x-hidden hide');
17612 if(Roo.isIE){ // fix IE 1px bogus margin
17613 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17617 this.frameId = Roo.id();
17621 var iframe = this.owner.wrap.createChild({
17623 cls: 'form-control', // bootstrap..
17625 name: this.frameId,
17626 frameBorder : 'no',
17627 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17632 this.iframe = iframe.dom;
17634 this.assignDocWin();
17636 this.doc.designMode = 'on';
17639 this.doc.write(this.getDocMarkup());
17643 var task = { // must defer to wait for browser to be ready
17645 //console.log("run task?" + this.doc.readyState);
17646 this.assignDocWin();
17647 if(this.doc.body || this.doc.readyState == 'complete'){
17649 this.doc.designMode="on";
17653 Roo.TaskMgr.stop(task);
17654 this.initEditor.defer(10, this);
17661 Roo.TaskMgr.start(task);
17666 onResize : function(w, h)
17668 Roo.log('resize: ' +w + ',' + h );
17669 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17673 if(typeof w == 'number'){
17675 this.iframe.style.width = w + 'px';
17677 if(typeof h == 'number'){
17679 this.iframe.style.height = h + 'px';
17681 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17688 * Toggles the editor between standard and source edit mode.
17689 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17691 toggleSourceEdit : function(sourceEditMode){
17693 this.sourceEditMode = sourceEditMode === true;
17695 if(this.sourceEditMode){
17697 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17700 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17701 //this.iframe.className = '';
17704 //this.setSize(this.owner.wrap.getSize());
17705 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17712 * Protected method that will not generally be called directly. If you need/want
17713 * custom HTML cleanup, this is the method you should override.
17714 * @param {String} html The HTML to be cleaned
17715 * return {String} The cleaned HTML
17717 cleanHtml : function(html){
17718 html = String(html);
17719 if(html.length > 5){
17720 if(Roo.isSafari){ // strip safari nonsense
17721 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17724 if(html == ' '){
17731 * HTML Editor -> Textarea
17732 * Protected method that will not generally be called directly. Syncs the contents
17733 * of the editor iframe with the textarea.
17735 syncValue : function(){
17736 if(this.initialized){
17737 var bd = (this.doc.body || this.doc.documentElement);
17738 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17739 var html = bd.innerHTML;
17741 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17742 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17744 html = '<div style="'+m[0]+'">' + html + '</div>';
17747 html = this.cleanHtml(html);
17748 // fix up the special chars.. normaly like back quotes in word...
17749 // however we do not want to do this with chinese..
17750 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17751 var cc = b.charCodeAt();
17753 (cc >= 0x4E00 && cc < 0xA000 ) ||
17754 (cc >= 0x3400 && cc < 0x4E00 ) ||
17755 (cc >= 0xf900 && cc < 0xfb00 )
17761 if(this.owner.fireEvent('beforesync', this, html) !== false){
17762 this.el.dom.value = html;
17763 this.owner.fireEvent('sync', this, html);
17769 * Protected method that will not generally be called directly. Pushes the value of the textarea
17770 * into the iframe editor.
17772 pushValue : function(){
17773 if(this.initialized){
17774 var v = this.el.dom.value.trim();
17776 // if(v.length < 1){
17780 if(this.owner.fireEvent('beforepush', this, v) !== false){
17781 var d = (this.doc.body || this.doc.documentElement);
17783 this.cleanUpPaste();
17784 this.el.dom.value = d.innerHTML;
17785 this.owner.fireEvent('push', this, v);
17791 deferFocus : function(){
17792 this.focus.defer(10, this);
17796 focus : function(){
17797 if(this.win && !this.sourceEditMode){
17804 assignDocWin: function()
17806 var iframe = this.iframe;
17809 this.doc = iframe.contentWindow.document;
17810 this.win = iframe.contentWindow;
17812 // if (!Roo.get(this.frameId)) {
17815 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17816 // this.win = Roo.get(this.frameId).dom.contentWindow;
17818 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17822 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17823 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17828 initEditor : function(){
17829 //console.log("INIT EDITOR");
17830 this.assignDocWin();
17834 this.doc.designMode="on";
17836 this.doc.write(this.getDocMarkup());
17839 var dbody = (this.doc.body || this.doc.documentElement);
17840 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17841 // this copies styles from the containing element into thsi one..
17842 // not sure why we need all of this..
17843 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17845 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17846 //ss['background-attachment'] = 'fixed'; // w3c
17847 dbody.bgProperties = 'fixed'; // ie
17848 //Roo.DomHelper.applyStyles(dbody, ss);
17849 Roo.EventManager.on(this.doc, {
17850 //'mousedown': this.onEditorEvent,
17851 'mouseup': this.onEditorEvent,
17852 'dblclick': this.onEditorEvent,
17853 'click': this.onEditorEvent,
17854 'keyup': this.onEditorEvent,
17859 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17861 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17862 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17864 this.initialized = true;
17866 this.owner.fireEvent('initialize', this);
17871 onDestroy : function(){
17877 //for (var i =0; i < this.toolbars.length;i++) {
17878 // // fixme - ask toolbars for heights?
17879 // this.toolbars[i].onDestroy();
17882 //this.wrap.dom.innerHTML = '';
17883 //this.wrap.remove();
17888 onFirstFocus : function(){
17890 this.assignDocWin();
17893 this.activated = true;
17896 if(Roo.isGecko){ // prevent silly gecko errors
17898 var s = this.win.getSelection();
17899 if(!s.focusNode || s.focusNode.nodeType != 3){
17900 var r = s.getRangeAt(0);
17901 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17906 this.execCmd('useCSS', true);
17907 this.execCmd('styleWithCSS', false);
17910 this.owner.fireEvent('activate', this);
17914 adjustFont: function(btn){
17915 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17916 //if(Roo.isSafari){ // safari
17919 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17920 if(Roo.isSafari){ // safari
17921 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17922 v = (v < 10) ? 10 : v;
17923 v = (v > 48) ? 48 : v;
17924 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17929 v = Math.max(1, v+adjust);
17931 this.execCmd('FontSize', v );
17934 onEditorEvent : function(e){
17935 this.owner.fireEvent('editorevent', this, e);
17936 // this.updateToolbar();
17937 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17940 insertTag : function(tg)
17942 // could be a bit smarter... -> wrap the current selected tRoo..
17943 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17945 range = this.createRange(this.getSelection());
17946 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17947 wrappingNode.appendChild(range.extractContents());
17948 range.insertNode(wrappingNode);
17955 this.execCmd("formatblock", tg);
17959 insertText : function(txt)
17963 var range = this.createRange();
17964 range.deleteContents();
17965 //alert(Sender.getAttribute('label'));
17967 range.insertNode(this.doc.createTextNode(txt));
17973 * Executes a Midas editor command on the editor document and performs necessary focus and
17974 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17975 * @param {String} cmd The Midas command
17976 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17978 relayCmd : function(cmd, value){
17980 this.execCmd(cmd, value);
17981 this.owner.fireEvent('editorevent', this);
17982 //this.updateToolbar();
17983 this.owner.deferFocus();
17987 * Executes a Midas editor command directly on the editor document.
17988 * For visual commands, you should use {@link #relayCmd} instead.
17989 * <b>This should only be called after the editor is initialized.</b>
17990 * @param {String} cmd The Midas command
17991 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17993 execCmd : function(cmd, value){
17994 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18001 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18003 * @param {String} text | dom node..
18005 insertAtCursor : function(text)
18010 if(!this.activated){
18016 var r = this.doc.selection.createRange();
18027 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18031 // from jquery ui (MIT licenced)
18033 var win = this.win;
18035 if (win.getSelection && win.getSelection().getRangeAt) {
18036 range = win.getSelection().getRangeAt(0);
18037 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18038 range.insertNode(node);
18039 } else if (win.document.selection && win.document.selection.createRange) {
18040 // no firefox support
18041 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18042 win.document.selection.createRange().pasteHTML(txt);
18044 // no firefox support
18045 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18046 this.execCmd('InsertHTML', txt);
18055 mozKeyPress : function(e){
18057 var c = e.getCharCode(), cmd;
18060 c = String.fromCharCode(c).toLowerCase();
18074 this.cleanUpPaste.defer(100, this);
18082 e.preventDefault();
18090 fixKeys : function(){ // load time branching for fastest keydown performance
18092 return function(e){
18093 var k = e.getKey(), r;
18096 r = this.doc.selection.createRange();
18099 r.pasteHTML('    ');
18106 r = this.doc.selection.createRange();
18108 var target = r.parentElement();
18109 if(!target || target.tagName.toLowerCase() != 'li'){
18111 r.pasteHTML('<br />');
18117 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18118 this.cleanUpPaste.defer(100, this);
18124 }else if(Roo.isOpera){
18125 return function(e){
18126 var k = e.getKey();
18130 this.execCmd('InsertHTML','    ');
18133 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18134 this.cleanUpPaste.defer(100, this);
18139 }else if(Roo.isSafari){
18140 return function(e){
18141 var k = e.getKey();
18145 this.execCmd('InsertText','\t');
18149 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18150 this.cleanUpPaste.defer(100, this);
18158 getAllAncestors: function()
18160 var p = this.getSelectedNode();
18163 a.push(p); // push blank onto stack..
18164 p = this.getParentElement();
18168 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18172 a.push(this.doc.body);
18176 lastSelNode : false,
18179 getSelection : function()
18181 this.assignDocWin();
18182 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18185 getSelectedNode: function()
18187 // this may only work on Gecko!!!
18189 // should we cache this!!!!
18194 var range = this.createRange(this.getSelection()).cloneRange();
18197 var parent = range.parentElement();
18199 var testRange = range.duplicate();
18200 testRange.moveToElementText(parent);
18201 if (testRange.inRange(range)) {
18204 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18207 parent = parent.parentElement;
18212 // is ancestor a text element.
18213 var ac = range.commonAncestorContainer;
18214 if (ac.nodeType == 3) {
18215 ac = ac.parentNode;
18218 var ar = ac.childNodes;
18221 var other_nodes = [];
18222 var has_other_nodes = false;
18223 for (var i=0;i<ar.length;i++) {
18224 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18227 // fullly contained node.
18229 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18234 // probably selected..
18235 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18236 other_nodes.push(ar[i]);
18240 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18245 has_other_nodes = true;
18247 if (!nodes.length && other_nodes.length) {
18248 nodes= other_nodes;
18250 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18256 createRange: function(sel)
18258 // this has strange effects when using with
18259 // top toolbar - not sure if it's a great idea.
18260 //this.editor.contentWindow.focus();
18261 if (typeof sel != "undefined") {
18263 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18265 return this.doc.createRange();
18268 return this.doc.createRange();
18271 getParentElement: function()
18274 this.assignDocWin();
18275 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18277 var range = this.createRange(sel);
18280 var p = range.commonAncestorContainer;
18281 while (p.nodeType == 3) { // text node
18292 * Range intersection.. the hard stuff...
18296 * [ -- selected range --- ]
18300 * if end is before start or hits it. fail.
18301 * if start is after end or hits it fail.
18303 * if either hits (but other is outside. - then it's not
18309 // @see http://www.thismuchiknow.co.uk/?p=64.
18310 rangeIntersectsNode : function(range, node)
18312 var nodeRange = node.ownerDocument.createRange();
18314 nodeRange.selectNode(node);
18316 nodeRange.selectNodeContents(node);
18319 var rangeStartRange = range.cloneRange();
18320 rangeStartRange.collapse(true);
18322 var rangeEndRange = range.cloneRange();
18323 rangeEndRange.collapse(false);
18325 var nodeStartRange = nodeRange.cloneRange();
18326 nodeStartRange.collapse(true);
18328 var nodeEndRange = nodeRange.cloneRange();
18329 nodeEndRange.collapse(false);
18331 return rangeStartRange.compareBoundaryPoints(
18332 Range.START_TO_START, nodeEndRange) == -1 &&
18333 rangeEndRange.compareBoundaryPoints(
18334 Range.START_TO_START, nodeStartRange) == 1;
18338 rangeCompareNode : function(range, node)
18340 var nodeRange = node.ownerDocument.createRange();
18342 nodeRange.selectNode(node);
18344 nodeRange.selectNodeContents(node);
18348 range.collapse(true);
18350 nodeRange.collapse(true);
18352 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18353 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18355 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18357 var nodeIsBefore = ss == 1;
18358 var nodeIsAfter = ee == -1;
18360 if (nodeIsBefore && nodeIsAfter)
18362 if (!nodeIsBefore && nodeIsAfter)
18363 return 1; //right trailed.
18365 if (nodeIsBefore && !nodeIsAfter)
18366 return 2; // left trailed.
18371 // private? - in a new class?
18372 cleanUpPaste : function()
18374 // cleans up the whole document..
18375 Roo.log('cleanuppaste');
18377 this.cleanUpChildren(this.doc.body);
18378 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18379 if (clean != this.doc.body.innerHTML) {
18380 this.doc.body.innerHTML = clean;
18385 cleanWordChars : function(input) {// change the chars to hex code
18386 var he = Roo.HtmlEditorCore;
18388 var output = input;
18389 Roo.each(he.swapCodes, function(sw) {
18390 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18392 output = output.replace(swapper, sw[1]);
18399 cleanUpChildren : function (n)
18401 if (!n.childNodes.length) {
18404 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18405 this.cleanUpChild(n.childNodes[i]);
18412 cleanUpChild : function (node)
18415 //console.log(node);
18416 if (node.nodeName == "#text") {
18417 // clean up silly Windows -- stuff?
18420 if (node.nodeName == "#comment") {
18421 node.parentNode.removeChild(node);
18422 // clean up silly Windows -- stuff?
18425 var lcname = node.tagName.toLowerCase();
18426 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18427 // whitelist of tags..
18429 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18431 node.parentNode.removeChild(node);
18436 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18438 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18439 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18441 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18442 // remove_keep_children = true;
18445 if (remove_keep_children) {
18446 this.cleanUpChildren(node);
18447 // inserts everything just before this node...
18448 while (node.childNodes.length) {
18449 var cn = node.childNodes[0];
18450 node.removeChild(cn);
18451 node.parentNode.insertBefore(cn, node);
18453 node.parentNode.removeChild(node);
18457 if (!node.attributes || !node.attributes.length) {
18458 this.cleanUpChildren(node);
18462 function cleanAttr(n,v)
18465 if (v.match(/^\./) || v.match(/^\//)) {
18468 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18471 if (v.match(/^#/)) {
18474 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18475 node.removeAttribute(n);
18479 var cwhite = this.cwhite;
18480 var cblack = this.cblack;
18482 function cleanStyle(n,v)
18484 if (v.match(/expression/)) { //XSS?? should we even bother..
18485 node.removeAttribute(n);
18489 var parts = v.split(/;/);
18492 Roo.each(parts, function(p) {
18493 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18497 var l = p.split(':').shift().replace(/\s+/g,'');
18498 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18500 if ( cwhite.length && cblack.indexOf(l) > -1) {
18501 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18502 //node.removeAttribute(n);
18506 // only allow 'c whitelisted system attributes'
18507 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18508 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18509 //node.removeAttribute(n);
18519 if (clean.length) {
18520 node.setAttribute(n, clean.join(';'));
18522 node.removeAttribute(n);
18528 for (var i = node.attributes.length-1; i > -1 ; i--) {
18529 var a = node.attributes[i];
18532 if (a.name.toLowerCase().substr(0,2)=='on') {
18533 node.removeAttribute(a.name);
18536 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18537 node.removeAttribute(a.name);
18540 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18541 cleanAttr(a.name,a.value); // fixme..
18544 if (a.name == 'style') {
18545 cleanStyle(a.name,a.value);
18548 /// clean up MS crap..
18549 // tecnically this should be a list of valid class'es..
18552 if (a.name == 'class') {
18553 if (a.value.match(/^Mso/)) {
18554 node.className = '';
18557 if (a.value.match(/body/)) {
18558 node.className = '';
18569 this.cleanUpChildren(node);
18574 * Clean up MS wordisms...
18576 cleanWord : function(node)
18579 var cleanWordChildren = function()
18581 if (!node.childNodes.length) {
18584 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18585 _t.cleanWord(node.childNodes[i]);
18591 this.cleanWord(this.doc.body);
18594 if (node.nodeName == "#text") {
18595 // clean up silly Windows -- stuff?
18598 if (node.nodeName == "#comment") {
18599 node.parentNode.removeChild(node);
18600 // clean up silly Windows -- stuff?
18604 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18605 node.parentNode.removeChild(node);
18609 // remove - but keep children..
18610 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18611 while (node.childNodes.length) {
18612 var cn = node.childNodes[0];
18613 node.removeChild(cn);
18614 node.parentNode.insertBefore(cn, node);
18616 node.parentNode.removeChild(node);
18617 cleanWordChildren();
18621 if (node.className.length) {
18623 var cn = node.className.split(/\W+/);
18625 Roo.each(cn, function(cls) {
18626 if (cls.match(/Mso[a-zA-Z]+/)) {
18631 node.className = cna.length ? cna.join(' ') : '';
18633 node.removeAttribute("class");
18637 if (node.hasAttribute("lang")) {
18638 node.removeAttribute("lang");
18641 if (node.hasAttribute("style")) {
18643 var styles = node.getAttribute("style").split(";");
18645 Roo.each(styles, function(s) {
18646 if (!s.match(/:/)) {
18649 var kv = s.split(":");
18650 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18653 // what ever is left... we allow.
18656 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18657 if (!nstyle.length) {
18658 node.removeAttribute('style');
18662 cleanWordChildren();
18666 domToHTML : function(currentElement, depth, nopadtext) {
18668 depth = depth || 0;
18669 nopadtext = nopadtext || false;
18671 if (!currentElement) {
18672 return this.domToHTML(this.doc.body);
18675 //Roo.log(currentElement);
18677 var allText = false;
18678 var nodeName = currentElement.nodeName;
18679 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18681 if (nodeName == '#text') {
18683 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18688 if (nodeName != 'BODY') {
18691 // Prints the node tagName, such as <A>, <IMG>, etc
18694 for(i = 0; i < currentElement.attributes.length;i++) {
18696 var aname = currentElement.attributes.item(i).name;
18697 if (!currentElement.attributes.item(i).value.length) {
18700 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18703 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18712 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18715 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18720 // Traverse the tree
18722 var currentElementChild = currentElement.childNodes.item(i);
18723 var allText = true;
18724 var innerHTML = '';
18726 while (currentElementChild) {
18727 // Formatting code (indent the tree so it looks nice on the screen)
18728 var nopad = nopadtext;
18729 if (lastnode == 'SPAN') {
18733 if (currentElementChild.nodeName == '#text') {
18734 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18735 toadd = nopadtext ? toadd : toadd.trim();
18736 if (!nopad && toadd.length > 80) {
18737 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18739 innerHTML += toadd;
18742 currentElementChild = currentElement.childNodes.item(i);
18748 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18750 // Recursively traverse the tree structure of the child node
18751 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18752 lastnode = currentElementChild.nodeName;
18754 currentElementChild=currentElement.childNodes.item(i);
18760 // The remaining code is mostly for formatting the tree
18761 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18766 ret+= "</"+tagName+">";
18772 applyBlacklists : function()
18774 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18775 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18779 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18780 if (b.indexOf(tag) > -1) {
18783 this.white.push(tag);
18787 Roo.each(w, function(tag) {
18788 if (b.indexOf(tag) > -1) {
18791 if (this.white.indexOf(tag) > -1) {
18794 this.white.push(tag);
18799 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18800 if (w.indexOf(tag) > -1) {
18803 this.black.push(tag);
18807 Roo.each(b, function(tag) {
18808 if (w.indexOf(tag) > -1) {
18811 if (this.black.indexOf(tag) > -1) {
18814 this.black.push(tag);
18819 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18820 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18824 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18825 if (b.indexOf(tag) > -1) {
18828 this.cwhite.push(tag);
18832 Roo.each(w, function(tag) {
18833 if (b.indexOf(tag) > -1) {
18836 if (this.cwhite.indexOf(tag) > -1) {
18839 this.cwhite.push(tag);
18844 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18845 if (w.indexOf(tag) > -1) {
18848 this.cblack.push(tag);
18852 Roo.each(b, function(tag) {
18853 if (w.indexOf(tag) > -1) {
18856 if (this.cblack.indexOf(tag) > -1) {
18859 this.cblack.push(tag);
18864 setStylesheets : function(stylesheets)
18866 if(typeof(stylesheets) == 'string'){
18867 Roo.get(this.iframe.contentDocument.head).createChild({
18869 rel : 'stylesheet',
18878 Roo.each(stylesheets, function(s) {
18883 Roo.get(_this.iframe.contentDocument.head).createChild({
18885 rel : 'stylesheet',
18894 removeStylesheets : function()
18898 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18903 // hide stuff that is not compatible
18917 * @event specialkey
18921 * @cfg {String} fieldClass @hide
18924 * @cfg {String} focusClass @hide
18927 * @cfg {String} autoCreate @hide
18930 * @cfg {String} inputType @hide
18933 * @cfg {String} invalidClass @hide
18936 * @cfg {String} invalidText @hide
18939 * @cfg {String} msgFx @hide
18942 * @cfg {String} validateOnBlur @hide
18946 Roo.HtmlEditorCore.white = [
18947 'area', 'br', 'img', 'input', 'hr', 'wbr',
18949 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18950 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18951 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18952 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18953 'table', 'ul', 'xmp',
18955 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18958 'dir', 'menu', 'ol', 'ul', 'dl',
18964 Roo.HtmlEditorCore.black = [
18965 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18967 'base', 'basefont', 'bgsound', 'blink', 'body',
18968 'frame', 'frameset', 'head', 'html', 'ilayer',
18969 'iframe', 'layer', 'link', 'meta', 'object',
18970 'script', 'style' ,'title', 'xml' // clean later..
18972 Roo.HtmlEditorCore.clean = [
18973 'script', 'style', 'title', 'xml'
18975 Roo.HtmlEditorCore.remove = [
18980 Roo.HtmlEditorCore.ablack = [
18984 Roo.HtmlEditorCore.aclean = [
18985 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18989 Roo.HtmlEditorCore.pwhite= [
18990 'http', 'https', 'mailto'
18993 // white listed style attributes.
18994 Roo.HtmlEditorCore.cwhite= [
18995 // 'text-align', /// default is to allow most things..
19001 // black listed style attributes.
19002 Roo.HtmlEditorCore.cblack= [
19003 // 'font-size' -- this can be set by the project
19007 Roo.HtmlEditorCore.swapCodes =[
19026 * @class Roo.bootstrap.HtmlEditor
19027 * @extends Roo.bootstrap.TextArea
19028 * Bootstrap HtmlEditor class
19031 * Create a new HtmlEditor
19032 * @param {Object} config The config object
19035 Roo.bootstrap.HtmlEditor = function(config){
19036 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19037 if (!this.toolbars) {
19038 this.toolbars = [];
19040 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19043 * @event initialize
19044 * Fires when the editor is fully initialized (including the iframe)
19045 * @param {HtmlEditor} this
19050 * Fires when the editor is first receives the focus. Any insertion must wait
19051 * until after this event.
19052 * @param {HtmlEditor} this
19056 * @event beforesync
19057 * Fires before the textarea is updated with content from the editor iframe. Return false
19058 * to cancel the sync.
19059 * @param {HtmlEditor} this
19060 * @param {String} html
19064 * @event beforepush
19065 * Fires before the iframe editor is updated with content from the textarea. Return false
19066 * to cancel the push.
19067 * @param {HtmlEditor} this
19068 * @param {String} html
19073 * Fires when the textarea is updated with content from the editor iframe.
19074 * @param {HtmlEditor} this
19075 * @param {String} html
19080 * Fires when the iframe editor is updated with content from the textarea.
19081 * @param {HtmlEditor} this
19082 * @param {String} html
19086 * @event editmodechange
19087 * Fires when the editor switches edit modes
19088 * @param {HtmlEditor} this
19089 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19091 editmodechange: true,
19093 * @event editorevent
19094 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19095 * @param {HtmlEditor} this
19099 * @event firstfocus
19100 * Fires when on first focus - needed by toolbars..
19101 * @param {HtmlEditor} this
19106 * Auto save the htmlEditor value as a file into Events
19107 * @param {HtmlEditor} this
19111 * @event savedpreview
19112 * preview the saved version of htmlEditor
19113 * @param {HtmlEditor} this
19120 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19124 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19129 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19134 * @cfg {Number} height (in pixels)
19138 * @cfg {Number} width (in pixels)
19143 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19146 stylesheets: false,
19151 // private properties
19152 validationEvent : false,
19154 initialized : false,
19157 onFocus : Roo.emptyFn,
19159 hideMode:'offsets',
19162 tbContainer : false,
19164 toolbarContainer :function() {
19165 return this.wrap.select('.x-html-editor-tb',true).first();
19169 * Protected method that will not generally be called directly. It
19170 * is called when the editor creates its toolbar. Override this method if you need to
19171 * add custom toolbar buttons.
19172 * @param {HtmlEditor} editor
19174 createToolbar : function(){
19176 Roo.log("create toolbars");
19178 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19179 this.toolbars[0].render(this.toolbarContainer());
19183 // if (!editor.toolbars || !editor.toolbars.length) {
19184 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19187 // for (var i =0 ; i < editor.toolbars.length;i++) {
19188 // editor.toolbars[i] = Roo.factory(
19189 // typeof(editor.toolbars[i]) == 'string' ?
19190 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19191 // Roo.bootstrap.HtmlEditor);
19192 // editor.toolbars[i].init(editor);
19198 onRender : function(ct, position)
19200 // Roo.log("Call onRender: " + this.xtype);
19202 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19204 this.wrap = this.inputEl().wrap({
19205 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19208 this.editorcore.onRender(ct, position);
19210 if (this.resizable) {
19211 this.resizeEl = new Roo.Resizable(this.wrap, {
19215 minHeight : this.height,
19216 height: this.height,
19217 handles : this.resizable,
19220 resize : function(r, w, h) {
19221 _t.onResize(w,h); // -something
19227 this.createToolbar(this);
19230 if(!this.width && this.resizable){
19231 this.setSize(this.wrap.getSize());
19233 if (this.resizeEl) {
19234 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19235 // should trigger onReize..
19241 onResize : function(w, h)
19243 Roo.log('resize: ' +w + ',' + h );
19244 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19248 if(this.inputEl() ){
19249 if(typeof w == 'number'){
19250 var aw = w - this.wrap.getFrameWidth('lr');
19251 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19254 if(typeof h == 'number'){
19255 var tbh = -11; // fixme it needs to tool bar size!
19256 for (var i =0; i < this.toolbars.length;i++) {
19257 // fixme - ask toolbars for heights?
19258 tbh += this.toolbars[i].el.getHeight();
19259 //if (this.toolbars[i].footer) {
19260 // tbh += this.toolbars[i].footer.el.getHeight();
19268 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19269 ah -= 5; // knock a few pixes off for look..
19270 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19274 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19275 this.editorcore.onResize(ew,eh);
19280 * Toggles the editor between standard and source edit mode.
19281 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19283 toggleSourceEdit : function(sourceEditMode)
19285 this.editorcore.toggleSourceEdit(sourceEditMode);
19287 if(this.editorcore.sourceEditMode){
19288 Roo.log('editor - showing textarea');
19291 // Roo.log(this.syncValue());
19293 this.inputEl().removeClass(['hide', 'x-hidden']);
19294 this.inputEl().dom.removeAttribute('tabIndex');
19295 this.inputEl().focus();
19297 Roo.log('editor - hiding textarea');
19299 // Roo.log(this.pushValue());
19302 this.inputEl().addClass(['hide', 'x-hidden']);
19303 this.inputEl().dom.setAttribute('tabIndex', -1);
19304 //this.deferFocus();
19307 if(this.resizable){
19308 this.setSize(this.wrap.getSize());
19311 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19314 // private (for BoxComponent)
19315 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19317 // private (for BoxComponent)
19318 getResizeEl : function(){
19322 // private (for BoxComponent)
19323 getPositionEl : function(){
19328 initEvents : function(){
19329 this.originalValue = this.getValue();
19333 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19336 // markInvalid : Roo.emptyFn,
19338 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19341 // clearInvalid : Roo.emptyFn,
19343 setValue : function(v){
19344 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19345 this.editorcore.pushValue();
19350 deferFocus : function(){
19351 this.focus.defer(10, this);
19355 focus : function(){
19356 this.editorcore.focus();
19362 onDestroy : function(){
19368 for (var i =0; i < this.toolbars.length;i++) {
19369 // fixme - ask toolbars for heights?
19370 this.toolbars[i].onDestroy();
19373 this.wrap.dom.innerHTML = '';
19374 this.wrap.remove();
19379 onFirstFocus : function(){
19380 //Roo.log("onFirstFocus");
19381 this.editorcore.onFirstFocus();
19382 for (var i =0; i < this.toolbars.length;i++) {
19383 this.toolbars[i].onFirstFocus();
19389 syncValue : function()
19391 this.editorcore.syncValue();
19394 pushValue : function()
19396 this.editorcore.pushValue();
19400 // hide stuff that is not compatible
19414 * @event specialkey
19418 * @cfg {String} fieldClass @hide
19421 * @cfg {String} focusClass @hide
19424 * @cfg {String} autoCreate @hide
19427 * @cfg {String} inputType @hide
19430 * @cfg {String} invalidClass @hide
19433 * @cfg {String} invalidText @hide
19436 * @cfg {String} msgFx @hide
19439 * @cfg {String} validateOnBlur @hide
19448 Roo.namespace('Roo.bootstrap.htmleditor');
19450 * @class Roo.bootstrap.HtmlEditorToolbar1
19455 new Roo.bootstrap.HtmlEditor({
19458 new Roo.bootstrap.HtmlEditorToolbar1({
19459 disable : { fonts: 1 , format: 1, ..., ... , ...],
19465 * @cfg {Object} disable List of elements to disable..
19466 * @cfg {Array} btns List of additional buttons.
19470 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19473 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19476 Roo.apply(this, config);
19478 // default disabled, based on 'good practice'..
19479 this.disable = this.disable || {};
19480 Roo.applyIf(this.disable, {
19483 specialElements : true
19485 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19487 this.editor = config.editor;
19488 this.editorcore = config.editor.editorcore;
19490 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19492 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19493 // dont call parent... till later.
19495 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19500 editorcore : false,
19505 "h1","h2","h3","h4","h5","h6",
19507 "abbr", "acronym", "address", "cite", "samp", "var",
19511 onRender : function(ct, position)
19513 // Roo.log("Call onRender: " + this.xtype);
19515 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19517 this.el.dom.style.marginBottom = '0';
19519 var editorcore = this.editorcore;
19520 var editor= this.editor;
19523 var btn = function(id,cmd , toggle, handler){
19525 var event = toggle ? 'toggle' : 'click';
19530 xns: Roo.bootstrap,
19533 enableToggle:toggle !== false,
19535 pressed : toggle ? false : null,
19538 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19539 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19548 xns: Roo.bootstrap,
19549 glyphicon : 'font',
19553 xns: Roo.bootstrap,
19557 Roo.each(this.formats, function(f) {
19558 style.menu.items.push({
19560 xns: Roo.bootstrap,
19561 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19566 editorcore.insertTag(this.tagname);
19573 children.push(style);
19576 btn('bold',false,true);
19577 btn('italic',false,true);
19578 btn('align-left', 'justifyleft',true);
19579 btn('align-center', 'justifycenter',true);
19580 btn('align-right' , 'justifyright',true);
19581 btn('link', false, false, function(btn) {
19582 //Roo.log("create link?");
19583 var url = prompt(this.createLinkText, this.defaultLinkValue);
19584 if(url && url != 'http:/'+'/'){
19585 this.editorcore.relayCmd('createlink', url);
19588 btn('list','insertunorderedlist',true);
19589 btn('pencil', false,true, function(btn){
19592 this.toggleSourceEdit(btn.pressed);
19598 xns: Roo.bootstrap,
19603 xns: Roo.bootstrap,
19608 cog.menu.items.push({
19610 xns: Roo.bootstrap,
19611 html : Clean styles,
19616 editorcore.insertTag(this.tagname);
19625 this.xtype = 'NavSimplebar';
19627 for(var i=0;i< children.length;i++) {
19629 this.buttons.add(this.addxtypeChild(children[i]));
19633 editor.on('editorevent', this.updateToolbar, this);
19635 onBtnClick : function(id)
19637 this.editorcore.relayCmd(id);
19638 this.editorcore.focus();
19642 * Protected method that will not generally be called directly. It triggers
19643 * a toolbar update by reading the markup state of the current selection in the editor.
19645 updateToolbar: function(){
19647 if(!this.editorcore.activated){
19648 this.editor.onFirstFocus(); // is this neeed?
19652 var btns = this.buttons;
19653 var doc = this.editorcore.doc;
19654 btns.get('bold').setActive(doc.queryCommandState('bold'));
19655 btns.get('italic').setActive(doc.queryCommandState('italic'));
19656 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19658 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19659 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19660 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19662 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19663 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19666 var ans = this.editorcore.getAllAncestors();
19667 if (this.formatCombo) {
19670 var store = this.formatCombo.store;
19671 this.formatCombo.setValue("");
19672 for (var i =0; i < ans.length;i++) {
19673 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19675 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19683 // hides menus... - so this cant be on a menu...
19684 Roo.bootstrap.MenuMgr.hideAll();
19686 Roo.bootstrap.MenuMgr.hideAll();
19687 //this.editorsyncValue();
19689 onFirstFocus: function() {
19690 this.buttons.each(function(item){
19694 toggleSourceEdit : function(sourceEditMode){
19697 if(sourceEditMode){
19698 Roo.log("disabling buttons");
19699 this.buttons.each( function(item){
19700 if(item.cmd != 'pencil'){
19706 Roo.log("enabling buttons");
19707 if(this.editorcore.initialized){
19708 this.buttons.each( function(item){
19714 Roo.log("calling toggole on editor");
19715 // tell the editor that it's been pressed..
19716 this.editor.toggleSourceEdit(sourceEditMode);
19726 * @class Roo.bootstrap.Table.AbstractSelectionModel
19727 * @extends Roo.util.Observable
19728 * Abstract base class for grid SelectionModels. It provides the interface that should be
19729 * implemented by descendant classes. This class should not be directly instantiated.
19732 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19733 this.locked = false;
19734 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19738 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19739 /** @ignore Called by the grid automatically. Do not call directly. */
19740 init : function(grid){
19746 * Locks the selections.
19749 this.locked = true;
19753 * Unlocks the selections.
19755 unlock : function(){
19756 this.locked = false;
19760 * Returns true if the selections are locked.
19761 * @return {Boolean}
19763 isLocked : function(){
19764 return this.locked;
19768 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19769 * @class Roo.bootstrap.Table.RowSelectionModel
19770 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19771 * It supports multiple selections and keyboard selection/navigation.
19773 * @param {Object} config
19776 Roo.bootstrap.Table.RowSelectionModel = function(config){
19777 Roo.apply(this, config);
19778 this.selections = new Roo.util.MixedCollection(false, function(o){
19783 this.lastActive = false;
19787 * @event selectionchange
19788 * Fires when the selection changes
19789 * @param {SelectionModel} this
19791 "selectionchange" : true,
19793 * @event afterselectionchange
19794 * Fires after the selection changes (eg. by key press or clicking)
19795 * @param {SelectionModel} this
19797 "afterselectionchange" : true,
19799 * @event beforerowselect
19800 * Fires when a row is selected being selected, return false to cancel.
19801 * @param {SelectionModel} this
19802 * @param {Number} rowIndex The selected index
19803 * @param {Boolean} keepExisting False if other selections will be cleared
19805 "beforerowselect" : true,
19808 * Fires when a row is selected.
19809 * @param {SelectionModel} this
19810 * @param {Number} rowIndex The selected index
19811 * @param {Roo.data.Record} r The record
19813 "rowselect" : true,
19815 * @event rowdeselect
19816 * Fires when a row is deselected.
19817 * @param {SelectionModel} this
19818 * @param {Number} rowIndex The selected index
19820 "rowdeselect" : true
19822 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19823 this.locked = false;
19826 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19828 * @cfg {Boolean} singleSelect
19829 * True to allow selection of only one row at a time (defaults to false)
19831 singleSelect : false,
19834 initEvents : function(){
19836 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19837 this.grid.on("mousedown", this.handleMouseDown, this);
19838 }else{ // allow click to work like normal
19839 this.grid.on("rowclick", this.handleDragableRowClick, this);
19842 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19843 "up" : function(e){
19845 this.selectPrevious(e.shiftKey);
19846 }else if(this.last !== false && this.lastActive !== false){
19847 var last = this.last;
19848 this.selectRange(this.last, this.lastActive-1);
19849 this.grid.getView().focusRow(this.lastActive);
19850 if(last !== false){
19854 this.selectFirstRow();
19856 this.fireEvent("afterselectionchange", this);
19858 "down" : function(e){
19860 this.selectNext(e.shiftKey);
19861 }else if(this.last !== false && this.lastActive !== false){
19862 var last = this.last;
19863 this.selectRange(this.last, this.lastActive+1);
19864 this.grid.getView().focusRow(this.lastActive);
19865 if(last !== false){
19869 this.selectFirstRow();
19871 this.fireEvent("afterselectionchange", this);
19876 var view = this.grid.view;
19877 view.on("refresh", this.onRefresh, this);
19878 view.on("rowupdated", this.onRowUpdated, this);
19879 view.on("rowremoved", this.onRemove, this);
19883 onRefresh : function(){
19884 var ds = this.grid.dataSource, i, v = this.grid.view;
19885 var s = this.selections;
19886 s.each(function(r){
19887 if((i = ds.indexOfId(r.id)) != -1){
19896 onRemove : function(v, index, r){
19897 this.selections.remove(r);
19901 onRowUpdated : function(v, index, r){
19902 if(this.isSelected(r)){
19903 v.onRowSelect(index);
19909 * @param {Array} records The records to select
19910 * @param {Boolean} keepExisting (optional) True to keep existing selections
19912 selectRecords : function(records, keepExisting){
19914 this.clearSelections();
19916 var ds = this.grid.dataSource;
19917 for(var i = 0, len = records.length; i < len; i++){
19918 this.selectRow(ds.indexOf(records[i]), true);
19923 * Gets the number of selected rows.
19926 getCount : function(){
19927 return this.selections.length;
19931 * Selects the first row in the grid.
19933 selectFirstRow : function(){
19938 * Select the last row.
19939 * @param {Boolean} keepExisting (optional) True to keep existing selections
19941 selectLastRow : function(keepExisting){
19942 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19946 * Selects the row immediately following the last selected row.
19947 * @param {Boolean} keepExisting (optional) True to keep existing selections
19949 selectNext : function(keepExisting){
19950 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19951 this.selectRow(this.last+1, keepExisting);
19952 this.grid.getView().focusRow(this.last);
19957 * Selects the row that precedes the last selected row.
19958 * @param {Boolean} keepExisting (optional) True to keep existing selections
19960 selectPrevious : function(keepExisting){
19962 this.selectRow(this.last-1, keepExisting);
19963 this.grid.getView().focusRow(this.last);
19968 * Returns the selected records
19969 * @return {Array} Array of selected records
19971 getSelections : function(){
19972 return [].concat(this.selections.items);
19976 * Returns the first selected record.
19979 getSelected : function(){
19980 return this.selections.itemAt(0);
19985 * Clears all selections.
19987 clearSelections : function(fast){
19988 if(this.locked) return;
19990 var ds = this.grid.dataSource;
19991 var s = this.selections;
19992 s.each(function(r){
19993 this.deselectRow(ds.indexOfId(r.id));
19997 this.selections.clear();
20004 * Selects all rows.
20006 selectAll : function(){
20007 if(this.locked) return;
20008 this.selections.clear();
20009 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20010 this.selectRow(i, true);
20015 * Returns True if there is a selection.
20016 * @return {Boolean}
20018 hasSelection : function(){
20019 return this.selections.length > 0;
20023 * Returns True if the specified row is selected.
20024 * @param {Number/Record} record The record or index of the record to check
20025 * @return {Boolean}
20027 isSelected : function(index){
20028 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20029 return (r && this.selections.key(r.id) ? true : false);
20033 * Returns True if the specified record id is selected.
20034 * @param {String} id The id of record to check
20035 * @return {Boolean}
20037 isIdSelected : function(id){
20038 return (this.selections.key(id) ? true : false);
20042 handleMouseDown : function(e, t){
20043 var view = this.grid.getView(), rowIndex;
20044 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20047 if(e.shiftKey && this.last !== false){
20048 var last = this.last;
20049 this.selectRange(last, rowIndex, e.ctrlKey);
20050 this.last = last; // reset the last
20051 view.focusRow(rowIndex);
20053 var isSelected = this.isSelected(rowIndex);
20054 if(e.button !== 0 && isSelected){
20055 view.focusRow(rowIndex);
20056 }else if(e.ctrlKey && isSelected){
20057 this.deselectRow(rowIndex);
20058 }else if(!isSelected){
20059 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20060 view.focusRow(rowIndex);
20063 this.fireEvent("afterselectionchange", this);
20066 handleDragableRowClick : function(grid, rowIndex, e)
20068 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20069 this.selectRow(rowIndex, false);
20070 grid.view.focusRow(rowIndex);
20071 this.fireEvent("afterselectionchange", this);
20076 * Selects multiple rows.
20077 * @param {Array} rows Array of the indexes of the row to select
20078 * @param {Boolean} keepExisting (optional) True to keep existing selections
20080 selectRows : function(rows, keepExisting){
20082 this.clearSelections();
20084 for(var i = 0, len = rows.length; i < len; i++){
20085 this.selectRow(rows[i], true);
20090 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20091 * @param {Number} startRow The index of the first row in the range
20092 * @param {Number} endRow The index of the last row in the range
20093 * @param {Boolean} keepExisting (optional) True to retain existing selections
20095 selectRange : function(startRow, endRow, keepExisting){
20096 if(this.locked) return;
20098 this.clearSelections();
20100 if(startRow <= endRow){
20101 for(var i = startRow; i <= endRow; i++){
20102 this.selectRow(i, true);
20105 for(var i = startRow; i >= endRow; i--){
20106 this.selectRow(i, true);
20112 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20113 * @param {Number} startRow The index of the first row in the range
20114 * @param {Number} endRow The index of the last row in the range
20116 deselectRange : function(startRow, endRow, preventViewNotify){
20117 if(this.locked) return;
20118 for(var i = startRow; i <= endRow; i++){
20119 this.deselectRow(i, preventViewNotify);
20125 * @param {Number} row The index of the row to select
20126 * @param {Boolean} keepExisting (optional) True to keep existing selections
20128 selectRow : function(index, keepExisting, preventViewNotify){
20129 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20130 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20131 if(!keepExisting || this.singleSelect){
20132 this.clearSelections();
20134 var r = this.grid.dataSource.getAt(index);
20135 this.selections.add(r);
20136 this.last = this.lastActive = index;
20137 if(!preventViewNotify){
20138 this.grid.getView().onRowSelect(index);
20140 this.fireEvent("rowselect", this, index, r);
20141 this.fireEvent("selectionchange", this);
20147 * @param {Number} row The index of the row to deselect
20149 deselectRow : function(index, preventViewNotify){
20150 if(this.locked) return;
20151 if(this.last == index){
20154 if(this.lastActive == index){
20155 this.lastActive = false;
20157 var r = this.grid.dataSource.getAt(index);
20158 this.selections.remove(r);
20159 if(!preventViewNotify){
20160 this.grid.getView().onRowDeselect(index);
20162 this.fireEvent("rowdeselect", this, index);
20163 this.fireEvent("selectionchange", this);
20167 restoreLast : function(){
20169 this.last = this._last;
20174 acceptsNav : function(row, col, cm){
20175 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20179 onEditorKey : function(field, e){
20180 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20185 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20187 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20189 }else if(k == e.ENTER && !e.ctrlKey){
20193 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20195 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20197 }else if(k == e.ESC){
20201 g.startEditing(newCell[0], newCell[1]);
20206 * Ext JS Library 1.1.1
20207 * Copyright(c) 2006-2007, Ext JS, LLC.
20209 * Originally Released Under LGPL - original licence link has changed is not relivant.
20212 * <script type="text/javascript">
20216 * @class Roo.bootstrap.PagingToolbar
20218 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20220 * Create a new PagingToolbar
20221 * @param {Object} config The config object
20223 Roo.bootstrap.PagingToolbar = function(config)
20225 // old args format still supported... - xtype is prefered..
20226 // created from xtype...
20227 var ds = config.dataSource;
20228 this.toolbarItems = [];
20229 if (config.items) {
20230 this.toolbarItems = config.items;
20231 // config.items = [];
20234 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20241 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20245 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20247 * @cfg {Roo.data.Store} dataSource
20248 * The underlying data store providing the paged data
20251 * @cfg {String/HTMLElement/Element} container
20252 * container The id or element that will contain the toolbar
20255 * @cfg {Boolean} displayInfo
20256 * True to display the displayMsg (defaults to false)
20259 * @cfg {Number} pageSize
20260 * The number of records to display per page (defaults to 20)
20264 * @cfg {String} displayMsg
20265 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20267 displayMsg : 'Displaying {0} - {1} of {2}',
20269 * @cfg {String} emptyMsg
20270 * The message to display when no records are found (defaults to "No data to display")
20272 emptyMsg : 'No data to display',
20274 * Customizable piece of the default paging text (defaults to "Page")
20277 beforePageText : "Page",
20279 * Customizable piece of the default paging text (defaults to "of %0")
20282 afterPageText : "of {0}",
20284 * Customizable piece of the default paging text (defaults to "First Page")
20287 firstText : "First Page",
20289 * Customizable piece of the default paging text (defaults to "Previous Page")
20292 prevText : "Previous Page",
20294 * Customizable piece of the default paging text (defaults to "Next Page")
20297 nextText : "Next Page",
20299 * Customizable piece of the default paging text (defaults to "Last Page")
20302 lastText : "Last Page",
20304 * Customizable piece of the default paging text (defaults to "Refresh")
20307 refreshText : "Refresh",
20311 onRender : function(ct, position)
20313 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20314 this.navgroup.parentId = this.id;
20315 this.navgroup.onRender(this.el, null);
20316 // add the buttons to the navgroup
20318 if(this.displayInfo){
20319 Roo.log(this.el.select('ul.navbar-nav',true).first());
20320 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20321 this.displayEl = this.el.select('.x-paging-info', true).first();
20322 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20323 // this.displayEl = navel.el.select('span',true).first();
20329 Roo.each(_this.buttons, function(e){
20330 Roo.factory(e).onRender(_this.el, null);
20334 Roo.each(_this.toolbarItems, function(e) {
20335 _this.navgroup.addItem(e);
20339 this.first = this.navgroup.addItem({
20340 tooltip: this.firstText,
20342 icon : 'fa fa-backward',
20344 preventDefault: true,
20345 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20348 this.prev = this.navgroup.addItem({
20349 tooltip: this.prevText,
20351 icon : 'fa fa-step-backward',
20353 preventDefault: true,
20354 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20356 //this.addSeparator();
20359 var field = this.navgroup.addItem( {
20361 cls : 'x-paging-position',
20363 html : this.beforePageText +
20364 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20365 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20368 this.field = field.el.select('input', true).first();
20369 this.field.on("keydown", this.onPagingKeydown, this);
20370 this.field.on("focus", function(){this.dom.select();});
20373 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20374 //this.field.setHeight(18);
20375 //this.addSeparator();
20376 this.next = this.navgroup.addItem({
20377 tooltip: this.nextText,
20379 html : ' <i class="fa fa-step-forward">',
20381 preventDefault: true,
20382 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20384 this.last = this.navgroup.addItem({
20385 tooltip: this.lastText,
20386 icon : 'fa fa-forward',
20389 preventDefault: true,
20390 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20392 //this.addSeparator();
20393 this.loading = this.navgroup.addItem({
20394 tooltip: this.refreshText,
20395 icon: 'fa fa-refresh',
20396 preventDefault: true,
20397 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20403 updateInfo : function(){
20404 if(this.displayEl){
20405 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20406 var msg = count == 0 ?
20410 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20412 this.displayEl.update(msg);
20417 onLoad : function(ds, r, o){
20418 this.cursor = o.params ? o.params.start : 0;
20419 var d = this.getPageData(),
20423 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20424 this.field.dom.value = ap;
20425 this.first.setDisabled(ap == 1);
20426 this.prev.setDisabled(ap == 1);
20427 this.next.setDisabled(ap == ps);
20428 this.last.setDisabled(ap == ps);
20429 this.loading.enable();
20434 getPageData : function(){
20435 var total = this.ds.getTotalCount();
20438 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20439 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20444 onLoadError : function(){
20445 this.loading.enable();
20449 onPagingKeydown : function(e){
20450 var k = e.getKey();
20451 var d = this.getPageData();
20453 var v = this.field.dom.value, pageNum;
20454 if(!v || isNaN(pageNum = parseInt(v, 10))){
20455 this.field.dom.value = d.activePage;
20458 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20459 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20462 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))
20464 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20465 this.field.dom.value = pageNum;
20466 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20469 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20471 var v = this.field.dom.value, pageNum;
20472 var increment = (e.shiftKey) ? 10 : 1;
20473 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20475 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20476 this.field.dom.value = d.activePage;
20479 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20481 this.field.dom.value = parseInt(v, 10) + increment;
20482 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20483 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20490 beforeLoad : function(){
20492 this.loading.disable();
20497 onClick : function(which){
20506 ds.load({params:{start: 0, limit: this.pageSize}});
20509 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20512 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20515 var total = ds.getTotalCount();
20516 var extra = total % this.pageSize;
20517 var lastStart = extra ? (total - extra) : total-this.pageSize;
20518 ds.load({params:{start: lastStart, limit: this.pageSize}});
20521 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20527 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20528 * @param {Roo.data.Store} store The data store to unbind
20530 unbind : function(ds){
20531 ds.un("beforeload", this.beforeLoad, this);
20532 ds.un("load", this.onLoad, this);
20533 ds.un("loadexception", this.onLoadError, this);
20534 ds.un("remove", this.updateInfo, this);
20535 ds.un("add", this.updateInfo, this);
20536 this.ds = undefined;
20540 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20541 * @param {Roo.data.Store} store The data store to bind
20543 bind : function(ds){
20544 ds.on("beforeload", this.beforeLoad, this);
20545 ds.on("load", this.onLoad, this);
20546 ds.on("loadexception", this.onLoadError, this);
20547 ds.on("remove", this.updateInfo, this);
20548 ds.on("add", this.updateInfo, this);
20559 * @class Roo.bootstrap.MessageBar
20560 * @extends Roo.bootstrap.Component
20561 * Bootstrap MessageBar class
20562 * @cfg {String} html contents of the MessageBar
20563 * @cfg {String} weight (info | success | warning | danger) default info
20564 * @cfg {String} beforeClass insert the bar before the given class
20565 * @cfg {Boolean} closable (true | false) default false
20566 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20569 * Create a new Element
20570 * @param {Object} config The config object
20573 Roo.bootstrap.MessageBar = function(config){
20574 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20577 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20583 beforeClass: 'bootstrap-sticky-wrap',
20585 getAutoCreate : function(){
20589 cls: 'alert alert-dismissable alert-' + this.weight,
20594 html: this.html || ''
20600 cfg.cls += ' alert-messages-fixed';
20614 onRender : function(ct, position)
20616 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20619 var cfg = Roo.apply({}, this.getAutoCreate());
20623 cfg.cls += ' ' + this.cls;
20626 cfg.style = this.style;
20628 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20630 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20633 this.el.select('>button.close').on('click', this.hide, this);
20639 if (!this.rendered) {
20645 this.fireEvent('show', this);
20651 if (!this.rendered) {
20657 this.fireEvent('hide', this);
20660 update : function()
20662 // var e = this.el.dom.firstChild;
20664 // if(this.closable){
20665 // e = e.nextSibling;
20668 // e.data = this.html || '';
20670 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20686 * @class Roo.bootstrap.Graph
20687 * @extends Roo.bootstrap.Component
20688 * Bootstrap Graph class
20692 @cfg {String} graphtype bar | vbar | pie
20693 @cfg {number} g_x coodinator | centre x (pie)
20694 @cfg {number} g_y coodinator | centre y (pie)
20695 @cfg {number} g_r radius (pie)
20696 @cfg {number} g_height height of the chart (respected by all elements in the set)
20697 @cfg {number} g_width width of the chart (respected by all elements in the set)
20698 @cfg {Object} title The title of the chart
20701 -opts (object) options for the chart
20703 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20704 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20706 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.
20707 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20709 o stretch (boolean)
20711 -opts (object) options for the pie
20714 o startAngle (number)
20715 o endAngle (number)
20719 * Create a new Input
20720 * @param {Object} config The config object
20723 Roo.bootstrap.Graph = function(config){
20724 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20730 * The img click event for the img.
20731 * @param {Roo.EventObject} e
20737 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20748 //g_colors: this.colors,
20755 getAutoCreate : function(){
20766 onRender : function(ct,position){
20767 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20768 this.raphael = Raphael(this.el.dom);
20770 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20771 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20772 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20773 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20775 r.text(160, 10, "Single Series Chart").attr(txtattr);
20776 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20777 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20778 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20780 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20781 r.barchart(330, 10, 300, 220, data1);
20782 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20783 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20786 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20787 // r.barchart(30, 30, 560, 250, xdata, {
20788 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20789 // axis : "0 0 1 1",
20790 // axisxlabels : xdata
20791 // //yvalues : cols,
20794 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20796 // this.load(null,xdata,{
20797 // axis : "0 0 1 1",
20798 // axisxlabels : xdata
20803 load : function(graphtype,xdata,opts){
20804 this.raphael.clear();
20806 graphtype = this.graphtype;
20811 var r = this.raphael,
20812 fin = function () {
20813 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20815 fout = function () {
20816 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20818 pfin = function() {
20819 this.sector.stop();
20820 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20823 this.label[0].stop();
20824 this.label[0].attr({ r: 7.5 });
20825 this.label[1].attr({ "font-weight": 800 });
20828 pfout = function() {
20829 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20832 this.label[0].animate({ r: 5 }, 500, "bounce");
20833 this.label[1].attr({ "font-weight": 400 });
20839 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20842 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20845 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20846 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20848 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20855 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20860 setTitle: function(o)
20865 initEvents: function() {
20868 this.el.on('click', this.onClick, this);
20872 onClick : function(e)
20874 Roo.log('img onclick');
20875 this.fireEvent('click', this, e);
20887 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20890 * @class Roo.bootstrap.dash.NumberBox
20891 * @extends Roo.bootstrap.Component
20892 * Bootstrap NumberBox class
20893 * @cfg {String} headline Box headline
20894 * @cfg {String} content Box content
20895 * @cfg {String} icon Box icon
20896 * @cfg {String} footer Footer text
20897 * @cfg {String} fhref Footer href
20900 * Create a new NumberBox
20901 * @param {Object} config The config object
20905 Roo.bootstrap.dash.NumberBox = function(config){
20906 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20910 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20919 getAutoCreate : function(){
20923 cls : 'small-box ',
20931 cls : 'roo-headline',
20932 html : this.headline
20936 cls : 'roo-content',
20937 html : this.content
20951 cls : 'ion ' + this.icon
20960 cls : 'small-box-footer',
20961 href : this.fhref || '#',
20965 cfg.cn.push(footer);
20972 onRender : function(ct,position){
20973 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20980 setHeadline: function (value)
20982 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20985 setFooter: function (value, href)
20987 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20990 this.el.select('a.small-box-footer',true).first().attr('href', href);
20995 setContent: function (value)
20997 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21000 initEvents: function()
21014 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21017 * @class Roo.bootstrap.dash.TabBox
21018 * @extends Roo.bootstrap.Component
21019 * Bootstrap TabBox class
21020 * @cfg {String} title Title of the TabBox
21021 * @cfg {String} icon Icon of the TabBox
21022 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21023 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21026 * Create a new TabBox
21027 * @param {Object} config The config object
21031 Roo.bootstrap.dash.TabBox = function(config){
21032 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21037 * When a pane is added
21038 * @param {Roo.bootstrap.dash.TabPane} pane
21042 * @event activatepane
21043 * When a pane is activated
21044 * @param {Roo.bootstrap.dash.TabPane} pane
21046 "activatepane" : true
21054 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21059 tabScrollable : false,
21061 getChildContainer : function()
21063 return this.el.select('.tab-content', true).first();
21066 getAutoCreate : function(){
21070 cls: 'pull-left header',
21078 cls: 'fa ' + this.icon
21084 cls: 'nav nav-tabs pull-right',
21090 if(this.tabScrollable){
21097 cls: 'nav nav-tabs pull-right',
21108 cls: 'nav-tabs-custom',
21113 cls: 'tab-content no-padding',
21121 initEvents : function()
21123 //Roo.log('add add pane handler');
21124 this.on('addpane', this.onAddPane, this);
21127 * Updates the box title
21128 * @param {String} html to set the title to.
21130 setTitle : function(value)
21132 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21134 onAddPane : function(pane)
21136 this.panes.push(pane);
21137 //Roo.log('addpane');
21139 // tabs are rendere left to right..
21140 if(!this.showtabs){
21144 var ctr = this.el.select('.nav-tabs', true).first();
21147 var existing = ctr.select('.nav-tab',true);
21148 var qty = existing.getCount();;
21151 var tab = ctr.createChild({
21153 cls : 'nav-tab' + (qty ? '' : ' active'),
21161 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21164 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21166 pane.el.addClass('active');
21171 onTabClick : function(ev,un,ob,pane)
21173 //Roo.log('tab - prev default');
21174 ev.preventDefault();
21177 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21178 pane.tab.addClass('active');
21179 //Roo.log(pane.title);
21180 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21181 // technically we should have a deactivate event.. but maybe add later.
21182 // and it should not de-activate the selected tab...
21183 this.fireEvent('activatepane', pane);
21184 pane.el.addClass('active');
21185 pane.fireEvent('activate');
21190 getActivePane : function()
21193 Roo.each(this.panes, function(p) {
21194 if(p.el.hasClass('active')){
21215 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21217 * @class Roo.bootstrap.TabPane
21218 * @extends Roo.bootstrap.Component
21219 * Bootstrap TabPane class
21220 * @cfg {Boolean} active (false | true) Default false
21221 * @cfg {String} title title of panel
21225 * Create a new TabPane
21226 * @param {Object} config The config object
21229 Roo.bootstrap.dash.TabPane = function(config){
21230 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21236 * When a pane is activated
21237 * @param {Roo.bootstrap.dash.TabPane} pane
21244 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21249 // the tabBox that this is attached to.
21252 getAutoCreate : function()
21260 cfg.cls += ' active';
21265 initEvents : function()
21267 //Roo.log('trigger add pane handler');
21268 this.parent().fireEvent('addpane', this)
21272 * Updates the tab title
21273 * @param {String} html to set the title to.
21275 setTitle: function(str)
21281 this.tab.select('a', true).first().dom.innerHTML = str;
21298 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21301 * @class Roo.bootstrap.menu.Menu
21302 * @extends Roo.bootstrap.Component
21303 * Bootstrap Menu class - container for Menu
21304 * @cfg {String} html Text of the menu
21305 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21306 * @cfg {String} icon Font awesome icon
21307 * @cfg {String} pos Menu align to (top | bottom) default bottom
21311 * Create a new Menu
21312 * @param {Object} config The config object
21316 Roo.bootstrap.menu.Menu = function(config){
21317 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21321 * @event beforeshow
21322 * Fires before this menu is displayed
21323 * @param {Roo.bootstrap.menu.Menu} this
21327 * @event beforehide
21328 * Fires before this menu is hidden
21329 * @param {Roo.bootstrap.menu.Menu} this
21334 * Fires after this menu is displayed
21335 * @param {Roo.bootstrap.menu.Menu} this
21340 * Fires after this menu is hidden
21341 * @param {Roo.bootstrap.menu.Menu} this
21346 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21347 * @param {Roo.bootstrap.menu.Menu} this
21348 * @param {Roo.EventObject} e
21355 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21359 weight : 'default',
21364 getChildContainer : function() {
21365 if(this.isSubMenu){
21369 return this.el.select('ul.dropdown-menu', true).first();
21372 getAutoCreate : function()
21377 cls : 'roo-menu-text',
21385 cls : 'fa ' + this.icon
21396 cls : 'dropdown-button btn btn-' + this.weight,
21401 cls : 'dropdown-toggle btn btn-' + this.weight,
21411 cls : 'dropdown-menu'
21417 if(this.pos == 'top'){
21418 cfg.cls += ' dropup';
21421 if(this.isSubMenu){
21424 cls : 'dropdown-menu'
21431 onRender : function(ct, position)
21433 this.isSubMenu = ct.hasClass('dropdown-submenu');
21435 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21438 initEvents : function()
21440 if(this.isSubMenu){
21444 this.hidden = true;
21446 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21447 this.triggerEl.on('click', this.onTriggerPress, this);
21449 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21450 this.buttonEl.on('click', this.onClick, this);
21456 if(this.isSubMenu){
21460 return this.el.select('ul.dropdown-menu', true).first();
21463 onClick : function(e)
21465 this.fireEvent("click", this, e);
21468 onTriggerPress : function(e)
21470 if (this.isVisible()) {
21477 isVisible : function(){
21478 return !this.hidden;
21483 this.fireEvent("beforeshow", this);
21485 this.hidden = false;
21486 this.el.addClass('open');
21488 Roo.get(document).on("mouseup", this.onMouseUp, this);
21490 this.fireEvent("show", this);
21497 this.fireEvent("beforehide", this);
21499 this.hidden = true;
21500 this.el.removeClass('open');
21502 Roo.get(document).un("mouseup", this.onMouseUp);
21504 this.fireEvent("hide", this);
21507 onMouseUp : function()
21521 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21524 * @class Roo.bootstrap.menu.Item
21525 * @extends Roo.bootstrap.Component
21526 * Bootstrap MenuItem class
21527 * @cfg {Boolean} submenu (true | false) default false
21528 * @cfg {String} html text of the item
21529 * @cfg {String} href the link
21530 * @cfg {Boolean} disable (true | false) default false
21531 * @cfg {Boolean} preventDefault (true | false) default true
21532 * @cfg {String} icon Font awesome icon
21533 * @cfg {String} pos Submenu align to (left | right) default right
21537 * Create a new Item
21538 * @param {Object} config The config object
21542 Roo.bootstrap.menu.Item = function(config){
21543 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21547 * Fires when the mouse is hovering over this menu
21548 * @param {Roo.bootstrap.menu.Item} this
21549 * @param {Roo.EventObject} e
21554 * Fires when the mouse exits this menu
21555 * @param {Roo.bootstrap.menu.Item} this
21556 * @param {Roo.EventObject} e
21562 * The raw click event for the entire grid.
21563 * @param {Roo.EventObject} e
21569 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21574 preventDefault: true,
21579 getAutoCreate : function()
21584 cls : 'roo-menu-item-text',
21592 cls : 'fa ' + this.icon
21601 href : this.href || '#',
21608 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21612 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21614 if(this.pos == 'left'){
21615 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21622 initEvents : function()
21624 this.el.on('mouseover', this.onMouseOver, this);
21625 this.el.on('mouseout', this.onMouseOut, this);
21627 this.el.select('a', true).first().on('click', this.onClick, this);
21631 onClick : function(e)
21633 if(this.preventDefault){
21634 e.preventDefault();
21637 this.fireEvent("click", this, e);
21640 onMouseOver : function(e)
21642 if(this.submenu && this.pos == 'left'){
21643 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21646 this.fireEvent("mouseover", this, e);
21649 onMouseOut : function(e)
21651 this.fireEvent("mouseout", this, e);
21663 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21666 * @class Roo.bootstrap.menu.Separator
21667 * @extends Roo.bootstrap.Component
21668 * Bootstrap Separator class
21671 * Create a new Separator
21672 * @param {Object} config The config object
21676 Roo.bootstrap.menu.Separator = function(config){
21677 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21680 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21682 getAutoCreate : function(){
21703 * @class Roo.bootstrap.Tooltip
21704 * Bootstrap Tooltip class
21705 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21706 * to determine which dom element triggers the tooltip.
21708 * It needs to add support for additional attributes like tooltip-position
21711 * Create a new Toolti
21712 * @param {Object} config The config object
21715 Roo.bootstrap.Tooltip = function(config){
21716 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21719 Roo.apply(Roo.bootstrap.Tooltip, {
21721 * @function init initialize tooltip monitoring.
21725 currentTip : false,
21726 currentRegion : false,
21732 Roo.get(document).on('mouseover', this.enter ,this);
21733 Roo.get(document).on('mouseout', this.leave, this);
21736 this.currentTip = new Roo.bootstrap.Tooltip();
21739 enter : function(ev)
21741 var dom = ev.getTarget();
21742 //Roo.log(['enter',dom]);
21743 var el = Roo.fly(dom);
21744 if (this.currentEl) {
21746 //Roo.log(this.currentEl);
21747 //Roo.log(this.currentEl.contains(dom));
21748 if (this.currentEl == el) {
21751 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21759 if (this.currentTip.el) {
21760 this.currentTip.el.hide(); // force hiding...
21763 if (!el.attr('tooltip')) { // parents who have tip?
21766 this.currentEl = el;
21767 this.currentTip.bind(el);
21768 this.currentRegion = Roo.lib.Region.getRegion(dom);
21769 this.currentTip.enter();
21772 leave : function(ev)
21774 var dom = ev.getTarget();
21775 //Roo.log(['leave',dom]);
21776 if (!this.currentEl) {
21781 if (dom != this.currentEl.dom) {
21784 var xy = ev.getXY();
21785 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21788 // only activate leave if mouse cursor is outside... bounding box..
21793 if (this.currentTip) {
21794 this.currentTip.leave();
21796 //Roo.log('clear currentEl');
21797 this.currentEl = false;
21802 'left' : ['r-l', [-2,0], 'right'],
21803 'right' : ['l-r', [2,0], 'left'],
21804 'bottom' : ['t-b', [0,2], 'top'],
21805 'top' : [ 'b-t', [0,-2], 'bottom']
21811 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21816 delay : null, // can be { show : 300 , hide: 500}
21820 hoverState : null, //???
21822 placement : 'bottom',
21824 getAutoCreate : function(){
21831 cls : 'tooltip-arrow'
21834 cls : 'tooltip-inner'
21841 bind : function(el)
21847 enter : function () {
21849 if (this.timeout != null) {
21850 clearTimeout(this.timeout);
21853 this.hoverState = 'in';
21854 //Roo.log("enter - show");
21855 if (!this.delay || !this.delay.show) {
21860 this.timeout = setTimeout(function () {
21861 if (_t.hoverState == 'in') {
21864 }, this.delay.show);
21868 clearTimeout(this.timeout);
21870 this.hoverState = 'out';
21871 if (!this.delay || !this.delay.hide) {
21877 this.timeout = setTimeout(function () {
21878 //Roo.log("leave - timeout");
21880 if (_t.hoverState == 'out') {
21882 Roo.bootstrap.Tooltip.currentEl = false;
21890 this.render(document.body);
21893 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21894 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21896 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21898 var placement = typeof this.placement == 'function' ?
21899 this.placement.call(this, this.el, on_el) :
21902 var autoToken = /\s?auto?\s?/i;
21903 var autoPlace = autoToken.test(placement);
21905 placement = placement.replace(autoToken, '') || 'top';
21909 //this.el.setXY([0,0]);
21911 //this.el.dom.style.display='block';
21912 this.el.addClass(placement);
21914 //this.el.appendTo(on_el);
21916 var p = this.getPosition();
21917 var box = this.el.getBox();
21922 var align = Roo.bootstrap.Tooltip.alignment[placement];
21923 this.el.alignTo(this.bindEl, align[0],align[1]);
21924 //var arrow = this.el.select('.arrow',true).first();
21925 //arrow.set(align[2],
21927 this.el.addClass('in fade');
21928 this.hoverState = null;
21930 if (this.el.hasClass('fade')) {
21941 //this.el.setXY([0,0]);
21942 this.el.removeClass('in');
21958 * @class Roo.bootstrap.LocationPicker
21959 * @extends Roo.bootstrap.Component
21960 * Bootstrap LocationPicker class
21961 * @cfg {Number} latitude Position when init default 0
21962 * @cfg {Number} longitude Position when init default 0
21963 * @cfg {Number} zoom default 15
21964 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21965 * @cfg {Boolean} mapTypeControl default false
21966 * @cfg {Boolean} disableDoubleClickZoom default false
21967 * @cfg {Boolean} scrollwheel default true
21968 * @cfg {Boolean} streetViewControl default false
21969 * @cfg {Number} radius default 0
21970 * @cfg {String} locationName
21971 * @cfg {Boolean} draggable default true
21972 * @cfg {Boolean} enableAutocomplete default false
21973 * @cfg {Boolean} enableReverseGeocode default true
21974 * @cfg {String} markerTitle
21977 * Create a new LocationPicker
21978 * @param {Object} config The config object
21982 Roo.bootstrap.LocationPicker = function(config){
21984 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21989 * Fires when the picker initialized.
21990 * @param {Roo.bootstrap.LocationPicker} this
21991 * @param {Google Location} location
21995 * @event positionchanged
21996 * Fires when the picker position changed.
21997 * @param {Roo.bootstrap.LocationPicker} this
21998 * @param {Google Location} location
22000 positionchanged : true,
22003 * Fires when the map resize.
22004 * @param {Roo.bootstrap.LocationPicker} this
22009 * Fires when the map show.
22010 * @param {Roo.bootstrap.LocationPicker} this
22015 * Fires when the map hide.
22016 * @param {Roo.bootstrap.LocationPicker} this
22021 * Fires when click the map.
22022 * @param {Roo.bootstrap.LocationPicker} this
22023 * @param {Map event} e
22027 * @event mapRightClick
22028 * Fires when right click the map.
22029 * @param {Roo.bootstrap.LocationPicker} this
22030 * @param {Map event} e
22032 mapRightClick : true,
22034 * @event markerClick
22035 * Fires when click the marker.
22036 * @param {Roo.bootstrap.LocationPicker} this
22037 * @param {Map event} e
22039 markerClick : true,
22041 * @event markerRightClick
22042 * Fires when right click the marker.
22043 * @param {Roo.bootstrap.LocationPicker} this
22044 * @param {Map event} e
22046 markerRightClick : true,
22048 * @event OverlayViewDraw
22049 * Fires when OverlayView Draw
22050 * @param {Roo.bootstrap.LocationPicker} this
22052 OverlayViewDraw : true,
22054 * @event OverlayViewOnAdd
22055 * Fires when OverlayView Draw
22056 * @param {Roo.bootstrap.LocationPicker} this
22058 OverlayViewOnAdd : true,
22060 * @event OverlayViewOnRemove
22061 * Fires when OverlayView Draw
22062 * @param {Roo.bootstrap.LocationPicker} this
22064 OverlayViewOnRemove : true,
22066 * @event OverlayViewShow
22067 * Fires when OverlayView Draw
22068 * @param {Roo.bootstrap.LocationPicker} this
22069 * @param {Pixel} cpx
22071 OverlayViewShow : true,
22073 * @event OverlayViewHide
22074 * Fires when OverlayView Draw
22075 * @param {Roo.bootstrap.LocationPicker} this
22077 OverlayViewHide : true
22082 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22084 gMapContext: false,
22090 mapTypeControl: false,
22091 disableDoubleClickZoom: false,
22093 streetViewControl: false,
22097 enableAutocomplete: false,
22098 enableReverseGeocode: true,
22101 getAutoCreate: function()
22106 cls: 'roo-location-picker'
22112 initEvents: function(ct, position)
22114 if(!this.el.getWidth() || this.isApplied()){
22118 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22123 initial: function()
22125 if(!this.mapTypeId){
22126 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22129 this.gMapContext = this.GMapContext();
22131 this.initOverlayView();
22133 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22137 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22138 _this.setPosition(_this.gMapContext.marker.position);
22141 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22142 _this.fireEvent('mapClick', this, event);
22146 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22147 _this.fireEvent('mapRightClick', this, event);
22151 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22152 _this.fireEvent('markerClick', this, event);
22156 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22157 _this.fireEvent('markerRightClick', this, event);
22161 this.setPosition(this.gMapContext.location);
22163 this.fireEvent('initial', this, this.gMapContext.location);
22166 initOverlayView: function()
22170 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22174 _this.fireEvent('OverlayViewDraw', _this);
22179 _this.fireEvent('OverlayViewOnAdd', _this);
22182 onRemove: function()
22184 _this.fireEvent('OverlayViewOnRemove', _this);
22187 show: function(cpx)
22189 _this.fireEvent('OverlayViewShow', _this, cpx);
22194 _this.fireEvent('OverlayViewHide', _this);
22200 fromLatLngToContainerPixel: function(event)
22202 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22205 isApplied: function()
22207 return this.getGmapContext() == false ? false : true;
22210 getGmapContext: function()
22212 return this.gMapContext
22215 GMapContext: function()
22217 var position = new google.maps.LatLng(this.latitude, this.longitude);
22219 var _map = new google.maps.Map(this.el.dom, {
22222 mapTypeId: this.mapTypeId,
22223 mapTypeControl: this.mapTypeControl,
22224 disableDoubleClickZoom: this.disableDoubleClickZoom,
22225 scrollwheel: this.scrollwheel,
22226 streetViewControl: this.streetViewControl,
22227 locationName: this.locationName,
22228 draggable: this.draggable,
22229 enableAutocomplete: this.enableAutocomplete,
22230 enableReverseGeocode: this.enableReverseGeocode
22233 var _marker = new google.maps.Marker({
22234 position: position,
22236 title: this.markerTitle,
22237 draggable: this.draggable
22244 location: position,
22245 radius: this.radius,
22246 locationName: this.locationName,
22247 addressComponents: {
22248 formatted_address: null,
22249 addressLine1: null,
22250 addressLine2: null,
22252 streetNumber: null,
22256 stateOrProvince: null
22259 domContainer: this.el.dom,
22260 geodecoder: new google.maps.Geocoder()
22264 drawCircle: function(center, radius, options)
22266 if (this.gMapContext.circle != null) {
22267 this.gMapContext.circle.setMap(null);
22271 options = Roo.apply({}, options, {
22272 strokeColor: "#0000FF",
22273 strokeOpacity: .35,
22275 fillColor: "#0000FF",
22279 options.map = this.gMapContext.map;
22280 options.radius = radius;
22281 options.center = center;
22282 this.gMapContext.circle = new google.maps.Circle(options);
22283 return this.gMapContext.circle;
22289 setPosition: function(location)
22291 this.gMapContext.location = location;
22292 this.gMapContext.marker.setPosition(location);
22293 this.gMapContext.map.panTo(location);
22294 this.drawCircle(location, this.gMapContext.radius, {});
22298 if (this.gMapContext.settings.enableReverseGeocode) {
22299 this.gMapContext.geodecoder.geocode({
22300 latLng: this.gMapContext.location
22301 }, function(results, status) {
22303 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22304 _this.gMapContext.locationName = results[0].formatted_address;
22305 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22307 _this.fireEvent('positionchanged', this, location);
22314 this.fireEvent('positionchanged', this, location);
22319 google.maps.event.trigger(this.gMapContext.map, "resize");
22321 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22323 this.fireEvent('resize', this);
22326 setPositionByLatLng: function(latitude, longitude)
22328 this.setPosition(new google.maps.LatLng(latitude, longitude));
22331 getCurrentPosition: function()
22334 latitude: this.gMapContext.location.lat(),
22335 longitude: this.gMapContext.location.lng()
22339 getAddressName: function()
22341 return this.gMapContext.locationName;
22344 getAddressComponents: function()
22346 return this.gMapContext.addressComponents;
22349 address_component_from_google_geocode: function(address_components)
22353 for (var i = 0; i < address_components.length; i++) {
22354 var component = address_components[i];
22355 if (component.types.indexOf("postal_code") >= 0) {
22356 result.postalCode = component.short_name;
22357 } else if (component.types.indexOf("street_number") >= 0) {
22358 result.streetNumber = component.short_name;
22359 } else if (component.types.indexOf("route") >= 0) {
22360 result.streetName = component.short_name;
22361 } else if (component.types.indexOf("neighborhood") >= 0) {
22362 result.city = component.short_name;
22363 } else if (component.types.indexOf("locality") >= 0) {
22364 result.city = component.short_name;
22365 } else if (component.types.indexOf("sublocality") >= 0) {
22366 result.district = component.short_name;
22367 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22368 result.stateOrProvince = component.short_name;
22369 } else if (component.types.indexOf("country") >= 0) {
22370 result.country = component.short_name;
22374 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22375 result.addressLine2 = "";
22379 setZoomLevel: function(zoom)
22381 this.gMapContext.map.setZoom(zoom);
22394 this.fireEvent('show', this);
22405 this.fireEvent('hide', this);
22410 Roo.apply(Roo.bootstrap.LocationPicker, {
22412 OverlayView : function(map, options)
22414 options = options || {};
22428 * @class Roo.bootstrap.Alert
22429 * @extends Roo.bootstrap.Component
22430 * Bootstrap Alert class
22431 * @cfg {String} title The title of alert
22432 * @cfg {String} html The content of alert
22433 * @cfg {String} weight ( success | info | warning | danger )
22434 * @cfg {String} faicon font-awesomeicon
22437 * Create a new alert
22438 * @param {Object} config The config object
22442 Roo.bootstrap.Alert = function(config){
22443 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22447 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22454 getAutoCreate : function()
22463 cls : 'roo-alert-icon'
22468 cls : 'roo-alert-title',
22473 cls : 'roo-alert-text',
22480 cfg.cn[0].cls += ' fa ' + this.faicon;
22484 cfg.cls += ' alert-' + this.weight;
22490 initEvents: function()
22492 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22495 setTitle : function(str)
22497 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22500 setText : function(str)
22502 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22505 setWeight : function(weight)
22508 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22511 this.weight = weight;
22513 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22516 setIcon : function(icon)
22519 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22524 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);