4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
33 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
36 allowDomMove : false, // to stop relocations in parent onRender...
46 * Initialize Events for the element
48 initEvents : function() { },
54 can_build_overlaid : true,
56 container_method : false,
63 // returns the parent component..
64 return Roo.ComponentMgr.get(this.parentId)
70 onRender : function(ct, position)
72 // Roo.log("Call onRender: " + this.xtype);
74 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
77 if (this.el.attr('xtype')) {
78 this.el.attr('xtypex', this.el.attr('xtype'));
79 this.el.dom.removeAttribute('xtype');
89 var cfg = Roo.apply({}, this.getAutoCreate());
92 // fill in the extra attributes
93 if (this.xattr && typeof(this.xattr) =='object') {
94 for (var i in this.xattr) {
95 cfg[i] = this.xattr[i];
100 cfg.dataId = this.dataId;
104 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
107 if (this.style) { // fixme needs to support more complex style data.
108 cfg.style = this.style;
112 cfg.name = this.name;
117 this.el = ct.createChild(cfg, position);
120 this.tooltipEl().attr('tooltip', this.tooltip);
123 if(this.tabIndex !== undefined){
124 this.el.dom.setAttribute('tabIndex', this.tabIndex);
131 * Fetch the element to add children to
132 * @return {Roo.Element} defaults to this.el
134 getChildContainer : function()
139 * Fetch the element to display the tooltip on.
140 * @return {Roo.Element} defaults to this.el
142 tooltipEl : function()
147 addxtype : function(tree,cntr)
151 cn = Roo.factory(tree);
153 cn.parentType = this.xtype; //??
154 cn.parentId = this.id;
156 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
157 if (typeof(cn.container_method) == 'string') {
158 cntr = cn.container_method;
162 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
164 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
166 var build_from_html = Roo.XComponent.build_from_html;
168 var is_body = (tree.xtype == 'Body') ;
170 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
172 var self_cntr_el = Roo.get(this[cntr](false));
174 // do not try and build conditional elements
175 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
179 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
180 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
181 return this.addxtypeChild(tree,cntr);
184 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
187 return this.addxtypeChild(Roo.apply({}, tree),cntr);
190 Roo.log('skipping render');
198 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
204 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
208 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
213 addxtypeChild : function (tree, cntr)
215 Roo.debug && Roo.log('addxtypeChild:' + cntr);
217 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
220 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
221 (typeof(tree['flexy:foreach']) != 'undefined');
225 skip_children = false;
226 // render the element if it's not BODY.
227 if (tree.xtype != 'Body') {
229 cn = Roo.factory(tree);
231 cn.parentType = this.xtype; //??
232 cn.parentId = this.id;
234 var build_from_html = Roo.XComponent.build_from_html;
237 // does the container contain child eleemnts with 'xtype' attributes.
238 // that match this xtype..
239 // note - when we render we create these as well..
240 // so we should check to see if body has xtype set.
241 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
243 var self_cntr_el = Roo.get(this[cntr](false));
244 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
247 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
248 // and are not displayed -this causes this to use up the wrong element when matching.
249 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
252 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
253 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
259 //echild.dom.removeAttribute('xtype');
261 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
262 Roo.debug && Roo.log(self_cntr_el);
263 Roo.debug && Roo.log(echild);
264 Roo.debug && Roo.log(cn);
270 // if object has flexy:if - then it may or may not be rendered.
271 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
272 // skip a flexy if element.
273 Roo.debug && Roo.log('skipping render');
274 Roo.debug && Roo.log(tree);
276 Roo.debug && Roo.log('skipping all children');
277 skip_children = true;
282 // actually if flexy:foreach is found, we really want to create
283 // multiple copies here...
285 //Roo.log(this[cntr]());
286 cn.render(this[cntr](true));
288 // then add the element..
296 if (typeof (tree.menu) != 'undefined') {
297 tree.menu.parentType = cn.xtype;
298 tree.menu.triggerEl = cn.el;
299 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
303 if (!tree.items || !tree.items.length) {
307 var items = tree.items;
310 //Roo.log(items.length);
312 if (!skip_children) {
313 for(var i =0;i < items.length;i++) {
314 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
336 * @class Roo.bootstrap.Body
337 * @extends Roo.bootstrap.Component
338 * Bootstrap Body class
342 * @param {Object} config The config object
345 Roo.bootstrap.Body = function(config){
346 Roo.bootstrap.Body.superclass.constructor.call(this, config);
347 this.el = Roo.get(document.body);
348 if (this.cls && this.cls.length) {
349 Roo.get(document.body).addClass(this.cls);
353 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
358 onRender : function(ct, position)
360 /* Roo.log("Roo.bootstrap.Body - onRender");
361 if (this.cls && this.cls.length) {
362 Roo.get(document.body).addClass(this.cls);
382 * @class Roo.bootstrap.ButtonGroup
383 * @extends Roo.bootstrap.Component
384 * Bootstrap ButtonGroup class
385 * @cfg {String} size lg | sm | xs (default empty normal)
386 * @cfg {String} align vertical | justified (default none)
387 * @cfg {String} direction up | down (default down)
388 * @cfg {Boolean} toolbar false | true
389 * @cfg {Boolean} btn true | false
394 * @param {Object} config The config object
397 Roo.bootstrap.ButtonGroup = function(config){
398 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
401 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
409 getAutoCreate : function(){
415 cfg.html = this.html || cfg.html;
426 if (['vertical','justified'].indexOf(this.align)!==-1) {
427 cfg.cls = 'btn-group-' + this.align;
429 if (this.align == 'justified') {
430 console.log(this.items);
434 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
435 cfg.cls += ' btn-group-' + this.size;
438 if (this.direction == 'up') {
439 cfg.cls += ' dropup' ;
455 * @class Roo.bootstrap.Button
456 * @extends Roo.bootstrap.Component
457 * Bootstrap Button class
458 * @cfg {String} html The button content
459 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
460 * @cfg {String} size ( lg | sm | xs)
461 * @cfg {String} tag ( a | input | submit)
462 * @cfg {String} href empty or href
463 * @cfg {Boolean} disabled default false;
464 * @cfg {Boolean} isClose default false;
465 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
466 * @cfg {String} badge text for badge
467 * @cfg {String} theme default
468 * @cfg {Boolean} inverse
469 * @cfg {Boolean} toggle
470 * @cfg {String} ontext text for on toggle state
471 * @cfg {String} offtext text for off toggle state
472 * @cfg {Boolean} defaulton
473 * @cfg {Boolean} preventDefault default true
474 * @cfg {Boolean} removeClass remove the standard class..
475 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
478 * Create a new button
479 * @param {Object} config The config object
483 Roo.bootstrap.Button = function(config){
484 Roo.bootstrap.Button.superclass.constructor.call(this, config);
489 * When a butotn is pressed
490 * @param {Roo.EventObject} e
495 * After the button has been toggles
496 * @param {Roo.EventObject} e
497 * @param {boolean} pressed (also available as button.pressed)
503 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
521 preventDefault: true,
530 getAutoCreate : function(){
538 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
539 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
544 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
546 if (this.toggle == true) {
549 cls: 'slider-frame roo-button',
554 'data-off-text':'OFF',
555 cls: 'slider-button',
561 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
562 cfg.cls += ' '+this.weight;
571 cfg["aria-hidden"] = true;
573 cfg.html = "×";
579 if (this.theme==='default') {
580 cfg.cls = 'btn roo-button';
582 //if (this.parentType != 'Navbar') {
583 this.weight = this.weight.length ? this.weight : 'default';
585 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
587 cfg.cls += ' btn-' + this.weight;
589 } else if (this.theme==='glow') {
592 cfg.cls = 'btn-glow roo-button';
594 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
596 cfg.cls += ' ' + this.weight;
602 this.cls += ' inverse';
607 cfg.cls += ' active';
611 cfg.disabled = 'disabled';
615 Roo.log('changing to ul' );
617 this.glyphicon = 'caret';
620 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
622 //gsRoo.log(this.parentType);
623 if (this.parentType === 'Navbar' && !this.parent().bar) {
624 Roo.log('changing to li?');
633 href : this.href || '#'
636 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
637 cfg.cls += ' dropdown';
644 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
646 if (this.glyphicon) {
647 cfg.html = ' ' + cfg.html;
652 cls: 'glyphicon glyphicon-' + this.glyphicon
662 // cfg.cls='btn roo-button';
666 var value = cfg.html;
671 cls: 'glyphicon glyphicon-' + this.glyphicon,
690 cfg.cls += ' dropdown';
691 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
694 if (cfg.tag !== 'a' && this.href !== '') {
695 throw "Tag must be a to set href.";
696 } else if (this.href.length > 0) {
697 cfg.href = this.href;
700 if(this.removeClass){
705 cfg.target = this.target;
710 initEvents: function() {
711 // Roo.log('init events?');
712 // Roo.log(this.el.dom);
715 if (typeof (this.menu) != 'undefined') {
716 this.menu.parentType = this.xtype;
717 this.menu.triggerEl = this.el;
718 this.addxtype(Roo.apply({}, this.menu));
722 if (this.el.hasClass('roo-button')) {
723 this.el.on('click', this.onClick, this);
725 this.el.select('.roo-button').on('click', this.onClick, this);
728 if(this.removeClass){
729 this.el.on('click', this.onClick, this);
732 this.el.enableDisplayMode();
735 onClick : function(e)
742 Roo.log('button on click ');
743 if(this.preventDefault){
746 if (this.pressed === true || this.pressed === false) {
747 this.pressed = !this.pressed;
748 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
749 this.fireEvent('toggle', this, e, this.pressed);
753 this.fireEvent('click', this, e);
757 * Enables this button
761 this.disabled = false;
762 this.el.removeClass('disabled');
766 * Disable this button
770 this.disabled = true;
771 this.el.addClass('disabled');
774 * sets the active state on/off,
775 * @param {Boolean} state (optional) Force a particular state
777 setActive : function(v) {
779 this.el[v ? 'addClass' : 'removeClass']('active');
782 * toggles the current active state
784 toggleActive : function()
786 var active = this.el.hasClass('active');
787 this.setActive(!active);
791 setText : function(str)
793 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
797 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
820 * @class Roo.bootstrap.Column
821 * @extends Roo.bootstrap.Component
822 * Bootstrap Column class
823 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
824 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
825 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
826 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
827 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
828 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
829 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
830 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
833 * @cfg {Boolean} hidden (true|false) hide the element
834 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
835 * @cfg {String} fa (ban|check|...) font awesome icon
836 * @cfg {Number} fasize (1|2|....) font awsome size
838 * @cfg {String} icon (info-sign|check|...) glyphicon name
840 * @cfg {String} html content of column.
843 * Create a new Column
844 * @param {Object} config The config object
847 Roo.bootstrap.Column = function(config){
848 Roo.bootstrap.Column.superclass.constructor.call(this, config);
851 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
869 getAutoCreate : function(){
870 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
878 ['xs','sm','md','lg'].map(function(size){
879 //Roo.log( size + ':' + settings[size]);
881 if (settings[size+'off'] !== false) {
882 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
885 if (settings[size] === false) {
888 Roo.log(settings[size]);
889 if (!settings[size]) { // 0 = hidden
890 cfg.cls += ' hidden-' + size;
893 cfg.cls += ' col-' + size + '-' + settings[size];
898 cfg.cls += ' hidden';
901 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
902 cfg.cls +=' alert alert-' + this.alert;
906 if (this.html.length) {
907 cfg.html = this.html;
911 if (this.fasize > 1) {
912 fasize = ' fa-' + this.fasize + 'x';
914 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
919 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
938 * @class Roo.bootstrap.Container
939 * @extends Roo.bootstrap.Component
940 * Bootstrap Container class
941 * @cfg {Boolean} jumbotron is it a jumbotron element
942 * @cfg {String} html content of element
943 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
944 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
945 * @cfg {String} header content of header (for panel)
946 * @cfg {String} footer content of footer (for panel)
947 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
948 * @cfg {String} tag (header|aside|section) type of HTML tag.
949 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
950 * @cfg {String} fa (ban|check|...) font awesome icon
951 * @cfg {String} icon (info-sign|check|...) glyphicon name
952 * @cfg {Boolean} hidden (true|false) hide the element
956 * Create a new Container
957 * @param {Object} config The config object
960 Roo.bootstrap.Container = function(config){
961 Roo.bootstrap.Container.superclass.constructor.call(this, config);
964 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
978 getChildContainer : function() {
984 if (this.panel.length) {
985 return this.el.select('.panel-body',true).first();
992 getAutoCreate : function(){
995 tag : this.tag || 'div',
999 if (this.jumbotron) {
1000 cfg.cls = 'jumbotron';
1005 // - this is applied by the parent..
1007 // cfg.cls = this.cls + '';
1010 if (this.sticky.length) {
1012 var bd = Roo.get(document.body);
1013 if (!bd.hasClass('bootstrap-sticky')) {
1014 bd.addClass('bootstrap-sticky');
1015 Roo.select('html',true).setStyle('height', '100%');
1018 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1022 if (this.well.length) {
1023 switch (this.well) {
1026 cfg.cls +=' well well-' +this.well;
1035 cfg.cls += ' hidden';
1039 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1040 cfg.cls +=' alert alert-' + this.alert;
1045 if (this.panel.length) {
1046 cfg.cls += ' panel panel-' + this.panel;
1048 if (this.header.length) {
1051 cls : 'panel-heading',
1054 cls : 'panel-title',
1067 if (this.footer.length) {
1069 cls : 'panel-footer',
1078 body.html = this.html || cfg.html;
1079 // prefix with the icons..
1081 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1084 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1089 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1090 cfg.cls = 'container';
1096 titleEl : function()
1098 if(!this.el || !this.panel.length || !this.header.length){
1102 return this.el.select('.panel-title',true).first();
1105 setTitle : function(v)
1107 var titleEl = this.titleEl();
1113 titleEl.dom.innerHTML = v;
1116 getTitle : function()
1119 var titleEl = this.titleEl();
1125 return titleEl.dom.innerHTML;
1129 this.el.removeClass('hidden');
1132 if (!this.el.hasClass('hidden')) {
1133 this.el.addClass('hidden');
1149 * @class Roo.bootstrap.Img
1150 * @extends Roo.bootstrap.Component
1151 * Bootstrap Img class
1152 * @cfg {Boolean} imgResponsive false | true
1153 * @cfg {String} border rounded | circle | thumbnail
1154 * @cfg {String} src image source
1155 * @cfg {String} alt image alternative text
1156 * @cfg {String} href a tag href
1157 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1160 * Create a new Input
1161 * @param {Object} config The config object
1164 Roo.bootstrap.Img = function(config){
1165 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1171 * The img click event for the img.
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1180 imgResponsive: true,
1186 getAutoCreate : function(){
1190 cls: (this.imgResponsive) ? 'img-responsive' : '',
1194 cfg.html = this.html || cfg.html;
1196 cfg.src = this.src || cfg.src;
1198 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1199 cfg.cls += ' img-' + this.border;
1216 a.target = this.target;
1222 return (this.href) ? a : cfg;
1225 initEvents: function() {
1228 this.el.on('click', this.onClick, this);
1232 onClick : function(e)
1234 Roo.log('img onclick');
1235 this.fireEvent('click', this, e);
1249 * @class Roo.bootstrap.Link
1250 * @extends Roo.bootstrap.Component
1251 * Bootstrap Link Class
1252 * @cfg {String} alt image alternative text
1253 * @cfg {String} href a tag href
1254 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1255 * @cfg {String} html the content of the link.
1256 * @cfg {String} anchor name for the anchor link
1258 * @cfg {Boolean} preventDefault (true | false) default false
1262 * Create a new Input
1263 * @param {Object} config The config object
1266 Roo.bootstrap.Link = function(config){
1267 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1273 * The img click event for the img.
1274 * @param {Roo.EventObject} e
1280 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1284 preventDefault: false,
1288 getAutoCreate : function()
1294 // anchor's do not require html/href...
1295 if (this.anchor === false) {
1296 cfg.html = this.html || 'html-missing';
1297 cfg.href = this.href || '#';
1299 cfg.name = this.anchor;
1300 if (this.html !== false) {
1301 cfg.html = this.html;
1303 if (this.href !== false) {
1304 cfg.href = this.href;
1308 if(this.alt !== false){
1313 if(this.target !== false) {
1314 cfg.target = this.target;
1320 initEvents: function() {
1322 if(!this.href || this.preventDefault){
1323 this.el.on('click', this.onClick, this);
1327 onClick : function(e)
1329 if(this.preventDefault){
1332 //Roo.log('img onclick');
1333 this.fireEvent('click', this, e);
1346 * @class Roo.bootstrap.Header
1347 * @extends Roo.bootstrap.Component
1348 * Bootstrap Header class
1349 * @cfg {String} html content of header
1350 * @cfg {Number} level (1|2|3|4|5|6) default 1
1353 * Create a new Header
1354 * @param {Object} config The config object
1358 Roo.bootstrap.Header = function(config){
1359 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1362 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1370 getAutoCreate : function(){
1373 tag: 'h' + (1 *this.level),
1374 html: this.html || 'fill in html'
1386 * Ext JS Library 1.1.1
1387 * Copyright(c) 2006-2007, Ext JS, LLC.
1389 * Originally Released Under LGPL - original licence link has changed is not relivant.
1392 * <script type="text/javascript">
1396 * @class Roo.bootstrap.MenuMgr
1397 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1400 Roo.bootstrap.MenuMgr = function(){
1401 var menus, active, groups = {}, attached = false, lastShow = new Date();
1403 // private - called when first menu is created
1406 active = new Roo.util.MixedCollection();
1407 Roo.get(document).addKeyListener(27, function(){
1408 if(active.length > 0){
1416 if(active && active.length > 0){
1417 var c = active.clone();
1427 if(active.length < 1){
1428 Roo.get(document).un("mouseup", onMouseDown);
1436 var last = active.last();
1437 lastShow = new Date();
1440 Roo.get(document).on("mouseup", onMouseDown);
1445 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1446 m.parentMenu.activeChild = m;
1447 }else if(last && last.isVisible()){
1448 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1453 function onBeforeHide(m){
1455 m.activeChild.hide();
1457 if(m.autoHideTimer){
1458 clearTimeout(m.autoHideTimer);
1459 delete m.autoHideTimer;
1464 function onBeforeShow(m){
1465 var pm = m.parentMenu;
1466 if(!pm && !m.allowOtherMenus){
1468 }else if(pm && pm.activeChild && active != m){
1469 pm.activeChild.hide();
1474 function onMouseDown(e){
1475 Roo.log("on MouseDown");
1476 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1484 function onBeforeCheck(mi, state){
1486 var g = groups[mi.group];
1487 for(var i = 0, l = g.length; i < l; i++){
1489 g[i].setChecked(false);
1498 * Hides all menus that are currently visible
1500 hideAll : function(){
1505 register : function(menu){
1509 menus[menu.id] = menu;
1510 menu.on("beforehide", onBeforeHide);
1511 menu.on("hide", onHide);
1512 menu.on("beforeshow", onBeforeShow);
1513 menu.on("show", onShow);
1515 if(g && menu.events["checkchange"]){
1519 groups[g].push(menu);
1520 menu.on("checkchange", onCheck);
1525 * Returns a {@link Roo.menu.Menu} object
1526 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1527 * be used to generate and return a new Menu instance.
1529 get : function(menu){
1530 if(typeof menu == "string"){ // menu id
1532 }else if(menu.events){ // menu instance
1535 /*else if(typeof menu.length == 'number'){ // array of menu items?
1536 return new Roo.bootstrap.Menu({items:menu});
1537 }else{ // otherwise, must be a config
1538 return new Roo.bootstrap.Menu(menu);
1545 unregister : function(menu){
1546 delete menus[menu.id];
1547 menu.un("beforehide", onBeforeHide);
1548 menu.un("hide", onHide);
1549 menu.un("beforeshow", onBeforeShow);
1550 menu.un("show", onShow);
1552 if(g && menu.events["checkchange"]){
1553 groups[g].remove(menu);
1554 menu.un("checkchange", onCheck);
1559 registerCheckable : function(menuItem){
1560 var g = menuItem.group;
1565 groups[g].push(menuItem);
1566 menuItem.on("beforecheckchange", onBeforeCheck);
1571 unregisterCheckable : function(menuItem){
1572 var g = menuItem.group;
1574 groups[g].remove(menuItem);
1575 menuItem.un("beforecheckchange", onBeforeCheck);
1587 * @class Roo.bootstrap.Menu
1588 * @extends Roo.bootstrap.Component
1589 * Bootstrap Menu class - container for MenuItems
1590 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1594 * @param {Object} config The config object
1598 Roo.bootstrap.Menu = function(config){
1599 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1600 if (this.registerMenu) {
1601 Roo.bootstrap.MenuMgr.register(this);
1606 * Fires before this menu is displayed
1607 * @param {Roo.menu.Menu} this
1612 * Fires before this menu is hidden
1613 * @param {Roo.menu.Menu} this
1618 * Fires after this menu is displayed
1619 * @param {Roo.menu.Menu} this
1624 * Fires after this menu is hidden
1625 * @param {Roo.menu.Menu} this
1630 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1631 * @param {Roo.menu.Menu} this
1632 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1633 * @param {Roo.EventObject} e
1638 * Fires when the mouse is hovering over this menu
1639 * @param {Roo.menu.Menu} this
1640 * @param {Roo.EventObject} e
1641 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1646 * Fires when the mouse exits this menu
1647 * @param {Roo.menu.Menu} this
1648 * @param {Roo.EventObject} e
1649 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1654 * Fires when a menu item contained in this menu is clicked
1655 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1656 * @param {Roo.EventObject} e
1660 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1663 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1667 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1670 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1672 registerMenu : true,
1674 menuItems :false, // stores the menu items..
1680 getChildContainer : function() {
1684 getAutoCreate : function(){
1686 //if (['right'].indexOf(this.align)!==-1) {
1687 // cfg.cn[1].cls += ' pull-right'
1693 cls : 'dropdown-menu' ,
1694 style : 'z-index:1000'
1698 if (this.type === 'submenu') {
1699 cfg.cls = 'submenu active';
1701 if (this.type === 'treeview') {
1702 cfg.cls = 'treeview-menu';
1707 initEvents : function() {
1709 // Roo.log("ADD event");
1710 // Roo.log(this.triggerEl.dom);
1711 this.triggerEl.on('click', this.onTriggerPress, this);
1712 this.triggerEl.addClass('dropdown-toggle');
1713 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1715 this.el.on("mouseover", this.onMouseOver, this);
1716 this.el.on("mouseout", this.onMouseOut, this);
1720 findTargetItem : function(e){
1721 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1725 //Roo.log(t); Roo.log(t.id);
1727 //Roo.log(this.menuitems);
1728 return this.menuitems.get(t.id);
1730 //return this.items.get(t.menuItemId);
1735 onClick : function(e){
1736 Roo.log("menu.onClick");
1737 var t = this.findTargetItem(e);
1738 if(!t || t.isContainer){
1743 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1744 if(t == this.activeItem && t.shouldDeactivate(e)){
1745 this.activeItem.deactivate();
1746 delete this.activeItem;
1750 this.setActiveItem(t, true);
1758 Roo.log('pass click event');
1762 this.fireEvent("click", this, t, e);
1766 onMouseOver : function(e){
1767 var t = this.findTargetItem(e);
1770 // if(t.canActivate && !t.disabled){
1771 // this.setActiveItem(t, true);
1775 this.fireEvent("mouseover", this, e, t);
1777 isVisible : function(){
1778 return !this.hidden;
1780 onMouseOut : function(e){
1781 var t = this.findTargetItem(e);
1784 // if(t == this.activeItem && t.shouldDeactivate(e)){
1785 // this.activeItem.deactivate();
1786 // delete this.activeItem;
1789 this.fireEvent("mouseout", this, e, t);
1794 * Displays this menu relative to another element
1795 * @param {String/HTMLElement/Roo.Element} element The element to align to
1796 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1797 * the element (defaults to this.defaultAlign)
1798 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1800 show : function(el, pos, parentMenu){
1801 this.parentMenu = parentMenu;
1805 this.fireEvent("beforeshow", this);
1806 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1809 * Displays this menu at a specific xy position
1810 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1811 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1813 showAt : function(xy, parentMenu, /* private: */_e){
1814 this.parentMenu = parentMenu;
1819 this.fireEvent("beforeshow", this);
1821 //xy = this.el.adjustForConstraints(xy);
1823 //this.el.setXY(xy);
1825 this.hideMenuItems();
1826 this.hidden = false;
1827 this.triggerEl.addClass('open');
1829 this.fireEvent("show", this);
1835 this.doFocus.defer(50, this);
1839 doFocus : function(){
1841 this.focusEl.focus();
1846 * Hides this menu and optionally all parent menus
1847 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1849 hide : function(deep){
1851 this.hideMenuItems();
1852 if(this.el && this.isVisible()){
1853 this.fireEvent("beforehide", this);
1854 if(this.activeItem){
1855 this.activeItem.deactivate();
1856 this.activeItem = null;
1858 this.triggerEl.removeClass('open');;
1860 this.fireEvent("hide", this);
1862 if(deep === true && this.parentMenu){
1863 this.parentMenu.hide(true);
1867 onTriggerPress : function(e)
1870 Roo.log('trigger press');
1871 //Roo.log(e.getTarget());
1872 // Roo.log(this.triggerEl.dom);
1873 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1876 if (this.isVisible()) {
1880 this.show(this.triggerEl, false, false);
1889 hideMenuItems : function()
1891 //$(backdrop).remove()
1892 Roo.select('.open',true).each(function(aa) {
1894 aa.removeClass('open');
1895 //var parent = getParent($(this))
1896 //var relatedTarget = { relatedTarget: this }
1898 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1899 //if (e.isDefaultPrevented()) return
1900 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1903 addxtypeChild : function (tree, cntr) {
1904 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1906 this.menuitems.add(comp);
1927 * @class Roo.bootstrap.MenuItem
1928 * @extends Roo.bootstrap.Component
1929 * Bootstrap MenuItem class
1930 * @cfg {String} html the menu label
1931 * @cfg {String} href the link
1932 * @cfg {Boolean} preventDefault (true | false) default true
1933 * @cfg {Boolean} isContainer (true | false) default false
1937 * Create a new MenuItem
1938 * @param {Object} config The config object
1942 Roo.bootstrap.MenuItem = function(config){
1943 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1948 * The raw click event for the entire grid.
1949 * @param {Roo.EventObject} e
1955 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1959 preventDefault: true,
1960 isContainer : false,
1962 getAutoCreate : function(){
1964 if(this.isContainer){
1967 cls: 'dropdown-menu-item'
1973 cls: 'dropdown-menu-item',
1982 if (this.parent().type == 'treeview') {
1983 cfg.cls = 'treeview-menu';
1986 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1987 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1991 initEvents: function() {
1993 //this.el.select('a').on('click', this.onClick, this);
1996 onClick : function(e)
1998 Roo.log('item on click ');
1999 //if(this.preventDefault){
2000 // e.preventDefault();
2002 //this.parent().hideMenuItems();
2004 this.fireEvent('click', this, e);
2023 * @class Roo.bootstrap.MenuSeparator
2024 * @extends Roo.bootstrap.Component
2025 * Bootstrap MenuSeparator class
2028 * Create a new MenuItem
2029 * @param {Object} config The config object
2033 Roo.bootstrap.MenuSeparator = function(config){
2034 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2037 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2039 getAutoCreate : function(){
2058 * @class Roo.bootstrap.Modal
2059 * @extends Roo.bootstrap.Component
2060 * Bootstrap Modal class
2061 * @cfg {String} title Title of dialog
2062 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2063 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2064 * @cfg {Boolean} specificTitle default false
2065 * @cfg {Array} buttons Array of buttons or standard button set..
2066 * @cfg {String} buttonPosition (left|right|center) default right
2067 * @cfg {Boolean} animate default true
2068 * @cfg {Boolean} allow_close default true
2071 * Create a new Modal Dialog
2072 * @param {Object} config The config object
2075 Roo.bootstrap.Modal = function(config){
2076 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2081 * The raw btnclick event for the button
2082 * @param {Roo.EventObject} e
2086 this.buttons = this.buttons || [];
2089 this.tmpl = Roo.factory(this.tmpl);
2094 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2096 title : 'test dialog',
2106 specificTitle: false,
2108 buttonPosition: 'right',
2122 onRender : function(ct, position)
2124 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2127 var cfg = Roo.apply({}, this.getAutoCreate());
2130 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2132 //if (!cfg.name.length) {
2136 cfg.cls += ' ' + this.cls;
2139 cfg.style = this.style;
2141 this.el = Roo.get(document.body).createChild(cfg, position);
2143 //var type = this.el.dom.type;
2145 if(this.tabIndex !== undefined){
2146 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2151 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2152 this.maskEl.enableDisplayMode("block");
2154 //this.el.addClass("x-dlg-modal");
2156 if (this.buttons.length) {
2157 Roo.each(this.buttons, function(bb) {
2158 b = Roo.apply({}, bb);
2159 b.xns = b.xns || Roo.bootstrap;
2160 b.xtype = b.xtype || 'Button';
2161 if (typeof(b.listeners) == 'undefined') {
2162 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2165 var btn = Roo.factory(b);
2167 btn.onRender(this.el.select('.modal-footer div').first());
2171 // render the children.
2174 if(typeof(this.items) != 'undefined'){
2175 var items = this.items;
2178 for(var i =0;i < items.length;i++) {
2179 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2183 this.items = nitems;
2185 // where are these used - they used to be body/close/footer
2187 this.bodyEl = this.el.select('.modal-body',true).first();
2188 this.closeEl = this.el.select('.modal-header .close', true).first();
2189 this.footerEl = this.el.select('.modal-footer',true).first();
2190 this.titleEl = this.el.select('.modal-title',true).first();
2193 //this.el.addClass([this.fieldClass, this.cls]);
2196 getAutoCreate : function(){
2201 html : this.html || ''
2206 cls : 'modal-title',
2210 if(this.specificTitle){
2216 if (this.allow_close) {
2227 style : 'display: none',
2230 cls: "modal-dialog",
2233 cls : "modal-content",
2236 cls : 'modal-header',
2241 cls : 'modal-footer',
2245 cls: 'btn-' + this.buttonPosition
2262 modal.cls += ' fade';
2268 getChildContainer : function() {
2273 getButtonContainer : function() {
2274 return this.el.select('.modal-footer div',true).first();
2277 initEvents : function()
2279 if (this.allow_close) {
2280 this.closeEl.on('click', this.hide, this);
2286 if (!this.rendered) {
2290 this.el.setStyle('display', 'block');
2294 (function(){ _this.el.addClass('in'); }).defer(50);
2296 this.el.addClass('in');
2299 // not sure how we can show data in here..
2301 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2304 Roo.get(document.body).addClass("x-body-masked");
2305 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2307 this.el.setStyle('zIndex', '10001');
2309 this.fireEvent('show', this);
2316 Roo.get(document.body).removeClass("x-body-masked");
2317 this.el.removeClass('in');
2321 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2323 this.el.setStyle('display', 'none');
2326 this.fireEvent('hide', this);
2329 addButton : function(str, cb)
2333 var b = Roo.apply({}, { html : str } );
2334 b.xns = b.xns || Roo.bootstrap;
2335 b.xtype = b.xtype || 'Button';
2336 if (typeof(b.listeners) == 'undefined') {
2337 b.listeners = { click : cb.createDelegate(this) };
2340 var btn = Roo.factory(b);
2342 btn.onRender(this.el.select('.modal-footer div').first());
2348 setDefaultButton : function(btn)
2350 //this.el.select('.modal-footer').()
2352 resizeTo: function(w,h)
2356 setContentSize : function(w, h)
2360 onButtonClick: function(btn,e)
2363 this.fireEvent('btnclick', btn.name, e);
2366 * Set the title of the Dialog
2367 * @param {String} str new Title
2369 setTitle: function(str) {
2370 this.titleEl.dom.innerHTML = str;
2373 * Set the body of the Dialog
2374 * @param {String} str new Title
2376 setBody: function(str) {
2377 this.bodyEl.dom.innerHTML = str;
2380 * Set the body of the Dialog using the template
2381 * @param {Obj} data - apply this data to the template and replace the body contents.
2383 applyBody: function(obj)
2386 Roo.log("Error - using apply Body without a template");
2389 this.tmpl.overwrite(this.bodyEl, obj);
2395 Roo.apply(Roo.bootstrap.Modal, {
2397 * Button config that displays a single OK button
2406 * Button config that displays Yes and No buttons
2422 * Button config that displays OK and Cancel buttons
2437 * Button config that displays Yes, No and Cancel buttons
2460 * messagebox - can be used as a replace
2464 * @class Roo.MessageBox
2465 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2469 Roo.Msg.alert('Status', 'Changes saved successfully.');
2471 // Prompt for user data:
2472 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2474 // process text value...
2478 // Show a dialog using config options:
2480 title:'Save Changes?',
2481 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2482 buttons: Roo.Msg.YESNOCANCEL,
2489 Roo.bootstrap.MessageBox = function(){
2490 var dlg, opt, mask, waitTimer;
2491 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2492 var buttons, activeTextEl, bwidth;
2496 var handleButton = function(button){
2498 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2502 var handleHide = function(){
2504 dlg.el.removeClass(opt.cls);
2507 // Roo.TaskMgr.stop(waitTimer);
2508 // waitTimer = null;
2513 var updateButtons = function(b){
2516 buttons["ok"].hide();
2517 buttons["cancel"].hide();
2518 buttons["yes"].hide();
2519 buttons["no"].hide();
2520 //dlg.footer.dom.style.display = 'none';
2523 dlg.footerEl.dom.style.display = '';
2524 for(var k in buttons){
2525 if(typeof buttons[k] != "function"){
2528 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2529 width += buttons[k].el.getWidth()+15;
2539 var handleEsc = function(d, k, e){
2540 if(opt && opt.closable !== false){
2550 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2551 * @return {Roo.BasicDialog} The BasicDialog element
2553 getDialog : function(){
2555 dlg = new Roo.bootstrap.Modal( {
2558 //constraintoviewport:false,
2560 //collapsible : false,
2565 //buttonAlign:"center",
2566 closeClick : function(){
2567 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2570 handleButton("cancel");
2575 dlg.on("hide", handleHide);
2577 //dlg.addKeyListener(27, handleEsc);
2579 this.buttons = buttons;
2580 var bt = this.buttonText;
2581 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2582 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2583 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2584 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2586 bodyEl = dlg.bodyEl.createChild({
2588 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2589 '<textarea class="roo-mb-textarea"></textarea>' +
2590 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2592 msgEl = bodyEl.dom.firstChild;
2593 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2594 textboxEl.enableDisplayMode();
2595 textboxEl.addKeyListener([10,13], function(){
2596 if(dlg.isVisible() && opt && opt.buttons){
2599 }else if(opt.buttons.yes){
2600 handleButton("yes");
2604 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2605 textareaEl.enableDisplayMode();
2606 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2607 progressEl.enableDisplayMode();
2608 var pf = progressEl.dom.firstChild;
2610 pp = Roo.get(pf.firstChild);
2611 pp.setHeight(pf.offsetHeight);
2619 * Updates the message box body text
2620 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2621 * the XHTML-compliant non-breaking space character '&#160;')
2622 * @return {Roo.MessageBox} This message box
2624 updateText : function(text){
2625 if(!dlg.isVisible() && !opt.width){
2626 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2628 msgEl.innerHTML = text || ' ';
2630 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2631 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2633 Math.min(opt.width || cw , this.maxWidth),
2634 Math.max(opt.minWidth || this.minWidth, bwidth)
2637 activeTextEl.setWidth(w);
2639 if(dlg.isVisible()){
2640 dlg.fixedcenter = false;
2642 // to big, make it scroll. = But as usual stupid IE does not support
2645 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2646 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2647 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2649 bodyEl.dom.style.height = '';
2650 bodyEl.dom.style.overflowY = '';
2653 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2655 bodyEl.dom.style.overflowX = '';
2658 dlg.setContentSize(w, bodyEl.getHeight());
2659 if(dlg.isVisible()){
2660 dlg.fixedcenter = true;
2666 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2667 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2668 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2669 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2670 * @return {Roo.MessageBox} This message box
2672 updateProgress : function(value, text){
2674 this.updateText(text);
2676 if (pp) { // weird bug on my firefox - for some reason this is not defined
2677 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2683 * Returns true if the message box is currently displayed
2684 * @return {Boolean} True if the message box is visible, else false
2686 isVisible : function(){
2687 return dlg && dlg.isVisible();
2691 * Hides the message box if it is displayed
2694 if(this.isVisible()){
2700 * Displays a new message box, or reinitializes an existing message box, based on the config options
2701 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2702 * The following config object properties are supported:
2704 Property Type Description
2705 ---------- --------------- ------------------------------------------------------------------------------------
2706 animEl String/Element An id or Element from which the message box should animate as it opens and
2707 closes (defaults to undefined)
2708 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2709 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2710 closable Boolean False to hide the top-right close button (defaults to true). Note that
2711 progress and wait dialogs will ignore this property and always hide the
2712 close button as they can only be closed programmatically.
2713 cls String A custom CSS class to apply to the message box element
2714 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2715 displayed (defaults to 75)
2716 fn Function A callback function to execute after closing the dialog. The arguments to the
2717 function will be btn (the name of the button that was clicked, if applicable,
2718 e.g. "ok"), and text (the value of the active text field, if applicable).
2719 Progress and wait dialogs will ignore this option since they do not respond to
2720 user actions and can only be closed programmatically, so any required function
2721 should be called by the same code after it closes the dialog.
2722 icon String A CSS class that provides a background image to be used as an icon for
2723 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2724 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2725 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2726 modal Boolean False to allow user interaction with the page while the message box is
2727 displayed (defaults to true)
2728 msg String A string that will replace the existing message box body text (defaults
2729 to the XHTML-compliant non-breaking space character ' ')
2730 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2731 progress Boolean True to display a progress bar (defaults to false)
2732 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2733 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2734 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2735 title String The title text
2736 value String The string value to set into the active textbox element if displayed
2737 wait Boolean True to display a progress bar (defaults to false)
2738 width Number The width of the dialog in pixels
2745 msg: 'Please enter your address:',
2747 buttons: Roo.MessageBox.OKCANCEL,
2750 animEl: 'addAddressBtn'
2753 * @param {Object} config Configuration options
2754 * @return {Roo.MessageBox} This message box
2756 show : function(options)
2759 // this causes nightmares if you show one dialog after another
2760 // especially on callbacks..
2762 if(this.isVisible()){
2765 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2766 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2767 Roo.log("New Dialog Message:" + options.msg )
2768 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2769 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2772 var d = this.getDialog();
2774 d.setTitle(opt.title || " ");
2775 d.closeEl.setDisplayed(opt.closable !== false);
2776 activeTextEl = textboxEl;
2777 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2782 textareaEl.setHeight(typeof opt.multiline == "number" ?
2783 opt.multiline : this.defaultTextHeight);
2784 activeTextEl = textareaEl;
2793 progressEl.setDisplayed(opt.progress === true);
2794 this.updateProgress(0);
2795 activeTextEl.dom.value = opt.value || "";
2797 dlg.setDefaultButton(activeTextEl);
2799 var bs = opt.buttons;
2803 }else if(bs && bs.yes){
2804 db = buttons["yes"];
2806 dlg.setDefaultButton(db);
2808 bwidth = updateButtons(opt.buttons);
2809 this.updateText(opt.msg);
2811 d.el.addClass(opt.cls);
2813 d.proxyDrag = opt.proxyDrag === true;
2814 d.modal = opt.modal !== false;
2815 d.mask = opt.modal !== false ? mask : false;
2817 // force it to the end of the z-index stack so it gets a cursor in FF
2818 document.body.appendChild(dlg.el.dom);
2819 d.animateTarget = null;
2820 d.show(options.animEl);
2826 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2827 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2828 * and closing the message box when the process is complete.
2829 * @param {String} title The title bar text
2830 * @param {String} msg The message box body text
2831 * @return {Roo.MessageBox} This message box
2833 progress : function(title, msg){
2840 minWidth: this.minProgressWidth,
2847 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2848 * If a callback function is passed it will be called after the user clicks the button, and the
2849 * id of the button that was clicked will be passed as the only parameter to the callback
2850 * (could also be the top-right close button).
2851 * @param {String} title The title bar text
2852 * @param {String} msg The message box body text
2853 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2854 * @param {Object} scope (optional) The scope of the callback function
2855 * @return {Roo.MessageBox} This message box
2857 alert : function(title, msg, fn, scope){
2870 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2871 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2872 * You are responsible for closing the message box when the process is complete.
2873 * @param {String} msg The message box body text
2874 * @param {String} title (optional) The title bar text
2875 * @return {Roo.MessageBox} This message box
2877 wait : function(msg, title){
2888 waitTimer = Roo.TaskMgr.start({
2890 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2898 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2899 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2900 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2901 * @param {String} title The title bar text
2902 * @param {String} msg The message box body text
2903 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2904 * @param {Object} scope (optional) The scope of the callback function
2905 * @return {Roo.MessageBox} This message box
2907 confirm : function(title, msg, fn, scope){
2911 buttons: this.YESNO,
2920 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2921 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2922 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2923 * (could also be the top-right close button) and the text that was entered will be passed as the two
2924 * parameters to the callback.
2925 * @param {String} title The title bar text
2926 * @param {String} msg The message box body text
2927 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2928 * @param {Object} scope (optional) The scope of the callback function
2929 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2930 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2931 * @return {Roo.MessageBox} This message box
2933 prompt : function(title, msg, fn, scope, multiline){
2937 buttons: this.OKCANCEL,
2942 multiline: multiline,
2949 * Button config that displays a single OK button
2954 * Button config that displays Yes and No buttons
2957 YESNO : {yes:true, no:true},
2959 * Button config that displays OK and Cancel buttons
2962 OKCANCEL : {ok:true, cancel:true},
2964 * Button config that displays Yes, No and Cancel buttons
2967 YESNOCANCEL : {yes:true, no:true, cancel:true},
2970 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2973 defaultTextHeight : 75,
2975 * The maximum width in pixels of the message box (defaults to 600)
2980 * The minimum width in pixels of the message box (defaults to 100)
2985 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2986 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2989 minProgressWidth : 250,
2991 * An object containing the default button text strings that can be overriden for localized language support.
2992 * Supported properties are: ok, cancel, yes and no.
2993 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3006 * Shorthand for {@link Roo.MessageBox}
3008 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3009 Roo.Msg = Roo.Msg || Roo.MessageBox;
3018 * @class Roo.bootstrap.Navbar
3019 * @extends Roo.bootstrap.Component
3020 * Bootstrap Navbar class
3023 * Create a new Navbar
3024 * @param {Object} config The config object
3028 Roo.bootstrap.Navbar = function(config){
3029 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3033 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3042 getAutoCreate : function(){
3045 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3049 initEvents :function ()
3051 //Roo.log(this.el.select('.navbar-toggle',true));
3052 this.el.select('.navbar-toggle',true).on('click', function() {
3053 // Roo.log('click');
3054 this.el.select('.navbar-collapse',true).toggleClass('in');
3062 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3064 var size = this.el.getSize();
3065 this.maskEl.setSize(size.width, size.height);
3066 this.maskEl.enableDisplayMode("block");
3075 getChildContainer : function()
3077 if (this.el.select('.collapse').getCount()) {
3078 return this.el.select('.collapse',true).first();
3111 * @class Roo.bootstrap.NavSimplebar
3112 * @extends Roo.bootstrap.Navbar
3113 * Bootstrap Sidebar class
3115 * @cfg {Boolean} inverse is inverted color
3117 * @cfg {String} type (nav | pills | tabs)
3118 * @cfg {Boolean} arrangement stacked | justified
3119 * @cfg {String} align (left | right) alignment
3121 * @cfg {Boolean} main (true|false) main nav bar? default false
3122 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3124 * @cfg {String} tag (header|footer|nav|div) default is nav
3130 * Create a new Sidebar
3131 * @param {Object} config The config object
3135 Roo.bootstrap.NavSimplebar = function(config){
3136 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3139 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3155 getAutoCreate : function(){
3159 tag : this.tag || 'div',
3172 this.type = this.type || 'nav';
3173 if (['tabs','pills'].indexOf(this.type)!==-1) {
3174 cfg.cn[0].cls += ' nav-' + this.type
3178 if (this.type!=='nav') {
3179 Roo.log('nav type must be nav/tabs/pills')
3181 cfg.cn[0].cls += ' navbar-nav'
3187 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3188 cfg.cn[0].cls += ' nav-' + this.arrangement;
3192 if (this.align === 'right') {
3193 cfg.cn[0].cls += ' navbar-right';
3197 cfg.cls += ' navbar-inverse';
3224 * @class Roo.bootstrap.NavHeaderbar
3225 * @extends Roo.bootstrap.NavSimplebar
3226 * Bootstrap Sidebar class
3228 * @cfg {String} brand what is brand
3229 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3230 * @cfg {String} brand_href href of the brand
3231 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3232 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3233 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3234 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3237 * Create a new Sidebar
3238 * @param {Object} config The config object
3242 Roo.bootstrap.NavHeaderbar = function(config){
3243 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3247 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3254 desktopCenter : false,
3257 getAutoCreate : function(){
3260 tag: this.nav || 'nav',
3267 if (this.desktopCenter) {
3268 cn.push({cls : 'container', cn : []});
3275 cls: 'navbar-header',
3280 cls: 'navbar-toggle',
3281 'data-toggle': 'collapse',
3286 html: 'Toggle navigation'
3308 cls: 'collapse navbar-collapse',
3312 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3314 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3315 cfg.cls += ' navbar-' + this.position;
3317 // tag can override this..
3319 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3322 if (this.brand !== '') {
3325 href: this.brand_href ? this.brand_href : '#',
3326 cls: 'navbar-brand',
3334 cfg.cls += ' main-nav';
3342 getHeaderChildContainer : function()
3344 if (this.el.select('.navbar-header').getCount()) {
3345 return this.el.select('.navbar-header',true).first();
3348 return this.getChildContainer();
3352 initEvents : function()
3354 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3356 if (this.autohide) {
3361 Roo.get(document).on('scroll',function(e) {
3362 var ns = Roo.get(document).getScroll().top;
3363 var os = prevScroll;
3367 ft.removeClass('slideDown');
3368 ft.addClass('slideUp');
3371 ft.removeClass('slideUp');
3372 ft.addClass('slideDown');
3396 * @class Roo.bootstrap.NavSidebar
3397 * @extends Roo.bootstrap.Navbar
3398 * Bootstrap Sidebar class
3401 * Create a new Sidebar
3402 * @param {Object} config The config object
3406 Roo.bootstrap.NavSidebar = function(config){
3407 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3410 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3412 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3414 getAutoCreate : function(){
3419 cls: 'sidebar sidebar-nav'
3441 * @class Roo.bootstrap.NavGroup
3442 * @extends Roo.bootstrap.Component
3443 * Bootstrap NavGroup class
3444 * @cfg {String} align left | right
3445 * @cfg {Boolean} inverse false | true
3446 * @cfg {String} type (nav|pills|tab) default nav
3447 * @cfg {String} navId - reference Id for navbar.
3451 * Create a new nav group
3452 * @param {Object} config The config object
3455 Roo.bootstrap.NavGroup = function(config){
3456 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3459 Roo.bootstrap.NavGroup.register(this);
3463 * Fires when the active item changes
3464 * @param {Roo.bootstrap.NavGroup} this
3465 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3466 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3473 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3484 getAutoCreate : function()
3486 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3493 if (['tabs','pills'].indexOf(this.type)!==-1) {
3494 cfg.cls += ' nav-' + this.type
3496 if (this.type!=='nav') {
3497 Roo.log('nav type must be nav/tabs/pills')
3499 cfg.cls += ' navbar-nav'
3502 if (this.parent().sidebar) {
3505 cls: 'dashboard-menu sidebar-menu'
3511 if (this.form === true) {
3517 if (this.align === 'right') {
3518 cfg.cls += ' navbar-right';
3520 cfg.cls += ' navbar-left';
3524 if (this.align === 'right') {
3525 cfg.cls += ' navbar-right';
3529 cfg.cls += ' navbar-inverse';
3537 * sets the active Navigation item
3538 * @param {Roo.bootstrap.NavItem} the new current navitem
3540 setActiveItem : function(item)
3543 Roo.each(this.navItems, function(v){
3548 v.setActive(false, true);
3555 item.setActive(true, true);
3556 this.fireEvent('changed', this, item, prev);
3561 * gets the active Navigation item
3562 * @return {Roo.bootstrap.NavItem} the current navitem
3564 getActive : function()
3568 Roo.each(this.navItems, function(v){
3579 indexOfNav : function()
3583 Roo.each(this.navItems, function(v,i){
3594 * adds a Navigation item
3595 * @param {Roo.bootstrap.NavItem} the navitem to add
3597 addItem : function(cfg)
3599 var cn = new Roo.bootstrap.NavItem(cfg);
3601 cn.parentId = this.id;
3602 cn.onRender(this.el, null);
3606 * register a Navigation item
3607 * @param {Roo.bootstrap.NavItem} the navitem to add
3609 register : function(item)
3611 this.navItems.push( item);
3612 item.navId = this.navId;
3617 * clear all the Navigation item
3620 clearAll : function()
3623 this.el.dom.innerHTML = '';
3626 getNavItem: function(tabId)
3629 Roo.each(this.navItems, function(e) {
3630 if (e.tabId == tabId) {
3640 setActiveNext : function()
3642 var i = this.indexOfNav(this.getActive());
3643 if (i > this.navItems.length) {
3646 this.setActiveItem(this.navItems[i+1]);
3648 setActivePrev : function()
3650 var i = this.indexOfNav(this.getActive());
3654 this.setActiveItem(this.navItems[i-1]);
3656 clearWasActive : function(except) {
3657 Roo.each(this.navItems, function(e) {
3658 if (e.tabId != except.tabId && e.was_active) {
3659 e.was_active = false;
3666 getWasActive : function ()
3669 Roo.each(this.navItems, function(e) {
3684 Roo.apply(Roo.bootstrap.NavGroup, {
3688 * register a Navigation Group
3689 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3691 register : function(navgrp)
3693 this.groups[navgrp.navId] = navgrp;
3697 * fetch a Navigation Group based on the navigation ID
3698 * @param {string} the navgroup to add
3699 * @returns {Roo.bootstrap.NavGroup} the navgroup
3701 get: function(navId) {
3702 if (typeof(this.groups[navId]) == 'undefined') {
3704 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3706 return this.groups[navId] ;
3721 * @class Roo.bootstrap.NavItem
3722 * @extends Roo.bootstrap.Component
3723 * Bootstrap Navbar.NavItem class
3724 * @cfg {String} href link to
3725 * @cfg {String} html content of button
3726 * @cfg {String} badge text inside badge
3727 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3728 * @cfg {String} glyphicon name of glyphicon
3729 * @cfg {String} icon name of font awesome icon
3730 * @cfg {Boolean} active Is item active
3731 * @cfg {Boolean} disabled Is item disabled
3733 * @cfg {Boolean} preventDefault (true | false) default false
3734 * @cfg {String} tabId the tab that this item activates.
3735 * @cfg {String} tagtype (a|span) render as a href or span?
3738 * Create a new Navbar Item
3739 * @param {Object} config The config object
3741 Roo.bootstrap.NavItem = function(config){
3742 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3747 * The raw click event for the entire grid.
3748 * @param {Roo.EventObject} e
3753 * Fires when the active item active state changes
3754 * @param {Roo.bootstrap.NavItem} this
3755 * @param {boolean} state the new state
3763 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3771 preventDefault : false,
3778 getAutoCreate : function(){
3786 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3788 if (this.disabled) {
3789 cfg.cls += ' disabled';
3792 if (this.href || this.html || this.glyphicon || this.icon) {
3796 href : this.href || "#",
3797 html: this.html || ''
3802 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3805 if(this.glyphicon) {
3806 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3811 cfg.cn[0].html += " <span class='caret'></span>";
3815 if (this.badge !== '') {
3817 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3825 initEvents: function()
3827 if (typeof (this.menu) != 'undefined') {
3828 this.menu.parentType = this.xtype;
3829 this.menu.triggerEl = this.el;
3830 this.menu = this.addxtype(Roo.apply({}, this.menu));
3833 this.el.select('a',true).on('click', this.onClick, this);
3835 if(this.tagtype == 'span'){
3836 this.el.select('span',true).on('click', this.onClick, this);
3839 // at this point parent should be available..
3840 this.parent().register(this);
3843 onClick : function(e)
3845 if(this.preventDefault || this.href == '#'){
3849 if (this.disabled) {
3853 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3854 if (tg && tg.transition) {
3855 Roo.log("waiting for the transitionend");
3859 Roo.log("fire event clicked");
3860 if(this.fireEvent('click', this, e) === false){
3864 if(this.tagtype == 'span'){
3868 var p = this.parent();
3869 if (['tabs','pills'].indexOf(p.type)!==-1) {
3870 if (typeof(p.setActiveItem) !== 'undefined') {
3871 p.setActiveItem(this);
3874 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3875 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3876 // remove the collapsed menu expand...
3877 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3882 isActive: function () {
3885 setActive : function(state, fire, is_was_active)
3887 if (this.active && !state & this.navId) {
3888 this.was_active = true;
3889 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3891 nv.clearWasActive(this);
3895 this.active = state;
3898 this.el.removeClass('active');
3899 } else if (!this.el.hasClass('active')) {
3900 this.el.addClass('active');
3903 this.fireEvent('changed', this, state);
3906 // show a panel if it's registered and related..
3908 if (!this.navId || !this.tabId || !state || is_was_active) {
3912 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3916 var pan = tg.getPanelByName(this.tabId);
3920 // if we can not flip to new panel - go back to old nav highlight..
3921 if (false == tg.showPanel(pan)) {
3922 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3924 var onav = nv.getWasActive();
3926 onav.setActive(true, false, true);
3935 // this should not be here...
3936 setDisabled : function(state)
3938 this.disabled = state;
3940 this.el.removeClass('disabled');
3941 } else if (!this.el.hasClass('disabled')) {
3942 this.el.addClass('disabled');
3948 * Fetch the element to display the tooltip on.
3949 * @return {Roo.Element} defaults to this.el
3951 tooltipEl : function()
3953 return this.el.select('' + this.tagtype + '', true).first();
3964 * <span> icon </span>
3965 * <span> text </span>
3966 * <span>badge </span>
3970 * @class Roo.bootstrap.NavSidebarItem
3971 * @extends Roo.bootstrap.NavItem
3972 * Bootstrap Navbar.NavSidebarItem class
3974 * Create a new Navbar Button
3975 * @param {Object} config The config object
3977 Roo.bootstrap.NavSidebarItem = function(config){
3978 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3983 * The raw click event for the entire grid.
3984 * @param {Roo.EventObject} e
3989 * Fires when the active item active state changes
3990 * @param {Roo.bootstrap.NavSidebarItem} this
3991 * @param {boolean} state the new state
3999 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4002 getAutoCreate : function(){
4007 href : this.href || '#',
4019 html : this.html || ''
4024 cfg.cls += ' active';
4028 if (this.glyphicon || this.icon) {
4029 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4030 a.cn.push({ tag : 'i', cls : c }) ;
4035 if (this.badge !== '') {
4036 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4040 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4041 a.cls += 'dropdown-toggle treeview' ;
4065 * @class Roo.bootstrap.Row
4066 * @extends Roo.bootstrap.Component
4067 * Bootstrap Row class (contains columns...)
4071 * @param {Object} config The config object
4074 Roo.bootstrap.Row = function(config){
4075 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4078 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4080 getAutoCreate : function(){
4099 * @class Roo.bootstrap.Element
4100 * @extends Roo.bootstrap.Component
4101 * Bootstrap Element class
4102 * @cfg {String} html contents of the element
4103 * @cfg {String} tag tag of the element
4104 * @cfg {String} cls class of the element
4107 * Create a new Element
4108 * @param {Object} config The config object
4111 Roo.bootstrap.Element = function(config){
4112 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4115 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4122 getAutoCreate : function(){
4147 * @class Roo.bootstrap.Pagination
4148 * @extends Roo.bootstrap.Component
4149 * Bootstrap Pagination class
4150 * @cfg {String} size xs | sm | md | lg
4151 * @cfg {Boolean} inverse false | true
4154 * Create a new Pagination
4155 * @param {Object} config The config object
4158 Roo.bootstrap.Pagination = function(config){
4159 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4162 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4168 getAutoCreate : function(){
4174 cfg.cls += ' inverse';
4180 cfg.cls += " " + this.cls;
4198 * @class Roo.bootstrap.PaginationItem
4199 * @extends Roo.bootstrap.Component
4200 * Bootstrap PaginationItem class
4201 * @cfg {String} html text
4202 * @cfg {String} href the link
4203 * @cfg {Boolean} preventDefault (true | false) default true
4204 * @cfg {Boolean} active (true | false) default false
4205 * @cfg {Boolean} disabled default false
4209 * Create a new PaginationItem
4210 * @param {Object} config The config object
4214 Roo.bootstrap.PaginationItem = function(config){
4215 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4220 * The raw click event for the entire grid.
4221 * @param {Roo.EventObject} e
4227 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4231 preventDefault: true,
4236 getAutoCreate : function(){
4242 href : this.href ? this.href : '#',
4243 html : this.html ? this.html : ''
4253 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4257 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4263 initEvents: function() {
4265 this.el.on('click', this.onClick, this);
4268 onClick : function(e)
4270 Roo.log('PaginationItem on click ');
4271 if(this.preventDefault){
4279 this.fireEvent('click', this, e);
4295 * @class Roo.bootstrap.Slider
4296 * @extends Roo.bootstrap.Component
4297 * Bootstrap Slider class
4300 * Create a new Slider
4301 * @param {Object} config The config object
4304 Roo.bootstrap.Slider = function(config){
4305 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4308 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4310 getAutoCreate : function(){
4314 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4318 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4330 * Ext JS Library 1.1.1
4331 * Copyright(c) 2006-2007, Ext JS, LLC.
4333 * Originally Released Under LGPL - original licence link has changed is not relivant.
4336 * <script type="text/javascript">
4341 * @class Roo.grid.ColumnModel
4342 * @extends Roo.util.Observable
4343 * This is the default implementation of a ColumnModel used by the Grid. It defines
4344 * the columns in the grid.
4347 var colModel = new Roo.grid.ColumnModel([
4348 {header: "Ticker", width: 60, sortable: true, locked: true},
4349 {header: "Company Name", width: 150, sortable: true},
4350 {header: "Market Cap.", width: 100, sortable: true},
4351 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4352 {header: "Employees", width: 100, sortable: true, resizable: false}
4357 * The config options listed for this class are options which may appear in each
4358 * individual column definition.
4359 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4361 * @param {Object} config An Array of column config objects. See this class's
4362 * config objects for details.
4364 Roo.grid.ColumnModel = function(config){
4366 * The config passed into the constructor
4368 this.config = config;
4371 // if no id, create one
4372 // if the column does not have a dataIndex mapping,
4373 // map it to the order it is in the config
4374 for(var i = 0, len = config.length; i < len; i++){
4376 if(typeof c.dataIndex == "undefined"){
4379 if(typeof c.renderer == "string"){
4380 c.renderer = Roo.util.Format[c.renderer];
4382 if(typeof c.id == "undefined"){
4385 if(c.editor && c.editor.xtype){
4386 c.editor = Roo.factory(c.editor, Roo.grid);
4388 if(c.editor && c.editor.isFormField){
4389 c.editor = new Roo.grid.GridEditor(c.editor);
4391 this.lookup[c.id] = c;
4395 * The width of columns which have no width specified (defaults to 100)
4398 this.defaultWidth = 100;
4401 * Default sortable of columns which have no sortable specified (defaults to false)
4404 this.defaultSortable = false;
4408 * @event widthchange
4409 * Fires when the width of a column changes.
4410 * @param {ColumnModel} this
4411 * @param {Number} columnIndex The column index
4412 * @param {Number} newWidth The new width
4414 "widthchange": true,
4416 * @event headerchange
4417 * Fires when the text of a header changes.
4418 * @param {ColumnModel} this
4419 * @param {Number} columnIndex The column index
4420 * @param {Number} newText The new header text
4422 "headerchange": true,
4424 * @event hiddenchange
4425 * Fires when a column is hidden or "unhidden".
4426 * @param {ColumnModel} this
4427 * @param {Number} columnIndex The column index
4428 * @param {Boolean} hidden true if hidden, false otherwise
4430 "hiddenchange": true,
4432 * @event columnmoved
4433 * Fires when a column is moved.
4434 * @param {ColumnModel} this
4435 * @param {Number} oldIndex
4436 * @param {Number} newIndex
4438 "columnmoved" : true,
4440 * @event columlockchange
4441 * Fires when a column's locked state is changed
4442 * @param {ColumnModel} this
4443 * @param {Number} colIndex
4444 * @param {Boolean} locked true if locked
4446 "columnlockchange" : true
4448 Roo.grid.ColumnModel.superclass.constructor.call(this);
4450 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4452 * @cfg {String} header The header text to display in the Grid view.
4455 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4456 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4457 * specified, the column's index is used as an index into the Record's data Array.
4460 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4461 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4464 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4465 * Defaults to the value of the {@link #defaultSortable} property.
4466 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4469 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4472 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4475 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4478 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4481 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4482 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4483 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4484 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4487 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4490 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4493 * @cfg {String} cursor (Optional)
4496 * @cfg {String} tooltip (Optional)
4499 * Returns the id of the column at the specified index.
4500 * @param {Number} index The column index
4501 * @return {String} the id
4503 getColumnId : function(index){
4504 return this.config[index].id;
4508 * Returns the column for a specified id.
4509 * @param {String} id The column id
4510 * @return {Object} the column
4512 getColumnById : function(id){
4513 return this.lookup[id];
4518 * Returns the column for a specified dataIndex.
4519 * @param {String} dataIndex The column dataIndex
4520 * @return {Object|Boolean} the column or false if not found
4522 getColumnByDataIndex: function(dataIndex){
4523 var index = this.findColumnIndex(dataIndex);
4524 return index > -1 ? this.config[index] : false;
4528 * Returns the index for a specified column id.
4529 * @param {String} id The column id
4530 * @return {Number} the index, or -1 if not found
4532 getIndexById : function(id){
4533 for(var i = 0, len = this.config.length; i < len; i++){
4534 if(this.config[i].id == id){
4542 * Returns the index for a specified column dataIndex.
4543 * @param {String} dataIndex The column dataIndex
4544 * @return {Number} the index, or -1 if not found
4547 findColumnIndex : function(dataIndex){
4548 for(var i = 0, len = this.config.length; i < len; i++){
4549 if(this.config[i].dataIndex == dataIndex){
4557 moveColumn : function(oldIndex, newIndex){
4558 var c = this.config[oldIndex];
4559 this.config.splice(oldIndex, 1);
4560 this.config.splice(newIndex, 0, c);
4561 this.dataMap = null;
4562 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4565 isLocked : function(colIndex){
4566 return this.config[colIndex].locked === true;
4569 setLocked : function(colIndex, value, suppressEvent){
4570 if(this.isLocked(colIndex) == value){
4573 this.config[colIndex].locked = value;
4575 this.fireEvent("columnlockchange", this, colIndex, value);
4579 getTotalLockedWidth : function(){
4581 for(var i = 0; i < this.config.length; i++){
4582 if(this.isLocked(i) && !this.isHidden(i)){
4583 this.totalWidth += this.getColumnWidth(i);
4589 getLockedCount : function(){
4590 for(var i = 0, len = this.config.length; i < len; i++){
4591 if(!this.isLocked(i)){
4598 * Returns the number of columns.
4601 getColumnCount : function(visibleOnly){
4602 if(visibleOnly === true){
4604 for(var i = 0, len = this.config.length; i < len; i++){
4605 if(!this.isHidden(i)){
4611 return this.config.length;
4615 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4616 * @param {Function} fn
4617 * @param {Object} scope (optional)
4618 * @return {Array} result
4620 getColumnsBy : function(fn, scope){
4622 for(var i = 0, len = this.config.length; i < len; i++){
4623 var c = this.config[i];
4624 if(fn.call(scope||this, c, i) === true){
4632 * Returns true if the specified column is sortable.
4633 * @param {Number} col The column index
4636 isSortable : function(col){
4637 if(typeof this.config[col].sortable == "undefined"){
4638 return this.defaultSortable;
4640 return this.config[col].sortable;
4644 * Returns the rendering (formatting) function defined for the column.
4645 * @param {Number} col The column index.
4646 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4648 getRenderer : function(col){
4649 if(!this.config[col].renderer){
4650 return Roo.grid.ColumnModel.defaultRenderer;
4652 return this.config[col].renderer;
4656 * Sets the rendering (formatting) function for a column.
4657 * @param {Number} col The column index
4658 * @param {Function} fn The function to use to process the cell's raw data
4659 * to return HTML markup for the grid view. The render function is called with
4660 * the following parameters:<ul>
4661 * <li>Data value.</li>
4662 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4663 * <li>css A CSS style string to apply to the table cell.</li>
4664 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4665 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4666 * <li>Row index</li>
4667 * <li>Column index</li>
4668 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4670 setRenderer : function(col, fn){
4671 this.config[col].renderer = fn;
4675 * Returns the width for the specified column.
4676 * @param {Number} col The column index
4679 getColumnWidth : function(col){
4680 return this.config[col].width * 1 || this.defaultWidth;
4684 * Sets the width for a column.
4685 * @param {Number} col The column index
4686 * @param {Number} width The new width
4688 setColumnWidth : function(col, width, suppressEvent){
4689 this.config[col].width = width;
4690 this.totalWidth = null;
4692 this.fireEvent("widthchange", this, col, width);
4697 * Returns the total width of all columns.
4698 * @param {Boolean} includeHidden True to include hidden column widths
4701 getTotalWidth : function(includeHidden){
4702 if(!this.totalWidth){
4703 this.totalWidth = 0;
4704 for(var i = 0, len = this.config.length; i < len; i++){
4705 if(includeHidden || !this.isHidden(i)){
4706 this.totalWidth += this.getColumnWidth(i);
4710 return this.totalWidth;
4714 * Returns the header for the specified column.
4715 * @param {Number} col The column index
4718 getColumnHeader : function(col){
4719 return this.config[col].header;
4723 * Sets the header for a column.
4724 * @param {Number} col The column index
4725 * @param {String} header The new header
4727 setColumnHeader : function(col, header){
4728 this.config[col].header = header;
4729 this.fireEvent("headerchange", this, col, header);
4733 * Returns the tooltip for the specified column.
4734 * @param {Number} col The column index
4737 getColumnTooltip : function(col){
4738 return this.config[col].tooltip;
4741 * Sets the tooltip for a column.
4742 * @param {Number} col The column index
4743 * @param {String} tooltip The new tooltip
4745 setColumnTooltip : function(col, tooltip){
4746 this.config[col].tooltip = tooltip;
4750 * Returns the dataIndex for the specified column.
4751 * @param {Number} col The column index
4754 getDataIndex : function(col){
4755 return this.config[col].dataIndex;
4759 * Sets the dataIndex for a column.
4760 * @param {Number} col The column index
4761 * @param {Number} dataIndex The new dataIndex
4763 setDataIndex : function(col, dataIndex){
4764 this.config[col].dataIndex = dataIndex;
4770 * Returns true if the cell is editable.
4771 * @param {Number} colIndex The column index
4772 * @param {Number} rowIndex The row index
4775 isCellEditable : function(colIndex, rowIndex){
4776 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4780 * Returns the editor defined for the cell/column.
4781 * return false or null to disable editing.
4782 * @param {Number} colIndex The column index
4783 * @param {Number} rowIndex The row index
4786 getCellEditor : function(colIndex, rowIndex){
4787 return this.config[colIndex].editor;
4791 * Sets if a column is editable.
4792 * @param {Number} col The column index
4793 * @param {Boolean} editable True if the column is editable
4795 setEditable : function(col, editable){
4796 this.config[col].editable = editable;
4801 * Returns true if the column is hidden.
4802 * @param {Number} colIndex The column index
4805 isHidden : function(colIndex){
4806 return this.config[colIndex].hidden;
4811 * Returns true if the column width cannot be changed
4813 isFixed : function(colIndex){
4814 return this.config[colIndex].fixed;
4818 * Returns true if the column can be resized
4821 isResizable : function(colIndex){
4822 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4825 * Sets if a column is hidden.
4826 * @param {Number} colIndex The column index
4827 * @param {Boolean} hidden True if the column is hidden
4829 setHidden : function(colIndex, hidden){
4830 this.config[colIndex].hidden = hidden;
4831 this.totalWidth = null;
4832 this.fireEvent("hiddenchange", this, colIndex, hidden);
4836 * Sets the editor for a column.
4837 * @param {Number} col The column index
4838 * @param {Object} editor The editor object
4840 setEditor : function(col, editor){
4841 this.config[col].editor = editor;
4845 Roo.grid.ColumnModel.defaultRenderer = function(value){
4846 if(typeof value == "string" && value.length < 1){
4852 // Alias for backwards compatibility
4853 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4856 * Ext JS Library 1.1.1
4857 * Copyright(c) 2006-2007, Ext JS, LLC.
4859 * Originally Released Under LGPL - original licence link has changed is not relivant.
4862 * <script type="text/javascript">
4866 * @class Roo.LoadMask
4867 * A simple utility class for generically masking elements while loading data. If the element being masked has
4868 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4869 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4870 * element's UpdateManager load indicator and will be destroyed after the initial load.
4872 * Create a new LoadMask
4873 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4874 * @param {Object} config The config object
4876 Roo.LoadMask = function(el, config){
4877 this.el = Roo.get(el);
4878 Roo.apply(this, config);
4880 this.store.on('beforeload', this.onBeforeLoad, this);
4881 this.store.on('load', this.onLoad, this);
4882 this.store.on('loadexception', this.onLoadException, this);
4883 this.removeMask = false;
4885 var um = this.el.getUpdateManager();
4886 um.showLoadIndicator = false; // disable the default indicator
4887 um.on('beforeupdate', this.onBeforeLoad, this);
4888 um.on('update', this.onLoad, this);
4889 um.on('failure', this.onLoad, this);
4890 this.removeMask = true;
4894 Roo.LoadMask.prototype = {
4896 * @cfg {Boolean} removeMask
4897 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4898 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4902 * The text to display in a centered loading message box (defaults to 'Loading...')
4906 * @cfg {String} msgCls
4907 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4909 msgCls : 'x-mask-loading',
4912 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4918 * Disables the mask to prevent it from being displayed
4920 disable : function(){
4921 this.disabled = true;
4925 * Enables the mask so that it can be displayed
4927 enable : function(){
4928 this.disabled = false;
4931 onLoadException : function()
4935 if (typeof(arguments[3]) != 'undefined') {
4936 Roo.MessageBox.alert("Error loading",arguments[3]);
4940 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4941 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4950 this.el.unmask(this.removeMask);
4955 this.el.unmask(this.removeMask);
4959 onBeforeLoad : function(){
4961 this.el.mask(this.msg, this.msgCls);
4966 destroy : function(){
4968 this.store.un('beforeload', this.onBeforeLoad, this);
4969 this.store.un('load', this.onLoad, this);
4970 this.store.un('loadexception', this.onLoadException, this);
4972 var um = this.el.getUpdateManager();
4973 um.un('beforeupdate', this.onBeforeLoad, this);
4974 um.un('update', this.onLoad, this);
4975 um.un('failure', this.onLoad, this);
4986 * @class Roo.bootstrap.Table
4987 * @extends Roo.bootstrap.Component
4988 * Bootstrap Table class
4989 * @cfg {String} cls table class
4990 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4991 * @cfg {String} bgcolor Specifies the background color for a table
4992 * @cfg {Number} border Specifies whether the table cells should have borders or not
4993 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4994 * @cfg {Number} cellspacing Specifies the space between cells
4995 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4996 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4997 * @cfg {String} sortable Specifies that the table should be sortable
4998 * @cfg {String} summary Specifies a summary of the content of a table
4999 * @cfg {Number} width Specifies the width of a table
5000 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5002 * @cfg {boolean} striped Should the rows be alternative striped
5003 * @cfg {boolean} bordered Add borders to the table
5004 * @cfg {boolean} hover Add hover highlighting
5005 * @cfg {boolean} condensed Format condensed
5006 * @cfg {boolean} responsive Format condensed
5007 * @cfg {Boolean} loadMask (true|false) default false
5008 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5009 * @cfg {Boolean} thead (true|false) generate thead, default true
5010 * @cfg {Boolean} RowSelection (true|false) default false
5011 * @cfg {Boolean} CellSelection (true|false) default false
5012 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5016 * Create a new Table
5017 * @param {Object} config The config object
5020 Roo.bootstrap.Table = function(config){
5021 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5024 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5025 this.sm = this.selModel;
5026 this.sm.xmodule = this.xmodule || false;
5028 if (this.cm && typeof(this.cm.config) == 'undefined') {
5029 this.colModel = new Roo.grid.ColumnModel(this.cm);
5030 this.cm = this.colModel;
5031 this.cm.xmodule = this.xmodule || false;
5034 this.store= Roo.factory(this.store, Roo.data);
5035 this.ds = this.store;
5036 this.ds.xmodule = this.xmodule || false;
5039 if (this.footer && this.store) {
5040 this.footer.dataSource = this.ds;
5041 this.footer = Roo.factory(this.footer);
5048 * Fires when a cell is clicked
5049 * @param {Roo.bootstrap.Table} this
5050 * @param {Roo.Element} el
5051 * @param {Number} rowIndex
5052 * @param {Number} columnIndex
5053 * @param {Roo.EventObject} e
5057 * @event celldblclick
5058 * Fires when a cell is double clicked
5059 * @param {Roo.bootstrap.Table} this
5060 * @param {Roo.Element} el
5061 * @param {Number} rowIndex
5062 * @param {Number} columnIndex
5063 * @param {Roo.EventObject} e
5065 "celldblclick" : true,
5068 * Fires when a row is clicked
5069 * @param {Roo.bootstrap.Table} this
5070 * @param {Roo.Element} el
5071 * @param {Number} rowIndex
5072 * @param {Roo.EventObject} e
5076 * @event rowdblclick
5077 * Fires when a row is double clicked
5078 * @param {Roo.bootstrap.Table} this
5079 * @param {Roo.Element} el
5080 * @param {Number} rowIndex
5081 * @param {Roo.EventObject} e
5083 "rowdblclick" : true,
5086 * Fires when a mouseover occur
5087 * @param {Roo.bootstrap.Table} this
5088 * @param {Roo.Element} el
5089 * @param {Number} rowIndex
5090 * @param {Number} columnIndex
5091 * @param {Roo.EventObject} e
5096 * Fires when a mouseout occur
5097 * @param {Roo.bootstrap.Table} this
5098 * @param {Roo.Element} el
5099 * @param {Number} rowIndex
5100 * @param {Number} columnIndex
5101 * @param {Roo.EventObject} e
5106 * Fires when a row is rendered, so you can change add a style to it.
5107 * @param {Roo.bootstrap.Table} this
5108 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5112 * @event rowsrendered
5113 * Fires when all the rows have been rendered
5114 * @param {Roo.bootstrap.Table} this
5116 'rowsrendered' : true
5121 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5145 RowSelection : false,
5146 CellSelection : false,
5149 // Roo.Element - the tbody
5152 getAutoCreate : function(){
5153 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5162 cfg.cls += ' table-striped';
5166 cfg.cls += ' table-hover';
5168 if (this.bordered) {
5169 cfg.cls += ' table-bordered';
5171 if (this.condensed) {
5172 cfg.cls += ' table-condensed';
5174 if (this.responsive) {
5175 cfg.cls += ' table-responsive';
5179 cfg.cls+= ' ' +this.cls;
5182 // this lot should be simplifed...
5185 cfg.align=this.align;
5188 cfg.bgcolor=this.bgcolor;
5191 cfg.border=this.border;
5193 if (this.cellpadding) {
5194 cfg.cellpadding=this.cellpadding;
5196 if (this.cellspacing) {
5197 cfg.cellspacing=this.cellspacing;
5200 cfg.frame=this.frame;
5203 cfg.rules=this.rules;
5205 if (this.sortable) {
5206 cfg.sortable=this.sortable;
5209 cfg.summary=this.summary;
5212 cfg.width=this.width;
5215 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5218 if(this.store || this.cm){
5220 cfg.cn.push(this.renderHeader());
5223 cfg.cn.push(this.renderBody());
5226 cfg.cn.push(this.renderFooter());
5229 cfg.cls+= ' TableGrid';
5232 return { cn : [ cfg ] };
5235 initEvents : function()
5237 if(!this.store || !this.cm){
5241 //Roo.log('initEvents with ds!!!!');
5243 this.mainBody = this.el.select('tbody', true).first();
5248 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5249 e.on('click', _this.sort, _this);
5252 this.el.on("click", this.onClick, this);
5253 this.el.on("dblclick", this.onDblClick, this);
5255 // why is this done????? = it breaks dialogs??
5256 //this.parent().el.setStyle('position', 'relative');
5260 this.footer.parentId = this.id;
5261 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5264 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5266 this.store.on('load', this.onLoad, this);
5267 this.store.on('beforeload', this.onBeforeLoad, this);
5268 this.store.on('update', this.onUpdate, this);
5269 this.store.on('add', this.onAdd, this);
5273 onMouseover : function(e, el)
5275 var cell = Roo.get(el);
5281 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5282 cell = cell.findParent('td', false, true);
5285 var row = cell.findParent('tr', false, true);
5286 var cellIndex = cell.dom.cellIndex;
5287 var rowIndex = row.dom.rowIndex - 1; // start from 0
5289 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5293 onMouseout : function(e, el)
5295 var cell = Roo.get(el);
5301 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5302 cell = cell.findParent('td', false, true);
5305 var row = cell.findParent('tr', false, true);
5306 var cellIndex = cell.dom.cellIndex;
5307 var rowIndex = row.dom.rowIndex - 1; // start from 0
5309 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5313 onClick : function(e, el)
5315 var cell = Roo.get(el);
5317 if(!cell || (!this.CellSelection && !this.RowSelection)){
5321 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5322 cell = cell.findParent('td', false, true);
5325 if(!cell || typeof(cell) == 'undefined'){
5329 var row = cell.findParent('tr', false, true);
5331 if(!row || typeof(row) == 'undefined'){
5335 var cellIndex = cell.dom.cellIndex;
5336 var rowIndex = this.getRowIndex(row);
5338 if(this.CellSelection){
5339 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5342 if(this.RowSelection){
5343 this.fireEvent('rowclick', this, row, rowIndex, e);
5349 onDblClick : function(e,el)
5351 var cell = Roo.get(el);
5353 if(!cell || (!this.CellSelection && !this.RowSelection)){
5357 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5358 cell = cell.findParent('td', false, true);
5361 if(!cell || typeof(cell) == 'undefined'){
5365 var row = cell.findParent('tr', false, true);
5367 if(!row || typeof(row) == 'undefined'){
5371 var cellIndex = cell.dom.cellIndex;
5372 var rowIndex = this.getRowIndex(row);
5374 if(this.CellSelection){
5375 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5378 if(this.RowSelection){
5379 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5383 sort : function(e,el)
5385 var col = Roo.get(el);
5387 if(!col.hasClass('sortable')){
5391 var sort = col.attr('sort');
5394 if(col.hasClass('glyphicon-arrow-up')){
5398 this.store.sortInfo = {field : sort, direction : dir};
5401 Roo.log("calling footer first");
5402 this.footer.onClick('first');
5405 this.store.load({ params : { start : 0 } });
5409 renderHeader : function()
5418 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5420 var config = cm.config[i];
5425 html: cm.getColumnHeader(i)
5428 if(typeof(config.tooltip) != 'undefined'){
5429 c.tooltip = config.tooltip;
5432 if(typeof(config.hidden) != 'undefined' && config.hidden){
5433 c.style += ' display:none;';
5436 if(typeof(config.dataIndex) != 'undefined'){
5437 c.sort = config.dataIndex;
5440 if(typeof(config.sortable) != 'undefined' && config.sortable){
5444 if(typeof(config.align) != 'undefined' && config.align.length){
5445 c.style += ' text-align:' + config.align + ';';
5448 if(typeof(config.width) != 'undefined'){
5449 c.style += ' width:' + config.width + 'px;';
5458 renderBody : function()
5468 colspan : this.cm.getColumnCount()
5478 renderFooter : function()
5488 colspan : this.cm.getColumnCount()
5502 Roo.log('ds onload');
5507 var ds = this.store;
5509 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5510 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5512 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5513 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5516 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5517 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5521 var tbody = this.mainBody;
5523 if(ds.getCount() > 0){
5524 ds.data.each(function(d,rowIndex){
5525 var row = this.renderRow(cm, ds, rowIndex);
5527 tbody.createChild(row);
5531 if(row.cellObjects.length){
5532 Roo.each(row.cellObjects, function(r){
5533 _this.renderCellObject(r);
5540 Roo.each(this.el.select('tbody td', true).elements, function(e){
5541 e.on('mouseover', _this.onMouseover, _this);
5544 Roo.each(this.el.select('tbody td', true).elements, function(e){
5545 e.on('mouseout', _this.onMouseout, _this);
5547 this.fireEvent('rowsrendered', this);
5548 //if(this.loadMask){
5549 // this.maskEl.hide();
5554 onUpdate : function(ds,record)
5556 this.refreshRow(record);
5559 onRemove : function(ds, record, index, isUpdate){
5560 if(isUpdate !== true){
5561 this.fireEvent("beforerowremoved", this, index, record);
5563 var bt = this.mainBody.dom;
5565 var rows = this.el.select('tbody > tr', true).elements;
5567 if(typeof(rows[index]) != 'undefined'){
5568 bt.removeChild(rows[index].dom);
5571 // if(bt.rows[index]){
5572 // bt.removeChild(bt.rows[index]);
5575 if(isUpdate !== true){
5576 //this.stripeRows(index);
5577 //this.syncRowHeights(index, index);
5579 this.fireEvent("rowremoved", this, index, record);
5583 onAdd : function(ds, records, rowIndex)
5585 //Roo.log('on Add called');
5586 // - note this does not handle multiple adding very well..
5587 var bt = this.mainBody.dom;
5588 for (var i =0 ; i < records.length;i++) {
5589 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5590 //Roo.log(records[i]);
5591 //Roo.log(this.store.getAt(rowIndex+i));
5592 this.insertRow(this.store, rowIndex + i, false);
5599 refreshRow : function(record){
5600 var ds = this.store, index;
5601 if(typeof record == 'number'){
5603 record = ds.getAt(index);
5605 index = ds.indexOf(record);
5607 this.insertRow(ds, index, true);
5608 this.onRemove(ds, record, index+1, true);
5609 //this.syncRowHeights(index, index);
5611 this.fireEvent("rowupdated", this, index, record);
5614 insertRow : function(dm, rowIndex, isUpdate){
5617 this.fireEvent("beforerowsinserted", this, rowIndex);
5619 //var s = this.getScrollState();
5620 var row = this.renderRow(this.cm, this.store, rowIndex);
5621 // insert before rowIndex..
5622 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5626 if(row.cellObjects.length){
5627 Roo.each(row.cellObjects, function(r){
5628 _this.renderCellObject(r);
5633 this.fireEvent("rowsinserted", this, rowIndex);
5634 //this.syncRowHeights(firstRow, lastRow);
5635 //this.stripeRows(firstRow);
5642 getRowDom : function(rowIndex)
5644 var rows = this.el.select('tbody > tr', true).elements;
5646 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5649 // returns the object tree for a tr..
5652 renderRow : function(cm, ds, rowIndex)
5655 var d = ds.getAt(rowIndex);
5662 var cellObjects = [];
5664 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5665 var config = cm.config[i];
5667 var renderer = cm.getRenderer(i);
5671 if(typeof(renderer) !== 'undefined'){
5672 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5674 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5675 // and are rendered into the cells after the row is rendered - using the id for the element.
5677 if(typeof(value) === 'object'){
5687 rowIndex : rowIndex,
5692 this.fireEvent('rowclass', this, rowcfg);
5696 cls : rowcfg.rowClass,
5698 html: (typeof(value) === 'object') ? '' : value
5705 if(typeof(config.hidden) != 'undefined' && config.hidden){
5706 td.style += ' display:none;';
5709 if(typeof(config.align) != 'undefined' && config.align.length){
5710 td.style += ' text-align:' + config.align + ';';
5713 if(typeof(config.width) != 'undefined'){
5714 td.style += ' width:' + config.width + 'px;';
5717 if(typeof(config.cursor) != 'undefined'){
5718 td.style += ' cursor:' + config.cursor + ';';
5725 row.cellObjects = cellObjects;
5733 onBeforeLoad : function()
5735 //Roo.log('ds onBeforeLoad');
5739 //if(this.loadMask){
5740 // this.maskEl.show();
5748 this.el.select('tbody', true).first().dom.innerHTML = '';
5751 * Show or hide a row.
5752 * @param {Number} rowIndex to show or hide
5753 * @param {Boolean} state hide
5755 setRowVisibility : function(rowIndex, state)
5757 var bt = this.mainBody.dom;
5759 var rows = this.el.select('tbody > tr', true).elements;
5761 if(typeof(rows[rowIndex]) == 'undefined'){
5764 rows[rowIndex].dom.style.display = state ? '' : 'none';
5768 getSelectionModel : function(){
5770 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5772 return this.selModel;
5775 * Render the Roo.bootstrap object from renderder
5777 renderCellObject : function(r)
5781 var t = r.cfg.render(r.container);
5784 Roo.each(r.cfg.cn, function(c){
5786 container: t.getChildContainer(),
5789 _this.renderCellObject(child);
5794 getRowIndex : function(row)
5798 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5821 * @class Roo.bootstrap.TableCell
5822 * @extends Roo.bootstrap.Component
5823 * Bootstrap TableCell class
5824 * @cfg {String} html cell contain text
5825 * @cfg {String} cls cell class
5826 * @cfg {String} tag cell tag (td|th) default td
5827 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5828 * @cfg {String} align Aligns the content in a cell
5829 * @cfg {String} axis Categorizes cells
5830 * @cfg {String} bgcolor Specifies the background color of a cell
5831 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5832 * @cfg {Number} colspan Specifies the number of columns a cell should span
5833 * @cfg {String} headers Specifies one or more header cells a cell is related to
5834 * @cfg {Number} height Sets the height of a cell
5835 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5836 * @cfg {Number} rowspan Sets the number of rows a cell should span
5837 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5838 * @cfg {String} valign Vertical aligns the content in a cell
5839 * @cfg {Number} width Specifies the width of a cell
5842 * Create a new TableCell
5843 * @param {Object} config The config object
5846 Roo.bootstrap.TableCell = function(config){
5847 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5850 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5870 getAutoCreate : function(){
5871 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5891 cfg.align=this.align
5897 cfg.bgcolor=this.bgcolor
5900 cfg.charoff=this.charoff
5903 cfg.colspan=this.colspan
5906 cfg.headers=this.headers
5909 cfg.height=this.height
5912 cfg.nowrap=this.nowrap
5915 cfg.rowspan=this.rowspan
5918 cfg.scope=this.scope
5921 cfg.valign=this.valign
5924 cfg.width=this.width
5943 * @class Roo.bootstrap.TableRow
5944 * @extends Roo.bootstrap.Component
5945 * Bootstrap TableRow class
5946 * @cfg {String} cls row class
5947 * @cfg {String} align Aligns the content in a table row
5948 * @cfg {String} bgcolor Specifies a background color for a table row
5949 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5950 * @cfg {String} valign Vertical aligns the content in a table row
5953 * Create a new TableRow
5954 * @param {Object} config The config object
5957 Roo.bootstrap.TableRow = function(config){
5958 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5961 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5969 getAutoCreate : function(){
5970 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5980 cfg.align = this.align;
5983 cfg.bgcolor = this.bgcolor;
5986 cfg.charoff = this.charoff;
5989 cfg.valign = this.valign;
6007 * @class Roo.bootstrap.TableBody
6008 * @extends Roo.bootstrap.Component
6009 * Bootstrap TableBody class
6010 * @cfg {String} cls element class
6011 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6012 * @cfg {String} align Aligns the content inside the element
6013 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6014 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6017 * Create a new TableBody
6018 * @param {Object} config The config object
6021 Roo.bootstrap.TableBody = function(config){
6022 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6025 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6033 getAutoCreate : function(){
6034 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6048 cfg.align = this.align;
6051 cfg.charoff = this.charoff;
6054 cfg.valign = this.valign;
6061 // initEvents : function()
6068 // this.store = Roo.factory(this.store, Roo.data);
6069 // this.store.on('load', this.onLoad, this);
6071 // this.store.load();
6075 // onLoad: function ()
6077 // this.fireEvent('load', this);
6087 * Ext JS Library 1.1.1
6088 * Copyright(c) 2006-2007, Ext JS, LLC.
6090 * Originally Released Under LGPL - original licence link has changed is not relivant.
6093 * <script type="text/javascript">
6096 // as we use this in bootstrap.
6097 Roo.namespace('Roo.form');
6099 * @class Roo.form.Action
6100 * Internal Class used to handle form actions
6102 * @param {Roo.form.BasicForm} el The form element or its id
6103 * @param {Object} config Configuration options
6108 // define the action interface
6109 Roo.form.Action = function(form, options){
6111 this.options = options || {};
6114 * Client Validation Failed
6117 Roo.form.Action.CLIENT_INVALID = 'client';
6119 * Server Validation Failed
6122 Roo.form.Action.SERVER_INVALID = 'server';
6124 * Connect to Server Failed
6127 Roo.form.Action.CONNECT_FAILURE = 'connect';
6129 * Reading Data from Server Failed
6132 Roo.form.Action.LOAD_FAILURE = 'load';
6134 Roo.form.Action.prototype = {
6136 failureType : undefined,
6137 response : undefined,
6141 run : function(options){
6146 success : function(response){
6151 handleResponse : function(response){
6155 // default connection failure
6156 failure : function(response){
6158 this.response = response;
6159 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6160 this.form.afterAction(this, false);
6163 processResponse : function(response){
6164 this.response = response;
6165 if(!response.responseText){
6168 this.result = this.handleResponse(response);
6172 // utility functions used internally
6173 getUrl : function(appendParams){
6174 var url = this.options.url || this.form.url || this.form.el.dom.action;
6176 var p = this.getParams();
6178 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6184 getMethod : function(){
6185 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6188 getParams : function(){
6189 var bp = this.form.baseParams;
6190 var p = this.options.params;
6192 if(typeof p == "object"){
6193 p = Roo.urlEncode(Roo.applyIf(p, bp));
6194 }else if(typeof p == 'string' && bp){
6195 p += '&' + Roo.urlEncode(bp);
6198 p = Roo.urlEncode(bp);
6203 createCallback : function(){
6205 success: this.success,
6206 failure: this.failure,
6208 timeout: (this.form.timeout*1000),
6209 upload: this.form.fileUpload ? this.success : undefined
6214 Roo.form.Action.Submit = function(form, options){
6215 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6218 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6221 haveProgress : false,
6222 uploadComplete : false,
6224 // uploadProgress indicator.
6225 uploadProgress : function()
6227 if (!this.form.progressUrl) {
6231 if (!this.haveProgress) {
6232 Roo.MessageBox.progress("Uploading", "Uploading");
6234 if (this.uploadComplete) {
6235 Roo.MessageBox.hide();
6239 this.haveProgress = true;
6241 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6243 var c = new Roo.data.Connection();
6245 url : this.form.progressUrl,
6250 success : function(req){
6251 //console.log(data);
6255 rdata = Roo.decode(req.responseText)
6257 Roo.log("Invalid data from server..");
6261 if (!rdata || !rdata.success) {
6263 Roo.MessageBox.alert(Roo.encode(rdata));
6266 var data = rdata.data;
6268 if (this.uploadComplete) {
6269 Roo.MessageBox.hide();
6274 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6275 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6278 this.uploadProgress.defer(2000,this);
6281 failure: function(data) {
6282 Roo.log('progress url failed ');
6293 // run get Values on the form, so it syncs any secondary forms.
6294 this.form.getValues();
6296 var o = this.options;
6297 var method = this.getMethod();
6298 var isPost = method == 'POST';
6299 if(o.clientValidation === false || this.form.isValid()){
6301 if (this.form.progressUrl) {
6302 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6303 (new Date() * 1) + '' + Math.random());
6308 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6309 form:this.form.el.dom,
6310 url:this.getUrl(!isPost),
6312 params:isPost ? this.getParams() : null,
6313 isUpload: this.form.fileUpload
6316 this.uploadProgress();
6318 }else if (o.clientValidation !== false){ // client validation failed
6319 this.failureType = Roo.form.Action.CLIENT_INVALID;
6320 this.form.afterAction(this, false);
6324 success : function(response)
6326 this.uploadComplete= true;
6327 if (this.haveProgress) {
6328 Roo.MessageBox.hide();
6332 var result = this.processResponse(response);
6333 if(result === true || result.success){
6334 this.form.afterAction(this, true);
6338 this.form.markInvalid(result.errors);
6339 this.failureType = Roo.form.Action.SERVER_INVALID;
6341 this.form.afterAction(this, false);
6343 failure : function(response)
6345 this.uploadComplete= true;
6346 if (this.haveProgress) {
6347 Roo.MessageBox.hide();
6350 this.response = response;
6351 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6352 this.form.afterAction(this, false);
6355 handleResponse : function(response){
6356 if(this.form.errorReader){
6357 var rs = this.form.errorReader.read(response);
6360 for(var i = 0, len = rs.records.length; i < len; i++) {
6361 var r = rs.records[i];
6365 if(errors.length < 1){
6369 success : rs.success,
6375 ret = Roo.decode(response.responseText);
6379 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6389 Roo.form.Action.Load = function(form, options){
6390 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6391 this.reader = this.form.reader;
6394 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6399 Roo.Ajax.request(Roo.apply(
6400 this.createCallback(), {
6401 method:this.getMethod(),
6402 url:this.getUrl(false),
6403 params:this.getParams()
6407 success : function(response){
6409 var result = this.processResponse(response);
6410 if(result === true || !result.success || !result.data){
6411 this.failureType = Roo.form.Action.LOAD_FAILURE;
6412 this.form.afterAction(this, false);
6415 this.form.clearInvalid();
6416 this.form.setValues(result.data);
6417 this.form.afterAction(this, true);
6420 handleResponse : function(response){
6421 if(this.form.reader){
6422 var rs = this.form.reader.read(response);
6423 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6425 success : rs.success,
6429 return Roo.decode(response.responseText);
6433 Roo.form.Action.ACTION_TYPES = {
6434 'load' : Roo.form.Action.Load,
6435 'submit' : Roo.form.Action.Submit
6444 * @class Roo.bootstrap.Form
6445 * @extends Roo.bootstrap.Component
6446 * Bootstrap Form class
6447 * @cfg {String} method GET | POST (default POST)
6448 * @cfg {String} labelAlign top | left (default top)
6449 * @cfg {String} align left | right - for navbars
6450 * @cfg {Boolean} loadMask load mask when submit (default true)
6455 * @param {Object} config The config object
6459 Roo.bootstrap.Form = function(config){
6460 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6463 * @event clientvalidation
6464 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6465 * @param {Form} this
6466 * @param {Boolean} valid true if the form has passed client-side validation
6468 clientvalidation: true,
6470 * @event beforeaction
6471 * Fires before any action is performed. Return false to cancel the action.
6472 * @param {Form} this
6473 * @param {Action} action The action to be performed
6477 * @event actionfailed
6478 * Fires when an action fails.
6479 * @param {Form} this
6480 * @param {Action} action The action that failed
6482 actionfailed : true,
6484 * @event actioncomplete
6485 * Fires when an action is completed.
6486 * @param {Form} this
6487 * @param {Action} action The action that completed
6489 actioncomplete : true
6494 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6497 * @cfg {String} method
6498 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6503 * The URL to use for form actions if one isn't supplied in the action options.
6506 * @cfg {Boolean} fileUpload
6507 * Set to true if this form is a file upload.
6511 * @cfg {Object} baseParams
6512 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6516 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6520 * @cfg {Sting} align (left|right) for navbar forms
6525 activeAction : null,
6528 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6529 * element by passing it or its id or mask the form itself by passing in true.
6532 waitMsgTarget : false,
6536 getAutoCreate : function(){
6540 method : this.method || 'POST',
6541 id : this.id || Roo.id(),
6544 if (this.parent().xtype.match(/^Nav/)) {
6545 cfg.cls = 'navbar-form navbar-' + this.align;
6549 if (this.labelAlign == 'left' ) {
6550 cfg.cls += ' form-horizontal';
6556 initEvents : function()
6558 this.el.on('submit', this.onSubmit, this);
6559 // this was added as random key presses on the form where triggering form submit.
6560 this.el.on('keypress', function(e) {
6561 if (e.getCharCode() != 13) {
6564 // we might need to allow it for textareas.. and some other items.
6565 // check e.getTarget().
6567 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6571 Roo.log("keypress blocked");
6579 onSubmit : function(e){
6584 * Returns true if client-side validation on the form is successful.
6587 isValid : function(){
6588 var items = this.getItems();
6590 items.each(function(f){
6599 * Returns true if any fields in this form have changed since their original load.
6602 isDirty : function(){
6604 var items = this.getItems();
6605 items.each(function(f){
6615 * Performs a predefined action (submit or load) or custom actions you define on this form.
6616 * @param {String} actionName The name of the action type
6617 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6618 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6619 * accept other config options):
6621 Property Type Description
6622 ---------------- --------------- ----------------------------------------------------------------------------------
6623 url String The url for the action (defaults to the form's url)
6624 method String The form method to use (defaults to the form's method, or POST if not defined)
6625 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6626 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6627 validate the form on the client (defaults to false)
6629 * @return {BasicForm} this
6631 doAction : function(action, options){
6632 if(typeof action == 'string'){
6633 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6635 if(this.fireEvent('beforeaction', this, action) !== false){
6636 this.beforeAction(action);
6637 action.run.defer(100, action);
6643 beforeAction : function(action){
6644 var o = action.options;
6647 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6649 // not really supported yet.. ??
6651 //if(this.waitMsgTarget === true){
6652 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6653 //}else if(this.waitMsgTarget){
6654 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6655 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6657 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6663 afterAction : function(action, success){
6664 this.activeAction = null;
6665 var o = action.options;
6667 //if(this.waitMsgTarget === true){
6669 //}else if(this.waitMsgTarget){
6670 // this.waitMsgTarget.unmask();
6672 // Roo.MessageBox.updateProgress(1);
6673 // Roo.MessageBox.hide();
6680 Roo.callback(o.success, o.scope, [this, action]);
6681 this.fireEvent('actioncomplete', this, action);
6685 // failure condition..
6686 // we have a scenario where updates need confirming.
6687 // eg. if a locking scenario exists..
6688 // we look for { errors : { needs_confirm : true }} in the response.
6690 (typeof(action.result) != 'undefined') &&
6691 (typeof(action.result.errors) != 'undefined') &&
6692 (typeof(action.result.errors.needs_confirm) != 'undefined')
6695 Roo.log("not supported yet");
6698 Roo.MessageBox.confirm(
6699 "Change requires confirmation",
6700 action.result.errorMsg,
6705 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6715 Roo.callback(o.failure, o.scope, [this, action]);
6716 // show an error message if no failed handler is set..
6717 if (!this.hasListener('actionfailed')) {
6718 Roo.log("need to add dialog support");
6720 Roo.MessageBox.alert("Error",
6721 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6722 action.result.errorMsg :
6723 "Saving Failed, please check your entries or try again"
6728 this.fireEvent('actionfailed', this, action);
6733 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6734 * @param {String} id The value to search for
6737 findField : function(id){
6738 var items = this.getItems();
6739 var field = items.get(id);
6741 items.each(function(f){
6742 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6749 return field || null;
6752 * Mark fields in this form invalid in bulk.
6753 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6754 * @return {BasicForm} this
6756 markInvalid : function(errors){
6757 if(errors instanceof Array){
6758 for(var i = 0, len = errors.length; i < len; i++){
6759 var fieldError = errors[i];
6760 var f = this.findField(fieldError.id);
6762 f.markInvalid(fieldError.msg);
6768 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6769 field.markInvalid(errors[id]);
6773 //Roo.each(this.childForms || [], function (f) {
6774 // f.markInvalid(errors);
6781 * Set values for fields in this form in bulk.
6782 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6783 * @return {BasicForm} this
6785 setValues : function(values){
6786 if(values instanceof Array){ // array of objects
6787 for(var i = 0, len = values.length; i < len; i++){
6789 var f = this.findField(v.id);
6791 f.setValue(v.value);
6792 if(this.trackResetOnLoad){
6793 f.originalValue = f.getValue();
6797 }else{ // object hash
6800 if(typeof values[id] != 'function' && (field = this.findField(id))){
6802 if (field.setFromData &&
6804 field.displayField &&
6805 // combos' with local stores can
6806 // be queried via setValue()
6807 // to set their value..
6808 (field.store && !field.store.isLocal)
6812 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6813 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6814 field.setFromData(sd);
6817 field.setValue(values[id]);
6821 if(this.trackResetOnLoad){
6822 field.originalValue = field.getValue();
6828 //Roo.each(this.childForms || [], function (f) {
6829 // f.setValues(values);
6836 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6837 * they are returned as an array.
6838 * @param {Boolean} asString
6841 getValues : function(asString){
6842 //if (this.childForms) {
6843 // copy values from the child forms
6844 // Roo.each(this.childForms, function (f) {
6845 // this.setValues(f.getValues());
6851 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6852 if(asString === true){
6855 return Roo.urlDecode(fs);
6859 * Returns the fields in this form as an object with key/value pairs.
6860 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6863 getFieldValues : function(with_hidden)
6865 var items = this.getItems();
6867 items.each(function(f){
6871 var v = f.getValue();
6872 if (f.inputType =='radio') {
6873 if (typeof(ret[f.getName()]) == 'undefined') {
6874 ret[f.getName()] = ''; // empty..
6877 if (!f.el.dom.checked) {
6885 // not sure if this supported any more..
6886 if ((typeof(v) == 'object') && f.getRawValue) {
6887 v = f.getRawValue() ; // dates..
6889 // combo boxes where name != hiddenName...
6890 if (f.name != f.getName()) {
6891 ret[f.name] = f.getRawValue();
6893 ret[f.getName()] = v;
6900 * Clears all invalid messages in this form.
6901 * @return {BasicForm} this
6903 clearInvalid : function(){
6904 var items = this.getItems();
6906 items.each(function(f){
6917 * @return {BasicForm} this
6920 var items = this.getItems();
6921 items.each(function(f){
6925 Roo.each(this.childForms || [], function (f) {
6932 getItems : function()
6934 var r=new Roo.util.MixedCollection(false, function(o){
6935 return o.id || (o.id = Roo.id());
6937 var iter = function(el) {
6944 Roo.each(el.items,function(e) {
6964 * Ext JS Library 1.1.1
6965 * Copyright(c) 2006-2007, Ext JS, LLC.
6967 * Originally Released Under LGPL - original licence link has changed is not relivant.
6970 * <script type="text/javascript">
6973 * @class Roo.form.VTypes
6974 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6977 Roo.form.VTypes = function(){
6978 // closure these in so they are only created once.
6979 var alpha = /^[a-zA-Z_]+$/;
6980 var alphanum = /^[a-zA-Z0-9_]+$/;
6981 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6982 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6984 // All these messages and functions are configurable
6987 * The function used to validate email addresses
6988 * @param {String} value The email address
6990 'email' : function(v){
6991 return email.test(v);
6994 * The error text to display when the email validation function returns false
6997 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6999 * The keystroke filter mask to be applied on email input
7002 'emailMask' : /[a-z0-9_\.\-@]/i,
7005 * The function used to validate URLs
7006 * @param {String} value The URL
7008 'url' : function(v){
7012 * The error text to display when the url validation function returns false
7015 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7018 * The function used to validate alpha values
7019 * @param {String} value The value
7021 'alpha' : function(v){
7022 return alpha.test(v);
7025 * The error text to display when the alpha validation function returns false
7028 'alphaText' : 'This field should only contain letters and _',
7030 * The keystroke filter mask to be applied on alpha input
7033 'alphaMask' : /[a-z_]/i,
7036 * The function used to validate alphanumeric values
7037 * @param {String} value The value
7039 'alphanum' : function(v){
7040 return alphanum.test(v);
7043 * The error text to display when the alphanumeric validation function returns false
7046 'alphanumText' : 'This field should only contain letters, numbers and _',
7048 * The keystroke filter mask to be applied on alphanumeric input
7051 'alphanumMask' : /[a-z0-9_]/i
7061 * @class Roo.bootstrap.Input
7062 * @extends Roo.bootstrap.Component
7063 * Bootstrap Input class
7064 * @cfg {Boolean} disabled is it disabled
7065 * @cfg {String} fieldLabel - the label associated
7066 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7067 * @cfg {String} name name of the input
7068 * @cfg {string} fieldLabel - the label associated
7069 * @cfg {string} inputType - input / file submit ...
7070 * @cfg {string} placeholder - placeholder to put in text.
7071 * @cfg {string} before - input group add on before
7072 * @cfg {string} after - input group add on after
7073 * @cfg {string} size - (lg|sm) or leave empty..
7074 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7075 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7076 * @cfg {Number} md colspan out of 12 for computer-sized screens
7077 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7078 * @cfg {string} value default value of the input
7079 * @cfg {Number} labelWidth set the width of label (0-12)
7080 * @cfg {String} labelAlign (top|left)
7081 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7082 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7084 * @cfg {String} align (left|center|right) Default left
7089 * Create a new Input
7090 * @param {Object} config The config object
7093 Roo.bootstrap.Input = function(config){
7094 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7099 * Fires when this field receives input focus.
7100 * @param {Roo.form.Field} this
7105 * Fires when this field loses input focus.
7106 * @param {Roo.form.Field} this
7111 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7112 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7113 * @param {Roo.form.Field} this
7114 * @param {Roo.EventObject} e The event object
7119 * Fires just before the field blurs if the field value has changed.
7120 * @param {Roo.form.Field} this
7121 * @param {Mixed} newValue The new value
7122 * @param {Mixed} oldValue The original value
7127 * Fires after the field has been marked as invalid.
7128 * @param {Roo.form.Field} this
7129 * @param {String} msg The validation message
7134 * Fires after the field has been validated with no errors.
7135 * @param {Roo.form.Field} this
7140 * Fires after the key up
7141 * @param {Roo.form.Field} this
7142 * @param {Roo.EventObject} e The event Object
7148 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7150 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7151 automatic validation (defaults to "keyup").
7153 validationEvent : "keyup",
7155 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7157 validateOnBlur : true,
7159 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7161 validationDelay : 250,
7163 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7165 focusClass : "x-form-focus", // not needed???
7169 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7171 invalidClass : "has-warning",
7174 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7176 validClass : "has-success",
7179 * @cfg {Boolean} hasFeedback (true|false) default true
7184 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7186 invalidFeedbackClass : "glyphicon-warning-sign",
7189 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7191 validFeedbackClass : "glyphicon-ok",
7194 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7196 selectOnFocus : false,
7199 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7203 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7208 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7210 disableKeyFilter : false,
7213 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7217 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7221 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7223 blankText : "This field is required",
7226 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7230 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7232 maxLength : Number.MAX_VALUE,
7234 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7236 minLengthText : "The minimum length for this field is {0}",
7238 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7240 maxLengthText : "The maximum length for this field is {0}",
7244 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7245 * If available, this function will be called only after the basic validators all return true, and will be passed the
7246 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7250 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7251 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7252 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7256 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7260 autocomplete: false,
7279 formatedValue : false,
7281 parentLabelAlign : function()
7284 while (parent.parent()) {
7285 parent = parent.parent();
7286 if (typeof(parent.labelAlign) !='undefined') {
7287 return parent.labelAlign;
7294 getAutoCreate : function(){
7296 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7302 if(this.inputType != 'hidden'){
7303 cfg.cls = 'form-group' //input-group
7309 type : this.inputType,
7311 cls : 'form-control',
7312 placeholder : this.placeholder || '',
7313 autocomplete : this.autocomplete || 'new-password'
7318 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7321 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7322 input.maxLength = this.maxLength;
7325 if (this.disabled) {
7326 input.disabled=true;
7329 if (this.readOnly) {
7330 input.readonly=true;
7334 input.name = this.name;
7337 input.cls += ' input-' + this.size;
7340 ['xs','sm','md','lg'].map(function(size){
7341 if (settings[size]) {
7342 cfg.cls += ' col-' + size + '-' + settings[size];
7346 var inputblock = input;
7348 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7352 cls: 'glyphicon form-control-feedback'
7356 cls : 'has-feedback',
7364 // var inputblock = input;
7366 if (this.before || this.after) {
7369 cls : 'input-group',
7373 if (this.before && typeof(this.before) == 'string') {
7375 inputblock.cn.push({
7377 cls : 'roo-input-before input-group-addon',
7381 if (this.before && typeof(this.before) == 'object') {
7382 this.before = Roo.factory(this.before);
7383 Roo.log(this.before);
7384 inputblock.cn.push({
7386 cls : 'roo-input-before input-group-' +
7387 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7391 inputblock.cn.push(input);
7393 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7394 inputblock.cls += ' has-feedback';
7395 inputblock.cn.push(feedback);
7398 if (this.after && typeof(this.after) == 'string') {
7399 inputblock.cn.push({
7401 cls : 'roo-input-after input-group-addon',
7405 if (this.after && typeof(this.after) == 'object') {
7406 this.after = Roo.factory(this.after);
7407 Roo.log(this.after);
7408 inputblock.cn.push({
7410 cls : 'roo-input-after input-group-' +
7411 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7416 if (align ==='left' && this.fieldLabel.length) {
7417 Roo.log("left and has label");
7423 cls : 'control-label col-sm-' + this.labelWidth,
7424 html : this.fieldLabel
7428 cls : "col-sm-" + (12 - this.labelWidth),
7435 } else if ( this.fieldLabel.length) {
7441 //cls : 'input-group-addon',
7442 html : this.fieldLabel
7452 Roo.log(" no label && no align");
7461 Roo.log('input-parentType: ' + this.parentType);
7463 if (this.parentType === 'Navbar' && this.parent().bar) {
7464 cfg.cls += ' navbar-form';
7472 * return the real input element.
7474 inputEl: function ()
7476 return this.el.select('input.form-control',true).first();
7479 tooltipEl : function()
7481 return this.inputEl();
7484 setDisabled : function(v)
7486 var i = this.inputEl().dom;
7488 i.removeAttribute('disabled');
7492 i.setAttribute('disabled','true');
7494 initEvents : function()
7497 this.inputEl().on("keydown" , this.fireKey, this);
7498 this.inputEl().on("focus", this.onFocus, this);
7499 this.inputEl().on("blur", this.onBlur, this);
7501 this.inputEl().relayEvent('keyup', this);
7503 // reference to original value for reset
7504 this.originalValue = this.getValue();
7505 //Roo.form.TextField.superclass.initEvents.call(this);
7506 if(this.validationEvent == 'keyup'){
7507 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7508 this.inputEl().on('keyup', this.filterValidation, this);
7510 else if(this.validationEvent !== false){
7511 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7514 if(this.selectOnFocus){
7515 this.on("focus", this.preFocus, this);
7518 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7519 this.inputEl().on("keypress", this.filterKeys, this);
7522 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7523 this.el.on("click", this.autoSize, this);
7526 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7527 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7530 if (typeof(this.before) == 'object') {
7531 this.before.render(this.el.select('.roo-input-before',true).first());
7533 if (typeof(this.after) == 'object') {
7534 this.after.render(this.el.select('.roo-input-after',true).first());
7539 filterValidation : function(e){
7540 if(!e.isNavKeyPress()){
7541 this.validationTask.delay(this.validationDelay);
7545 * Validates the field value
7546 * @return {Boolean} True if the value is valid, else false
7548 validate : function(){
7549 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7550 if(this.disabled || this.validateValue(this.getRawValue())){
7561 * Validates a value according to the field's validation rules and marks the field as invalid
7562 * if the validation fails
7563 * @param {Mixed} value The value to validate
7564 * @return {Boolean} True if the value is valid, else false
7566 validateValue : function(value){
7567 if(value.length < 1) { // if it's blank
7568 if(this.allowBlank){
7574 if(value.length < this.minLength){
7577 if(value.length > this.maxLength){
7581 var vt = Roo.form.VTypes;
7582 if(!vt[this.vtype](value, this)){
7586 if(typeof this.validator == "function"){
7587 var msg = this.validator(value);
7593 if(this.regex && !this.regex.test(value)){
7603 fireKey : function(e){
7604 //Roo.log('field ' + e.getKey());
7605 if(e.isNavKeyPress()){
7606 this.fireEvent("specialkey", this, e);
7609 focus : function (selectText){
7611 this.inputEl().focus();
7612 if(selectText === true){
7613 this.inputEl().dom.select();
7619 onFocus : function(){
7620 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7621 // this.el.addClass(this.focusClass);
7624 this.hasFocus = true;
7625 this.startValue = this.getValue();
7626 this.fireEvent("focus", this);
7630 beforeBlur : Roo.emptyFn,
7634 onBlur : function(){
7636 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7637 //this.el.removeClass(this.focusClass);
7639 this.hasFocus = false;
7640 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7643 var v = this.getValue();
7644 if(String(v) !== String(this.startValue)){
7645 this.fireEvent('change', this, v, this.startValue);
7647 this.fireEvent("blur", this);
7651 * Resets the current field value to the originally loaded value and clears any validation messages
7654 this.setValue(this.originalValue);
7658 * Returns the name of the field
7659 * @return {Mixed} name The name field
7661 getName: function(){
7665 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7666 * @return {Mixed} value The field value
7668 getValue : function(){
7670 var v = this.inputEl().getValue();
7675 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7676 * @return {Mixed} value The field value
7678 getRawValue : function(){
7679 var v = this.inputEl().getValue();
7685 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7686 * @param {Mixed} value The value to set
7688 setRawValue : function(v){
7689 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7692 selectText : function(start, end){
7693 var v = this.getRawValue();
7695 start = start === undefined ? 0 : start;
7696 end = end === undefined ? v.length : end;
7697 var d = this.inputEl().dom;
7698 if(d.setSelectionRange){
7699 d.setSelectionRange(start, end);
7700 }else if(d.createTextRange){
7701 var range = d.createTextRange();
7702 range.moveStart("character", start);
7703 range.moveEnd("character", v.length-end);
7710 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7711 * @param {Mixed} value The value to set
7713 setValue : function(v){
7716 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7722 processValue : function(value){
7723 if(this.stripCharsRe){
7724 var newValue = value.replace(this.stripCharsRe, '');
7725 if(newValue !== value){
7726 this.setRawValue(newValue);
7733 preFocus : function(){
7735 if(this.selectOnFocus){
7736 this.inputEl().dom.select();
7739 filterKeys : function(e){
7741 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7744 var c = e.getCharCode(), cc = String.fromCharCode(c);
7745 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7748 if(!this.maskRe.test(cc)){
7753 * Clear any invalid styles/messages for this field
7755 clearInvalid : function(){
7757 if(!this.el || this.preventMark){ // not rendered
7760 this.el.removeClass(this.invalidClass);
7762 this.fireEvent('valid', this);
7766 * Mark this field as valid
7768 markValid : function(){
7769 if(!this.el || this.preventMark){ // not rendered
7773 this.el.removeClass([this.invalidClass, this.validClass]);
7775 if(this.disabled || this.allowBlank){
7779 this.el.addClass(this.validClass);
7781 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7783 var feedback = this.el.select('.form-control-feedback', true).first();
7786 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7787 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7792 this.fireEvent('valid', this);
7796 * Mark this field as invalid
7797 * @param {String} msg The validation message
7799 markInvalid : function(msg){
7800 if(!this.el || this.preventMark){ // not rendered
7804 this.el.removeClass([this.invalidClass, this.validClass]);
7806 if(this.disabled || this.allowBlank){
7810 this.el.addClass(this.invalidClass);
7812 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7814 var feedback = this.el.select('.form-control-feedback', true).first();
7817 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7819 if(this.getValue().length){
7820 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7827 this.fireEvent('invalid', this, msg);
7830 SafariOnKeyDown : function(event)
7832 // this is a workaround for a password hang bug on chrome/ webkit.
7834 var isSelectAll = false;
7836 if(this.inputEl().dom.selectionEnd > 0){
7837 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7839 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7840 event.preventDefault();
7845 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7847 event.preventDefault();
7848 // this is very hacky as keydown always get's upper case.
7850 var cc = String.fromCharCode(event.getCharCode());
7851 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7855 adjustWidth : function(tag, w){
7856 tag = tag.toLowerCase();
7857 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7858 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7862 if(tag == 'textarea'){
7865 }else if(Roo.isOpera){
7869 if(tag == 'textarea'){
7888 * @class Roo.bootstrap.TextArea
7889 * @extends Roo.bootstrap.Input
7890 * Bootstrap TextArea class
7891 * @cfg {Number} cols Specifies the visible width of a text area
7892 * @cfg {Number} rows Specifies the visible number of lines in a text area
7893 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7894 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7895 * @cfg {string} html text
7898 * Create a new TextArea
7899 * @param {Object} config The config object
7902 Roo.bootstrap.TextArea = function(config){
7903 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7907 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7917 getAutoCreate : function(){
7919 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7930 value : this.value || '',
7931 html: this.html || '',
7932 cls : 'form-control',
7933 placeholder : this.placeholder || ''
7937 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7938 input.maxLength = this.maxLength;
7942 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7946 input.cols = this.cols;
7949 if (this.readOnly) {
7950 input.readonly = true;
7954 input.name = this.name;
7958 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7962 ['xs','sm','md','lg'].map(function(size){
7963 if (settings[size]) {
7964 cfg.cls += ' col-' + size + '-' + settings[size];
7968 var inputblock = input;
7970 if(this.hasFeedback && !this.allowBlank){
7974 cls: 'glyphicon form-control-feedback'
7978 cls : 'has-feedback',
7987 if (this.before || this.after) {
7990 cls : 'input-group',
7994 inputblock.cn.push({
7996 cls : 'input-group-addon',
8001 inputblock.cn.push(input);
8003 if(this.hasFeedback && !this.allowBlank){
8004 inputblock.cls += ' has-feedback';
8005 inputblock.cn.push(feedback);
8009 inputblock.cn.push({
8011 cls : 'input-group-addon',
8018 if (align ==='left' && this.fieldLabel.length) {
8019 Roo.log("left and has label");
8025 cls : 'control-label col-sm-' + this.labelWidth,
8026 html : this.fieldLabel
8030 cls : "col-sm-" + (12 - this.labelWidth),
8037 } else if ( this.fieldLabel.length) {
8043 //cls : 'input-group-addon',
8044 html : this.fieldLabel
8054 Roo.log(" no label && no align");
8064 if (this.disabled) {
8065 input.disabled=true;
8072 * return the real textarea element.
8074 inputEl: function ()
8076 return this.el.select('textarea.form-control',true).first();
8084 * trigger field - base class for combo..
8089 * @class Roo.bootstrap.TriggerField
8090 * @extends Roo.bootstrap.Input
8091 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8092 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8093 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8094 * for which you can provide a custom implementation. For example:
8096 var trigger = new Roo.bootstrap.TriggerField();
8097 trigger.onTriggerClick = myTriggerFn;
8098 trigger.applyTo('my-field');
8101 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8102 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8103 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8104 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8105 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8108 * Create a new TriggerField.
8109 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8110 * to the base TextField)
8112 Roo.bootstrap.TriggerField = function(config){
8113 this.mimicing = false;
8114 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8117 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8119 * @cfg {String} triggerClass A CSS class to apply to the trigger
8122 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8126 /** @cfg {Boolean} grow @hide */
8127 /** @cfg {Number} growMin @hide */
8128 /** @cfg {Number} growMax @hide */
8134 autoSize: Roo.emptyFn,
8141 actionMode : 'wrap',
8146 getAutoCreate : function(){
8148 var align = this.labelAlign || this.parentLabelAlign();
8153 cls: 'form-group' //input-group
8160 type : this.inputType,
8161 cls : 'form-control',
8162 autocomplete: 'new-password',
8163 placeholder : this.placeholder || ''
8167 input.name = this.name;
8170 input.cls += ' input-' + this.size;
8173 if (this.disabled) {
8174 input.disabled=true;
8177 var inputblock = input;
8179 if(this.hasFeedback && !this.allowBlank){
8183 cls: 'glyphicon form-control-feedback'
8187 cls : 'has-feedback',
8195 if (this.before || this.after) {
8198 cls : 'input-group',
8202 inputblock.cn.push({
8204 cls : 'input-group-addon',
8209 inputblock.cn.push(input);
8211 if(this.hasFeedback && !this.allowBlank){
8212 inputblock.cls += ' has-feedback';
8213 inputblock.cn.push(feedback);
8217 inputblock.cn.push({
8219 cls : 'input-group-addon',
8232 cls: 'form-hidden-field'
8240 Roo.log('multiple');
8248 cls: 'form-hidden-field'
8252 cls: 'select2-choices',
8256 cls: 'select2-search-field',
8269 cls: 'select2-container input-group',
8274 // cls: 'typeahead typeahead-long dropdown-menu',
8275 // style: 'display:none'
8280 if(!this.multiple && this.showToggleBtn){
8286 if (this.caret != false) {
8289 cls: 'fa fa-' + this.caret
8296 cls : 'input-group-addon btn dropdown-toggle',
8301 cls: 'combobox-clear',
8315 combobox.cls += ' select2-container-multi';
8318 if (align ==='left' && this.fieldLabel.length) {
8320 Roo.log("left and has label");
8326 cls : 'control-label col-sm-' + this.labelWidth,
8327 html : this.fieldLabel
8331 cls : "col-sm-" + (12 - this.labelWidth),
8338 } else if ( this.fieldLabel.length) {
8344 //cls : 'input-group-addon',
8345 html : this.fieldLabel
8355 Roo.log(" no label && no align");
8362 ['xs','sm','md','lg'].map(function(size){
8363 if (settings[size]) {
8364 cfg.cls += ' col-' + size + '-' + settings[size];
8375 onResize : function(w, h){
8376 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8377 // if(typeof w == 'number'){
8378 // var x = w - this.trigger.getWidth();
8379 // this.inputEl().setWidth(this.adjustWidth('input', x));
8380 // this.trigger.setStyle('left', x+'px');
8385 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8388 getResizeEl : function(){
8389 return this.inputEl();
8393 getPositionEl : function(){
8394 return this.inputEl();
8398 alignErrorIcon : function(){
8399 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8403 initEvents : function(){
8407 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8408 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8409 if(!this.multiple && this.showToggleBtn){
8410 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8411 if(this.hideTrigger){
8412 this.trigger.setDisplayed(false);
8414 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8418 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8421 //this.trigger.addClassOnOver('x-form-trigger-over');
8422 //this.trigger.addClassOnClick('x-form-trigger-click');
8425 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8429 createList : function()
8431 this.list = Roo.get(document.body).createChild({
8433 cls: 'typeahead typeahead-long dropdown-menu',
8434 style: 'display:none'
8437 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8442 initTrigger : function(){
8447 onDestroy : function(){
8449 this.trigger.removeAllListeners();
8450 // this.trigger.remove();
8453 // this.wrap.remove();
8455 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8459 onFocus : function(){
8460 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8463 this.wrap.addClass('x-trigger-wrap-focus');
8464 this.mimicing = true;
8465 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8466 if(this.monitorTab){
8467 this.el.on("keydown", this.checkTab, this);
8474 checkTab : function(e){
8475 if(e.getKey() == e.TAB){
8481 onBlur : function(){
8486 mimicBlur : function(e, t){
8488 if(!this.wrap.contains(t) && this.validateBlur()){
8495 triggerBlur : function(){
8496 this.mimicing = false;
8497 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8498 if(this.monitorTab){
8499 this.el.un("keydown", this.checkTab, this);
8501 //this.wrap.removeClass('x-trigger-wrap-focus');
8502 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8506 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8507 validateBlur : function(e, t){
8512 onDisable : function(){
8513 this.inputEl().dom.disabled = true;
8514 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8516 // this.wrap.addClass('x-item-disabled');
8521 onEnable : function(){
8522 this.inputEl().dom.disabled = false;
8523 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8525 // this.el.removeClass('x-item-disabled');
8530 onShow : function(){
8531 var ae = this.getActionEl();
8534 ae.dom.style.display = '';
8535 ae.dom.style.visibility = 'visible';
8541 onHide : function(){
8542 var ae = this.getActionEl();
8543 ae.dom.style.display = 'none';
8547 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8548 * by an implementing function.
8550 * @param {EventObject} e
8552 onTriggerClick : Roo.emptyFn
8556 * Ext JS Library 1.1.1
8557 * Copyright(c) 2006-2007, Ext JS, LLC.
8559 * Originally Released Under LGPL - original licence link has changed is not relivant.
8562 * <script type="text/javascript">
8567 * @class Roo.data.SortTypes
8569 * Defines the default sorting (casting?) comparison functions used when sorting data.
8571 Roo.data.SortTypes = {
8573 * Default sort that does nothing
8574 * @param {Mixed} s The value being converted
8575 * @return {Mixed} The comparison value
8582 * The regular expression used to strip tags
8586 stripTagsRE : /<\/?[^>]+>/gi,
8589 * Strips all HTML tags to sort on text only
8590 * @param {Mixed} s The value being converted
8591 * @return {String} The comparison value
8593 asText : function(s){
8594 return String(s).replace(this.stripTagsRE, "");
8598 * Strips all HTML tags to sort on text only - Case insensitive
8599 * @param {Mixed} s The value being converted
8600 * @return {String} The comparison value
8602 asUCText : function(s){
8603 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8607 * Case insensitive string
8608 * @param {Mixed} s The value being converted
8609 * @return {String} The comparison value
8611 asUCString : function(s) {
8612 return String(s).toUpperCase();
8617 * @param {Mixed} s The value being converted
8618 * @return {Number} The comparison value
8620 asDate : function(s) {
8624 if(s instanceof Date){
8627 return Date.parse(String(s));
8632 * @param {Mixed} s The value being converted
8633 * @return {Float} The comparison value
8635 asFloat : function(s) {
8636 var val = parseFloat(String(s).replace(/,/g, ""));
8637 if(isNaN(val)) val = 0;
8643 * @param {Mixed} s The value being converted
8644 * @return {Number} The comparison value
8646 asInt : function(s) {
8647 var val = parseInt(String(s).replace(/,/g, ""));
8648 if(isNaN(val)) val = 0;
8653 * Ext JS Library 1.1.1
8654 * Copyright(c) 2006-2007, Ext JS, LLC.
8656 * Originally Released Under LGPL - original licence link has changed is not relivant.
8659 * <script type="text/javascript">
8663 * @class Roo.data.Record
8664 * Instances of this class encapsulate both record <em>definition</em> information, and record
8665 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8666 * to access Records cached in an {@link Roo.data.Store} object.<br>
8668 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8669 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8672 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8674 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8675 * {@link #create}. The parameters are the same.
8676 * @param {Array} data An associative Array of data values keyed by the field name.
8677 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8678 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8679 * not specified an integer id is generated.
8681 Roo.data.Record = function(data, id){
8682 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8687 * Generate a constructor for a specific record layout.
8688 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8689 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8690 * Each field definition object may contain the following properties: <ul>
8691 * <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,
8692 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8693 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8694 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8695 * is being used, then this is a string containing the javascript expression to reference the data relative to
8696 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8697 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8698 * this may be omitted.</p></li>
8699 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8700 * <ul><li>auto (Default, implies no conversion)</li>
8705 * <li>date</li></ul></p></li>
8706 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8707 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8708 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8709 * by the Reader into an object that will be stored in the Record. It is passed the
8710 * following parameters:<ul>
8711 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8713 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8715 * <br>usage:<br><pre><code>
8716 var TopicRecord = Roo.data.Record.create(
8717 {name: 'title', mapping: 'topic_title'},
8718 {name: 'author', mapping: 'username'},
8719 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8720 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8721 {name: 'lastPoster', mapping: 'user2'},
8722 {name: 'excerpt', mapping: 'post_text'}
8725 var myNewRecord = new TopicRecord({
8726 title: 'Do my job please',
8729 lastPost: new Date(),
8730 lastPoster: 'Animal',
8731 excerpt: 'No way dude!'
8733 myStore.add(myNewRecord);
8738 Roo.data.Record.create = function(o){
8740 f.superclass.constructor.apply(this, arguments);
8742 Roo.extend(f, Roo.data.Record);
8743 var p = f.prototype;
8744 p.fields = new Roo.util.MixedCollection(false, function(field){
8747 for(var i = 0, len = o.length; i < len; i++){
8748 p.fields.add(new Roo.data.Field(o[i]));
8750 f.getField = function(name){
8751 return p.fields.get(name);
8756 Roo.data.Record.AUTO_ID = 1000;
8757 Roo.data.Record.EDIT = 'edit';
8758 Roo.data.Record.REJECT = 'reject';
8759 Roo.data.Record.COMMIT = 'commit';
8761 Roo.data.Record.prototype = {
8763 * Readonly flag - true if this record has been modified.
8772 join : function(store){
8777 * Set the named field to the specified value.
8778 * @param {String} name The name of the field to set.
8779 * @param {Object} value The value to set the field to.
8781 set : function(name, value){
8782 if(this.data[name] == value){
8789 if(typeof this.modified[name] == 'undefined'){
8790 this.modified[name] = this.data[name];
8792 this.data[name] = value;
8793 if(!this.editing && this.store){
8794 this.store.afterEdit(this);
8799 * Get the value of the named field.
8800 * @param {String} name The name of the field to get the value of.
8801 * @return {Object} The value of the field.
8803 get : function(name){
8804 return this.data[name];
8808 beginEdit : function(){
8809 this.editing = true;
8814 cancelEdit : function(){
8815 this.editing = false;
8816 delete this.modified;
8820 endEdit : function(){
8821 this.editing = false;
8822 if(this.dirty && this.store){
8823 this.store.afterEdit(this);
8828 * Usually called by the {@link Roo.data.Store} which owns the Record.
8829 * Rejects all changes made to the Record since either creation, or the last commit operation.
8830 * Modified fields are reverted to their original values.
8832 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8833 * of reject operations.
8835 reject : function(){
8836 var m = this.modified;
8838 if(typeof m[n] != "function"){
8839 this.data[n] = m[n];
8843 delete this.modified;
8844 this.editing = false;
8846 this.store.afterReject(this);
8851 * Usually called by the {@link Roo.data.Store} which owns the Record.
8852 * Commits all changes made to the Record since either creation, or the last commit operation.
8854 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8855 * of commit operations.
8857 commit : function(){
8859 delete this.modified;
8860 this.editing = false;
8862 this.store.afterCommit(this);
8867 hasError : function(){
8868 return this.error != null;
8872 clearError : function(){
8877 * Creates a copy of this record.
8878 * @param {String} id (optional) A new record id if you don't want to use this record's id
8881 copy : function(newId) {
8882 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8886 * Ext JS Library 1.1.1
8887 * Copyright(c) 2006-2007, Ext JS, LLC.
8889 * Originally Released Under LGPL - original licence link has changed is not relivant.
8892 * <script type="text/javascript">
8898 * @class Roo.data.Store
8899 * @extends Roo.util.Observable
8900 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8901 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8903 * 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
8904 * has no knowledge of the format of the data returned by the Proxy.<br>
8906 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8907 * instances from the data object. These records are cached and made available through accessor functions.
8909 * Creates a new Store.
8910 * @param {Object} config A config object containing the objects needed for the Store to access data,
8911 * and read the data into Records.
8913 Roo.data.Store = function(config){
8914 this.data = new Roo.util.MixedCollection(false);
8915 this.data.getKey = function(o){
8918 this.baseParams = {};
8925 "multisort" : "_multisort"
8928 if(config && config.data){
8929 this.inlineData = config.data;
8933 Roo.apply(this, config);
8935 if(this.reader){ // reader passed
8936 this.reader = Roo.factory(this.reader, Roo.data);
8937 this.reader.xmodule = this.xmodule || false;
8938 if(!this.recordType){
8939 this.recordType = this.reader.recordType;
8941 if(this.reader.onMetaChange){
8942 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8946 if(this.recordType){
8947 this.fields = this.recordType.prototype.fields;
8953 * @event datachanged
8954 * Fires when the data cache has changed, and a widget which is using this Store
8955 * as a Record cache should refresh its view.
8956 * @param {Store} this
8961 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8962 * @param {Store} this
8963 * @param {Object} meta The JSON metadata
8968 * Fires when Records have been added to the Store
8969 * @param {Store} this
8970 * @param {Roo.data.Record[]} records The array of Records added
8971 * @param {Number} index The index at which the record(s) were added
8976 * Fires when a Record has been removed from the Store
8977 * @param {Store} this
8978 * @param {Roo.data.Record} record The Record that was removed
8979 * @param {Number} index The index at which the record was removed
8984 * Fires when a Record has been updated
8985 * @param {Store} this
8986 * @param {Roo.data.Record} record The Record that was updated
8987 * @param {String} operation The update operation being performed. Value may be one of:
8989 Roo.data.Record.EDIT
8990 Roo.data.Record.REJECT
8991 Roo.data.Record.COMMIT
8997 * Fires when the data cache has been cleared.
8998 * @param {Store} this
9003 * Fires before a request is made for a new data object. If the beforeload handler returns false
9004 * the load action will be canceled.
9005 * @param {Store} this
9006 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9010 * @event beforeloadadd
9011 * Fires after a new set of Records has been loaded.
9012 * @param {Store} this
9013 * @param {Roo.data.Record[]} records The Records that were loaded
9014 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9016 beforeloadadd : true,
9019 * Fires after a new set of Records has been loaded, before they are added to the store.
9020 * @param {Store} this
9021 * @param {Roo.data.Record[]} records The Records that were loaded
9022 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9023 * @params {Object} return from reader
9027 * @event loadexception
9028 * Fires if an exception occurs in the Proxy during loading.
9029 * Called with the signature of the Proxy's "loadexception" event.
9030 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9033 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9034 * @param {Object} load options
9035 * @param {Object} jsonData from your request (normally this contains the Exception)
9037 loadexception : true
9041 this.proxy = Roo.factory(this.proxy, Roo.data);
9042 this.proxy.xmodule = this.xmodule || false;
9043 this.relayEvents(this.proxy, ["loadexception"]);
9045 this.sortToggle = {};
9046 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9048 Roo.data.Store.superclass.constructor.call(this);
9050 if(this.inlineData){
9051 this.loadData(this.inlineData);
9052 delete this.inlineData;
9056 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9058 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9059 * without a remote query - used by combo/forms at present.
9063 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9066 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9069 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9070 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9073 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9074 * on any HTTP request
9077 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9080 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9084 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9085 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9090 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9091 * loaded or when a record is removed. (defaults to false).
9093 pruneModifiedRecords : false,
9099 * Add Records to the Store and fires the add event.
9100 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9102 add : function(records){
9103 records = [].concat(records);
9104 for(var i = 0, len = records.length; i < len; i++){
9105 records[i].join(this);
9107 var index = this.data.length;
9108 this.data.addAll(records);
9109 this.fireEvent("add", this, records, index);
9113 * Remove a Record from the Store and fires the remove event.
9114 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9116 remove : function(record){
9117 var index = this.data.indexOf(record);
9118 this.data.removeAt(index);
9119 if(this.pruneModifiedRecords){
9120 this.modified.remove(record);
9122 this.fireEvent("remove", this, record, index);
9126 * Remove all Records from the Store and fires the clear event.
9128 removeAll : function(){
9130 if(this.pruneModifiedRecords){
9133 this.fireEvent("clear", this);
9137 * Inserts Records to the Store at the given index and fires the add event.
9138 * @param {Number} index The start index at which to insert the passed Records.
9139 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9141 insert : function(index, records){
9142 records = [].concat(records);
9143 for(var i = 0, len = records.length; i < len; i++){
9144 this.data.insert(index, records[i]);
9145 records[i].join(this);
9147 this.fireEvent("add", this, records, index);
9151 * Get the index within the cache of the passed Record.
9152 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9153 * @return {Number} The index of the passed Record. Returns -1 if not found.
9155 indexOf : function(record){
9156 return this.data.indexOf(record);
9160 * Get the index within the cache of the Record with the passed id.
9161 * @param {String} id The id of the Record to find.
9162 * @return {Number} The index of the Record. Returns -1 if not found.
9164 indexOfId : function(id){
9165 return this.data.indexOfKey(id);
9169 * Get the Record with the specified id.
9170 * @param {String} id The id of the Record to find.
9171 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9173 getById : function(id){
9174 return this.data.key(id);
9178 * Get the Record at the specified index.
9179 * @param {Number} index The index of the Record to find.
9180 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9182 getAt : function(index){
9183 return this.data.itemAt(index);
9187 * Returns a range of Records between specified indices.
9188 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9189 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9190 * @return {Roo.data.Record[]} An array of Records
9192 getRange : function(start, end){
9193 return this.data.getRange(start, end);
9197 storeOptions : function(o){
9198 o = Roo.apply({}, o);
9201 this.lastOptions = o;
9205 * Loads the Record cache from the configured Proxy using the configured Reader.
9207 * If using remote paging, then the first load call must specify the <em>start</em>
9208 * and <em>limit</em> properties in the options.params property to establish the initial
9209 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9211 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9212 * and this call will return before the new data has been loaded. Perform any post-processing
9213 * in a callback function, or in a "load" event handler.</strong>
9215 * @param {Object} options An object containing properties which control loading options:<ul>
9216 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9217 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9218 * passed the following arguments:<ul>
9219 * <li>r : Roo.data.Record[]</li>
9220 * <li>options: Options object from the load call</li>
9221 * <li>success: Boolean success indicator</li></ul></li>
9222 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9223 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9226 load : function(options){
9227 options = options || {};
9228 if(this.fireEvent("beforeload", this, options) !== false){
9229 this.storeOptions(options);
9230 var p = Roo.apply(options.params || {}, this.baseParams);
9231 // if meta was not loaded from remote source.. try requesting it.
9232 if (!this.reader.metaFromRemote) {
9235 if(this.sortInfo && this.remoteSort){
9236 var pn = this.paramNames;
9237 p[pn["sort"]] = this.sortInfo.field;
9238 p[pn["dir"]] = this.sortInfo.direction;
9240 if (this.multiSort) {
9241 var pn = this.paramNames;
9242 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9245 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9250 * Reloads the Record cache from the configured Proxy using the configured Reader and
9251 * the options from the last load operation performed.
9252 * @param {Object} options (optional) An object containing properties which may override the options
9253 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9254 * the most recently used options are reused).
9256 reload : function(options){
9257 this.load(Roo.applyIf(options||{}, this.lastOptions));
9261 // Called as a callback by the Reader during a load operation.
9262 loadRecords : function(o, options, success){
9263 if(!o || success === false){
9264 if(success !== false){
9265 this.fireEvent("load", this, [], options, o);
9267 if(options.callback){
9268 options.callback.call(options.scope || this, [], options, false);
9272 // if data returned failure - throw an exception.
9273 if (o.success === false) {
9274 // show a message if no listener is registered.
9275 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9276 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9278 // loadmask wil be hooked into this..
9279 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9282 var r = o.records, t = o.totalRecords || r.length;
9284 this.fireEvent("beforeloadadd", this, r, options, o);
9286 if(!options || options.add !== true){
9287 if(this.pruneModifiedRecords){
9290 for(var i = 0, len = r.length; i < len; i++){
9294 this.data = this.snapshot;
9295 delete this.snapshot;
9298 this.data.addAll(r);
9299 this.totalLength = t;
9301 this.fireEvent("datachanged", this);
9303 this.totalLength = Math.max(t, this.data.length+r.length);
9306 this.fireEvent("load", this, r, options, o);
9307 if(options.callback){
9308 options.callback.call(options.scope || this, r, options, true);
9314 * Loads data from a passed data block. A Reader which understands the format of the data
9315 * must have been configured in the constructor.
9316 * @param {Object} data The data block from which to read the Records. The format of the data expected
9317 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9318 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9320 loadData : function(o, append){
9321 var r = this.reader.readRecords(o);
9322 this.loadRecords(r, {add: append}, true);
9326 * Gets the number of cached records.
9328 * <em>If using paging, this may not be the total size of the dataset. If the data object
9329 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9330 * the data set size</em>
9332 getCount : function(){
9333 return this.data.length || 0;
9337 * Gets the total number of records in the dataset as returned by the server.
9339 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9340 * the dataset size</em>
9342 getTotalCount : function(){
9343 return this.totalLength || 0;
9347 * Returns the sort state of the Store as an object with two properties:
9349 field {String} The name of the field by which the Records are sorted
9350 direction {String} The sort order, "ASC" or "DESC"
9353 getSortState : function(){
9354 return this.sortInfo;
9358 applySort : function(){
9359 if(this.sortInfo && !this.remoteSort){
9360 var s = this.sortInfo, f = s.field;
9361 var st = this.fields.get(f).sortType;
9362 var fn = function(r1, r2){
9363 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9364 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9366 this.data.sort(s.direction, fn);
9367 if(this.snapshot && this.snapshot != this.data){
9368 this.snapshot.sort(s.direction, fn);
9374 * Sets the default sort column and order to be used by the next load operation.
9375 * @param {String} fieldName The name of the field to sort by.
9376 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9378 setDefaultSort : function(field, dir){
9379 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9384 * If remote sorting is used, the sort is performed on the server, and the cache is
9385 * reloaded. If local sorting is used, the cache is sorted internally.
9386 * @param {String} fieldName The name of the field to sort by.
9387 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9389 sort : function(fieldName, dir){
9390 var f = this.fields.get(fieldName);
9392 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9394 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9395 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9400 this.sortToggle[f.name] = dir;
9401 this.sortInfo = {field: f.name, direction: dir};
9402 if(!this.remoteSort){
9404 this.fireEvent("datachanged", this);
9406 this.load(this.lastOptions);
9411 * Calls the specified function for each of the Records in the cache.
9412 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9413 * Returning <em>false</em> aborts and exits the iteration.
9414 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9416 each : function(fn, scope){
9417 this.data.each(fn, scope);
9421 * Gets all records modified since the last commit. Modified records are persisted across load operations
9422 * (e.g., during paging).
9423 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9425 getModifiedRecords : function(){
9426 return this.modified;
9430 createFilterFn : function(property, value, anyMatch){
9431 if(!value.exec){ // not a regex
9432 value = String(value);
9433 if(value.length == 0){
9436 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9439 return value.test(r.data[property]);
9444 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9445 * @param {String} property A field on your records
9446 * @param {Number} start The record index to start at (defaults to 0)
9447 * @param {Number} end The last record index to include (defaults to length - 1)
9448 * @return {Number} The sum
9450 sum : function(property, start, end){
9451 var rs = this.data.items, v = 0;
9453 end = (end || end === 0) ? end : rs.length-1;
9455 for(var i = start; i <= end; i++){
9456 v += (rs[i].data[property] || 0);
9462 * Filter the records by a specified property.
9463 * @param {String} field A field on your records
9464 * @param {String/RegExp} value Either a string that the field
9465 * should start with or a RegExp to test against the field
9466 * @param {Boolean} anyMatch True to match any part not just the beginning
9468 filter : function(property, value, anyMatch){
9469 var fn = this.createFilterFn(property, value, anyMatch);
9470 return fn ? this.filterBy(fn) : this.clearFilter();
9474 * Filter by a function. The specified function will be called with each
9475 * record in this data source. If the function returns true the record is included,
9476 * otherwise it is filtered.
9477 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9478 * @param {Object} scope (optional) The scope of the function (defaults to this)
9480 filterBy : function(fn, scope){
9481 this.snapshot = this.snapshot || this.data;
9482 this.data = this.queryBy(fn, scope||this);
9483 this.fireEvent("datachanged", this);
9487 * Query the records by a specified property.
9488 * @param {String} field A field on your records
9489 * @param {String/RegExp} value Either a string that the field
9490 * should start with or a RegExp to test against the field
9491 * @param {Boolean} anyMatch True to match any part not just the beginning
9492 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9494 query : function(property, value, anyMatch){
9495 var fn = this.createFilterFn(property, value, anyMatch);
9496 return fn ? this.queryBy(fn) : this.data.clone();
9500 * Query by a function. The specified function will be called with each
9501 * record in this data source. If the function returns true the record is included
9503 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9504 * @param {Object} scope (optional) The scope of the function (defaults to this)
9505 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9507 queryBy : function(fn, scope){
9508 var data = this.snapshot || this.data;
9509 return data.filterBy(fn, scope||this);
9513 * Collects unique values for a particular dataIndex from this store.
9514 * @param {String} dataIndex The property to collect
9515 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9516 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9517 * @return {Array} An array of the unique values
9519 collect : function(dataIndex, allowNull, bypassFilter){
9520 var d = (bypassFilter === true && this.snapshot) ?
9521 this.snapshot.items : this.data.items;
9522 var v, sv, r = [], l = {};
9523 for(var i = 0, len = d.length; i < len; i++){
9524 v = d[i].data[dataIndex];
9526 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9535 * Revert to a view of the Record cache with no filtering applied.
9536 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9538 clearFilter : function(suppressEvent){
9539 if(this.snapshot && this.snapshot != this.data){
9540 this.data = this.snapshot;
9541 delete this.snapshot;
9542 if(suppressEvent !== true){
9543 this.fireEvent("datachanged", this);
9549 afterEdit : function(record){
9550 if(this.modified.indexOf(record) == -1){
9551 this.modified.push(record);
9553 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9557 afterReject : function(record){
9558 this.modified.remove(record);
9559 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9563 afterCommit : function(record){
9564 this.modified.remove(record);
9565 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9569 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9570 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9572 commitChanges : function(){
9573 var m = this.modified.slice(0);
9575 for(var i = 0, len = m.length; i < len; i++){
9581 * Cancel outstanding changes on all changed records.
9583 rejectChanges : function(){
9584 var m = this.modified.slice(0);
9586 for(var i = 0, len = m.length; i < len; i++){
9591 onMetaChange : function(meta, rtype, o){
9592 this.recordType = rtype;
9593 this.fields = rtype.prototype.fields;
9594 delete this.snapshot;
9595 this.sortInfo = meta.sortInfo || this.sortInfo;
9597 this.fireEvent('metachange', this, this.reader.meta);
9600 moveIndex : function(data, type)
9602 var index = this.indexOf(data);
9604 var newIndex = index + type;
9608 this.insert(newIndex, data);
9613 * Ext JS Library 1.1.1
9614 * Copyright(c) 2006-2007, Ext JS, LLC.
9616 * Originally Released Under LGPL - original licence link has changed is not relivant.
9619 * <script type="text/javascript">
9623 * @class Roo.data.SimpleStore
9624 * @extends Roo.data.Store
9625 * Small helper class to make creating Stores from Array data easier.
9626 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9627 * @cfg {Array} fields An array of field definition objects, or field name strings.
9628 * @cfg {Array} data The multi-dimensional array of data
9630 * @param {Object} config
9632 Roo.data.SimpleStore = function(config){
9633 Roo.data.SimpleStore.superclass.constructor.call(this, {
9635 reader: new Roo.data.ArrayReader({
9638 Roo.data.Record.create(config.fields)
9640 proxy : new Roo.data.MemoryProxy(config.data)
9644 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9646 * Ext JS Library 1.1.1
9647 * Copyright(c) 2006-2007, Ext JS, LLC.
9649 * Originally Released Under LGPL - original licence link has changed is not relivant.
9652 * <script type="text/javascript">
9657 * @extends Roo.data.Store
9658 * @class Roo.data.JsonStore
9659 * Small helper class to make creating Stores for JSON data easier. <br/>
9661 var store = new Roo.data.JsonStore({
9662 url: 'get-images.php',
9664 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9667 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9668 * JsonReader and HttpProxy (unless inline data is provided).</b>
9669 * @cfg {Array} fields An array of field definition objects, or field name strings.
9671 * @param {Object} config
9673 Roo.data.JsonStore = function(c){
9674 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9675 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9676 reader: new Roo.data.JsonReader(c, c.fields)
9679 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9681 * Ext JS Library 1.1.1
9682 * Copyright(c) 2006-2007, Ext JS, LLC.
9684 * Originally Released Under LGPL - original licence link has changed is not relivant.
9687 * <script type="text/javascript">
9691 Roo.data.Field = function(config){
9692 if(typeof config == "string"){
9693 config = {name: config};
9695 Roo.apply(this, config);
9701 var st = Roo.data.SortTypes;
9702 // named sortTypes are supported, here we look them up
9703 if(typeof this.sortType == "string"){
9704 this.sortType = st[this.sortType];
9707 // set default sortType for strings and dates
9711 this.sortType = st.asUCString;
9714 this.sortType = st.asDate;
9717 this.sortType = st.none;
9722 var stripRe = /[\$,%]/g;
9724 // prebuilt conversion function for this field, instead of
9725 // switching every time we're reading a value
9727 var cv, dateFormat = this.dateFormat;
9732 cv = function(v){ return v; };
9735 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9739 return v !== undefined && v !== null && v !== '' ?
9740 parseInt(String(v).replace(stripRe, ""), 10) : '';
9745 return v !== undefined && v !== null && v !== '' ?
9746 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9751 cv = function(v){ return v === true || v === "true" || v == 1; };
9758 if(v instanceof Date){
9762 if(dateFormat == "timestamp"){
9763 return new Date(v*1000);
9765 return Date.parseDate(v, dateFormat);
9767 var parsed = Date.parse(v);
9768 return parsed ? new Date(parsed) : null;
9777 Roo.data.Field.prototype = {
9785 * Ext JS Library 1.1.1
9786 * Copyright(c) 2006-2007, Ext JS, LLC.
9788 * Originally Released Under LGPL - original licence link has changed is not relivant.
9791 * <script type="text/javascript">
9794 // Base class for reading structured data from a data source. This class is intended to be
9795 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9798 * @class Roo.data.DataReader
9799 * Base class for reading structured data from a data source. This class is intended to be
9800 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9803 Roo.data.DataReader = function(meta, recordType){
9807 this.recordType = recordType instanceof Array ?
9808 Roo.data.Record.create(recordType) : recordType;
9811 Roo.data.DataReader.prototype = {
9813 * Create an empty record
9814 * @param {Object} data (optional) - overlay some values
9815 * @return {Roo.data.Record} record created.
9817 newRow : function(d) {
9819 this.recordType.prototype.fields.each(function(c) {
9821 case 'int' : da[c.name] = 0; break;
9822 case 'date' : da[c.name] = new Date(); break;
9823 case 'float' : da[c.name] = 0.0; break;
9824 case 'boolean' : da[c.name] = false; break;
9825 default : da[c.name] = ""; break;
9829 return new this.recordType(Roo.apply(da, d));
9834 * Ext JS Library 1.1.1
9835 * Copyright(c) 2006-2007, Ext JS, LLC.
9837 * Originally Released Under LGPL - original licence link has changed is not relivant.
9840 * <script type="text/javascript">
9844 * @class Roo.data.DataProxy
9845 * @extends Roo.data.Observable
9846 * This class is an abstract base class for implementations which provide retrieval of
9847 * unformatted data objects.<br>
9849 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9850 * (of the appropriate type which knows how to parse the data object) to provide a block of
9851 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9853 * Custom implementations must implement the load method as described in
9854 * {@link Roo.data.HttpProxy#load}.
9856 Roo.data.DataProxy = function(){
9860 * Fires before a network request is made to retrieve a data object.
9861 * @param {Object} This DataProxy object.
9862 * @param {Object} params The params parameter to the load function.
9867 * Fires before the load method's callback is called.
9868 * @param {Object} This DataProxy object.
9869 * @param {Object} o The data object.
9870 * @param {Object} arg The callback argument object passed to the load function.
9874 * @event loadexception
9875 * Fires if an Exception occurs during data retrieval.
9876 * @param {Object} This DataProxy object.
9877 * @param {Object} o The data object.
9878 * @param {Object} arg The callback argument object passed to the load function.
9879 * @param {Object} e The Exception.
9881 loadexception : true
9883 Roo.data.DataProxy.superclass.constructor.call(this);
9886 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9889 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9893 * Ext JS Library 1.1.1
9894 * Copyright(c) 2006-2007, Ext JS, LLC.
9896 * Originally Released Under LGPL - original licence link has changed is not relivant.
9899 * <script type="text/javascript">
9902 * @class Roo.data.MemoryProxy
9903 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9904 * to the Reader when its load method is called.
9906 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9908 Roo.data.MemoryProxy = function(data){
9912 Roo.data.MemoryProxy.superclass.constructor.call(this);
9916 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9918 * Load data from the requested source (in this case an in-memory
9919 * data object passed to the constructor), read the data object into
9920 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9921 * process that block using the passed callback.
9922 * @param {Object} params This parameter is not used by the MemoryProxy class.
9923 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9924 * object into a block of Roo.data.Records.
9925 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9926 * The function must be passed <ul>
9927 * <li>The Record block object</li>
9928 * <li>The "arg" argument from the load function</li>
9929 * <li>A boolean success indicator</li>
9931 * @param {Object} scope The scope in which to call the callback
9932 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9934 load : function(params, reader, callback, scope, arg){
9935 params = params || {};
9938 result = reader.readRecords(this.data);
9940 this.fireEvent("loadexception", this, arg, null, e);
9941 callback.call(scope, null, arg, false);
9944 callback.call(scope, result, arg, true);
9948 update : function(params, records){
9953 * Ext JS Library 1.1.1
9954 * Copyright(c) 2006-2007, Ext JS, LLC.
9956 * Originally Released Under LGPL - original licence link has changed is not relivant.
9959 * <script type="text/javascript">
9962 * @class Roo.data.HttpProxy
9963 * @extends Roo.data.DataProxy
9964 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9965 * configured to reference a certain URL.<br><br>
9967 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9968 * from which the running page was served.<br><br>
9970 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9972 * Be aware that to enable the browser to parse an XML document, the server must set
9973 * the Content-Type header in the HTTP response to "text/xml".
9975 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9976 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9977 * will be used to make the request.
9979 Roo.data.HttpProxy = function(conn){
9980 Roo.data.HttpProxy.superclass.constructor.call(this);
9981 // is conn a conn config or a real conn?
9983 this.useAjax = !conn || !conn.events;
9987 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9988 // thse are take from connection...
9991 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9994 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9995 * extra parameters to each request made by this object. (defaults to undefined)
9998 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9999 * to each request made by this object. (defaults to undefined)
10002 * @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)
10005 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10008 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10014 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10018 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10019 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10020 * a finer-grained basis than the DataProxy events.
10022 getConnection : function(){
10023 return this.useAjax ? Roo.Ajax : this.conn;
10027 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10028 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10029 * process that block using the passed callback.
10030 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10031 * for the request to the remote server.
10032 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10033 * object into a block of Roo.data.Records.
10034 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10035 * The function must be passed <ul>
10036 * <li>The Record block object</li>
10037 * <li>The "arg" argument from the load function</li>
10038 * <li>A boolean success indicator</li>
10040 * @param {Object} scope The scope in which to call the callback
10041 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10043 load : function(params, reader, callback, scope, arg){
10044 if(this.fireEvent("beforeload", this, params) !== false){
10046 params : params || {},
10048 callback : callback,
10053 callback : this.loadResponse,
10057 Roo.applyIf(o, this.conn);
10058 if(this.activeRequest){
10059 Roo.Ajax.abort(this.activeRequest);
10061 this.activeRequest = Roo.Ajax.request(o);
10063 this.conn.request(o);
10066 callback.call(scope||this, null, arg, false);
10071 loadResponse : function(o, success, response){
10072 delete this.activeRequest;
10074 this.fireEvent("loadexception", this, o, response);
10075 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10080 result = o.reader.read(response);
10082 this.fireEvent("loadexception", this, o, response, e);
10083 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10087 this.fireEvent("load", this, o, o.request.arg);
10088 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10092 update : function(dataSet){
10097 updateResponse : function(dataSet){
10102 * Ext JS Library 1.1.1
10103 * Copyright(c) 2006-2007, Ext JS, LLC.
10105 * Originally Released Under LGPL - original licence link has changed is not relivant.
10108 * <script type="text/javascript">
10112 * @class Roo.data.ScriptTagProxy
10113 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10114 * other than the originating domain of the running page.<br><br>
10116 * <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
10117 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10119 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10120 * source code that is used as the source inside a <script> tag.<br><br>
10122 * In order for the browser to process the returned data, the server must wrap the data object
10123 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10124 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10125 * depending on whether the callback name was passed:
10128 boolean scriptTag = false;
10129 String cb = request.getParameter("callback");
10132 response.setContentType("text/javascript");
10134 response.setContentType("application/x-json");
10136 Writer out = response.getWriter();
10138 out.write(cb + "(");
10140 out.print(dataBlock.toJsonString());
10147 * @param {Object} config A configuration object.
10149 Roo.data.ScriptTagProxy = function(config){
10150 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10151 Roo.apply(this, config);
10152 this.head = document.getElementsByTagName("head")[0];
10155 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10157 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10159 * @cfg {String} url The URL from which to request the data object.
10162 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10166 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10167 * the server the name of the callback function set up by the load call to process the returned data object.
10168 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10169 * javascript output which calls this named function passing the data object as its only parameter.
10171 callbackParam : "callback",
10173 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10174 * name to the request.
10179 * Load data from the configured URL, read the data object into
10180 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10181 * process that block using the passed callback.
10182 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10183 * for the request to the remote server.
10184 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10185 * object into a block of Roo.data.Records.
10186 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10187 * The function must be passed <ul>
10188 * <li>The Record block object</li>
10189 * <li>The "arg" argument from the load function</li>
10190 * <li>A boolean success indicator</li>
10192 * @param {Object} scope The scope in which to call the callback
10193 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10195 load : function(params, reader, callback, scope, arg){
10196 if(this.fireEvent("beforeload", this, params) !== false){
10198 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10200 var url = this.url;
10201 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10203 url += "&_dc=" + (new Date().getTime());
10205 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10208 cb : "stcCallback"+transId,
10209 scriptId : "stcScript"+transId,
10213 callback : callback,
10219 window[trans.cb] = function(o){
10220 conn.handleResponse(o, trans);
10223 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10225 if(this.autoAbort !== false){
10229 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10231 var script = document.createElement("script");
10232 script.setAttribute("src", url);
10233 script.setAttribute("type", "text/javascript");
10234 script.setAttribute("id", trans.scriptId);
10235 this.head.appendChild(script);
10237 this.trans = trans;
10239 callback.call(scope||this, null, arg, false);
10244 isLoading : function(){
10245 return this.trans ? true : false;
10249 * Abort the current server request.
10251 abort : function(){
10252 if(this.isLoading()){
10253 this.destroyTrans(this.trans);
10258 destroyTrans : function(trans, isLoaded){
10259 this.head.removeChild(document.getElementById(trans.scriptId));
10260 clearTimeout(trans.timeoutId);
10262 window[trans.cb] = undefined;
10264 delete window[trans.cb];
10267 // if hasn't been loaded, wait for load to remove it to prevent script error
10268 window[trans.cb] = function(){
10269 window[trans.cb] = undefined;
10271 delete window[trans.cb];
10278 handleResponse : function(o, trans){
10279 this.trans = false;
10280 this.destroyTrans(trans, true);
10283 result = trans.reader.readRecords(o);
10285 this.fireEvent("loadexception", this, o, trans.arg, e);
10286 trans.callback.call(trans.scope||window, null, trans.arg, false);
10289 this.fireEvent("load", this, o, trans.arg);
10290 trans.callback.call(trans.scope||window, result, trans.arg, true);
10294 handleFailure : function(trans){
10295 this.trans = false;
10296 this.destroyTrans(trans, false);
10297 this.fireEvent("loadexception", this, null, trans.arg);
10298 trans.callback.call(trans.scope||window, null, trans.arg, false);
10302 * Ext JS Library 1.1.1
10303 * Copyright(c) 2006-2007, Ext JS, LLC.
10305 * Originally Released Under LGPL - original licence link has changed is not relivant.
10308 * <script type="text/javascript">
10312 * @class Roo.data.JsonReader
10313 * @extends Roo.data.DataReader
10314 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10315 * based on mappings in a provided Roo.data.Record constructor.
10317 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10318 * in the reply previously.
10323 var RecordDef = Roo.data.Record.create([
10324 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10325 {name: 'occupation'} // This field will use "occupation" as the mapping.
10327 var myReader = new Roo.data.JsonReader({
10328 totalProperty: "results", // The property which contains the total dataset size (optional)
10329 root: "rows", // The property which contains an Array of row objects
10330 id: "id" // The property within each row object that provides an ID for the record (optional)
10334 * This would consume a JSON file like this:
10336 { 'results': 2, 'rows': [
10337 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10338 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10341 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10342 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10343 * paged from the remote server.
10344 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10345 * @cfg {String} root name of the property which contains the Array of row objects.
10346 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10348 * Create a new JsonReader
10349 * @param {Object} meta Metadata configuration options
10350 * @param {Object} recordType Either an Array of field definition objects,
10351 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10353 Roo.data.JsonReader = function(meta, recordType){
10356 // set some defaults:
10357 Roo.applyIf(meta, {
10358 totalProperty: 'total',
10359 successProperty : 'success',
10364 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10366 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10369 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10370 * Used by Store query builder to append _requestMeta to params.
10373 metaFromRemote : false,
10375 * This method is only used by a DataProxy which has retrieved data from a remote server.
10376 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10377 * @return {Object} data A data block which is used by an Roo.data.Store object as
10378 * a cache of Roo.data.Records.
10380 read : function(response){
10381 var json = response.responseText;
10383 var o = /* eval:var:o */ eval("("+json+")");
10385 throw {message: "JsonReader.read: Json object not found"};
10391 this.metaFromRemote = true;
10392 this.meta = o.metaData;
10393 this.recordType = Roo.data.Record.create(o.metaData.fields);
10394 this.onMetaChange(this.meta, this.recordType, o);
10396 return this.readRecords(o);
10399 // private function a store will implement
10400 onMetaChange : function(meta, recordType, o){
10407 simpleAccess: function(obj, subsc) {
10414 getJsonAccessor: function(){
10416 return function(expr) {
10418 return(re.test(expr))
10419 ? new Function("obj", "return obj." + expr)
10424 return Roo.emptyFn;
10429 * Create a data block containing Roo.data.Records from an XML document.
10430 * @param {Object} o An object which contains an Array of row objects in the property specified
10431 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10432 * which contains the total size of the dataset.
10433 * @return {Object} data A data block which is used by an Roo.data.Store object as
10434 * a cache of Roo.data.Records.
10436 readRecords : function(o){
10438 * After any data loads, the raw JSON data is available for further custom processing.
10442 var s = this.meta, Record = this.recordType,
10443 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10445 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10447 if(s.totalProperty) {
10448 this.getTotal = this.getJsonAccessor(s.totalProperty);
10450 if(s.successProperty) {
10451 this.getSuccess = this.getJsonAccessor(s.successProperty);
10453 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10455 var g = this.getJsonAccessor(s.id);
10456 this.getId = function(rec) {
10458 return (r === undefined || r === "") ? null : r;
10461 this.getId = function(){return null;};
10464 for(var jj = 0; jj < fl; jj++){
10466 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10467 this.ef[jj] = this.getJsonAccessor(map);
10471 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10472 if(s.totalProperty){
10473 var vt = parseInt(this.getTotal(o), 10);
10478 if(s.successProperty){
10479 var vs = this.getSuccess(o);
10480 if(vs === false || vs === 'false'){
10485 for(var i = 0; i < c; i++){
10488 var id = this.getId(n);
10489 for(var j = 0; j < fl; j++){
10491 var v = this.ef[j](n);
10493 Roo.log('missing convert for ' + f.name);
10497 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10499 var record = new Record(values, id);
10501 records[i] = record;
10507 totalRecords : totalRecords
10512 * Ext JS Library 1.1.1
10513 * Copyright(c) 2006-2007, Ext JS, LLC.
10515 * Originally Released Under LGPL - original licence link has changed is not relivant.
10518 * <script type="text/javascript">
10522 * @class Roo.data.ArrayReader
10523 * @extends Roo.data.DataReader
10524 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10525 * Each element of that Array represents a row of data fields. The
10526 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10527 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10531 var RecordDef = Roo.data.Record.create([
10532 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10533 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10535 var myReader = new Roo.data.ArrayReader({
10536 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10540 * This would consume an Array like this:
10542 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10544 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10546 * Create a new JsonReader
10547 * @param {Object} meta Metadata configuration options.
10548 * @param {Object} recordType Either an Array of field definition objects
10549 * as specified to {@link Roo.data.Record#create},
10550 * or an {@link Roo.data.Record} object
10551 * created using {@link Roo.data.Record#create}.
10553 Roo.data.ArrayReader = function(meta, recordType){
10554 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10557 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10559 * Create a data block containing Roo.data.Records from an XML document.
10560 * @param {Object} o An Array of row objects which represents the dataset.
10561 * @return {Object} data A data block which is used by an Roo.data.Store object as
10562 * a cache of Roo.data.Records.
10564 readRecords : function(o){
10565 var sid = this.meta ? this.meta.id : null;
10566 var recordType = this.recordType, fields = recordType.prototype.fields;
10569 for(var i = 0; i < root.length; i++){
10572 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10573 for(var j = 0, jlen = fields.length; j < jlen; j++){
10574 var f = fields.items[j];
10575 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10576 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10578 values[f.name] = v;
10580 var record = new recordType(values, id);
10582 records[records.length] = record;
10586 totalRecords : records.length
10595 * @class Roo.bootstrap.ComboBox
10596 * @extends Roo.bootstrap.TriggerField
10597 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10598 * @cfg {Boolean} append (true|false) default false
10599 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10600 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10601 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10602 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10603 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10605 * Create a new ComboBox.
10606 * @param {Object} config Configuration options
10608 Roo.bootstrap.ComboBox = function(config){
10609 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10613 * Fires when the dropdown list is expanded
10614 * @param {Roo.bootstrap.ComboBox} combo This combo box
10619 * Fires when the dropdown list is collapsed
10620 * @param {Roo.bootstrap.ComboBox} combo This combo box
10624 * @event beforeselect
10625 * Fires before a list item is selected. Return false to cancel the selection.
10626 * @param {Roo.bootstrap.ComboBox} combo This combo box
10627 * @param {Roo.data.Record} record The data record returned from the underlying store
10628 * @param {Number} index The index of the selected item in the dropdown list
10630 'beforeselect' : true,
10633 * Fires when a list item is selected
10634 * @param {Roo.bootstrap.ComboBox} combo This combo box
10635 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10636 * @param {Number} index The index of the selected item in the dropdown list
10640 * @event beforequery
10641 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10642 * The event object passed has these properties:
10643 * @param {Roo.bootstrap.ComboBox} combo This combo box
10644 * @param {String} query The query
10645 * @param {Boolean} forceAll true to force "all" query
10646 * @param {Boolean} cancel true to cancel the query
10647 * @param {Object} e The query event object
10649 'beforequery': true,
10652 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10653 * @param {Roo.bootstrap.ComboBox} combo This combo box
10658 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10659 * @param {Roo.bootstrap.ComboBox} combo This combo box
10660 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10665 * Fires when the remove value from the combobox array
10666 * @param {Roo.bootstrap.ComboBox} combo This combo box
10673 this.tickItems = [];
10675 this.selectedIndex = -1;
10676 if(this.mode == 'local'){
10677 if(config.queryDelay === undefined){
10678 this.queryDelay = 10;
10680 if(config.minChars === undefined){
10686 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10689 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10690 * rendering into an Roo.Editor, defaults to false)
10693 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10694 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10697 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10700 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10701 * the dropdown list (defaults to undefined, with no header element)
10705 * @cfg {String/Roo.Template} tpl The template to use to render the output
10709 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10711 listWidth: undefined,
10713 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10714 * mode = 'remote' or 'text' if mode = 'local')
10716 displayField: undefined,
10718 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10719 * mode = 'remote' or 'value' if mode = 'local').
10720 * Note: use of a valueField requires the user make a selection
10721 * in order for a value to be mapped.
10723 valueField: undefined,
10727 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10728 * field's data value (defaults to the underlying DOM element's name)
10730 hiddenName: undefined,
10732 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10736 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10738 selectedClass: 'active',
10741 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10745 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10746 * anchor positions (defaults to 'tl-bl')
10748 listAlign: 'tl-bl?',
10750 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10754 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10755 * query specified by the allQuery config option (defaults to 'query')
10757 triggerAction: 'query',
10759 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10760 * (defaults to 4, does not apply if editable = false)
10764 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10765 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10769 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10770 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10774 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10775 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10779 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10780 * when editable = true (defaults to false)
10782 selectOnFocus:false,
10784 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10786 queryParam: 'query',
10788 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10789 * when mode = 'remote' (defaults to 'Loading...')
10791 loadingText: 'Loading...',
10793 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10797 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10801 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10802 * traditional select (defaults to true)
10806 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10810 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10814 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10815 * listWidth has a higher value)
10819 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10820 * allow the user to set arbitrary text into the field (defaults to false)
10822 forceSelection:false,
10824 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10825 * if typeAhead = true (defaults to 250)
10827 typeAheadDelay : 250,
10829 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10830 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10832 valueNotFoundText : undefined,
10834 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10836 blockFocus : false,
10839 * @cfg {Boolean} disableClear Disable showing of clear button.
10841 disableClear : false,
10843 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10845 alwaysQuery : false,
10848 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10853 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10855 invalidClass : "has-warning",
10858 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10860 validClass : "has-success",
10872 btnPosition : 'right',
10873 triggerList : true,
10874 showToggleBtn : true,
10875 // element that contains real text value.. (when hidden is used..)
10877 getAutoCreate : function()
10884 if(!this.tickable){
10885 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10890 * ComboBox with tickable selections
10893 var align = this.labelAlign || this.parentLabelAlign();
10896 cls : 'form-group roo-combobox-tickable' //input-group
10902 cls : 'tickable-buttons',
10907 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10914 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10921 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10928 Roo.each(buttons.cn, function(c){
10930 c.cls += ' btn-' + _this.size;
10933 if (_this.disabled) {
10944 cls: 'form-hidden-field'
10948 cls: 'select2-choices',
10952 cls: 'select2-search-field',
10964 cls: 'select2-container input-group select2-container-multi',
10969 // cls: 'typeahead typeahead-long dropdown-menu',
10970 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10975 if(this.hasFeedback && !this.allowBlank){
10979 cls: 'glyphicon form-control-feedback'
10982 combobox.cn.push(feedback);
10985 if (align ==='left' && this.fieldLabel.length) {
10987 Roo.log("left and has label");
10993 cls : 'control-label col-sm-' + this.labelWidth,
10994 html : this.fieldLabel
10998 cls : "col-sm-" + (12 - this.labelWidth),
11005 } else if ( this.fieldLabel.length) {
11011 //cls : 'input-group-addon',
11012 html : this.fieldLabel
11022 Roo.log(" no label && no align");
11029 ['xs','sm','md','lg'].map(function(size){
11030 if (settings[size]) {
11031 cfg.cls += ' col-' + size + '-' + settings[size];
11040 initEvents: function()
11044 throw "can not find store for combo";
11046 this.store = Roo.factory(this.store, Roo.data);
11049 this.initTickableEvents();
11053 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11055 if(this.hiddenName){
11057 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11059 this.hiddenField.dom.value =
11060 this.hiddenValue !== undefined ? this.hiddenValue :
11061 this.value !== undefined ? this.value : '';
11063 // prevent input submission
11064 this.el.dom.removeAttribute('name');
11065 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11070 // this.el.dom.setAttribute('autocomplete', 'off');
11073 var cls = 'x-combo-list';
11075 //this.list = new Roo.Layer({
11076 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11082 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11083 _this.list.setWidth(lw);
11086 this.list.on('mouseover', this.onViewOver, this);
11087 this.list.on('mousemove', this.onViewMove, this);
11089 this.list.on('scroll', this.onViewScroll, this);
11092 this.list.swallowEvent('mousewheel');
11093 this.assetHeight = 0;
11096 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11097 this.assetHeight += this.header.getHeight();
11100 this.innerList = this.list.createChild({cls:cls+'-inner'});
11101 this.innerList.on('mouseover', this.onViewOver, this);
11102 this.innerList.on('mousemove', this.onViewMove, this);
11103 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11105 if(this.allowBlank && !this.pageSize && !this.disableClear){
11106 this.footer = this.list.createChild({cls:cls+'-ft'});
11107 this.pageTb = new Roo.Toolbar(this.footer);
11111 this.footer = this.list.createChild({cls:cls+'-ft'});
11112 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11113 {pageSize: this.pageSize});
11117 if (this.pageTb && this.allowBlank && !this.disableClear) {
11119 this.pageTb.add(new Roo.Toolbar.Fill(), {
11120 cls: 'x-btn-icon x-btn-clear',
11122 handler: function()
11125 _this.clearValue();
11126 _this.onSelect(false, -1);
11131 this.assetHeight += this.footer.getHeight();
11136 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11139 this.view = new Roo.View(this.list, this.tpl, {
11140 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11142 //this.view.wrapEl.setDisplayed(false);
11143 this.view.on('click', this.onViewClick, this);
11147 this.store.on('beforeload', this.onBeforeLoad, this);
11148 this.store.on('load', this.onLoad, this);
11149 this.store.on('loadexception', this.onLoadException, this);
11151 if(this.resizable){
11152 this.resizer = new Roo.Resizable(this.list, {
11153 pinned:true, handles:'se'
11155 this.resizer.on('resize', function(r, w, h){
11156 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11157 this.listWidth = w;
11158 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11159 this.restrictHeight();
11161 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11164 if(!this.editable){
11165 this.editable = true;
11166 this.setEditable(false);
11171 if (typeof(this.events.add.listeners) != 'undefined') {
11173 this.addicon = this.wrap.createChild(
11174 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11176 this.addicon.on('click', function(e) {
11177 this.fireEvent('add', this);
11180 if (typeof(this.events.edit.listeners) != 'undefined') {
11182 this.editicon = this.wrap.createChild(
11183 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11184 if (this.addicon) {
11185 this.editicon.setStyle('margin-left', '40px');
11187 this.editicon.on('click', function(e) {
11189 // we fire even if inothing is selected..
11190 this.fireEvent('edit', this, this.lastData );
11196 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11197 "up" : function(e){
11198 this.inKeyMode = true;
11202 "down" : function(e){
11203 if(!this.isExpanded()){
11204 this.onTriggerClick();
11206 this.inKeyMode = true;
11211 "enter" : function(e){
11212 // this.onViewClick();
11216 if(this.fireEvent("specialkey", this, e)){
11217 this.onViewClick(false);
11223 "esc" : function(e){
11227 "tab" : function(e){
11230 if(this.fireEvent("specialkey", this, e)){
11231 this.onViewClick(false);
11239 doRelay : function(foo, bar, hname){
11240 if(hname == 'down' || this.scope.isExpanded()){
11241 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11250 this.queryDelay = Math.max(this.queryDelay || 10,
11251 this.mode == 'local' ? 10 : 250);
11254 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11256 if(this.typeAhead){
11257 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11259 if(this.editable !== false){
11260 this.inputEl().on("keyup", this.onKeyUp, this);
11262 if(this.forceSelection){
11263 this.inputEl().on('blur', this.doForce, this);
11267 this.choices = this.el.select('ul.select2-choices', true).first();
11268 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11272 initTickableEvents: function()
11276 if(this.hiddenName){
11278 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11280 this.hiddenField.dom.value =
11281 this.hiddenValue !== undefined ? this.hiddenValue :
11282 this.value !== undefined ? this.value : '';
11284 // prevent input submission
11285 this.el.dom.removeAttribute('name');
11286 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11291 // this.list = this.el.select('ul.dropdown-menu',true).first();
11293 this.choices = this.el.select('ul.select2-choices', true).first();
11294 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11295 if(this.triggerList){
11296 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11299 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11300 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11302 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11303 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11305 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11306 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11308 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11309 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11310 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11313 this.cancelBtn.hide();
11318 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11319 _this.list.setWidth(lw);
11322 this.list.on('mouseover', this.onViewOver, this);
11323 this.list.on('mousemove', this.onViewMove, this);
11325 this.list.on('scroll', this.onViewScroll, this);
11328 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>';
11331 this.view = new Roo.View(this.list, this.tpl, {
11332 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11335 //this.view.wrapEl.setDisplayed(false);
11336 this.view.on('click', this.onViewClick, this);
11340 this.store.on('beforeload', this.onBeforeLoad, this);
11341 this.store.on('load', this.onLoad, this);
11342 this.store.on('loadexception', this.onLoadException, this);
11344 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11345 // "up" : function(e){
11346 // this.inKeyMode = true;
11347 // this.selectPrev();
11350 // "down" : function(e){
11351 // if(!this.isExpanded()){
11352 // this.onTriggerClick();
11354 // this.inKeyMode = true;
11355 // this.selectNext();
11359 // "enter" : function(e){
11360 //// this.onViewClick();
11362 // this.collapse();
11364 // if(this.fireEvent("specialkey", this, e)){
11365 // this.onViewClick(false);
11371 // "esc" : function(e){
11372 // this.collapse();
11375 // "tab" : function(e){
11376 // this.collapse();
11378 // if(this.fireEvent("specialkey", this, e)){
11379 // this.onViewClick(false);
11387 // doRelay : function(foo, bar, hname){
11388 // if(hname == 'down' || this.scope.isExpanded()){
11389 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11394 // forceKeyDown: true
11398 this.queryDelay = Math.max(this.queryDelay || 10,
11399 this.mode == 'local' ? 10 : 250);
11402 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11404 if(this.typeAhead){
11405 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11410 onDestroy : function(){
11412 this.view.setStore(null);
11413 this.view.el.removeAllListeners();
11414 this.view.el.remove();
11415 this.view.purgeListeners();
11418 this.list.dom.innerHTML = '';
11422 this.store.un('beforeload', this.onBeforeLoad, this);
11423 this.store.un('load', this.onLoad, this);
11424 this.store.un('loadexception', this.onLoadException, this);
11426 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11430 fireKey : function(e){
11431 if(e.isNavKeyPress() && !this.list.isVisible()){
11432 this.fireEvent("specialkey", this, e);
11437 onResize: function(w, h){
11438 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11440 // if(typeof w != 'number'){
11441 // // we do not handle it!?!?
11444 // var tw = this.trigger.getWidth();
11445 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11446 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11448 // this.inputEl().setWidth( this.adjustWidth('input', x));
11450 // //this.trigger.setStyle('left', x+'px');
11452 // if(this.list && this.listWidth === undefined){
11453 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11454 // this.list.setWidth(lw);
11455 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11463 * Allow or prevent the user from directly editing the field text. If false is passed,
11464 * the user will only be able to select from the items defined in the dropdown list. This method
11465 * is the runtime equivalent of setting the 'editable' config option at config time.
11466 * @param {Boolean} value True to allow the user to directly edit the field text
11468 setEditable : function(value){
11469 if(value == this.editable){
11472 this.editable = value;
11474 this.inputEl().dom.setAttribute('readOnly', true);
11475 this.inputEl().on('mousedown', this.onTriggerClick, this);
11476 this.inputEl().addClass('x-combo-noedit');
11478 this.inputEl().dom.setAttribute('readOnly', false);
11479 this.inputEl().un('mousedown', this.onTriggerClick, this);
11480 this.inputEl().removeClass('x-combo-noedit');
11486 onBeforeLoad : function(combo,opts){
11487 if(!this.hasFocus){
11491 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11493 this.restrictHeight();
11494 this.selectedIndex = -1;
11498 onLoad : function(){
11500 this.hasQuery = false;
11502 if(!this.hasFocus){
11506 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11507 this.loading.hide();
11510 if(this.store.getCount() > 0){
11512 // this.restrictHeight();
11513 if(this.lastQuery == this.allQuery){
11514 if(this.editable && !this.tickable){
11515 this.inputEl().dom.select();
11519 !this.selectByValue(this.value, true) &&
11520 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11521 this.store.lastOptions.add != true)
11523 this.select(0, true);
11526 if(this.autoFocus){
11529 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11530 this.taTask.delay(this.typeAheadDelay);
11534 this.onEmptyResults();
11540 onLoadException : function()
11542 this.hasQuery = false;
11544 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11545 this.loading.hide();
11549 Roo.log(this.store.reader.jsonData);
11550 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11552 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11558 onTypeAhead : function(){
11559 if(this.store.getCount() > 0){
11560 var r = this.store.getAt(0);
11561 var newValue = r.data[this.displayField];
11562 var len = newValue.length;
11563 var selStart = this.getRawValue().length;
11565 if(selStart != len){
11566 this.setRawValue(newValue);
11567 this.selectText(selStart, newValue.length);
11573 onSelect : function(record, index){
11575 if(this.fireEvent('beforeselect', this, record, index) !== false){
11577 this.setFromData(index > -1 ? record.data : false);
11580 this.fireEvent('select', this, record, index);
11585 * Returns the currently selected field value or empty string if no value is set.
11586 * @return {String} value The selected value
11588 getValue : function(){
11591 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11594 if(this.valueField){
11595 return typeof this.value != 'undefined' ? this.value : '';
11597 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11602 * Clears any text/value currently set in the field
11604 clearValue : function(){
11605 if(this.hiddenField){
11606 this.hiddenField.dom.value = '';
11609 this.setRawValue('');
11610 this.lastSelectionText = '';
11611 this.lastData = false;
11616 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11617 * will be displayed in the field. If the value does not match the data value of an existing item,
11618 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11619 * Otherwise the field will be blank (although the value will still be set).
11620 * @param {String} value The value to match
11622 setValue : function(v){
11629 if(this.valueField){
11630 var r = this.findRecord(this.valueField, v);
11632 text = r.data[this.displayField];
11633 }else if(this.valueNotFoundText !== undefined){
11634 text = this.valueNotFoundText;
11637 this.lastSelectionText = text;
11638 if(this.hiddenField){
11639 this.hiddenField.dom.value = v;
11641 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11645 * @property {Object} the last set data for the element
11650 * Sets the value of the field based on a object which is related to the record format for the store.
11651 * @param {Object} value the value to set as. or false on reset?
11653 setFromData : function(o){
11660 var dv = ''; // display value
11661 var vv = ''; // value value..
11663 if (this.displayField) {
11664 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11666 // this is an error condition!!!
11667 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11670 if(this.valueField){
11671 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11674 if(this.hiddenField){
11675 this.hiddenField.dom.value = vv;
11677 this.lastSelectionText = dv;
11678 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11682 // no hidden field.. - we store the value in 'value', but still display
11683 // display field!!!!
11684 this.lastSelectionText = dv;
11685 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11691 reset : function(){
11692 // overridden so that last data is reset..
11693 this.setValue(this.originalValue);
11694 this.clearInvalid();
11695 this.lastData = false;
11697 this.view.clearSelections();
11701 findRecord : function(prop, value){
11703 if(this.store.getCount() > 0){
11704 this.store.each(function(r){
11705 if(r.data[prop] == value){
11715 getName: function()
11717 // returns hidden if it's set..
11718 if (!this.rendered) {return ''};
11719 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11723 onViewMove : function(e, t){
11724 this.inKeyMode = false;
11728 onViewOver : function(e, t){
11729 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11732 var item = this.view.findItemFromChild(t);
11735 var index = this.view.indexOf(item);
11736 this.select(index, false);
11741 onViewClick : function(view, doFocus, el, e)
11743 var index = this.view.getSelectedIndexes()[0];
11745 var r = this.store.getAt(index);
11749 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11756 Roo.each(this.tickItems, function(v,k){
11758 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11759 _this.tickItems.splice(k, 1);
11769 this.tickItems.push(r.data);
11774 this.onSelect(r, index);
11776 if(doFocus !== false && !this.blockFocus){
11777 this.inputEl().focus();
11782 restrictHeight : function(){
11783 //this.innerList.dom.style.height = '';
11784 //var inner = this.innerList.dom;
11785 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11786 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11787 //this.list.beginUpdate();
11788 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11789 this.list.alignTo(this.inputEl(), this.listAlign);
11790 this.list.alignTo(this.inputEl(), this.listAlign);
11791 //this.list.endUpdate();
11795 onEmptyResults : function(){
11800 * Returns true if the dropdown list is expanded, else false.
11802 isExpanded : function(){
11803 return this.list.isVisible();
11807 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11808 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11809 * @param {String} value The data value of the item to select
11810 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11811 * selected item if it is not currently in view (defaults to true)
11812 * @return {Boolean} True if the value matched an item in the list, else false
11814 selectByValue : function(v, scrollIntoView){
11815 if(v !== undefined && v !== null){
11816 var r = this.findRecord(this.valueField || this.displayField, v);
11818 this.select(this.store.indexOf(r), scrollIntoView);
11826 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11827 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11828 * @param {Number} index The zero-based index of the list item to select
11829 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11830 * selected item if it is not currently in view (defaults to true)
11832 select : function(index, scrollIntoView){
11833 this.selectedIndex = index;
11834 this.view.select(index);
11835 if(scrollIntoView !== false){
11836 var el = this.view.getNode(index);
11837 if(el && !this.multiple && !this.tickable){
11838 this.list.scrollChildIntoView(el, false);
11844 selectNext : function(){
11845 var ct = this.store.getCount();
11847 if(this.selectedIndex == -1){
11849 }else if(this.selectedIndex < ct-1){
11850 this.select(this.selectedIndex+1);
11856 selectPrev : function(){
11857 var ct = this.store.getCount();
11859 if(this.selectedIndex == -1){
11861 }else if(this.selectedIndex != 0){
11862 this.select(this.selectedIndex-1);
11868 onKeyUp : function(e){
11869 if(this.editable !== false && !e.isSpecialKey()){
11870 this.lastKey = e.getKey();
11871 this.dqTask.delay(this.queryDelay);
11876 validateBlur : function(){
11877 return !this.list || !this.list.isVisible();
11881 initQuery : function(){
11882 this.doQuery(this.getRawValue());
11886 doForce : function(){
11887 if(this.inputEl().dom.value.length > 0){
11888 this.inputEl().dom.value =
11889 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11895 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11896 * query allowing the query action to be canceled if needed.
11897 * @param {String} query The SQL query to execute
11898 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11899 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11900 * saved in the current store (defaults to false)
11902 doQuery : function(q, forceAll){
11904 if(q === undefined || q === null){
11909 forceAll: forceAll,
11913 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11918 forceAll = qe.forceAll;
11919 if(forceAll === true || (q.length >= this.minChars)){
11921 this.hasQuery = true;
11923 if(this.lastQuery != q || this.alwaysQuery){
11924 this.lastQuery = q;
11925 if(this.mode == 'local'){
11926 this.selectedIndex = -1;
11928 this.store.clearFilter();
11930 this.store.filter(this.displayField, q);
11934 this.store.baseParams[this.queryParam] = q;
11936 var options = {params : this.getParams(q)};
11939 options.add = true;
11940 options.params.start = this.page * this.pageSize;
11943 this.store.load(options);
11945 * this code will make the page width larger, at the beginning, the list not align correctly,
11946 * we should expand the list on onLoad
11947 * so command out it
11952 this.selectedIndex = -1;
11957 this.loadNext = false;
11961 getParams : function(q){
11963 //p[this.queryParam] = q;
11967 p.limit = this.pageSize;
11973 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11975 collapse : function(){
11976 if(!this.isExpanded()){
11983 this.hasFocus = false;
11985 this.cancelBtn.hide();
11986 this.trigger.show();
11989 Roo.get(document).un('mousedown', this.collapseIf, this);
11990 Roo.get(document).un('mousewheel', this.collapseIf, this);
11991 if (!this.editable) {
11992 Roo.get(document).un('keydown', this.listKeyPress, this);
11994 this.fireEvent('collapse', this);
11998 collapseIf : function(e){
11999 var in_combo = e.within(this.el);
12000 var in_list = e.within(this.list);
12001 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12003 if (in_combo || in_list || is_list) {
12004 //e.stopPropagation();
12009 this.onTickableFooterButtonClick(e, false, false);
12017 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12019 expand : function(){
12021 if(this.isExpanded() || !this.hasFocus){
12025 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12026 this.list.setWidth(lw);
12033 this.restrictHeight();
12037 this.tickItems = Roo.apply([], this.item);
12040 this.cancelBtn.show();
12041 this.trigger.hide();
12045 Roo.get(document).on('mousedown', this.collapseIf, this);
12046 Roo.get(document).on('mousewheel', this.collapseIf, this);
12047 if (!this.editable) {
12048 Roo.get(document).on('keydown', this.listKeyPress, this);
12051 this.fireEvent('expand', this);
12055 // Implements the default empty TriggerField.onTriggerClick function
12056 onTriggerClick : function(e)
12058 Roo.log('trigger click');
12060 if(this.disabled || !this.triggerList){
12065 this.loadNext = false;
12067 if(this.isExpanded()){
12069 if (!this.blockFocus) {
12070 this.inputEl().focus();
12074 this.hasFocus = true;
12075 if(this.triggerAction == 'all') {
12076 this.doQuery(this.allQuery, true);
12078 this.doQuery(this.getRawValue());
12080 if (!this.blockFocus) {
12081 this.inputEl().focus();
12086 onTickableTriggerClick : function(e)
12093 this.loadNext = false;
12094 this.hasFocus = true;
12096 if(this.triggerAction == 'all') {
12097 this.doQuery(this.allQuery, true);
12099 this.doQuery(this.getRawValue());
12103 onSearchFieldClick : function(e)
12105 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12106 this.onTickableFooterButtonClick(e, false, false);
12110 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12115 this.loadNext = false;
12116 this.hasFocus = true;
12118 if(this.triggerAction == 'all') {
12119 this.doQuery(this.allQuery, true);
12121 this.doQuery(this.getRawValue());
12125 listKeyPress : function(e)
12127 //Roo.log('listkeypress');
12128 // scroll to first matching element based on key pres..
12129 if (e.isSpecialKey()) {
12132 var k = String.fromCharCode(e.getKey()).toUpperCase();
12135 var csel = this.view.getSelectedNodes();
12136 var cselitem = false;
12138 var ix = this.view.indexOf(csel[0]);
12139 cselitem = this.store.getAt(ix);
12140 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12146 this.store.each(function(v) {
12148 // start at existing selection.
12149 if (cselitem.id == v.id) {
12155 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12156 match = this.store.indexOf(v);
12162 if (match === false) {
12163 return true; // no more action?
12166 this.view.select(match);
12167 var sn = Roo.get(this.view.getSelectedNodes()[0])
12168 sn.scrollIntoView(sn.dom.parentNode, false);
12171 onViewScroll : function(e, t){
12173 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){
12177 this.hasQuery = true;
12179 this.loading = this.list.select('.loading', true).first();
12181 if(this.loading === null){
12182 this.list.createChild({
12184 cls: 'loading select2-more-results select2-active',
12185 html: 'Loading more results...'
12188 this.loading = this.list.select('.loading', true).first();
12190 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12192 this.loading.hide();
12195 this.loading.show();
12200 this.loadNext = true;
12202 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12207 addItem : function(o)
12209 var dv = ''; // display value
12211 if (this.displayField) {
12212 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12214 // this is an error condition!!!
12215 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12222 var choice = this.choices.createChild({
12224 cls: 'select2-search-choice',
12233 cls: 'select2-search-choice-close',
12238 }, this.searchField);
12240 var close = choice.select('a.select2-search-choice-close', true).first()
12242 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12250 this.inputEl().dom.value = '';
12255 onRemoveItem : function(e, _self, o)
12257 e.preventDefault();
12259 this.lastItem = Roo.apply([], this.item);
12261 var index = this.item.indexOf(o.data) * 1;
12264 Roo.log('not this item?!');
12268 this.item.splice(index, 1);
12273 this.fireEvent('remove', this, e);
12279 syncValue : function()
12281 if(!this.item.length){
12288 Roo.each(this.item, function(i){
12289 if(_this.valueField){
12290 value.push(i[_this.valueField]);
12297 this.value = value.join(',');
12299 if(this.hiddenField){
12300 this.hiddenField.dom.value = this.value;
12304 clearItem : function()
12306 if(!this.multiple){
12312 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12321 inputEl: function ()
12324 return this.searchField;
12326 return this.el.select('input.form-control',true).first();
12330 onTickableFooterButtonClick : function(e, btn, el)
12332 e.preventDefault();
12334 this.lastItem = Roo.apply([], this.item);
12336 if(btn && btn.name == 'cancel'){
12337 this.tickItems = Roo.apply([], this.item);
12346 Roo.each(this.tickItems, function(o){
12354 validate : function()
12356 var v = this.getRawValue();
12359 v = this.getValue();
12362 if(this.disabled || this.allowBlank || v.length){
12367 this.markInvalid();
12374 * @cfg {Boolean} grow
12378 * @cfg {Number} growMin
12382 * @cfg {Number} growMax
12392 * Ext JS Library 1.1.1
12393 * Copyright(c) 2006-2007, Ext JS, LLC.
12395 * Originally Released Under LGPL - original licence link has changed is not relivant.
12398 * <script type="text/javascript">
12403 * @extends Roo.util.Observable
12404 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12405 * This class also supports single and multi selection modes. <br>
12406 * Create a data model bound view:
12408 var store = new Roo.data.Store(...);
12410 var view = new Roo.View({
12412 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12414 singleSelect: true,
12415 selectedClass: "ydataview-selected",
12419 // listen for node click?
12420 view.on("click", function(vw, index, node, e){
12421 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12425 dataModel.load("foobar.xml");
12427 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12429 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12430 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12432 * Note: old style constructor is still suported (container, template, config)
12435 * Create a new View
12436 * @param {Object} config The config object
12439 Roo.View = function(config, depreciated_tpl, depreciated_config){
12441 this.parent = false;
12443 if (typeof(depreciated_tpl) == 'undefined') {
12444 // new way.. - universal constructor.
12445 Roo.apply(this, config);
12446 this.el = Roo.get(this.el);
12449 this.el = Roo.get(config);
12450 this.tpl = depreciated_tpl;
12451 Roo.apply(this, depreciated_config);
12453 this.wrapEl = this.el.wrap().wrap();
12454 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12457 if(typeof(this.tpl) == "string"){
12458 this.tpl = new Roo.Template(this.tpl);
12460 // support xtype ctors..
12461 this.tpl = new Roo.factory(this.tpl, Roo);
12465 this.tpl.compile();
12470 * @event beforeclick
12471 * Fires before a click is processed. Returns false to cancel the default action.
12472 * @param {Roo.View} this
12473 * @param {Number} index The index of the target node
12474 * @param {HTMLElement} node The target node
12475 * @param {Roo.EventObject} e The raw event object
12477 "beforeclick" : true,
12480 * Fires when a template node is clicked.
12481 * @param {Roo.View} this
12482 * @param {Number} index The index of the target node
12483 * @param {HTMLElement} node The target node
12484 * @param {Roo.EventObject} e The raw event object
12489 * Fires when a template node is double clicked.
12490 * @param {Roo.View} this
12491 * @param {Number} index The index of the target node
12492 * @param {HTMLElement} node The target node
12493 * @param {Roo.EventObject} e The raw event object
12497 * @event contextmenu
12498 * Fires when a template node is right clicked.
12499 * @param {Roo.View} this
12500 * @param {Number} index The index of the target node
12501 * @param {HTMLElement} node The target node
12502 * @param {Roo.EventObject} e The raw event object
12504 "contextmenu" : true,
12506 * @event selectionchange
12507 * Fires when the selected nodes change.
12508 * @param {Roo.View} this
12509 * @param {Array} selections Array of the selected nodes
12511 "selectionchange" : true,
12514 * @event beforeselect
12515 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12516 * @param {Roo.View} this
12517 * @param {HTMLElement} node The node to be selected
12518 * @param {Array} selections Array of currently selected nodes
12520 "beforeselect" : true,
12522 * @event preparedata
12523 * Fires on every row to render, to allow you to change the data.
12524 * @param {Roo.View} this
12525 * @param {Object} data to be rendered (change this)
12527 "preparedata" : true
12535 "click": this.onClick,
12536 "dblclick": this.onDblClick,
12537 "contextmenu": this.onContextMenu,
12541 this.selections = [];
12543 this.cmp = new Roo.CompositeElementLite([]);
12545 this.store = Roo.factory(this.store, Roo.data);
12546 this.setStore(this.store, true);
12549 if ( this.footer && this.footer.xtype) {
12551 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12553 this.footer.dataSource = this.store
12554 this.footer.container = fctr;
12555 this.footer = Roo.factory(this.footer, Roo);
12556 fctr.insertFirst(this.el);
12558 // this is a bit insane - as the paging toolbar seems to detach the el..
12559 // dom.parentNode.parentNode.parentNode
12560 // they get detached?
12564 Roo.View.superclass.constructor.call(this);
12569 Roo.extend(Roo.View, Roo.util.Observable, {
12572 * @cfg {Roo.data.Store} store Data store to load data from.
12577 * @cfg {String|Roo.Element} el The container element.
12582 * @cfg {String|Roo.Template} tpl The template used by this View
12586 * @cfg {String} dataName the named area of the template to use as the data area
12587 * Works with domtemplates roo-name="name"
12591 * @cfg {String} selectedClass The css class to add to selected nodes
12593 selectedClass : "x-view-selected",
12595 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12600 * @cfg {String} text to display on mask (default Loading)
12604 * @cfg {Boolean} multiSelect Allow multiple selection
12606 multiSelect : false,
12608 * @cfg {Boolean} singleSelect Allow single selection
12610 singleSelect: false,
12613 * @cfg {Boolean} toggleSelect - selecting
12615 toggleSelect : false,
12618 * @cfg {Boolean} tickable - selecting
12623 * Returns the element this view is bound to.
12624 * @return {Roo.Element}
12626 getEl : function(){
12627 return this.wrapEl;
12633 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12635 refresh : function(){
12636 //Roo.log('refresh');
12639 // if we are using something like 'domtemplate', then
12640 // the what gets used is:
12641 // t.applySubtemplate(NAME, data, wrapping data..)
12642 // the outer template then get' applied with
12643 // the store 'extra data'
12644 // and the body get's added to the
12645 // roo-name="data" node?
12646 // <span class='roo-tpl-{name}'></span> ?????
12650 this.clearSelections();
12651 this.el.update("");
12653 var records = this.store.getRange();
12654 if(records.length < 1) {
12656 // is this valid?? = should it render a template??
12658 this.el.update(this.emptyText);
12662 if (this.dataName) {
12663 this.el.update(t.apply(this.store.meta)); //????
12664 el = this.el.child('.roo-tpl-' + this.dataName);
12667 for(var i = 0, len = records.length; i < len; i++){
12668 var data = this.prepareData(records[i].data, i, records[i]);
12669 this.fireEvent("preparedata", this, data, i, records[i]);
12671 var d = Roo.apply({}, data);
12674 Roo.apply(d, {'roo-id' : Roo.id()});
12678 Roo.each(this.parent.item, function(item){
12679 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12682 Roo.apply(d, {'roo-data-checked' : 'checked'});
12686 html[html.length] = Roo.util.Format.trim(
12688 t.applySubtemplate(this.dataName, d, this.store.meta) :
12695 el.update(html.join(""));
12696 this.nodes = el.dom.childNodes;
12697 this.updateIndexes(0);
12702 * Function to override to reformat the data that is sent to
12703 * the template for each node.
12704 * DEPRICATED - use the preparedata event handler.
12705 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12706 * a JSON object for an UpdateManager bound view).
12708 prepareData : function(data, index, record)
12710 this.fireEvent("preparedata", this, data, index, record);
12714 onUpdate : function(ds, record){
12715 // Roo.log('on update');
12716 this.clearSelections();
12717 var index = this.store.indexOf(record);
12718 var n = this.nodes[index];
12719 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12720 n.parentNode.removeChild(n);
12721 this.updateIndexes(index, index);
12727 onAdd : function(ds, records, index)
12729 //Roo.log(['on Add', ds, records, index] );
12730 this.clearSelections();
12731 if(this.nodes.length == 0){
12735 var n = this.nodes[index];
12736 for(var i = 0, len = records.length; i < len; i++){
12737 var d = this.prepareData(records[i].data, i, records[i]);
12739 this.tpl.insertBefore(n, d);
12742 this.tpl.append(this.el, d);
12745 this.updateIndexes(index);
12748 onRemove : function(ds, record, index){
12749 // Roo.log('onRemove');
12750 this.clearSelections();
12751 var el = this.dataName ?
12752 this.el.child('.roo-tpl-' + this.dataName) :
12755 el.dom.removeChild(this.nodes[index]);
12756 this.updateIndexes(index);
12760 * Refresh an individual node.
12761 * @param {Number} index
12763 refreshNode : function(index){
12764 this.onUpdate(this.store, this.store.getAt(index));
12767 updateIndexes : function(startIndex, endIndex){
12768 var ns = this.nodes;
12769 startIndex = startIndex || 0;
12770 endIndex = endIndex || ns.length - 1;
12771 for(var i = startIndex; i <= endIndex; i++){
12772 ns[i].nodeIndex = i;
12777 * Changes the data store this view uses and refresh the view.
12778 * @param {Store} store
12780 setStore : function(store, initial){
12781 if(!initial && this.store){
12782 this.store.un("datachanged", this.refresh);
12783 this.store.un("add", this.onAdd);
12784 this.store.un("remove", this.onRemove);
12785 this.store.un("update", this.onUpdate);
12786 this.store.un("clear", this.refresh);
12787 this.store.un("beforeload", this.onBeforeLoad);
12788 this.store.un("load", this.onLoad);
12789 this.store.un("loadexception", this.onLoad);
12793 store.on("datachanged", this.refresh, this);
12794 store.on("add", this.onAdd, this);
12795 store.on("remove", this.onRemove, this);
12796 store.on("update", this.onUpdate, this);
12797 store.on("clear", this.refresh, this);
12798 store.on("beforeload", this.onBeforeLoad, this);
12799 store.on("load", this.onLoad, this);
12800 store.on("loadexception", this.onLoad, this);
12808 * onbeforeLoad - masks the loading area.
12811 onBeforeLoad : function(store,opts)
12813 //Roo.log('onBeforeLoad');
12815 this.el.update("");
12817 this.el.mask(this.mask ? this.mask : "Loading" );
12819 onLoad : function ()
12826 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12827 * @param {HTMLElement} node
12828 * @return {HTMLElement} The template node
12830 findItemFromChild : function(node){
12831 var el = this.dataName ?
12832 this.el.child('.roo-tpl-' + this.dataName,true) :
12835 if(!node || node.parentNode == el){
12838 var p = node.parentNode;
12839 while(p && p != el){
12840 if(p.parentNode == el){
12849 onClick : function(e){
12850 var item = this.findItemFromChild(e.getTarget());
12852 var index = this.indexOf(item);
12853 if(this.onItemClick(item, index, e) !== false){
12854 this.fireEvent("click", this, index, item, e);
12857 this.clearSelections();
12862 onContextMenu : function(e){
12863 var item = this.findItemFromChild(e.getTarget());
12865 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12870 onDblClick : function(e){
12871 var item = this.findItemFromChild(e.getTarget());
12873 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12877 onItemClick : function(item, index, e)
12879 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12882 if (this.toggleSelect) {
12883 var m = this.isSelected(item) ? 'unselect' : 'select';
12886 _t[m](item, true, false);
12889 if(this.multiSelect || this.singleSelect){
12890 if(this.multiSelect && e.shiftKey && this.lastSelection){
12891 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12893 this.select(item, this.multiSelect && e.ctrlKey);
12894 this.lastSelection = item;
12897 if(!this.tickable){
12898 e.preventDefault();
12906 * Get the number of selected nodes.
12909 getSelectionCount : function(){
12910 return this.selections.length;
12914 * Get the currently selected nodes.
12915 * @return {Array} An array of HTMLElements
12917 getSelectedNodes : function(){
12918 return this.selections;
12922 * Get the indexes of the selected nodes.
12925 getSelectedIndexes : function(){
12926 var indexes = [], s = this.selections;
12927 for(var i = 0, len = s.length; i < len; i++){
12928 indexes.push(s[i].nodeIndex);
12934 * Clear all selections
12935 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12937 clearSelections : function(suppressEvent){
12938 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12939 this.cmp.elements = this.selections;
12940 this.cmp.removeClass(this.selectedClass);
12941 this.selections = [];
12942 if(!suppressEvent){
12943 this.fireEvent("selectionchange", this, this.selections);
12949 * Returns true if the passed node is selected
12950 * @param {HTMLElement/Number} node The node or node index
12951 * @return {Boolean}
12953 isSelected : function(node){
12954 var s = this.selections;
12958 node = this.getNode(node);
12959 return s.indexOf(node) !== -1;
12964 * @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
12965 * @param {Boolean} keepExisting (optional) true to keep existing selections
12966 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12968 select : function(nodeInfo, keepExisting, suppressEvent){
12969 if(nodeInfo instanceof Array){
12971 this.clearSelections(true);
12973 for(var i = 0, len = nodeInfo.length; i < len; i++){
12974 this.select(nodeInfo[i], true, true);
12978 var node = this.getNode(nodeInfo);
12979 if(!node || this.isSelected(node)){
12980 return; // already selected.
12983 this.clearSelections(true);
12986 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12987 Roo.fly(node).addClass(this.selectedClass);
12988 this.selections.push(node);
12989 if(!suppressEvent){
12990 this.fireEvent("selectionchange", this, this.selections);
12998 * @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
12999 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13000 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13002 unselect : function(nodeInfo, keepExisting, suppressEvent)
13004 if(nodeInfo instanceof Array){
13005 Roo.each(this.selections, function(s) {
13006 this.unselect(s, nodeInfo);
13010 var node = this.getNode(nodeInfo);
13011 if(!node || !this.isSelected(node)){
13012 //Roo.log("not selected");
13013 return; // not selected.
13017 Roo.each(this.selections, function(s) {
13019 Roo.fly(node).removeClass(this.selectedClass);
13026 this.selections= ns;
13027 this.fireEvent("selectionchange", this, this.selections);
13031 * Gets a template node.
13032 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13033 * @return {HTMLElement} The node or null if it wasn't found
13035 getNode : function(nodeInfo){
13036 if(typeof nodeInfo == "string"){
13037 return document.getElementById(nodeInfo);
13038 }else if(typeof nodeInfo == "number"){
13039 return this.nodes[nodeInfo];
13045 * Gets a range template nodes.
13046 * @param {Number} startIndex
13047 * @param {Number} endIndex
13048 * @return {Array} An array of nodes
13050 getNodes : function(start, end){
13051 var ns = this.nodes;
13052 start = start || 0;
13053 end = typeof end == "undefined" ? ns.length - 1 : end;
13056 for(var i = start; i <= end; i++){
13060 for(var i = start; i >= end; i--){
13068 * Finds the index of the passed node
13069 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13070 * @return {Number} The index of the node or -1
13072 indexOf : function(node){
13073 node = this.getNode(node);
13074 if(typeof node.nodeIndex == "number"){
13075 return node.nodeIndex;
13077 var ns = this.nodes;
13078 for(var i = 0, len = ns.length; i < len; i++){
13089 * based on jquery fullcalendar
13093 Roo.bootstrap = Roo.bootstrap || {};
13095 * @class Roo.bootstrap.Calendar
13096 * @extends Roo.bootstrap.Component
13097 * Bootstrap Calendar class
13098 * @cfg {Boolean} loadMask (true|false) default false
13099 * @cfg {Object} header generate the user specific header of the calendar, default false
13102 * Create a new Container
13103 * @param {Object} config The config object
13108 Roo.bootstrap.Calendar = function(config){
13109 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13113 * Fires when a date is selected
13114 * @param {DatePicker} this
13115 * @param {Date} date The selected date
13119 * @event monthchange
13120 * Fires when the displayed month changes
13121 * @param {DatePicker} this
13122 * @param {Date} date The selected month
13124 'monthchange': true,
13126 * @event evententer
13127 * Fires when mouse over an event
13128 * @param {Calendar} this
13129 * @param {event} Event
13131 'evententer': true,
13133 * @event eventleave
13134 * Fires when the mouse leaves an
13135 * @param {Calendar} this
13138 'eventleave': true,
13140 * @event eventclick
13141 * Fires when the mouse click an
13142 * @param {Calendar} this
13151 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13154 * @cfg {Number} startDay
13155 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13163 getAutoCreate : function(){
13166 var fc_button = function(name, corner, style, content ) {
13167 return Roo.apply({},{
13169 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13171 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13174 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13185 style : 'width:100%',
13192 cls : 'fc-header-left',
13194 fc_button('prev', 'left', 'arrow', '‹' ),
13195 fc_button('next', 'right', 'arrow', '›' ),
13196 { tag: 'span', cls: 'fc-header-space' },
13197 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13205 cls : 'fc-header-center',
13209 cls: 'fc-header-title',
13212 html : 'month / year'
13220 cls : 'fc-header-right',
13222 /* fc_button('month', 'left', '', 'month' ),
13223 fc_button('week', '', '', 'week' ),
13224 fc_button('day', 'right', '', 'day' )
13236 header = this.header;
13239 var cal_heads = function() {
13241 // fixme - handle this.
13243 for (var i =0; i < Date.dayNames.length; i++) {
13244 var d = Date.dayNames[i];
13247 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13248 html : d.substring(0,3)
13252 ret[0].cls += ' fc-first';
13253 ret[6].cls += ' fc-last';
13256 var cal_cell = function(n) {
13259 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13264 cls: 'fc-day-number',
13268 cls: 'fc-day-content',
13272 style: 'position: relative;' // height: 17px;
13284 var cal_rows = function() {
13287 for (var r = 0; r < 6; r++) {
13294 for (var i =0; i < Date.dayNames.length; i++) {
13295 var d = Date.dayNames[i];
13296 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13299 row.cn[0].cls+=' fc-first';
13300 row.cn[0].cn[0].style = 'min-height:90px';
13301 row.cn[6].cls+=' fc-last';
13305 ret[0].cls += ' fc-first';
13306 ret[4].cls += ' fc-prev-last';
13307 ret[5].cls += ' fc-last';
13314 cls: 'fc-border-separate',
13315 style : 'width:100%',
13323 cls : 'fc-first fc-last',
13341 cls : 'fc-content',
13342 style : "position: relative;",
13345 cls : 'fc-view fc-view-month fc-grid',
13346 style : 'position: relative',
13347 unselectable : 'on',
13350 cls : 'fc-event-container',
13351 style : 'position:absolute;z-index:8;top:0;left:0;'
13369 initEvents : function()
13372 throw "can not find store for calendar";
13378 style: "text-align:center",
13382 style: "background-color:white;width:50%;margin:250 auto",
13386 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13397 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13399 var size = this.el.select('.fc-content', true).first().getSize();
13400 this.maskEl.setSize(size.width, size.height);
13401 this.maskEl.enableDisplayMode("block");
13402 if(!this.loadMask){
13403 this.maskEl.hide();
13406 this.store = Roo.factory(this.store, Roo.data);
13407 this.store.on('load', this.onLoad, this);
13408 this.store.on('beforeload', this.onBeforeLoad, this);
13412 this.cells = this.el.select('.fc-day',true);
13413 //Roo.log(this.cells);
13414 this.textNodes = this.el.query('.fc-day-number');
13415 this.cells.addClassOnOver('fc-state-hover');
13417 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13418 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13419 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13420 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13422 this.on('monthchange', this.onMonthChange, this);
13424 this.update(new Date().clearTime());
13427 resize : function() {
13428 var sz = this.el.getSize();
13430 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13431 this.el.select('.fc-day-content div',true).setHeight(34);
13436 showPrevMonth : function(e){
13437 this.update(this.activeDate.add("mo", -1));
13439 showToday : function(e){
13440 this.update(new Date().clearTime());
13443 showNextMonth : function(e){
13444 this.update(this.activeDate.add("mo", 1));
13448 showPrevYear : function(){
13449 this.update(this.activeDate.add("y", -1));
13453 showNextYear : function(){
13454 this.update(this.activeDate.add("y", 1));
13459 update : function(date)
13461 var vd = this.activeDate;
13462 this.activeDate = date;
13463 // if(vd && this.el){
13464 // var t = date.getTime();
13465 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13466 // Roo.log('using add remove');
13468 // this.fireEvent('monthchange', this, date);
13470 // this.cells.removeClass("fc-state-highlight");
13471 // this.cells.each(function(c){
13472 // if(c.dateValue == t){
13473 // c.addClass("fc-state-highlight");
13474 // setTimeout(function(){
13475 // try{c.dom.firstChild.focus();}catch(e){}
13485 var days = date.getDaysInMonth();
13487 var firstOfMonth = date.getFirstDateOfMonth();
13488 var startingPos = firstOfMonth.getDay()-this.startDay;
13490 if(startingPos < this.startDay){
13494 var pm = date.add(Date.MONTH, -1);
13495 var prevStart = pm.getDaysInMonth()-startingPos;
13497 this.cells = this.el.select('.fc-day',true);
13498 this.textNodes = this.el.query('.fc-day-number');
13499 this.cells.addClassOnOver('fc-state-hover');
13501 var cells = this.cells.elements;
13502 var textEls = this.textNodes;
13504 Roo.each(cells, function(cell){
13505 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13508 days += startingPos;
13510 // convert everything to numbers so it's fast
13511 var day = 86400000;
13512 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13515 //Roo.log(prevStart);
13517 var today = new Date().clearTime().getTime();
13518 var sel = date.clearTime().getTime();
13519 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13520 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13521 var ddMatch = this.disabledDatesRE;
13522 var ddText = this.disabledDatesText;
13523 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13524 var ddaysText = this.disabledDaysText;
13525 var format = this.format;
13527 var setCellClass = function(cal, cell){
13531 //Roo.log('set Cell Class');
13533 var t = d.getTime();
13537 cell.dateValue = t;
13539 cell.className += " fc-today";
13540 cell.className += " fc-state-highlight";
13541 cell.title = cal.todayText;
13544 // disable highlight in other month..
13545 //cell.className += " fc-state-highlight";
13550 cell.className = " fc-state-disabled";
13551 cell.title = cal.minText;
13555 cell.className = " fc-state-disabled";
13556 cell.title = cal.maxText;
13560 if(ddays.indexOf(d.getDay()) != -1){
13561 cell.title = ddaysText;
13562 cell.className = " fc-state-disabled";
13565 if(ddMatch && format){
13566 var fvalue = d.dateFormat(format);
13567 if(ddMatch.test(fvalue)){
13568 cell.title = ddText.replace("%0", fvalue);
13569 cell.className = " fc-state-disabled";
13573 if (!cell.initialClassName) {
13574 cell.initialClassName = cell.dom.className;
13577 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13582 for(; i < startingPos; i++) {
13583 textEls[i].innerHTML = (++prevStart);
13584 d.setDate(d.getDate()+1);
13586 cells[i].className = "fc-past fc-other-month";
13587 setCellClass(this, cells[i]);
13592 for(; i < days; i++){
13593 intDay = i - startingPos + 1;
13594 textEls[i].innerHTML = (intDay);
13595 d.setDate(d.getDate()+1);
13597 cells[i].className = ''; // "x-date-active";
13598 setCellClass(this, cells[i]);
13602 for(; i < 42; i++) {
13603 textEls[i].innerHTML = (++extraDays);
13604 d.setDate(d.getDate()+1);
13606 cells[i].className = "fc-future fc-other-month";
13607 setCellClass(this, cells[i]);
13610 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13612 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13614 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13615 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13617 if(totalRows != 6){
13618 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13619 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13622 this.fireEvent('monthchange', this, date);
13626 if(!this.internalRender){
13627 var main = this.el.dom.firstChild;
13628 var w = main.offsetWidth;
13629 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13630 Roo.fly(main).setWidth(w);
13631 this.internalRender = true;
13632 // opera does not respect the auto grow header center column
13633 // then, after it gets a width opera refuses to recalculate
13634 // without a second pass
13635 if(Roo.isOpera && !this.secondPass){
13636 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13637 this.secondPass = true;
13638 this.update.defer(10, this, [date]);
13645 findCell : function(dt) {
13646 dt = dt.clearTime().getTime();
13648 this.cells.each(function(c){
13649 //Roo.log("check " +c.dateValue + '?=' + dt);
13650 if(c.dateValue == dt){
13660 findCells : function(ev) {
13661 var s = ev.start.clone().clearTime().getTime();
13663 var e= ev.end.clone().clearTime().getTime();
13666 this.cells.each(function(c){
13667 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13669 if(c.dateValue > e){
13672 if(c.dateValue < s){
13681 // findBestRow: function(cells)
13685 // for (var i =0 ; i < cells.length;i++) {
13686 // ret = Math.max(cells[i].rows || 0,ret);
13693 addItem : function(ev)
13695 // look for vertical location slot in
13696 var cells = this.findCells(ev);
13698 // ev.row = this.findBestRow(cells);
13700 // work out the location.
13704 for(var i =0; i < cells.length; i++) {
13706 cells[i].row = cells[0].row;
13709 cells[i].row = cells[i].row + 1;
13719 if (crow.start.getY() == cells[i].getY()) {
13721 crow.end = cells[i];
13738 cells[0].events.push(ev);
13740 this.calevents.push(ev);
13743 clearEvents: function() {
13745 if(!this.calevents){
13749 Roo.each(this.cells.elements, function(c){
13755 Roo.each(this.calevents, function(e) {
13756 Roo.each(e.els, function(el) {
13757 el.un('mouseenter' ,this.onEventEnter, this);
13758 el.un('mouseleave' ,this.onEventLeave, this);
13763 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13769 renderEvents: function()
13773 this.cells.each(function(c) {
13782 if(c.row != c.events.length){
13783 r = 4 - (4 - (c.row - c.events.length));
13786 c.events = ev.slice(0, r);
13787 c.more = ev.slice(r);
13789 if(c.more.length && c.more.length == 1){
13790 c.events.push(c.more.pop());
13793 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13797 this.cells.each(function(c) {
13799 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13802 for (var e = 0; e < c.events.length; e++){
13803 var ev = c.events[e];
13804 var rows = ev.rows;
13806 for(var i = 0; i < rows.length; i++) {
13808 // how many rows should it span..
13811 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13812 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13814 unselectable : "on",
13817 cls: 'fc-event-inner',
13821 // cls: 'fc-event-time',
13822 // html : cells.length > 1 ? '' : ev.time
13826 cls: 'fc-event-title',
13827 html : String.format('{0}', ev.title)
13834 cls: 'ui-resizable-handle ui-resizable-e',
13835 html : '  '
13842 cfg.cls += ' fc-event-start';
13844 if ((i+1) == rows.length) {
13845 cfg.cls += ' fc-event-end';
13848 var ctr = _this.el.select('.fc-event-container',true).first();
13849 var cg = ctr.createChild(cfg);
13851 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13852 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13854 var r = (c.more.length) ? 1 : 0;
13855 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13856 cg.setWidth(ebox.right - sbox.x -2);
13858 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13859 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13860 cg.on('click', _this.onEventClick, _this, ev);
13871 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13872 style : 'position: absolute',
13873 unselectable : "on",
13876 cls: 'fc-event-inner',
13880 cls: 'fc-event-title',
13888 cls: 'ui-resizable-handle ui-resizable-e',
13889 html : '  '
13895 var ctr = _this.el.select('.fc-event-container',true).first();
13896 var cg = ctr.createChild(cfg);
13898 var sbox = c.select('.fc-day-content',true).first().getBox();
13899 var ebox = c.select('.fc-day-content',true).first().getBox();
13901 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13902 cg.setWidth(ebox.right - sbox.x -2);
13904 cg.on('click', _this.onMoreEventClick, _this, c.more);
13914 onEventEnter: function (e, el,event,d) {
13915 this.fireEvent('evententer', this, el, event);
13918 onEventLeave: function (e, el,event,d) {
13919 this.fireEvent('eventleave', this, el, event);
13922 onEventClick: function (e, el,event,d) {
13923 this.fireEvent('eventclick', this, el, event);
13926 onMonthChange: function () {
13930 onMoreEventClick: function(e, el, more)
13934 this.calpopover.placement = 'right';
13935 this.calpopover.setTitle('More');
13937 this.calpopover.setContent('');
13939 var ctr = this.calpopover.el.select('.popover-content', true).first();
13941 Roo.each(more, function(m){
13943 cls : 'fc-event-hori fc-event-draggable',
13946 var cg = ctr.createChild(cfg);
13948 cg.on('click', _this.onEventClick, _this, m);
13951 this.calpopover.show(el);
13956 onLoad: function ()
13958 this.calevents = [];
13961 if(this.store.getCount() > 0){
13962 this.store.data.each(function(d){
13965 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13966 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13967 time : d.data.start_time,
13968 title : d.data.title,
13969 description : d.data.description,
13970 venue : d.data.venue
13975 this.renderEvents();
13977 if(this.calevents.length && this.loadMask){
13978 this.maskEl.hide();
13982 onBeforeLoad: function()
13984 this.clearEvents();
13986 this.maskEl.show();
14000 * @class Roo.bootstrap.Popover
14001 * @extends Roo.bootstrap.Component
14002 * Bootstrap Popover class
14003 * @cfg {String} html contents of the popover (or false to use children..)
14004 * @cfg {String} title of popover (or false to hide)
14005 * @cfg {String} placement how it is placed
14006 * @cfg {String} trigger click || hover (or false to trigger manually)
14007 * @cfg {String} over what (parent or false to trigger manually.)
14008 * @cfg {Number} delay - delay before showing
14011 * Create a new Popover
14012 * @param {Object} config The config object
14015 Roo.bootstrap.Popover = function(config){
14016 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14019 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14021 title: 'Fill in a title',
14024 placement : 'right',
14025 trigger : 'hover', // hover
14031 can_build_overlaid : false,
14033 getChildContainer : function()
14035 return this.el.select('.popover-content',true).first();
14038 getAutoCreate : function(){
14039 Roo.log('make popover?');
14041 cls : 'popover roo-dynamic',
14042 style: 'display:block',
14048 cls : 'popover-inner',
14052 cls: 'popover-title',
14056 cls : 'popover-content',
14067 setTitle: function(str)
14069 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14071 setContent: function(str)
14073 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14075 // as it get's added to the bottom of the page.
14076 onRender : function(ct, position)
14078 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14080 var cfg = Roo.apply({}, this.getAutoCreate());
14084 cfg.cls += ' ' + this.cls;
14087 cfg.style = this.style;
14089 Roo.log("adding to ")
14090 this.el = Roo.get(document.body).createChild(cfg, position);
14096 initEvents : function()
14098 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14099 this.el.enableDisplayMode('block');
14101 if (this.over === false) {
14104 if (this.triggers === false) {
14107 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14108 var triggers = this.trigger ? this.trigger.split(' ') : [];
14109 Roo.each(triggers, function(trigger) {
14111 if (trigger == 'click') {
14112 on_el.on('click', this.toggle, this);
14113 } else if (trigger != 'manual') {
14114 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14115 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14117 on_el.on(eventIn ,this.enter, this);
14118 on_el.on(eventOut, this.leave, this);
14129 toggle : function () {
14130 this.hoverState == 'in' ? this.leave() : this.enter();
14133 enter : function () {
14136 clearTimeout(this.timeout);
14138 this.hoverState = 'in';
14140 if (!this.delay || !this.delay.show) {
14145 this.timeout = setTimeout(function () {
14146 if (_t.hoverState == 'in') {
14149 }, this.delay.show)
14151 leave : function() {
14152 clearTimeout(this.timeout);
14154 this.hoverState = 'out';
14156 if (!this.delay || !this.delay.hide) {
14161 this.timeout = setTimeout(function () {
14162 if (_t.hoverState == 'out') {
14165 }, this.delay.hide)
14168 show : function (on_el)
14171 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14174 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14175 if (this.html !== false) {
14176 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14178 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14179 if (!this.title.length) {
14180 this.el.select('.popover-title',true).hide();
14183 var placement = typeof this.placement == 'function' ?
14184 this.placement.call(this, this.el, on_el) :
14187 var autoToken = /\s?auto?\s?/i;
14188 var autoPlace = autoToken.test(placement);
14190 placement = placement.replace(autoToken, '') || 'top';
14194 //this.el.setXY([0,0]);
14196 this.el.dom.style.display='block';
14197 this.el.addClass(placement);
14199 //this.el.appendTo(on_el);
14201 var p = this.getPosition();
14202 var box = this.el.getBox();
14207 var align = Roo.bootstrap.Popover.alignment[placement];
14208 this.el.alignTo(on_el, align[0],align[1]);
14209 //var arrow = this.el.select('.arrow',true).first();
14210 //arrow.set(align[2],
14212 this.el.addClass('in');
14213 this.hoverState = null;
14215 if (this.el.hasClass('fade')) {
14222 this.el.setXY([0,0]);
14223 this.el.removeClass('in');
14230 Roo.bootstrap.Popover.alignment = {
14231 'left' : ['r-l', [-10,0], 'right'],
14232 'right' : ['l-r', [10,0], 'left'],
14233 'bottom' : ['t-b', [0,10], 'top'],
14234 'top' : [ 'b-t', [0,-10], 'bottom']
14245 * @class Roo.bootstrap.Progress
14246 * @extends Roo.bootstrap.Component
14247 * Bootstrap Progress class
14248 * @cfg {Boolean} striped striped of the progress bar
14249 * @cfg {Boolean} active animated of the progress bar
14253 * Create a new Progress
14254 * @param {Object} config The config object
14257 Roo.bootstrap.Progress = function(config){
14258 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14261 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14266 getAutoCreate : function(){
14274 cfg.cls += ' progress-striped';
14278 cfg.cls += ' active';
14297 * @class Roo.bootstrap.ProgressBar
14298 * @extends Roo.bootstrap.Component
14299 * Bootstrap ProgressBar class
14300 * @cfg {Number} aria_valuenow aria-value now
14301 * @cfg {Number} aria_valuemin aria-value min
14302 * @cfg {Number} aria_valuemax aria-value max
14303 * @cfg {String} label label for the progress bar
14304 * @cfg {String} panel (success | info | warning | danger )
14305 * @cfg {String} role role of the progress bar
14306 * @cfg {String} sr_only text
14310 * Create a new ProgressBar
14311 * @param {Object} config The config object
14314 Roo.bootstrap.ProgressBar = function(config){
14315 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14318 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14322 aria_valuemax : 100,
14328 getAutoCreate : function()
14333 cls: 'progress-bar',
14334 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14346 cfg.role = this.role;
14349 if(this.aria_valuenow){
14350 cfg['aria-valuenow'] = this.aria_valuenow;
14353 if(this.aria_valuemin){
14354 cfg['aria-valuemin'] = this.aria_valuemin;
14357 if(this.aria_valuemax){
14358 cfg['aria-valuemax'] = this.aria_valuemax;
14361 if(this.label && !this.sr_only){
14362 cfg.html = this.label;
14366 cfg.cls += ' progress-bar-' + this.panel;
14372 update : function(aria_valuenow)
14374 this.aria_valuenow = aria_valuenow;
14376 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14391 * @class Roo.bootstrap.TabGroup
14392 * @extends Roo.bootstrap.Column
14393 * Bootstrap Column class
14394 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14395 * @cfg {Boolean} carousel true to make the group behave like a carousel
14398 * Create a new TabGroup
14399 * @param {Object} config The config object
14402 Roo.bootstrap.TabGroup = function(config){
14403 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14405 this.navId = Roo.id();
14408 Roo.bootstrap.TabGroup.register(this);
14412 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14415 transition : false,
14417 getAutoCreate : function()
14419 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14421 cfg.cls += ' tab-content';
14423 if (this.carousel) {
14424 cfg.cls += ' carousel slide';
14426 cls : 'carousel-inner'
14433 getChildContainer : function()
14435 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14439 * register a Navigation item
14440 * @param {Roo.bootstrap.NavItem} the navitem to add
14442 register : function(item)
14444 this.tabs.push( item);
14445 item.navId = this.navId; // not really needed..
14449 getActivePanel : function()
14452 Roo.each(this.tabs, function(t) {
14462 getPanelByName : function(n)
14465 Roo.each(this.tabs, function(t) {
14466 if (t.tabId == n) {
14474 indexOfPanel : function(p)
14477 Roo.each(this.tabs, function(t,i) {
14478 if (t.tabId == p.tabId) {
14487 * show a specific panel
14488 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14489 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14491 showPanel : function (pan)
14494 if (typeof(pan) == 'number') {
14495 pan = this.tabs[pan];
14497 if (typeof(pan) == 'string') {
14498 pan = this.getPanelByName(pan);
14500 if (pan.tabId == this.getActivePanel().tabId) {
14503 var cur = this.getActivePanel();
14505 if (false === cur.fireEvent('beforedeactivate')) {
14509 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14511 this.transition = true;
14512 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14513 var lr = dir == 'next' ? 'left' : 'right';
14514 pan.el.addClass(dir); // or prev
14515 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14516 cur.el.addClass(lr); // or right
14517 pan.el.addClass(lr);
14520 cur.el.on('transitionend', function() {
14521 Roo.log("trans end?");
14523 pan.el.removeClass([lr,dir]);
14524 pan.setActive(true);
14526 cur.el.removeClass([lr]);
14527 cur.setActive(false);
14529 _this.transition = false;
14531 }, this, { single: true } );
14535 cur.setActive(false);
14536 pan.setActive(true);
14540 showPanelNext : function()
14542 var i = this.indexOfPanel(this.getActivePanel());
14543 if (i > this.tabs.length) {
14546 this.showPanel(this.tabs[i+1]);
14548 showPanelPrev : function()
14550 var i = this.indexOfPanel(this.getActivePanel());
14554 this.showPanel(this.tabs[i-1]);
14565 Roo.apply(Roo.bootstrap.TabGroup, {
14569 * register a Navigation Group
14570 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14572 register : function(navgrp)
14574 this.groups[navgrp.navId] = navgrp;
14578 * fetch a Navigation Group based on the navigation ID
14579 * if one does not exist , it will get created.
14580 * @param {string} the navgroup to add
14581 * @returns {Roo.bootstrap.NavGroup} the navgroup
14583 get: function(navId) {
14584 if (typeof(this.groups[navId]) == 'undefined') {
14585 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14587 return this.groups[navId] ;
14602 * @class Roo.bootstrap.TabPanel
14603 * @extends Roo.bootstrap.Component
14604 * Bootstrap TabPanel class
14605 * @cfg {Boolean} active panel active
14606 * @cfg {String} html panel content
14607 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14608 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14612 * Create a new TabPanel
14613 * @param {Object} config The config object
14616 Roo.bootstrap.TabPanel = function(config){
14617 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14621 * Fires when the active status changes
14622 * @param {Roo.bootstrap.TabPanel} this
14623 * @param {Boolean} state the new state
14628 * @event beforedeactivate
14629 * Fires before a tab is de-activated - can be used to do validation on a form.
14630 * @param {Roo.bootstrap.TabPanel} this
14631 * @return {Boolean} false if there is an error
14634 'beforedeactivate': true
14637 this.tabId = this.tabId || Roo.id();
14641 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14648 getAutoCreate : function(){
14651 // item is needed for carousel - not sure if it has any effect otherwise
14652 cls: 'tab-pane item',
14653 html: this.html || ''
14657 cfg.cls += ' active';
14661 cfg.tabId = this.tabId;
14668 initEvents: function()
14670 Roo.log('-------- init events on tab panel ---------');
14672 var p = this.parent();
14673 this.navId = this.navId || p.navId;
14675 if (typeof(this.navId) != 'undefined') {
14676 // not really needed.. but just in case.. parent should be a NavGroup.
14677 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14678 Roo.log(['register', tg, this]);
14684 onRender : function(ct, position)
14686 // Roo.log("Call onRender: " + this.xtype);
14688 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14696 setActive: function(state)
14698 Roo.log("panel - set active " + this.tabId + "=" + state);
14700 this.active = state;
14702 this.el.removeClass('active');
14704 } else if (!this.el.hasClass('active')) {
14705 this.el.addClass('active');
14707 this.fireEvent('changed', this, state);
14724 * @class Roo.bootstrap.DateField
14725 * @extends Roo.bootstrap.Input
14726 * Bootstrap DateField class
14727 * @cfg {Number} weekStart default 0
14728 * @cfg {String} viewMode default empty, (months|years)
14729 * @cfg {String} minViewMode default empty, (months|years)
14730 * @cfg {Number} startDate default -Infinity
14731 * @cfg {Number} endDate default Infinity
14732 * @cfg {Boolean} todayHighlight default false
14733 * @cfg {Boolean} todayBtn default false
14734 * @cfg {Boolean} calendarWeeks default false
14735 * @cfg {Object} daysOfWeekDisabled default empty
14736 * @cfg {Boolean} singleMode default false (true | false)
14738 * @cfg {Boolean} keyboardNavigation default true
14739 * @cfg {String} language default en
14742 * Create a new DateField
14743 * @param {Object} config The config object
14746 Roo.bootstrap.DateField = function(config){
14747 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14751 * Fires when this field show.
14752 * @param {Roo.bootstrap.DateField} this
14753 * @param {Mixed} date The date value
14758 * Fires when this field hide.
14759 * @param {Roo.bootstrap.DateField} this
14760 * @param {Mixed} date The date value
14765 * Fires when select a date.
14766 * @param {Roo.bootstrap.DateField} this
14767 * @param {Mixed} date The date value
14773 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14776 * @cfg {String} format
14777 * The default date format string which can be overriden for localization support. The format must be
14778 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14782 * @cfg {String} altFormats
14783 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14784 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14786 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14794 todayHighlight : false,
14800 keyboardNavigation: true,
14802 calendarWeeks: false,
14804 startDate: -Infinity,
14808 daysOfWeekDisabled: [],
14812 singleMode : false,
14814 UTCDate: function()
14816 return new Date(Date.UTC.apply(Date, arguments));
14819 UTCToday: function()
14821 var today = new Date();
14822 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14825 getDate: function() {
14826 var d = this.getUTCDate();
14827 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14830 getUTCDate: function() {
14834 setDate: function(d) {
14835 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14838 setUTCDate: function(d) {
14840 this.setValue(this.formatDate(this.date));
14843 onRender: function(ct, position)
14846 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14848 this.language = this.language || 'en';
14849 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14850 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14852 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14853 this.format = this.format || 'm/d/y';
14854 this.isInline = false;
14855 this.isInput = true;
14856 this.component = this.el.select('.add-on', true).first() || false;
14857 this.component = (this.component && this.component.length === 0) ? false : this.component;
14858 this.hasInput = this.component && this.inputEL().length;
14860 if (typeof(this.minViewMode === 'string')) {
14861 switch (this.minViewMode) {
14863 this.minViewMode = 1;
14866 this.minViewMode = 2;
14869 this.minViewMode = 0;
14874 if (typeof(this.viewMode === 'string')) {
14875 switch (this.viewMode) {
14888 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14890 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14892 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14894 this.picker().on('mousedown', this.onMousedown, this);
14895 this.picker().on('click', this.onClick, this);
14897 this.picker().addClass('datepicker-dropdown');
14899 this.startViewMode = this.viewMode;
14901 if(this.singleMode){
14902 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14903 v.setVisibilityMode(Roo.Element.DISPLAY)
14907 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14908 v.setStyle('width', '189px');
14912 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14913 if(!this.calendarWeeks){
14918 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14919 v.attr('colspan', function(i, val){
14920 return parseInt(val) + 1;
14925 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14927 this.setStartDate(this.startDate);
14928 this.setEndDate(this.endDate);
14930 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14937 if(this.isInline) {
14942 picker : function()
14944 return this.pickerEl;
14945 // return this.el.select('.datepicker', true).first();
14948 fillDow: function()
14950 var dowCnt = this.weekStart;
14959 if(this.calendarWeeks){
14967 while (dowCnt < this.weekStart + 7) {
14971 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14975 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14978 fillMonths: function()
14981 var months = this.picker().select('>.datepicker-months td', true).first();
14983 months.dom.innerHTML = '';
14989 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14992 months.createChild(month);
14999 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;
15001 if (this.date < this.startDate) {
15002 this.viewDate = new Date(this.startDate);
15003 } else if (this.date > this.endDate) {
15004 this.viewDate = new Date(this.endDate);
15006 this.viewDate = new Date(this.date);
15014 var d = new Date(this.viewDate),
15015 year = d.getUTCFullYear(),
15016 month = d.getUTCMonth(),
15017 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15018 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15019 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15020 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15021 currentDate = this.date && this.date.valueOf(),
15022 today = this.UTCToday();
15024 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15026 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15028 // this.picker.select('>tfoot th.today').
15029 // .text(dates[this.language].today)
15030 // .toggle(this.todayBtn !== false);
15032 this.updateNavArrows();
15035 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15037 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15039 prevMonth.setUTCDate(day);
15041 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15043 var nextMonth = new Date(prevMonth);
15045 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15047 nextMonth = nextMonth.valueOf();
15049 var fillMonths = false;
15051 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15053 while(prevMonth.valueOf() < nextMonth) {
15056 if (prevMonth.getUTCDay() === this.weekStart) {
15058 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15066 if(this.calendarWeeks){
15067 // ISO 8601: First week contains first thursday.
15068 // ISO also states week starts on Monday, but we can be more abstract here.
15070 // Start of current week: based on weekstart/current date
15071 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15072 // Thursday of this week
15073 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15074 // First Thursday of year, year from thursday
15075 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15076 // Calendar week: ms between thursdays, div ms per day, div 7 days
15077 calWeek = (th - yth) / 864e5 / 7 + 1;
15079 fillMonths.cn.push({
15087 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15089 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15092 if (this.todayHighlight &&
15093 prevMonth.getUTCFullYear() == today.getFullYear() &&
15094 prevMonth.getUTCMonth() == today.getMonth() &&
15095 prevMonth.getUTCDate() == today.getDate()) {
15096 clsName += ' today';
15099 if (currentDate && prevMonth.valueOf() === currentDate) {
15100 clsName += ' active';
15103 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15104 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15105 clsName += ' disabled';
15108 fillMonths.cn.push({
15110 cls: 'day ' + clsName,
15111 html: prevMonth.getDate()
15114 prevMonth.setDate(prevMonth.getDate()+1);
15117 var currentYear = this.date && this.date.getUTCFullYear();
15118 var currentMonth = this.date && this.date.getUTCMonth();
15120 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15122 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15123 v.removeClass('active');
15125 if(currentYear === year && k === currentMonth){
15126 v.addClass('active');
15129 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15130 v.addClass('disabled');
15136 year = parseInt(year/10, 10) * 10;
15138 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15140 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15143 for (var i = -1; i < 11; i++) {
15144 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15146 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15154 showMode: function(dir)
15157 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15160 Roo.each(this.picker().select('>div',true).elements, function(v){
15161 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15164 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15169 if(this.isInline) return;
15171 this.picker().removeClass(['bottom', 'top']);
15173 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15175 * place to the top of element!
15179 this.picker().addClass('top');
15180 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15185 this.picker().addClass('bottom');
15187 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15190 parseDate : function(value)
15192 if(!value || value instanceof Date){
15195 var v = Date.parseDate(value, this.format);
15196 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15197 v = Date.parseDate(value, 'Y-m-d');
15199 if(!v && this.altFormats){
15200 if(!this.altFormatsArray){
15201 this.altFormatsArray = this.altFormats.split("|");
15203 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15204 v = Date.parseDate(value, this.altFormatsArray[i]);
15210 formatDate : function(date, fmt)
15212 return (!date || !(date instanceof Date)) ?
15213 date : date.dateFormat(fmt || this.format);
15216 onFocus : function()
15218 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15222 onBlur : function()
15224 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15226 var d = this.inputEl().getValue();
15235 this.picker().show();
15239 this.fireEvent('show', this, this.date);
15244 if(this.isInline) return;
15245 this.picker().hide();
15246 this.viewMode = this.startViewMode;
15249 this.fireEvent('hide', this, this.date);
15253 onMousedown: function(e)
15255 e.stopPropagation();
15256 e.preventDefault();
15261 Roo.bootstrap.DateField.superclass.keyup.call(this);
15265 setValue: function(v)
15268 // v can be a string or a date..
15271 var d = new Date(this.parseDate(v) ).clearTime();
15273 if(isNaN(d.getTime())){
15274 this.date = this.viewDate = '';
15275 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15279 v = this.formatDate(d);
15281 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15283 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15287 this.fireEvent('select', this, this.date);
15291 getValue: function()
15293 return this.formatDate(this.date);
15296 fireKey: function(e)
15298 if (!this.picker().isVisible()){
15299 if (e.keyCode == 27) // allow escape to hide and re-show picker
15304 var dateChanged = false,
15306 newDate, newViewDate;
15311 e.preventDefault();
15315 if (!this.keyboardNavigation) break;
15316 dir = e.keyCode == 37 ? -1 : 1;
15319 newDate = this.moveYear(this.date, dir);
15320 newViewDate = this.moveYear(this.viewDate, dir);
15321 } else if (e.shiftKey){
15322 newDate = this.moveMonth(this.date, dir);
15323 newViewDate = this.moveMonth(this.viewDate, dir);
15325 newDate = new Date(this.date);
15326 newDate.setUTCDate(this.date.getUTCDate() + dir);
15327 newViewDate = new Date(this.viewDate);
15328 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15330 if (this.dateWithinRange(newDate)){
15331 this.date = newDate;
15332 this.viewDate = newViewDate;
15333 this.setValue(this.formatDate(this.date));
15335 e.preventDefault();
15336 dateChanged = true;
15341 if (!this.keyboardNavigation) break;
15342 dir = e.keyCode == 38 ? -1 : 1;
15344 newDate = this.moveYear(this.date, dir);
15345 newViewDate = this.moveYear(this.viewDate, dir);
15346 } else if (e.shiftKey){
15347 newDate = this.moveMonth(this.date, dir);
15348 newViewDate = this.moveMonth(this.viewDate, dir);
15350 newDate = new Date(this.date);
15351 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15352 newViewDate = new Date(this.viewDate);
15353 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15355 if (this.dateWithinRange(newDate)){
15356 this.date = newDate;
15357 this.viewDate = newViewDate;
15358 this.setValue(this.formatDate(this.date));
15360 e.preventDefault();
15361 dateChanged = true;
15365 this.setValue(this.formatDate(this.date));
15367 e.preventDefault();
15370 this.setValue(this.formatDate(this.date));
15384 onClick: function(e)
15386 e.stopPropagation();
15387 e.preventDefault();
15389 var target = e.getTarget();
15391 if(target.nodeName.toLowerCase() === 'i'){
15392 target = Roo.get(target).dom.parentNode;
15395 var nodeName = target.nodeName;
15396 var className = target.className;
15397 var html = target.innerHTML;
15398 //Roo.log(nodeName);
15400 switch(nodeName.toLowerCase()) {
15402 switch(className) {
15408 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15409 switch(this.viewMode){
15411 this.viewDate = this.moveMonth(this.viewDate, dir);
15415 this.viewDate = this.moveYear(this.viewDate, dir);
15421 var date = new Date();
15422 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15424 this.setValue(this.formatDate(this.date));
15431 if (className.indexOf('disabled') < 0) {
15432 this.viewDate.setUTCDate(1);
15433 if (className.indexOf('month') > -1) {
15434 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15436 var year = parseInt(html, 10) || 0;
15437 this.viewDate.setUTCFullYear(year);
15441 if(this.singleMode){
15442 this.setValue(this.formatDate(this.viewDate));
15453 //Roo.log(className);
15454 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15455 var day = parseInt(html, 10) || 1;
15456 var year = this.viewDate.getUTCFullYear(),
15457 month = this.viewDate.getUTCMonth();
15459 if (className.indexOf('old') > -1) {
15466 } else if (className.indexOf('new') > -1) {
15474 //Roo.log([year,month,day]);
15475 this.date = this.UTCDate(year, month, day,0,0,0,0);
15476 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15478 //Roo.log(this.formatDate(this.date));
15479 this.setValue(this.formatDate(this.date));
15486 setStartDate: function(startDate)
15488 this.startDate = startDate || -Infinity;
15489 if (this.startDate !== -Infinity) {
15490 this.startDate = this.parseDate(this.startDate);
15493 this.updateNavArrows();
15496 setEndDate: function(endDate)
15498 this.endDate = endDate || Infinity;
15499 if (this.endDate !== Infinity) {
15500 this.endDate = this.parseDate(this.endDate);
15503 this.updateNavArrows();
15506 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15508 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15509 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15510 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15512 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15513 return parseInt(d, 10);
15516 this.updateNavArrows();
15519 updateNavArrows: function()
15521 if(this.singleMode){
15525 var d = new Date(this.viewDate),
15526 year = d.getUTCFullYear(),
15527 month = d.getUTCMonth();
15529 Roo.each(this.picker().select('.prev', true).elements, function(v){
15531 switch (this.viewMode) {
15534 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15540 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15547 Roo.each(this.picker().select('.next', true).elements, function(v){
15549 switch (this.viewMode) {
15552 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15558 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15566 moveMonth: function(date, dir)
15568 if (!dir) return date;
15569 var new_date = new Date(date.valueOf()),
15570 day = new_date.getUTCDate(),
15571 month = new_date.getUTCMonth(),
15572 mag = Math.abs(dir),
15574 dir = dir > 0 ? 1 : -1;
15577 // If going back one month, make sure month is not current month
15578 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15580 return new_date.getUTCMonth() == month;
15582 // If going forward one month, make sure month is as expected
15583 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15585 return new_date.getUTCMonth() != new_month;
15587 new_month = month + dir;
15588 new_date.setUTCMonth(new_month);
15589 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15590 if (new_month < 0 || new_month > 11)
15591 new_month = (new_month + 12) % 12;
15593 // For magnitudes >1, move one month at a time...
15594 for (var i=0; i<mag; i++)
15595 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15596 new_date = this.moveMonth(new_date, dir);
15597 // ...then reset the day, keeping it in the new month
15598 new_month = new_date.getUTCMonth();
15599 new_date.setUTCDate(day);
15601 return new_month != new_date.getUTCMonth();
15604 // Common date-resetting loop -- if date is beyond end of month, make it
15607 new_date.setUTCDate(--day);
15608 new_date.setUTCMonth(new_month);
15613 moveYear: function(date, dir)
15615 return this.moveMonth(date, dir*12);
15618 dateWithinRange: function(date)
15620 return date >= this.startDate && date <= this.endDate;
15626 this.picker().remove();
15631 Roo.apply(Roo.bootstrap.DateField, {
15642 html: '<i class="fa fa-arrow-left"/>'
15652 html: '<i class="fa fa-arrow-right"/>'
15694 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15695 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15696 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15697 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15698 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15711 navFnc: 'FullYear',
15716 navFnc: 'FullYear',
15721 Roo.apply(Roo.bootstrap.DateField, {
15725 cls: 'datepicker dropdown-menu roo-dynamic',
15729 cls: 'datepicker-days',
15733 cls: 'table-condensed',
15735 Roo.bootstrap.DateField.head,
15739 Roo.bootstrap.DateField.footer
15746 cls: 'datepicker-months',
15750 cls: 'table-condensed',
15752 Roo.bootstrap.DateField.head,
15753 Roo.bootstrap.DateField.content,
15754 Roo.bootstrap.DateField.footer
15761 cls: 'datepicker-years',
15765 cls: 'table-condensed',
15767 Roo.bootstrap.DateField.head,
15768 Roo.bootstrap.DateField.content,
15769 Roo.bootstrap.DateField.footer
15788 * @class Roo.bootstrap.TimeField
15789 * @extends Roo.bootstrap.Input
15790 * Bootstrap DateField class
15794 * Create a new TimeField
15795 * @param {Object} config The config object
15798 Roo.bootstrap.TimeField = function(config){
15799 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15803 * Fires when this field show.
15804 * @param {Roo.bootstrap.DateField} thisthis
15805 * @param {Mixed} date The date value
15810 * Fires when this field hide.
15811 * @param {Roo.bootstrap.DateField} this
15812 * @param {Mixed} date The date value
15817 * Fires when select a date.
15818 * @param {Roo.bootstrap.DateField} this
15819 * @param {Mixed} date The date value
15825 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15828 * @cfg {String} format
15829 * The default time format string which can be overriden for localization support. The format must be
15830 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15834 onRender: function(ct, position)
15837 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15839 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15841 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15843 this.pop = this.picker().select('>.datepicker-time',true).first();
15844 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15846 this.picker().on('mousedown', this.onMousedown, this);
15847 this.picker().on('click', this.onClick, this);
15849 this.picker().addClass('datepicker-dropdown');
15854 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15855 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15856 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15857 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15858 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15859 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15863 fireKey: function(e){
15864 if (!this.picker().isVisible()){
15865 if (e.keyCode == 27) { // allow escape to hide and re-show picker
15871 e.preventDefault();
15879 this.onTogglePeriod();
15882 this.onIncrementMinutes();
15885 this.onDecrementMinutes();
15894 onClick: function(e) {
15895 e.stopPropagation();
15896 e.preventDefault();
15899 picker : function()
15901 return this.el.select('.datepicker', true).first();
15904 fillTime: function()
15906 var time = this.pop.select('tbody', true).first();
15908 time.dom.innerHTML = '';
15923 cls: 'hours-up glyphicon glyphicon-chevron-up'
15943 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15964 cls: 'timepicker-hour',
15979 cls: 'timepicker-minute',
15994 cls: 'btn btn-primary period',
16016 cls: 'hours-down glyphicon glyphicon-chevron-down'
16036 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16054 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16061 var hours = this.time.getHours();
16062 var minutes = this.time.getMinutes();
16075 hours = hours - 12;
16079 hours = '0' + hours;
16083 minutes = '0' + minutes;
16086 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16087 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16088 this.pop.select('button', true).first().dom.innerHTML = period;
16094 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16096 var cls = ['bottom'];
16098 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16105 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16110 this.picker().addClass(cls.join('-'));
16114 Roo.each(cls, function(c){
16116 _this.picker().setTop(_this.inputEl().getHeight());
16120 _this.picker().setTop(0 - _this.picker().getHeight());
16125 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16129 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16136 onFocus : function()
16138 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16142 onBlur : function()
16144 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16150 this.picker().show();
16155 this.fireEvent('show', this, this.date);
16160 this.picker().hide();
16163 this.fireEvent('hide', this, this.date);
16166 setTime : function()
16169 this.setValue(this.time.format(this.format));
16171 this.fireEvent('select', this, this.date);
16176 onMousedown: function(e){
16177 e.stopPropagation();
16178 e.preventDefault();
16181 onIncrementHours: function()
16183 Roo.log('onIncrementHours');
16184 this.time = this.time.add(Date.HOUR, 1);
16189 onDecrementHours: function()
16191 Roo.log('onDecrementHours');
16192 this.time = this.time.add(Date.HOUR, -1);
16196 onIncrementMinutes: function()
16198 Roo.log('onIncrementMinutes');
16199 this.time = this.time.add(Date.MINUTE, 1);
16203 onDecrementMinutes: function()
16205 Roo.log('onDecrementMinutes');
16206 this.time = this.time.add(Date.MINUTE, -1);
16210 onTogglePeriod: function()
16212 Roo.log('onTogglePeriod');
16213 this.time = this.time.add(Date.HOUR, 12);
16220 Roo.apply(Roo.bootstrap.TimeField, {
16250 cls: 'btn btn-info ok',
16262 Roo.apply(Roo.bootstrap.TimeField, {
16266 cls: 'datepicker dropdown-menu',
16270 cls: 'datepicker-time',
16274 cls: 'table-condensed',
16276 Roo.bootstrap.TimeField.content,
16277 Roo.bootstrap.TimeField.footer
16296 * @class Roo.bootstrap.MonthField
16297 * @extends Roo.bootstrap.Input
16298 * Bootstrap MonthField class
16300 * @cfg {String} language default en
16303 * Create a new MonthField
16304 * @param {Object} config The config object
16307 Roo.bootstrap.MonthField = function(config){
16308 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16313 * Fires when this field show.
16314 * @param {Roo.bootstrap.MonthField} this
16315 * @param {Mixed} date The date value
16320 * Fires when this field hide.
16321 * @param {Roo.bootstrap.MonthField} this
16322 * @param {Mixed} date The date value
16327 * Fires when select a date.
16328 * @param {Roo.bootstrap.MonthField} this
16329 * @param {String} oldvalue The old value
16330 * @param {String} newvalue The new value
16336 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16338 onRender: function(ct, position)
16341 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16343 this.language = this.language || 'en';
16344 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16345 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16347 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16348 this.isInline = false;
16349 this.isInput = true;
16350 this.component = this.el.select('.add-on', true).first() || false;
16351 this.component = (this.component && this.component.length === 0) ? false : this.component;
16352 this.hasInput = this.component && this.inputEL().length;
16354 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16356 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16358 this.picker().on('mousedown', this.onMousedown, this);
16359 this.picker().on('click', this.onClick, this);
16361 this.picker().addClass('datepicker-dropdown');
16363 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16364 v.setStyle('width', '189px');
16371 if(this.isInline) {
16377 setValue: function(v, suppressEvent)
16379 var o = this.getValue();
16381 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16385 if(suppressEvent !== true){
16386 this.fireEvent('select', this, o, v);
16391 getValue: function()
16396 onClick: function(e)
16398 e.stopPropagation();
16399 e.preventDefault();
16401 var target = e.getTarget();
16403 if(target.nodeName.toLowerCase() === 'i'){
16404 target = Roo.get(target).dom.parentNode;
16407 var nodeName = target.nodeName;
16408 var className = target.className;
16409 var html = target.innerHTML;
16411 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16415 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16417 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16423 picker : function()
16425 return this.pickerEl;
16428 fillMonths: function()
16431 var months = this.picker().select('>.datepicker-months td', true).first();
16433 months.dom.innerHTML = '';
16439 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16442 months.createChild(month);
16451 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16452 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16455 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16456 e.removeClass('active');
16458 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16459 e.addClass('active');
16466 if(this.isInline) return;
16468 this.picker().removeClass(['bottom', 'top']);
16470 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16472 * place to the top of element!
16476 this.picker().addClass('top');
16477 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16482 this.picker().addClass('bottom');
16484 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16487 onFocus : function()
16489 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16493 onBlur : function()
16495 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16497 var d = this.inputEl().getValue();
16506 this.picker().show();
16507 this.picker().select('>.datepicker-months', true).first().show();
16511 this.fireEvent('show', this, this.date);
16516 if(this.isInline) return;
16517 this.picker().hide();
16518 this.fireEvent('hide', this, this.date);
16522 onMousedown: function(e)
16524 e.stopPropagation();
16525 e.preventDefault();
16530 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16534 fireKey: function(e)
16536 if (!this.picker().isVisible()){
16537 if (e.keyCode == 27) // allow escape to hide and re-show picker
16547 e.preventDefault();
16551 dir = e.keyCode == 37 ? -1 : 1;
16553 this.vIndex = this.vIndex + dir;
16555 if(this.vIndex < 0){
16559 if(this.vIndex > 11){
16563 if(isNaN(this.vIndex)){
16567 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16573 dir = e.keyCode == 38 ? -1 : 1;
16575 this.vIndex = this.vIndex + dir * 4;
16577 if(this.vIndex < 0){
16581 if(this.vIndex > 11){
16585 if(isNaN(this.vIndex)){
16589 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16594 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16595 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16599 e.preventDefault();
16602 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16603 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16619 this.picker().remove();
16624 Roo.apply(Roo.bootstrap.MonthField, {
16643 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16644 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16649 Roo.apply(Roo.bootstrap.MonthField, {
16653 cls: 'datepicker dropdown-menu roo-dynamic',
16657 cls: 'datepicker-months',
16661 cls: 'table-condensed',
16663 Roo.bootstrap.DateField.content
16683 * @class Roo.bootstrap.CheckBox
16684 * @extends Roo.bootstrap.Input
16685 * Bootstrap CheckBox class
16687 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16688 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16689 * @cfg {String} boxLabel The text that appears beside the checkbox
16690 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16691 * @cfg {Boolean} checked initnal the element
16692 * @cfg {Boolean} inline inline the element (default false)
16693 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16696 * Create a new CheckBox
16697 * @param {Object} config The config object
16700 Roo.bootstrap.CheckBox = function(config){
16701 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16706 * Fires when the element is checked or unchecked.
16707 * @param {Roo.bootstrap.CheckBox} this This input
16708 * @param {Boolean} checked The new checked value
16715 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16717 inputType: 'checkbox',
16725 getAutoCreate : function()
16727 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16733 cfg.cls = 'form-group ' + this.inputType; //input-group
16736 cfg.cls += ' ' + this.inputType + '-inline';
16742 type : this.inputType,
16743 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16744 cls : 'roo-' + this.inputType, //'form-box',
16745 placeholder : this.placeholder || ''
16749 if (this.weight) { // Validity check?
16750 cfg.cls += " " + this.inputType + "-" + this.weight;
16753 if (this.disabled) {
16754 input.disabled=true;
16758 input.checked = this.checked;
16762 input.name = this.name;
16766 input.cls += ' input-' + this.size;
16771 ['xs','sm','md','lg'].map(function(size){
16772 if (settings[size]) {
16773 cfg.cls += ' col-' + size + '-' + settings[size];
16777 var inputblock = input;
16779 if (this.before || this.after) {
16782 cls : 'input-group',
16787 inputblock.cn.push({
16789 cls : 'input-group-addon',
16794 inputblock.cn.push(input);
16797 inputblock.cn.push({
16799 cls : 'input-group-addon',
16806 if (align ==='left' && this.fieldLabel.length) {
16807 Roo.log("left and has label");
16813 cls : 'control-label col-md-' + this.labelWidth,
16814 html : this.fieldLabel
16818 cls : "col-md-" + (12 - this.labelWidth),
16825 } else if ( this.fieldLabel.length) {
16830 tag: this.boxLabel ? 'span' : 'label',
16832 cls: 'control-label box-input-label',
16833 //cls : 'input-group-addon',
16834 html : this.fieldLabel
16844 Roo.log(" no label && no align");
16845 cfg.cn = [ inputblock ] ;
16850 var boxLabelCfg = {
16852 //'for': id, // box label is handled by onclick - so no for...
16854 html: this.boxLabel
16858 boxLabelCfg.tooltip = this.tooltip;
16861 cfg.cn.push(boxLabelCfg);
16871 * return the real input element.
16873 inputEl: function ()
16875 return this.el.select('input.roo-' + this.inputType,true).first();
16878 labelEl: function()
16880 return this.el.select('label.control-label',true).first();
16882 /* depricated... */
16886 return this.labelEl();
16889 initEvents : function()
16891 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16893 this.inputEl().on('click', this.onClick, this);
16895 if (this.boxLabel) {
16896 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16899 this.startValue = this.getValue();
16902 Roo.bootstrap.CheckBox.register(this);
16906 onClick : function()
16908 this.setChecked(!this.checked);
16911 setChecked : function(state,suppressEvent)
16913 this.startValue = this.getValue();
16915 if(this.inputType == 'radio'){
16917 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16918 e.dom.checked = false;
16921 this.inputEl().dom.checked = true;
16923 this.inputEl().dom.value = this.inputValue;
16925 if(suppressEvent !== true){
16926 this.fireEvent('check', this, true);
16934 this.checked = state;
16936 this.inputEl().dom.checked = state;
16938 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16940 if(suppressEvent !== true){
16941 this.fireEvent('check', this, state);
16947 getValue : function()
16949 if(this.inputType == 'radio'){
16950 return this.getGroupValue();
16953 return this.inputEl().getValue();
16957 getGroupValue : function()
16959 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16963 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16966 setValue : function(v,suppressEvent)
16968 if(this.inputType == 'radio'){
16969 this.setGroupValue(v, suppressEvent);
16973 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16978 setGroupValue : function(v, suppressEvent)
16980 this.startValue = this.getValue();
16982 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16983 e.dom.checked = false;
16985 if(e.dom.value == v){
16986 e.dom.checked = true;
16990 if(suppressEvent !== true){
16991 this.fireEvent('check', this, true);
16999 validate : function()
17003 (this.inputType == 'radio' && this.validateRadio()) ||
17004 (this.inputType == 'checkbox' && this.validateCheckbox())
17010 this.markInvalid();
17014 validateRadio : function()
17018 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17019 if(!e.dom.checked){
17031 validateCheckbox : function()
17034 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17037 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17045 for(var i in group){
17050 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17057 * Mark this field as valid
17059 markValid : function()
17063 this.fireEvent('valid', this);
17065 if(this.inputType == 'radio'){
17066 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17067 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17068 e.findParent('.form-group', false, true).addClass(_this.validClass);
17075 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17076 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17080 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17086 for(var i in group){
17087 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17088 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17093 * Mark this field as invalid
17094 * @param {String} msg The validation message
17096 markInvalid : function(msg)
17100 this.fireEvent('invalid', this, msg);
17102 if(this.inputType == 'radio'){
17103 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17104 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17105 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17112 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17113 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17117 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17123 for(var i in group){
17124 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17125 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17132 Roo.apply(Roo.bootstrap.CheckBox, {
17137 * register a CheckBox Group
17138 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17140 register : function(checkbox)
17142 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17143 this.groups[checkbox.groupId] = {};
17146 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17150 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17154 * fetch a CheckBox Group based on the group ID
17155 * @param {string} the group ID
17156 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17158 get: function(groupId) {
17159 if (typeof(this.groups[groupId]) == 'undefined') {
17163 return this.groups[groupId] ;
17175 *<div class="radio">
17177 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17178 Option one is this and that—be sure to include why it's great
17185 *<label class="radio-inline">fieldLabel</label>
17186 *<label class="radio-inline">
17187 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17195 * @class Roo.bootstrap.Radio
17196 * @extends Roo.bootstrap.CheckBox
17197 * Bootstrap Radio class
17200 * Create a new Radio
17201 * @param {Object} config The config object
17204 Roo.bootstrap.Radio = function(config){
17205 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17209 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17211 inputType: 'radio',
17215 getAutoCreate : function()
17217 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17218 align = align || 'left'; // default...
17225 tag : this.inline ? 'span' : 'div',
17230 var inline = this.inline ? ' radio-inline' : '';
17234 // does not need for, as we wrap the input with it..
17236 cls : 'control-label box-label' + inline,
17239 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17243 //cls : 'control-label' + inline,
17244 html : this.fieldLabel,
17245 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17254 type : this.inputType,
17255 //value : (!this.checked) ? this.valueOff : this.inputValue,
17256 value : this.inputValue,
17258 placeholder : this.placeholder || '' // ?? needed????
17261 if (this.weight) { // Validity check?
17262 input.cls += " radio-" + this.weight;
17264 if (this.disabled) {
17265 input.disabled=true;
17269 input.checked = this.checked;
17273 input.name = this.name;
17277 input.cls += ' input-' + this.size;
17280 //?? can span's inline have a width??
17283 ['xs','sm','md','lg'].map(function(size){
17284 if (settings[size]) {
17285 cfg.cls += ' col-' + size + '-' + settings[size];
17289 var inputblock = input;
17291 if (this.before || this.after) {
17294 cls : 'input-group',
17299 inputblock.cn.push({
17301 cls : 'input-group-addon',
17305 inputblock.cn.push(input);
17307 inputblock.cn.push({
17309 cls : 'input-group-addon',
17317 if (this.fieldLabel && this.fieldLabel.length) {
17318 cfg.cn.push(fieldLabel);
17321 // normal bootstrap puts the input inside the label.
17322 // however with our styled version - it has to go after the input.
17324 //lbl.cn.push(inputblock);
17328 cls: 'radio' + inline,
17335 cfg.cn.push( lblwrap);
17340 html: this.boxLabel
17349 initEvents : function()
17351 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17353 this.inputEl().on('click', this.onClick, this);
17354 if (this.boxLabel) {
17355 Roo.log('find label')
17356 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17361 inputEl: function ()
17363 return this.el.select('input.roo-radio',true).first();
17365 onClick : function()
17368 this.setChecked(true);
17371 setChecked : function(state,suppressEvent)
17374 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17375 v.dom.checked = false;
17378 Roo.log(this.inputEl().dom);
17379 this.checked = state;
17380 this.inputEl().dom.checked = state;
17382 if(suppressEvent !== true){
17383 this.fireEvent('check', this, state);
17386 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17390 getGroupValue : function()
17393 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17394 if(v.dom.checked == true){
17395 value = v.dom.value;
17403 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17404 * @return {Mixed} value The field value
17406 getValue : function(){
17407 return this.getGroupValue();
17413 //<script type="text/javascript">
17416 * Based Ext JS Library 1.1.1
17417 * Copyright(c) 2006-2007, Ext JS, LLC.
17423 * @class Roo.HtmlEditorCore
17424 * @extends Roo.Component
17425 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17427 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17430 Roo.HtmlEditorCore = function(config){
17433 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17438 * @event initialize
17439 * Fires when the editor is fully initialized (including the iframe)
17440 * @param {Roo.HtmlEditorCore} this
17445 * Fires when the editor is first receives the focus. Any insertion must wait
17446 * until after this event.
17447 * @param {Roo.HtmlEditorCore} this
17451 * @event beforesync
17452 * Fires before the textarea is updated with content from the editor iframe. Return false
17453 * to cancel the sync.
17454 * @param {Roo.HtmlEditorCore} this
17455 * @param {String} html
17459 * @event beforepush
17460 * Fires before the iframe editor is updated with content from the textarea. Return false
17461 * to cancel the push.
17462 * @param {Roo.HtmlEditorCore} this
17463 * @param {String} html
17468 * Fires when the textarea is updated with content from the editor iframe.
17469 * @param {Roo.HtmlEditorCore} this
17470 * @param {String} html
17475 * Fires when the iframe editor is updated with content from the textarea.
17476 * @param {Roo.HtmlEditorCore} this
17477 * @param {String} html
17482 * @event editorevent
17483 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17484 * @param {Roo.HtmlEditorCore} this
17490 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17492 // defaults : white / black...
17493 this.applyBlacklists();
17500 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17504 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17510 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17515 * @cfg {Number} height (in pixels)
17519 * @cfg {Number} width (in pixels)
17524 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17527 stylesheets: false,
17532 // private properties
17533 validationEvent : false,
17535 initialized : false,
17537 sourceEditMode : false,
17538 onFocus : Roo.emptyFn,
17540 hideMode:'offsets',
17544 // blacklist + whitelisted elements..
17551 * Protected method that will not generally be called directly. It
17552 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17553 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17555 getDocMarkup : function(){
17559 // inherit styels from page...??
17560 if (this.stylesheets === false) {
17562 Roo.get(document.head).select('style').each(function(node) {
17563 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17566 Roo.get(document.head).select('link').each(function(node) {
17567 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17570 } else if (!this.stylesheets.length) {
17572 st = '<style type="text/css">' +
17573 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17579 st += '<style type="text/css">' +
17580 'IMG { cursor: pointer } ' +
17584 return '<html><head>' + st +
17585 //<style type="text/css">' +
17586 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17588 ' </head><body class="roo-htmleditor-body"></body></html>';
17592 onRender : function(ct, position)
17595 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17596 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17599 this.el.dom.style.border = '0 none';
17600 this.el.dom.setAttribute('tabIndex', -1);
17601 this.el.addClass('x-hidden hide');
17605 if(Roo.isIE){ // fix IE 1px bogus margin
17606 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17610 this.frameId = Roo.id();
17614 var iframe = this.owner.wrap.createChild({
17616 cls: 'form-control', // bootstrap..
17618 name: this.frameId,
17619 frameBorder : 'no',
17620 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17625 this.iframe = iframe.dom;
17627 this.assignDocWin();
17629 this.doc.designMode = 'on';
17632 this.doc.write(this.getDocMarkup());
17636 var task = { // must defer to wait for browser to be ready
17638 //console.log("run task?" + this.doc.readyState);
17639 this.assignDocWin();
17640 if(this.doc.body || this.doc.readyState == 'complete'){
17642 this.doc.designMode="on";
17646 Roo.TaskMgr.stop(task);
17647 this.initEditor.defer(10, this);
17654 Roo.TaskMgr.start(task);
17659 onResize : function(w, h)
17661 Roo.log('resize: ' +w + ',' + h );
17662 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17666 if(typeof w == 'number'){
17668 this.iframe.style.width = w + 'px';
17670 if(typeof h == 'number'){
17672 this.iframe.style.height = h + 'px';
17674 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17681 * Toggles the editor between standard and source edit mode.
17682 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17684 toggleSourceEdit : function(sourceEditMode){
17686 this.sourceEditMode = sourceEditMode === true;
17688 if(this.sourceEditMode){
17690 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17693 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17694 //this.iframe.className = '';
17697 //this.setSize(this.owner.wrap.getSize());
17698 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17705 * Protected method that will not generally be called directly. If you need/want
17706 * custom HTML cleanup, this is the method you should override.
17707 * @param {String} html The HTML to be cleaned
17708 * return {String} The cleaned HTML
17710 cleanHtml : function(html){
17711 html = String(html);
17712 if(html.length > 5){
17713 if(Roo.isSafari){ // strip safari nonsense
17714 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17717 if(html == ' '){
17724 * HTML Editor -> Textarea
17725 * Protected method that will not generally be called directly. Syncs the contents
17726 * of the editor iframe with the textarea.
17728 syncValue : function(){
17729 if(this.initialized){
17730 var bd = (this.doc.body || this.doc.documentElement);
17731 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17732 var html = bd.innerHTML;
17734 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17735 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17737 html = '<div style="'+m[0]+'">' + html + '</div>';
17740 html = this.cleanHtml(html);
17741 // fix up the special chars.. normaly like back quotes in word...
17742 // however we do not want to do this with chinese..
17743 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17744 var cc = b.charCodeAt();
17746 (cc >= 0x4E00 && cc < 0xA000 ) ||
17747 (cc >= 0x3400 && cc < 0x4E00 ) ||
17748 (cc >= 0xf900 && cc < 0xfb00 )
17754 if(this.owner.fireEvent('beforesync', this, html) !== false){
17755 this.el.dom.value = html;
17756 this.owner.fireEvent('sync', this, html);
17762 * Protected method that will not generally be called directly. Pushes the value of the textarea
17763 * into the iframe editor.
17765 pushValue : function(){
17766 if(this.initialized){
17767 var v = this.el.dom.value.trim();
17769 // if(v.length < 1){
17773 if(this.owner.fireEvent('beforepush', this, v) !== false){
17774 var d = (this.doc.body || this.doc.documentElement);
17776 this.cleanUpPaste();
17777 this.el.dom.value = d.innerHTML;
17778 this.owner.fireEvent('push', this, v);
17784 deferFocus : function(){
17785 this.focus.defer(10, this);
17789 focus : function(){
17790 if(this.win && !this.sourceEditMode){
17797 assignDocWin: function()
17799 var iframe = this.iframe;
17802 this.doc = iframe.contentWindow.document;
17803 this.win = iframe.contentWindow;
17805 // if (!Roo.get(this.frameId)) {
17808 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17809 // this.win = Roo.get(this.frameId).dom.contentWindow;
17811 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17815 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17816 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17821 initEditor : function(){
17822 //console.log("INIT EDITOR");
17823 this.assignDocWin();
17827 this.doc.designMode="on";
17829 this.doc.write(this.getDocMarkup());
17832 var dbody = (this.doc.body || this.doc.documentElement);
17833 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17834 // this copies styles from the containing element into thsi one..
17835 // not sure why we need all of this..
17836 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17838 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17839 //ss['background-attachment'] = 'fixed'; // w3c
17840 dbody.bgProperties = 'fixed'; // ie
17841 //Roo.DomHelper.applyStyles(dbody, ss);
17842 Roo.EventManager.on(this.doc, {
17843 //'mousedown': this.onEditorEvent,
17844 'mouseup': this.onEditorEvent,
17845 'dblclick': this.onEditorEvent,
17846 'click': this.onEditorEvent,
17847 'keyup': this.onEditorEvent,
17852 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17854 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17855 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17857 this.initialized = true;
17859 this.owner.fireEvent('initialize', this);
17864 onDestroy : function(){
17870 //for (var i =0; i < this.toolbars.length;i++) {
17871 // // fixme - ask toolbars for heights?
17872 // this.toolbars[i].onDestroy();
17875 //this.wrap.dom.innerHTML = '';
17876 //this.wrap.remove();
17881 onFirstFocus : function(){
17883 this.assignDocWin();
17886 this.activated = true;
17889 if(Roo.isGecko){ // prevent silly gecko errors
17891 var s = this.win.getSelection();
17892 if(!s.focusNode || s.focusNode.nodeType != 3){
17893 var r = s.getRangeAt(0);
17894 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17899 this.execCmd('useCSS', true);
17900 this.execCmd('styleWithCSS', false);
17903 this.owner.fireEvent('activate', this);
17907 adjustFont: function(btn){
17908 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17909 //if(Roo.isSafari){ // safari
17912 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17913 if(Roo.isSafari){ // safari
17914 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17915 v = (v < 10) ? 10 : v;
17916 v = (v > 48) ? 48 : v;
17917 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17922 v = Math.max(1, v+adjust);
17924 this.execCmd('FontSize', v );
17927 onEditorEvent : function(e){
17928 this.owner.fireEvent('editorevent', this, e);
17929 // this.updateToolbar();
17930 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17933 insertTag : function(tg)
17935 // could be a bit smarter... -> wrap the current selected tRoo..
17936 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17938 range = this.createRange(this.getSelection());
17939 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17940 wrappingNode.appendChild(range.extractContents());
17941 range.insertNode(wrappingNode);
17948 this.execCmd("formatblock", tg);
17952 insertText : function(txt)
17956 var range = this.createRange();
17957 range.deleteContents();
17958 //alert(Sender.getAttribute('label'));
17960 range.insertNode(this.doc.createTextNode(txt));
17966 * Executes a Midas editor command on the editor document and performs necessary focus and
17967 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17968 * @param {String} cmd The Midas command
17969 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17971 relayCmd : function(cmd, value){
17973 this.execCmd(cmd, value);
17974 this.owner.fireEvent('editorevent', this);
17975 //this.updateToolbar();
17976 this.owner.deferFocus();
17980 * Executes a Midas editor command directly on the editor document.
17981 * For visual commands, you should use {@link #relayCmd} instead.
17982 * <b>This should only be called after the editor is initialized.</b>
17983 * @param {String} cmd The Midas command
17984 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17986 execCmd : function(cmd, value){
17987 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17994 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17996 * @param {String} text | dom node..
17998 insertAtCursor : function(text)
18003 if(!this.activated){
18009 var r = this.doc.selection.createRange();
18020 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18024 // from jquery ui (MIT licenced)
18026 var win = this.win;
18028 if (win.getSelection && win.getSelection().getRangeAt) {
18029 range = win.getSelection().getRangeAt(0);
18030 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18031 range.insertNode(node);
18032 } else if (win.document.selection && win.document.selection.createRange) {
18033 // no firefox support
18034 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18035 win.document.selection.createRange().pasteHTML(txt);
18037 // no firefox support
18038 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18039 this.execCmd('InsertHTML', txt);
18048 mozKeyPress : function(e){
18050 var c = e.getCharCode(), cmd;
18053 c = String.fromCharCode(c).toLowerCase();
18067 this.cleanUpPaste.defer(100, this);
18075 e.preventDefault();
18083 fixKeys : function(){ // load time branching for fastest keydown performance
18085 return function(e){
18086 var k = e.getKey(), r;
18089 r = this.doc.selection.createRange();
18092 r.pasteHTML('    ');
18099 r = this.doc.selection.createRange();
18101 var target = r.parentElement();
18102 if(!target || target.tagName.toLowerCase() != 'li'){
18104 r.pasteHTML('<br />');
18110 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18111 this.cleanUpPaste.defer(100, this);
18117 }else if(Roo.isOpera){
18118 return function(e){
18119 var k = e.getKey();
18123 this.execCmd('InsertHTML','    ');
18126 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18127 this.cleanUpPaste.defer(100, this);
18132 }else if(Roo.isSafari){
18133 return function(e){
18134 var k = e.getKey();
18138 this.execCmd('InsertText','\t');
18142 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18143 this.cleanUpPaste.defer(100, this);
18151 getAllAncestors: function()
18153 var p = this.getSelectedNode();
18156 a.push(p); // push blank onto stack..
18157 p = this.getParentElement();
18161 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18165 a.push(this.doc.body);
18169 lastSelNode : false,
18172 getSelection : function()
18174 this.assignDocWin();
18175 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18178 getSelectedNode: function()
18180 // this may only work on Gecko!!!
18182 // should we cache this!!!!
18187 var range = this.createRange(this.getSelection()).cloneRange();
18190 var parent = range.parentElement();
18192 var testRange = range.duplicate();
18193 testRange.moveToElementText(parent);
18194 if (testRange.inRange(range)) {
18197 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18200 parent = parent.parentElement;
18205 // is ancestor a text element.
18206 var ac = range.commonAncestorContainer;
18207 if (ac.nodeType == 3) {
18208 ac = ac.parentNode;
18211 var ar = ac.childNodes;
18214 var other_nodes = [];
18215 var has_other_nodes = false;
18216 for (var i=0;i<ar.length;i++) {
18217 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18220 // fullly contained node.
18222 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18227 // probably selected..
18228 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18229 other_nodes.push(ar[i]);
18233 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18238 has_other_nodes = true;
18240 if (!nodes.length && other_nodes.length) {
18241 nodes= other_nodes;
18243 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18249 createRange: function(sel)
18251 // this has strange effects when using with
18252 // top toolbar - not sure if it's a great idea.
18253 //this.editor.contentWindow.focus();
18254 if (typeof sel != "undefined") {
18256 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18258 return this.doc.createRange();
18261 return this.doc.createRange();
18264 getParentElement: function()
18267 this.assignDocWin();
18268 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18270 var range = this.createRange(sel);
18273 var p = range.commonAncestorContainer;
18274 while (p.nodeType == 3) { // text node
18285 * Range intersection.. the hard stuff...
18289 * [ -- selected range --- ]
18293 * if end is before start or hits it. fail.
18294 * if start is after end or hits it fail.
18296 * if either hits (but other is outside. - then it's not
18302 // @see http://www.thismuchiknow.co.uk/?p=64.
18303 rangeIntersectsNode : function(range, node)
18305 var nodeRange = node.ownerDocument.createRange();
18307 nodeRange.selectNode(node);
18309 nodeRange.selectNodeContents(node);
18312 var rangeStartRange = range.cloneRange();
18313 rangeStartRange.collapse(true);
18315 var rangeEndRange = range.cloneRange();
18316 rangeEndRange.collapse(false);
18318 var nodeStartRange = nodeRange.cloneRange();
18319 nodeStartRange.collapse(true);
18321 var nodeEndRange = nodeRange.cloneRange();
18322 nodeEndRange.collapse(false);
18324 return rangeStartRange.compareBoundaryPoints(
18325 Range.START_TO_START, nodeEndRange) == -1 &&
18326 rangeEndRange.compareBoundaryPoints(
18327 Range.START_TO_START, nodeStartRange) == 1;
18331 rangeCompareNode : function(range, node)
18333 var nodeRange = node.ownerDocument.createRange();
18335 nodeRange.selectNode(node);
18337 nodeRange.selectNodeContents(node);
18341 range.collapse(true);
18343 nodeRange.collapse(true);
18345 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18346 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18348 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18350 var nodeIsBefore = ss == 1;
18351 var nodeIsAfter = ee == -1;
18353 if (nodeIsBefore && nodeIsAfter)
18355 if (!nodeIsBefore && nodeIsAfter)
18356 return 1; //right trailed.
18358 if (nodeIsBefore && !nodeIsAfter)
18359 return 2; // left trailed.
18364 // private? - in a new class?
18365 cleanUpPaste : function()
18367 // cleans up the whole document..
18368 Roo.log('cleanuppaste');
18370 this.cleanUpChildren(this.doc.body);
18371 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18372 if (clean != this.doc.body.innerHTML) {
18373 this.doc.body.innerHTML = clean;
18378 cleanWordChars : function(input) {// change the chars to hex code
18379 var he = Roo.HtmlEditorCore;
18381 var output = input;
18382 Roo.each(he.swapCodes, function(sw) {
18383 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18385 output = output.replace(swapper, sw[1]);
18392 cleanUpChildren : function (n)
18394 if (!n.childNodes.length) {
18397 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18398 this.cleanUpChild(n.childNodes[i]);
18405 cleanUpChild : function (node)
18408 //console.log(node);
18409 if (node.nodeName == "#text") {
18410 // clean up silly Windows -- stuff?
18413 if (node.nodeName == "#comment") {
18414 node.parentNode.removeChild(node);
18415 // clean up silly Windows -- stuff?
18418 var lcname = node.tagName.toLowerCase();
18419 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18420 // whitelist of tags..
18422 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18424 node.parentNode.removeChild(node);
18429 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18431 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18432 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18434 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18435 // remove_keep_children = true;
18438 if (remove_keep_children) {
18439 this.cleanUpChildren(node);
18440 // inserts everything just before this node...
18441 while (node.childNodes.length) {
18442 var cn = node.childNodes[0];
18443 node.removeChild(cn);
18444 node.parentNode.insertBefore(cn, node);
18446 node.parentNode.removeChild(node);
18450 if (!node.attributes || !node.attributes.length) {
18451 this.cleanUpChildren(node);
18455 function cleanAttr(n,v)
18458 if (v.match(/^\./) || v.match(/^\//)) {
18461 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18464 if (v.match(/^#/)) {
18467 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18468 node.removeAttribute(n);
18472 var cwhite = this.cwhite;
18473 var cblack = this.cblack;
18475 function cleanStyle(n,v)
18477 if (v.match(/expression/)) { //XSS?? should we even bother..
18478 node.removeAttribute(n);
18482 var parts = v.split(/;/);
18485 Roo.each(parts, function(p) {
18486 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18490 var l = p.split(':').shift().replace(/\s+/g,'');
18491 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18493 if ( cwhite.length && cblack.indexOf(l) > -1) {
18494 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18495 //node.removeAttribute(n);
18499 // only allow 'c whitelisted system attributes'
18500 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18501 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18502 //node.removeAttribute(n);
18512 if (clean.length) {
18513 node.setAttribute(n, clean.join(';'));
18515 node.removeAttribute(n);
18521 for (var i = node.attributes.length-1; i > -1 ; i--) {
18522 var a = node.attributes[i];
18525 if (a.name.toLowerCase().substr(0,2)=='on') {
18526 node.removeAttribute(a.name);
18529 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18530 node.removeAttribute(a.name);
18533 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18534 cleanAttr(a.name,a.value); // fixme..
18537 if (a.name == 'style') {
18538 cleanStyle(a.name,a.value);
18541 /// clean up MS crap..
18542 // tecnically this should be a list of valid class'es..
18545 if (a.name == 'class') {
18546 if (a.value.match(/^Mso/)) {
18547 node.className = '';
18550 if (a.value.match(/body/)) {
18551 node.className = '';
18562 this.cleanUpChildren(node);
18567 * Clean up MS wordisms...
18569 cleanWord : function(node)
18572 var cleanWordChildren = function()
18574 if (!node.childNodes.length) {
18577 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18578 _t.cleanWord(node.childNodes[i]);
18584 this.cleanWord(this.doc.body);
18587 if (node.nodeName == "#text") {
18588 // clean up silly Windows -- stuff?
18591 if (node.nodeName == "#comment") {
18592 node.parentNode.removeChild(node);
18593 // clean up silly Windows -- stuff?
18597 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18598 node.parentNode.removeChild(node);
18602 // remove - but keep children..
18603 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18604 while (node.childNodes.length) {
18605 var cn = node.childNodes[0];
18606 node.removeChild(cn);
18607 node.parentNode.insertBefore(cn, node);
18609 node.parentNode.removeChild(node);
18610 cleanWordChildren();
18614 if (node.className.length) {
18616 var cn = node.className.split(/\W+/);
18618 Roo.each(cn, function(cls) {
18619 if (cls.match(/Mso[a-zA-Z]+/)) {
18624 node.className = cna.length ? cna.join(' ') : '';
18626 node.removeAttribute("class");
18630 if (node.hasAttribute("lang")) {
18631 node.removeAttribute("lang");
18634 if (node.hasAttribute("style")) {
18636 var styles = node.getAttribute("style").split(";");
18638 Roo.each(styles, function(s) {
18639 if (!s.match(/:/)) {
18642 var kv = s.split(":");
18643 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18646 // what ever is left... we allow.
18649 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18650 if (!nstyle.length) {
18651 node.removeAttribute('style');
18655 cleanWordChildren();
18659 domToHTML : function(currentElement, depth, nopadtext) {
18661 depth = depth || 0;
18662 nopadtext = nopadtext || false;
18664 if (!currentElement) {
18665 return this.domToHTML(this.doc.body);
18668 //Roo.log(currentElement);
18670 var allText = false;
18671 var nodeName = currentElement.nodeName;
18672 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18674 if (nodeName == '#text') {
18676 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18681 if (nodeName != 'BODY') {
18684 // Prints the node tagName, such as <A>, <IMG>, etc
18687 for(i = 0; i < currentElement.attributes.length;i++) {
18689 var aname = currentElement.attributes.item(i).name;
18690 if (!currentElement.attributes.item(i).value.length) {
18693 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18696 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18705 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18708 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18713 // Traverse the tree
18715 var currentElementChild = currentElement.childNodes.item(i);
18716 var allText = true;
18717 var innerHTML = '';
18719 while (currentElementChild) {
18720 // Formatting code (indent the tree so it looks nice on the screen)
18721 var nopad = nopadtext;
18722 if (lastnode == 'SPAN') {
18726 if (currentElementChild.nodeName == '#text') {
18727 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18728 toadd = nopadtext ? toadd : toadd.trim();
18729 if (!nopad && toadd.length > 80) {
18730 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18732 innerHTML += toadd;
18735 currentElementChild = currentElement.childNodes.item(i);
18741 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18743 // Recursively traverse the tree structure of the child node
18744 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18745 lastnode = currentElementChild.nodeName;
18747 currentElementChild=currentElement.childNodes.item(i);
18753 // The remaining code is mostly for formatting the tree
18754 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18759 ret+= "</"+tagName+">";
18765 applyBlacklists : function()
18767 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18768 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18772 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18773 if (b.indexOf(tag) > -1) {
18776 this.white.push(tag);
18780 Roo.each(w, function(tag) {
18781 if (b.indexOf(tag) > -1) {
18784 if (this.white.indexOf(tag) > -1) {
18787 this.white.push(tag);
18792 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18793 if (w.indexOf(tag) > -1) {
18796 this.black.push(tag);
18800 Roo.each(b, function(tag) {
18801 if (w.indexOf(tag) > -1) {
18804 if (this.black.indexOf(tag) > -1) {
18807 this.black.push(tag);
18812 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18813 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18817 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18818 if (b.indexOf(tag) > -1) {
18821 this.cwhite.push(tag);
18825 Roo.each(w, function(tag) {
18826 if (b.indexOf(tag) > -1) {
18829 if (this.cwhite.indexOf(tag) > -1) {
18832 this.cwhite.push(tag);
18837 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18838 if (w.indexOf(tag) > -1) {
18841 this.cblack.push(tag);
18845 Roo.each(b, function(tag) {
18846 if (w.indexOf(tag) > -1) {
18849 if (this.cblack.indexOf(tag) > -1) {
18852 this.cblack.push(tag);
18857 setStylesheets : function(stylesheets)
18859 if(typeof(stylesheets) == 'string'){
18860 Roo.get(this.iframe.contentDocument.head).createChild({
18862 rel : 'stylesheet',
18871 Roo.each(stylesheets, function(s) {
18876 Roo.get(_this.iframe.contentDocument.head).createChild({
18878 rel : 'stylesheet',
18887 removeStylesheets : function()
18891 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18896 // hide stuff that is not compatible
18910 * @event specialkey
18914 * @cfg {String} fieldClass @hide
18917 * @cfg {String} focusClass @hide
18920 * @cfg {String} autoCreate @hide
18923 * @cfg {String} inputType @hide
18926 * @cfg {String} invalidClass @hide
18929 * @cfg {String} invalidText @hide
18932 * @cfg {String} msgFx @hide
18935 * @cfg {String} validateOnBlur @hide
18939 Roo.HtmlEditorCore.white = [
18940 'area', 'br', 'img', 'input', 'hr', 'wbr',
18942 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18943 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18944 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18945 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18946 'table', 'ul', 'xmp',
18948 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18951 'dir', 'menu', 'ol', 'ul', 'dl',
18957 Roo.HtmlEditorCore.black = [
18958 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18960 'base', 'basefont', 'bgsound', 'blink', 'body',
18961 'frame', 'frameset', 'head', 'html', 'ilayer',
18962 'iframe', 'layer', 'link', 'meta', 'object',
18963 'script', 'style' ,'title', 'xml' // clean later..
18965 Roo.HtmlEditorCore.clean = [
18966 'script', 'style', 'title', 'xml'
18968 Roo.HtmlEditorCore.remove = [
18973 Roo.HtmlEditorCore.ablack = [
18977 Roo.HtmlEditorCore.aclean = [
18978 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18982 Roo.HtmlEditorCore.pwhite= [
18983 'http', 'https', 'mailto'
18986 // white listed style attributes.
18987 Roo.HtmlEditorCore.cwhite= [
18988 // 'text-align', /// default is to allow most things..
18994 // black listed style attributes.
18995 Roo.HtmlEditorCore.cblack= [
18996 // 'font-size' -- this can be set by the project
19000 Roo.HtmlEditorCore.swapCodes =[
19019 * @class Roo.bootstrap.HtmlEditor
19020 * @extends Roo.bootstrap.TextArea
19021 * Bootstrap HtmlEditor class
19024 * Create a new HtmlEditor
19025 * @param {Object} config The config object
19028 Roo.bootstrap.HtmlEditor = function(config){
19029 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19030 if (!this.toolbars) {
19031 this.toolbars = [];
19033 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19036 * @event initialize
19037 * Fires when the editor is fully initialized (including the iframe)
19038 * @param {HtmlEditor} this
19043 * Fires when the editor is first receives the focus. Any insertion must wait
19044 * until after this event.
19045 * @param {HtmlEditor} this
19049 * @event beforesync
19050 * Fires before the textarea is updated with content from the editor iframe. Return false
19051 * to cancel the sync.
19052 * @param {HtmlEditor} this
19053 * @param {String} html
19057 * @event beforepush
19058 * Fires before the iframe editor is updated with content from the textarea. Return false
19059 * to cancel the push.
19060 * @param {HtmlEditor} this
19061 * @param {String} html
19066 * Fires when the textarea is updated with content from the editor iframe.
19067 * @param {HtmlEditor} this
19068 * @param {String} html
19073 * Fires when the iframe editor is updated with content from the textarea.
19074 * @param {HtmlEditor} this
19075 * @param {String} html
19079 * @event editmodechange
19080 * Fires when the editor switches edit modes
19081 * @param {HtmlEditor} this
19082 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19084 editmodechange: true,
19086 * @event editorevent
19087 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19088 * @param {HtmlEditor} this
19092 * @event firstfocus
19093 * Fires when on first focus - needed by toolbars..
19094 * @param {HtmlEditor} this
19099 * Auto save the htmlEditor value as a file into Events
19100 * @param {HtmlEditor} this
19104 * @event savedpreview
19105 * preview the saved version of htmlEditor
19106 * @param {HtmlEditor} this
19113 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19117 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19122 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19127 * @cfg {Number} height (in pixels)
19131 * @cfg {Number} width (in pixels)
19136 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19139 stylesheets: false,
19144 // private properties
19145 validationEvent : false,
19147 initialized : false,
19150 onFocus : Roo.emptyFn,
19152 hideMode:'offsets',
19155 tbContainer : false,
19157 toolbarContainer :function() {
19158 return this.wrap.select('.x-html-editor-tb',true).first();
19162 * Protected method that will not generally be called directly. It
19163 * is called when the editor creates its toolbar. Override this method if you need to
19164 * add custom toolbar buttons.
19165 * @param {HtmlEditor} editor
19167 createToolbar : function(){
19169 Roo.log("create toolbars");
19171 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19172 this.toolbars[0].render(this.toolbarContainer());
19176 // if (!editor.toolbars || !editor.toolbars.length) {
19177 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19180 // for (var i =0 ; i < editor.toolbars.length;i++) {
19181 // editor.toolbars[i] = Roo.factory(
19182 // typeof(editor.toolbars[i]) == 'string' ?
19183 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19184 // Roo.bootstrap.HtmlEditor);
19185 // editor.toolbars[i].init(editor);
19191 onRender : function(ct, position)
19193 // Roo.log("Call onRender: " + this.xtype);
19195 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19197 this.wrap = this.inputEl().wrap({
19198 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19201 this.editorcore.onRender(ct, position);
19203 if (this.resizable) {
19204 this.resizeEl = new Roo.Resizable(this.wrap, {
19208 minHeight : this.height,
19209 height: this.height,
19210 handles : this.resizable,
19213 resize : function(r, w, h) {
19214 _t.onResize(w,h); // -something
19220 this.createToolbar(this);
19223 if(!this.width && this.resizable){
19224 this.setSize(this.wrap.getSize());
19226 if (this.resizeEl) {
19227 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19228 // should trigger onReize..
19234 onResize : function(w, h)
19236 Roo.log('resize: ' +w + ',' + h );
19237 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19241 if(this.inputEl() ){
19242 if(typeof w == 'number'){
19243 var aw = w - this.wrap.getFrameWidth('lr');
19244 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19247 if(typeof h == 'number'){
19248 var tbh = -11; // fixme it needs to tool bar size!
19249 for (var i =0; i < this.toolbars.length;i++) {
19250 // fixme - ask toolbars for heights?
19251 tbh += this.toolbars[i].el.getHeight();
19252 //if (this.toolbars[i].footer) {
19253 // tbh += this.toolbars[i].footer.el.getHeight();
19261 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19262 ah -= 5; // knock a few pixes off for look..
19263 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19267 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19268 this.editorcore.onResize(ew,eh);
19273 * Toggles the editor between standard and source edit mode.
19274 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19276 toggleSourceEdit : function(sourceEditMode)
19278 this.editorcore.toggleSourceEdit(sourceEditMode);
19280 if(this.editorcore.sourceEditMode){
19281 Roo.log('editor - showing textarea');
19284 // Roo.log(this.syncValue());
19286 this.inputEl().removeClass(['hide', 'x-hidden']);
19287 this.inputEl().dom.removeAttribute('tabIndex');
19288 this.inputEl().focus();
19290 Roo.log('editor - hiding textarea');
19292 // Roo.log(this.pushValue());
19295 this.inputEl().addClass(['hide', 'x-hidden']);
19296 this.inputEl().dom.setAttribute('tabIndex', -1);
19297 //this.deferFocus();
19300 if(this.resizable){
19301 this.setSize(this.wrap.getSize());
19304 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19307 // private (for BoxComponent)
19308 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19310 // private (for BoxComponent)
19311 getResizeEl : function(){
19315 // private (for BoxComponent)
19316 getPositionEl : function(){
19321 initEvents : function(){
19322 this.originalValue = this.getValue();
19326 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19329 // markInvalid : Roo.emptyFn,
19331 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19334 // clearInvalid : Roo.emptyFn,
19336 setValue : function(v){
19337 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19338 this.editorcore.pushValue();
19343 deferFocus : function(){
19344 this.focus.defer(10, this);
19348 focus : function(){
19349 this.editorcore.focus();
19355 onDestroy : function(){
19361 for (var i =0; i < this.toolbars.length;i++) {
19362 // fixme - ask toolbars for heights?
19363 this.toolbars[i].onDestroy();
19366 this.wrap.dom.innerHTML = '';
19367 this.wrap.remove();
19372 onFirstFocus : function(){
19373 //Roo.log("onFirstFocus");
19374 this.editorcore.onFirstFocus();
19375 for (var i =0; i < this.toolbars.length;i++) {
19376 this.toolbars[i].onFirstFocus();
19382 syncValue : function()
19384 this.editorcore.syncValue();
19387 pushValue : function()
19389 this.editorcore.pushValue();
19393 // hide stuff that is not compatible
19407 * @event specialkey
19411 * @cfg {String} fieldClass @hide
19414 * @cfg {String} focusClass @hide
19417 * @cfg {String} autoCreate @hide
19420 * @cfg {String} inputType @hide
19423 * @cfg {String} invalidClass @hide
19426 * @cfg {String} invalidText @hide
19429 * @cfg {String} msgFx @hide
19432 * @cfg {String} validateOnBlur @hide
19441 Roo.namespace('Roo.bootstrap.htmleditor');
19443 * @class Roo.bootstrap.HtmlEditorToolbar1
19448 new Roo.bootstrap.HtmlEditor({
19451 new Roo.bootstrap.HtmlEditorToolbar1({
19452 disable : { fonts: 1 , format: 1, ..., ... , ...],
19458 * @cfg {Object} disable List of elements to disable..
19459 * @cfg {Array} btns List of additional buttons.
19463 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19466 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19469 Roo.apply(this, config);
19471 // default disabled, based on 'good practice'..
19472 this.disable = this.disable || {};
19473 Roo.applyIf(this.disable, {
19476 specialElements : true
19478 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19480 this.editor = config.editor;
19481 this.editorcore = config.editor.editorcore;
19483 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19485 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19486 // dont call parent... till later.
19488 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19493 editorcore : false,
19498 "h1","h2","h3","h4","h5","h6",
19500 "abbr", "acronym", "address", "cite", "samp", "var",
19504 onRender : function(ct, position)
19506 // Roo.log("Call onRender: " + this.xtype);
19508 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19510 this.el.dom.style.marginBottom = '0';
19512 var editorcore = this.editorcore;
19513 var editor= this.editor;
19516 var btn = function(id,cmd , toggle, handler){
19518 var event = toggle ? 'toggle' : 'click';
19523 xns: Roo.bootstrap,
19526 enableToggle:toggle !== false,
19528 pressed : toggle ? false : null,
19531 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19532 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19541 xns: Roo.bootstrap,
19542 glyphicon : 'font',
19546 xns: Roo.bootstrap,
19550 Roo.each(this.formats, function(f) {
19551 style.menu.items.push({
19553 xns: Roo.bootstrap,
19554 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19559 editorcore.insertTag(this.tagname);
19566 children.push(style);
19569 btn('bold',false,true);
19570 btn('italic',false,true);
19571 btn('align-left', 'justifyleft',true);
19572 btn('align-center', 'justifycenter',true);
19573 btn('align-right' , 'justifyright',true);
19574 btn('link', false, false, function(btn) {
19575 //Roo.log("create link?");
19576 var url = prompt(this.createLinkText, this.defaultLinkValue);
19577 if(url && url != 'http:/'+'/'){
19578 this.editorcore.relayCmd('createlink', url);
19581 btn('list','insertunorderedlist',true);
19582 btn('pencil', false,true, function(btn){
19585 this.toggleSourceEdit(btn.pressed);
19591 xns: Roo.bootstrap,
19596 xns: Roo.bootstrap,
19601 cog.menu.items.push({
19603 xns: Roo.bootstrap,
19604 html : Clean styles,
19609 editorcore.insertTag(this.tagname);
19618 this.xtype = 'NavSimplebar';
19620 for(var i=0;i< children.length;i++) {
19622 this.buttons.add(this.addxtypeChild(children[i]));
19626 editor.on('editorevent', this.updateToolbar, this);
19628 onBtnClick : function(id)
19630 this.editorcore.relayCmd(id);
19631 this.editorcore.focus();
19635 * Protected method that will not generally be called directly. It triggers
19636 * a toolbar update by reading the markup state of the current selection in the editor.
19638 updateToolbar: function(){
19640 if(!this.editorcore.activated){
19641 this.editor.onFirstFocus(); // is this neeed?
19645 var btns = this.buttons;
19646 var doc = this.editorcore.doc;
19647 btns.get('bold').setActive(doc.queryCommandState('bold'));
19648 btns.get('italic').setActive(doc.queryCommandState('italic'));
19649 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19651 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19652 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19653 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19655 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19656 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19659 var ans = this.editorcore.getAllAncestors();
19660 if (this.formatCombo) {
19663 var store = this.formatCombo.store;
19664 this.formatCombo.setValue("");
19665 for (var i =0; i < ans.length;i++) {
19666 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19668 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19676 // hides menus... - so this cant be on a menu...
19677 Roo.bootstrap.MenuMgr.hideAll();
19679 Roo.bootstrap.MenuMgr.hideAll();
19680 //this.editorsyncValue();
19682 onFirstFocus: function() {
19683 this.buttons.each(function(item){
19687 toggleSourceEdit : function(sourceEditMode){
19690 if(sourceEditMode){
19691 Roo.log("disabling buttons");
19692 this.buttons.each( function(item){
19693 if(item.cmd != 'pencil'){
19699 Roo.log("enabling buttons");
19700 if(this.editorcore.initialized){
19701 this.buttons.each( function(item){
19707 Roo.log("calling toggole on editor");
19708 // tell the editor that it's been pressed..
19709 this.editor.toggleSourceEdit(sourceEditMode);
19719 * @class Roo.bootstrap.Table.AbstractSelectionModel
19720 * @extends Roo.util.Observable
19721 * Abstract base class for grid SelectionModels. It provides the interface that should be
19722 * implemented by descendant classes. This class should not be directly instantiated.
19725 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19726 this.locked = false;
19727 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19731 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19732 /** @ignore Called by the grid automatically. Do not call directly. */
19733 init : function(grid){
19739 * Locks the selections.
19742 this.locked = true;
19746 * Unlocks the selections.
19748 unlock : function(){
19749 this.locked = false;
19753 * Returns true if the selections are locked.
19754 * @return {Boolean}
19756 isLocked : function(){
19757 return this.locked;
19761 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19762 * @class Roo.bootstrap.Table.RowSelectionModel
19763 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19764 * It supports multiple selections and keyboard selection/navigation.
19766 * @param {Object} config
19769 Roo.bootstrap.Table.RowSelectionModel = function(config){
19770 Roo.apply(this, config);
19771 this.selections = new Roo.util.MixedCollection(false, function(o){
19776 this.lastActive = false;
19780 * @event selectionchange
19781 * Fires when the selection changes
19782 * @param {SelectionModel} this
19784 "selectionchange" : true,
19786 * @event afterselectionchange
19787 * Fires after the selection changes (eg. by key press or clicking)
19788 * @param {SelectionModel} this
19790 "afterselectionchange" : true,
19792 * @event beforerowselect
19793 * Fires when a row is selected being selected, return false to cancel.
19794 * @param {SelectionModel} this
19795 * @param {Number} rowIndex The selected index
19796 * @param {Boolean} keepExisting False if other selections will be cleared
19798 "beforerowselect" : true,
19801 * Fires when a row is selected.
19802 * @param {SelectionModel} this
19803 * @param {Number} rowIndex The selected index
19804 * @param {Roo.data.Record} r The record
19806 "rowselect" : true,
19808 * @event rowdeselect
19809 * Fires when a row is deselected.
19810 * @param {SelectionModel} this
19811 * @param {Number} rowIndex The selected index
19813 "rowdeselect" : true
19815 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19816 this.locked = false;
19819 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19821 * @cfg {Boolean} singleSelect
19822 * True to allow selection of only one row at a time (defaults to false)
19824 singleSelect : false,
19827 initEvents : function(){
19829 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19830 this.grid.on("mousedown", this.handleMouseDown, this);
19831 }else{ // allow click to work like normal
19832 this.grid.on("rowclick", this.handleDragableRowClick, this);
19835 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19836 "up" : function(e){
19838 this.selectPrevious(e.shiftKey);
19839 }else if(this.last !== false && this.lastActive !== false){
19840 var last = this.last;
19841 this.selectRange(this.last, this.lastActive-1);
19842 this.grid.getView().focusRow(this.lastActive);
19843 if(last !== false){
19847 this.selectFirstRow();
19849 this.fireEvent("afterselectionchange", this);
19851 "down" : function(e){
19853 this.selectNext(e.shiftKey);
19854 }else if(this.last !== false && this.lastActive !== false){
19855 var last = this.last;
19856 this.selectRange(this.last, this.lastActive+1);
19857 this.grid.getView().focusRow(this.lastActive);
19858 if(last !== false){
19862 this.selectFirstRow();
19864 this.fireEvent("afterselectionchange", this);
19869 var view = this.grid.view;
19870 view.on("refresh", this.onRefresh, this);
19871 view.on("rowupdated", this.onRowUpdated, this);
19872 view.on("rowremoved", this.onRemove, this);
19876 onRefresh : function(){
19877 var ds = this.grid.dataSource, i, v = this.grid.view;
19878 var s = this.selections;
19879 s.each(function(r){
19880 if((i = ds.indexOfId(r.id)) != -1){
19889 onRemove : function(v, index, r){
19890 this.selections.remove(r);
19894 onRowUpdated : function(v, index, r){
19895 if(this.isSelected(r)){
19896 v.onRowSelect(index);
19902 * @param {Array} records The records to select
19903 * @param {Boolean} keepExisting (optional) True to keep existing selections
19905 selectRecords : function(records, keepExisting){
19907 this.clearSelections();
19909 var ds = this.grid.dataSource;
19910 for(var i = 0, len = records.length; i < len; i++){
19911 this.selectRow(ds.indexOf(records[i]), true);
19916 * Gets the number of selected rows.
19919 getCount : function(){
19920 return this.selections.length;
19924 * Selects the first row in the grid.
19926 selectFirstRow : function(){
19931 * Select the last row.
19932 * @param {Boolean} keepExisting (optional) True to keep existing selections
19934 selectLastRow : function(keepExisting){
19935 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19939 * Selects the row immediately following the last selected row.
19940 * @param {Boolean} keepExisting (optional) True to keep existing selections
19942 selectNext : function(keepExisting){
19943 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19944 this.selectRow(this.last+1, keepExisting);
19945 this.grid.getView().focusRow(this.last);
19950 * Selects the row that precedes the last selected row.
19951 * @param {Boolean} keepExisting (optional) True to keep existing selections
19953 selectPrevious : function(keepExisting){
19955 this.selectRow(this.last-1, keepExisting);
19956 this.grid.getView().focusRow(this.last);
19961 * Returns the selected records
19962 * @return {Array} Array of selected records
19964 getSelections : function(){
19965 return [].concat(this.selections.items);
19969 * Returns the first selected record.
19972 getSelected : function(){
19973 return this.selections.itemAt(0);
19978 * Clears all selections.
19980 clearSelections : function(fast){
19981 if(this.locked) return;
19983 var ds = this.grid.dataSource;
19984 var s = this.selections;
19985 s.each(function(r){
19986 this.deselectRow(ds.indexOfId(r.id));
19990 this.selections.clear();
19997 * Selects all rows.
19999 selectAll : function(){
20000 if(this.locked) return;
20001 this.selections.clear();
20002 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20003 this.selectRow(i, true);
20008 * Returns True if there is a selection.
20009 * @return {Boolean}
20011 hasSelection : function(){
20012 return this.selections.length > 0;
20016 * Returns True if the specified row is selected.
20017 * @param {Number/Record} record The record or index of the record to check
20018 * @return {Boolean}
20020 isSelected : function(index){
20021 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20022 return (r && this.selections.key(r.id) ? true : false);
20026 * Returns True if the specified record id is selected.
20027 * @param {String} id The id of record to check
20028 * @return {Boolean}
20030 isIdSelected : function(id){
20031 return (this.selections.key(id) ? true : false);
20035 handleMouseDown : function(e, t){
20036 var view = this.grid.getView(), rowIndex;
20037 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20040 if(e.shiftKey && this.last !== false){
20041 var last = this.last;
20042 this.selectRange(last, rowIndex, e.ctrlKey);
20043 this.last = last; // reset the last
20044 view.focusRow(rowIndex);
20046 var isSelected = this.isSelected(rowIndex);
20047 if(e.button !== 0 && isSelected){
20048 view.focusRow(rowIndex);
20049 }else if(e.ctrlKey && isSelected){
20050 this.deselectRow(rowIndex);
20051 }else if(!isSelected){
20052 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20053 view.focusRow(rowIndex);
20056 this.fireEvent("afterselectionchange", this);
20059 handleDragableRowClick : function(grid, rowIndex, e)
20061 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20062 this.selectRow(rowIndex, false);
20063 grid.view.focusRow(rowIndex);
20064 this.fireEvent("afterselectionchange", this);
20069 * Selects multiple rows.
20070 * @param {Array} rows Array of the indexes of the row to select
20071 * @param {Boolean} keepExisting (optional) True to keep existing selections
20073 selectRows : function(rows, keepExisting){
20075 this.clearSelections();
20077 for(var i = 0, len = rows.length; i < len; i++){
20078 this.selectRow(rows[i], true);
20083 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20084 * @param {Number} startRow The index of the first row in the range
20085 * @param {Number} endRow The index of the last row in the range
20086 * @param {Boolean} keepExisting (optional) True to retain existing selections
20088 selectRange : function(startRow, endRow, keepExisting){
20089 if(this.locked) return;
20091 this.clearSelections();
20093 if(startRow <= endRow){
20094 for(var i = startRow; i <= endRow; i++){
20095 this.selectRow(i, true);
20098 for(var i = startRow; i >= endRow; i--){
20099 this.selectRow(i, true);
20105 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20106 * @param {Number} startRow The index of the first row in the range
20107 * @param {Number} endRow The index of the last row in the range
20109 deselectRange : function(startRow, endRow, preventViewNotify){
20110 if(this.locked) return;
20111 for(var i = startRow; i <= endRow; i++){
20112 this.deselectRow(i, preventViewNotify);
20118 * @param {Number} row The index of the row to select
20119 * @param {Boolean} keepExisting (optional) True to keep existing selections
20121 selectRow : function(index, keepExisting, preventViewNotify){
20122 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20123 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20124 if(!keepExisting || this.singleSelect){
20125 this.clearSelections();
20127 var r = this.grid.dataSource.getAt(index);
20128 this.selections.add(r);
20129 this.last = this.lastActive = index;
20130 if(!preventViewNotify){
20131 this.grid.getView().onRowSelect(index);
20133 this.fireEvent("rowselect", this, index, r);
20134 this.fireEvent("selectionchange", this);
20140 * @param {Number} row The index of the row to deselect
20142 deselectRow : function(index, preventViewNotify){
20143 if(this.locked) return;
20144 if(this.last == index){
20147 if(this.lastActive == index){
20148 this.lastActive = false;
20150 var r = this.grid.dataSource.getAt(index);
20151 this.selections.remove(r);
20152 if(!preventViewNotify){
20153 this.grid.getView().onRowDeselect(index);
20155 this.fireEvent("rowdeselect", this, index);
20156 this.fireEvent("selectionchange", this);
20160 restoreLast : function(){
20162 this.last = this._last;
20167 acceptsNav : function(row, col, cm){
20168 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20172 onEditorKey : function(field, e){
20173 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20178 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20180 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20182 }else if(k == e.ENTER && !e.ctrlKey){
20186 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20188 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20190 }else if(k == e.ESC){
20194 g.startEditing(newCell[0], newCell[1]);
20199 * Ext JS Library 1.1.1
20200 * Copyright(c) 2006-2007, Ext JS, LLC.
20202 * Originally Released Under LGPL - original licence link has changed is not relivant.
20205 * <script type="text/javascript">
20209 * @class Roo.bootstrap.PagingToolbar
20211 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20213 * Create a new PagingToolbar
20214 * @param {Object} config The config object
20216 Roo.bootstrap.PagingToolbar = function(config)
20218 // old args format still supported... - xtype is prefered..
20219 // created from xtype...
20220 var ds = config.dataSource;
20221 this.toolbarItems = [];
20222 if (config.items) {
20223 this.toolbarItems = config.items;
20224 // config.items = [];
20227 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20234 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20238 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20240 * @cfg {Roo.data.Store} dataSource
20241 * The underlying data store providing the paged data
20244 * @cfg {String/HTMLElement/Element} container
20245 * container The id or element that will contain the toolbar
20248 * @cfg {Boolean} displayInfo
20249 * True to display the displayMsg (defaults to false)
20252 * @cfg {Number} pageSize
20253 * The number of records to display per page (defaults to 20)
20257 * @cfg {String} displayMsg
20258 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20260 displayMsg : 'Displaying {0} - {1} of {2}',
20262 * @cfg {String} emptyMsg
20263 * The message to display when no records are found (defaults to "No data to display")
20265 emptyMsg : 'No data to display',
20267 * Customizable piece of the default paging text (defaults to "Page")
20270 beforePageText : "Page",
20272 * Customizable piece of the default paging text (defaults to "of %0")
20275 afterPageText : "of {0}",
20277 * Customizable piece of the default paging text (defaults to "First Page")
20280 firstText : "First Page",
20282 * Customizable piece of the default paging text (defaults to "Previous Page")
20285 prevText : "Previous Page",
20287 * Customizable piece of the default paging text (defaults to "Next Page")
20290 nextText : "Next Page",
20292 * Customizable piece of the default paging text (defaults to "Last Page")
20295 lastText : "Last Page",
20297 * Customizable piece of the default paging text (defaults to "Refresh")
20300 refreshText : "Refresh",
20304 onRender : function(ct, position)
20306 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20307 this.navgroup.parentId = this.id;
20308 this.navgroup.onRender(this.el, null);
20309 // add the buttons to the navgroup
20311 if(this.displayInfo){
20312 Roo.log(this.el.select('ul.navbar-nav',true).first());
20313 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20314 this.displayEl = this.el.select('.x-paging-info', true).first();
20315 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20316 // this.displayEl = navel.el.select('span',true).first();
20322 Roo.each(_this.buttons, function(e){
20323 Roo.factory(e).onRender(_this.el, null);
20327 Roo.each(_this.toolbarItems, function(e) {
20328 _this.navgroup.addItem(e);
20332 this.first = this.navgroup.addItem({
20333 tooltip: this.firstText,
20335 icon : 'fa fa-backward',
20337 preventDefault: true,
20338 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20341 this.prev = this.navgroup.addItem({
20342 tooltip: this.prevText,
20344 icon : 'fa fa-step-backward',
20346 preventDefault: true,
20347 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20349 //this.addSeparator();
20352 var field = this.navgroup.addItem( {
20354 cls : 'x-paging-position',
20356 html : this.beforePageText +
20357 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20358 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20361 this.field = field.el.select('input', true).first();
20362 this.field.on("keydown", this.onPagingKeydown, this);
20363 this.field.on("focus", function(){this.dom.select();});
20366 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20367 //this.field.setHeight(18);
20368 //this.addSeparator();
20369 this.next = this.navgroup.addItem({
20370 tooltip: this.nextText,
20372 html : ' <i class="fa fa-step-forward">',
20374 preventDefault: true,
20375 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20377 this.last = this.navgroup.addItem({
20378 tooltip: this.lastText,
20379 icon : 'fa fa-forward',
20382 preventDefault: true,
20383 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20385 //this.addSeparator();
20386 this.loading = this.navgroup.addItem({
20387 tooltip: this.refreshText,
20388 icon: 'fa fa-refresh',
20389 preventDefault: true,
20390 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20396 updateInfo : function(){
20397 if(this.displayEl){
20398 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20399 var msg = count == 0 ?
20403 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20405 this.displayEl.update(msg);
20410 onLoad : function(ds, r, o){
20411 this.cursor = o.params ? o.params.start : 0;
20412 var d = this.getPageData(),
20416 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20417 this.field.dom.value = ap;
20418 this.first.setDisabled(ap == 1);
20419 this.prev.setDisabled(ap == 1);
20420 this.next.setDisabled(ap == ps);
20421 this.last.setDisabled(ap == ps);
20422 this.loading.enable();
20427 getPageData : function(){
20428 var total = this.ds.getTotalCount();
20431 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20432 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20437 onLoadError : function(){
20438 this.loading.enable();
20442 onPagingKeydown : function(e){
20443 var k = e.getKey();
20444 var d = this.getPageData();
20446 var v = this.field.dom.value, pageNum;
20447 if(!v || isNaN(pageNum = parseInt(v, 10))){
20448 this.field.dom.value = d.activePage;
20451 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20452 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20455 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))
20457 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20458 this.field.dom.value = pageNum;
20459 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20462 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20464 var v = this.field.dom.value, pageNum;
20465 var increment = (e.shiftKey) ? 10 : 1;
20466 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20468 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20469 this.field.dom.value = d.activePage;
20472 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20474 this.field.dom.value = parseInt(v, 10) + increment;
20475 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20476 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20483 beforeLoad : function(){
20485 this.loading.disable();
20490 onClick : function(which){
20499 ds.load({params:{start: 0, limit: this.pageSize}});
20502 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20505 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20508 var total = ds.getTotalCount();
20509 var extra = total % this.pageSize;
20510 var lastStart = extra ? (total - extra) : total-this.pageSize;
20511 ds.load({params:{start: lastStart, limit: this.pageSize}});
20514 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20520 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20521 * @param {Roo.data.Store} store The data store to unbind
20523 unbind : function(ds){
20524 ds.un("beforeload", this.beforeLoad, this);
20525 ds.un("load", this.onLoad, this);
20526 ds.un("loadexception", this.onLoadError, this);
20527 ds.un("remove", this.updateInfo, this);
20528 ds.un("add", this.updateInfo, this);
20529 this.ds = undefined;
20533 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20534 * @param {Roo.data.Store} store The data store to bind
20536 bind : function(ds){
20537 ds.on("beforeload", this.beforeLoad, this);
20538 ds.on("load", this.onLoad, this);
20539 ds.on("loadexception", this.onLoadError, this);
20540 ds.on("remove", this.updateInfo, this);
20541 ds.on("add", this.updateInfo, this);
20552 * @class Roo.bootstrap.MessageBar
20553 * @extends Roo.bootstrap.Component
20554 * Bootstrap MessageBar class
20555 * @cfg {String} html contents of the MessageBar
20556 * @cfg {String} weight (info | success | warning | danger) default info
20557 * @cfg {String} beforeClass insert the bar before the given class
20558 * @cfg {Boolean} closable (true | false) default false
20559 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20562 * Create a new Element
20563 * @param {Object} config The config object
20566 Roo.bootstrap.MessageBar = function(config){
20567 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20570 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20576 beforeClass: 'bootstrap-sticky-wrap',
20578 getAutoCreate : function(){
20582 cls: 'alert alert-dismissable alert-' + this.weight,
20587 html: this.html || ''
20593 cfg.cls += ' alert-messages-fixed';
20607 onRender : function(ct, position)
20609 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20612 var cfg = Roo.apply({}, this.getAutoCreate());
20616 cfg.cls += ' ' + this.cls;
20619 cfg.style = this.style;
20621 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20623 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20626 this.el.select('>button.close').on('click', this.hide, this);
20632 if (!this.rendered) {
20638 this.fireEvent('show', this);
20644 if (!this.rendered) {
20650 this.fireEvent('hide', this);
20653 update : function()
20655 // var e = this.el.dom.firstChild;
20657 // if(this.closable){
20658 // e = e.nextSibling;
20661 // e.data = this.html || '';
20663 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20679 * @class Roo.bootstrap.Graph
20680 * @extends Roo.bootstrap.Component
20681 * Bootstrap Graph class
20685 @cfg {String} graphtype bar | vbar | pie
20686 @cfg {number} g_x coodinator | centre x (pie)
20687 @cfg {number} g_y coodinator | centre y (pie)
20688 @cfg {number} g_r radius (pie)
20689 @cfg {number} g_height height of the chart (respected by all elements in the set)
20690 @cfg {number} g_width width of the chart (respected by all elements in the set)
20691 @cfg {Object} title The title of the chart
20694 -opts (object) options for the chart
20696 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20697 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20699 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.
20700 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20702 o stretch (boolean)
20704 -opts (object) options for the pie
20707 o startAngle (number)
20708 o endAngle (number)
20712 * Create a new Input
20713 * @param {Object} config The config object
20716 Roo.bootstrap.Graph = function(config){
20717 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20723 * The img click event for the img.
20724 * @param {Roo.EventObject} e
20730 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20741 //g_colors: this.colors,
20748 getAutoCreate : function(){
20759 onRender : function(ct,position){
20760 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20761 this.raphael = Raphael(this.el.dom);
20763 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20764 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20765 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20766 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20768 r.text(160, 10, "Single Series Chart").attr(txtattr);
20769 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20770 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20771 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20773 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20774 r.barchart(330, 10, 300, 220, data1);
20775 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20776 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20779 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20780 // r.barchart(30, 30, 560, 250, xdata, {
20781 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20782 // axis : "0 0 1 1",
20783 // axisxlabels : xdata
20784 // //yvalues : cols,
20787 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20789 // this.load(null,xdata,{
20790 // axis : "0 0 1 1",
20791 // axisxlabels : xdata
20796 load : function(graphtype,xdata,opts){
20797 this.raphael.clear();
20799 graphtype = this.graphtype;
20804 var r = this.raphael,
20805 fin = function () {
20806 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20808 fout = function () {
20809 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20811 pfin = function() {
20812 this.sector.stop();
20813 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20816 this.label[0].stop();
20817 this.label[0].attr({ r: 7.5 });
20818 this.label[1].attr({ "font-weight": 800 });
20821 pfout = function() {
20822 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20825 this.label[0].animate({ r: 5 }, 500, "bounce");
20826 this.label[1].attr({ "font-weight": 400 });
20832 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20835 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20838 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20839 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20841 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20848 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20853 setTitle: function(o)
20858 initEvents: function() {
20861 this.el.on('click', this.onClick, this);
20865 onClick : function(e)
20867 Roo.log('img onclick');
20868 this.fireEvent('click', this, e);
20880 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20883 * @class Roo.bootstrap.dash.NumberBox
20884 * @extends Roo.bootstrap.Component
20885 * Bootstrap NumberBox class
20886 * @cfg {String} headline Box headline
20887 * @cfg {String} content Box content
20888 * @cfg {String} icon Box icon
20889 * @cfg {String} footer Footer text
20890 * @cfg {String} fhref Footer href
20893 * Create a new NumberBox
20894 * @param {Object} config The config object
20898 Roo.bootstrap.dash.NumberBox = function(config){
20899 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20903 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20912 getAutoCreate : function(){
20916 cls : 'small-box ',
20924 cls : 'roo-headline',
20925 html : this.headline
20929 cls : 'roo-content',
20930 html : this.content
20944 cls : 'ion ' + this.icon
20953 cls : 'small-box-footer',
20954 href : this.fhref || '#',
20958 cfg.cn.push(footer);
20965 onRender : function(ct,position){
20966 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20973 setHeadline: function (value)
20975 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20978 setFooter: function (value, href)
20980 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20983 this.el.select('a.small-box-footer',true).first().attr('href', href);
20988 setContent: function (value)
20990 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20993 initEvents: function()
21007 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21010 * @class Roo.bootstrap.dash.TabBox
21011 * @extends Roo.bootstrap.Component
21012 * Bootstrap TabBox class
21013 * @cfg {String} title Title of the TabBox
21014 * @cfg {String} icon Icon of the TabBox
21015 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21016 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21019 * Create a new TabBox
21020 * @param {Object} config The config object
21024 Roo.bootstrap.dash.TabBox = function(config){
21025 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21030 * When a pane is added
21031 * @param {Roo.bootstrap.dash.TabPane} pane
21035 * @event activatepane
21036 * When a pane is activated
21037 * @param {Roo.bootstrap.dash.TabPane} pane
21039 "activatepane" : true
21047 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21052 tabScrollable : false,
21054 getChildContainer : function()
21056 return this.el.select('.tab-content', true).first();
21059 getAutoCreate : function(){
21063 cls: 'pull-left header',
21071 cls: 'fa ' + this.icon
21077 cls: 'nav nav-tabs pull-right',
21083 if(this.tabScrollable){
21090 cls: 'nav nav-tabs pull-right',
21101 cls: 'nav-tabs-custom',
21106 cls: 'tab-content no-padding',
21114 initEvents : function()
21116 //Roo.log('add add pane handler');
21117 this.on('addpane', this.onAddPane, this);
21120 * Updates the box title
21121 * @param {String} html to set the title to.
21123 setTitle : function(value)
21125 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21127 onAddPane : function(pane)
21129 this.panes.push(pane);
21130 //Roo.log('addpane');
21132 // tabs are rendere left to right..
21133 if(!this.showtabs){
21137 var ctr = this.el.select('.nav-tabs', true).first();
21140 var existing = ctr.select('.nav-tab',true);
21141 var qty = existing.getCount();;
21144 var tab = ctr.createChild({
21146 cls : 'nav-tab' + (qty ? '' : ' active'),
21154 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21157 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21159 pane.el.addClass('active');
21164 onTabClick : function(ev,un,ob,pane)
21166 //Roo.log('tab - prev default');
21167 ev.preventDefault();
21170 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21171 pane.tab.addClass('active');
21172 //Roo.log(pane.title);
21173 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21174 // technically we should have a deactivate event.. but maybe add later.
21175 // and it should not de-activate the selected tab...
21176 this.fireEvent('activatepane', pane);
21177 pane.el.addClass('active');
21178 pane.fireEvent('activate');
21183 getActivePane : function()
21186 Roo.each(this.panes, function(p) {
21187 if(p.el.hasClass('active')){
21208 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21210 * @class Roo.bootstrap.TabPane
21211 * @extends Roo.bootstrap.Component
21212 * Bootstrap TabPane class
21213 * @cfg {Boolean} active (false | true) Default false
21214 * @cfg {String} title title of panel
21218 * Create a new TabPane
21219 * @param {Object} config The config object
21222 Roo.bootstrap.dash.TabPane = function(config){
21223 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21229 * When a pane is activated
21230 * @param {Roo.bootstrap.dash.TabPane} pane
21237 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21242 // the tabBox that this is attached to.
21245 getAutoCreate : function()
21253 cfg.cls += ' active';
21258 initEvents : function()
21260 //Roo.log('trigger add pane handler');
21261 this.parent().fireEvent('addpane', this)
21265 * Updates the tab title
21266 * @param {String} html to set the title to.
21268 setTitle: function(str)
21274 this.tab.select('a', true).first().dom.innerHTML = str;
21291 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21294 * @class Roo.bootstrap.menu.Menu
21295 * @extends Roo.bootstrap.Component
21296 * Bootstrap Menu class - container for Menu
21297 * @cfg {String} html Text of the menu
21298 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21299 * @cfg {String} icon Font awesome icon
21300 * @cfg {String} pos Menu align to (top | bottom) default bottom
21304 * Create a new Menu
21305 * @param {Object} config The config object
21309 Roo.bootstrap.menu.Menu = function(config){
21310 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21314 * @event beforeshow
21315 * Fires before this menu is displayed
21316 * @param {Roo.bootstrap.menu.Menu} this
21320 * @event beforehide
21321 * Fires before this menu is hidden
21322 * @param {Roo.bootstrap.menu.Menu} this
21327 * Fires after this menu is displayed
21328 * @param {Roo.bootstrap.menu.Menu} this
21333 * Fires after this menu is hidden
21334 * @param {Roo.bootstrap.menu.Menu} this
21339 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21340 * @param {Roo.bootstrap.menu.Menu} this
21341 * @param {Roo.EventObject} e
21348 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21352 weight : 'default',
21357 getChildContainer : function() {
21358 if(this.isSubMenu){
21362 return this.el.select('ul.dropdown-menu', true).first();
21365 getAutoCreate : function()
21370 cls : 'roo-menu-text',
21378 cls : 'fa ' + this.icon
21389 cls : 'dropdown-button btn btn-' + this.weight,
21394 cls : 'dropdown-toggle btn btn-' + this.weight,
21404 cls : 'dropdown-menu'
21410 if(this.pos == 'top'){
21411 cfg.cls += ' dropup';
21414 if(this.isSubMenu){
21417 cls : 'dropdown-menu'
21424 onRender : function(ct, position)
21426 this.isSubMenu = ct.hasClass('dropdown-submenu');
21428 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21431 initEvents : function()
21433 if(this.isSubMenu){
21437 this.hidden = true;
21439 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21440 this.triggerEl.on('click', this.onTriggerPress, this);
21442 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21443 this.buttonEl.on('click', this.onClick, this);
21449 if(this.isSubMenu){
21453 return this.el.select('ul.dropdown-menu', true).first();
21456 onClick : function(e)
21458 this.fireEvent("click", this, e);
21461 onTriggerPress : function(e)
21463 if (this.isVisible()) {
21470 isVisible : function(){
21471 return !this.hidden;
21476 this.fireEvent("beforeshow", this);
21478 this.hidden = false;
21479 this.el.addClass('open');
21481 Roo.get(document).on("mouseup", this.onMouseUp, this);
21483 this.fireEvent("show", this);
21490 this.fireEvent("beforehide", this);
21492 this.hidden = true;
21493 this.el.removeClass('open');
21495 Roo.get(document).un("mouseup", this.onMouseUp);
21497 this.fireEvent("hide", this);
21500 onMouseUp : function()
21514 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21517 * @class Roo.bootstrap.menu.Item
21518 * @extends Roo.bootstrap.Component
21519 * Bootstrap MenuItem class
21520 * @cfg {Boolean} submenu (true | false) default false
21521 * @cfg {String} html text of the item
21522 * @cfg {String} href the link
21523 * @cfg {Boolean} disable (true | false) default false
21524 * @cfg {Boolean} preventDefault (true | false) default true
21525 * @cfg {String} icon Font awesome icon
21526 * @cfg {String} pos Submenu align to (left | right) default right
21530 * Create a new Item
21531 * @param {Object} config The config object
21535 Roo.bootstrap.menu.Item = function(config){
21536 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21540 * Fires when the mouse is hovering over this menu
21541 * @param {Roo.bootstrap.menu.Item} this
21542 * @param {Roo.EventObject} e
21547 * Fires when the mouse exits this menu
21548 * @param {Roo.bootstrap.menu.Item} this
21549 * @param {Roo.EventObject} e
21555 * The raw click event for the entire grid.
21556 * @param {Roo.EventObject} e
21562 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21567 preventDefault: true,
21572 getAutoCreate : function()
21577 cls : 'roo-menu-item-text',
21585 cls : 'fa ' + this.icon
21594 href : this.href || '#',
21601 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21605 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21607 if(this.pos == 'left'){
21608 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21615 initEvents : function()
21617 this.el.on('mouseover', this.onMouseOver, this);
21618 this.el.on('mouseout', this.onMouseOut, this);
21620 this.el.select('a', true).first().on('click', this.onClick, this);
21624 onClick : function(e)
21626 if(this.preventDefault){
21627 e.preventDefault();
21630 this.fireEvent("click", this, e);
21633 onMouseOver : function(e)
21635 if(this.submenu && this.pos == 'left'){
21636 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21639 this.fireEvent("mouseover", this, e);
21642 onMouseOut : function(e)
21644 this.fireEvent("mouseout", this, e);
21656 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21659 * @class Roo.bootstrap.menu.Separator
21660 * @extends Roo.bootstrap.Component
21661 * Bootstrap Separator class
21664 * Create a new Separator
21665 * @param {Object} config The config object
21669 Roo.bootstrap.menu.Separator = function(config){
21670 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21673 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21675 getAutoCreate : function(){
21696 * @class Roo.bootstrap.Tooltip
21697 * Bootstrap Tooltip class
21698 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21699 * to determine which dom element triggers the tooltip.
21701 * It needs to add support for additional attributes like tooltip-position
21704 * Create a new Toolti
21705 * @param {Object} config The config object
21708 Roo.bootstrap.Tooltip = function(config){
21709 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21712 Roo.apply(Roo.bootstrap.Tooltip, {
21714 * @function init initialize tooltip monitoring.
21718 currentTip : false,
21719 currentRegion : false,
21725 Roo.get(document).on('mouseover', this.enter ,this);
21726 Roo.get(document).on('mouseout', this.leave, this);
21729 this.currentTip = new Roo.bootstrap.Tooltip();
21732 enter : function(ev)
21734 var dom = ev.getTarget();
21735 //Roo.log(['enter',dom]);
21736 var el = Roo.fly(dom);
21737 if (this.currentEl) {
21739 //Roo.log(this.currentEl);
21740 //Roo.log(this.currentEl.contains(dom));
21741 if (this.currentEl == el) {
21744 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21752 if (this.currentTip.el) {
21753 this.currentTip.el.hide(); // force hiding...
21756 if (!el.attr('tooltip')) { // parents who have tip?
21759 this.currentEl = el;
21760 this.currentTip.bind(el);
21761 this.currentRegion = Roo.lib.Region.getRegion(dom);
21762 this.currentTip.enter();
21765 leave : function(ev)
21767 var dom = ev.getTarget();
21768 //Roo.log(['leave',dom]);
21769 if (!this.currentEl) {
21774 if (dom != this.currentEl.dom) {
21777 var xy = ev.getXY();
21778 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21781 // only activate leave if mouse cursor is outside... bounding box..
21786 if (this.currentTip) {
21787 this.currentTip.leave();
21789 //Roo.log('clear currentEl');
21790 this.currentEl = false;
21795 'left' : ['r-l', [-2,0], 'right'],
21796 'right' : ['l-r', [2,0], 'left'],
21797 'bottom' : ['t-b', [0,2], 'top'],
21798 'top' : [ 'b-t', [0,-2], 'bottom']
21804 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21809 delay : null, // can be { show : 300 , hide: 500}
21813 hoverState : null, //???
21815 placement : 'bottom',
21817 getAutoCreate : function(){
21824 cls : 'tooltip-arrow'
21827 cls : 'tooltip-inner'
21834 bind : function(el)
21840 enter : function () {
21842 if (this.timeout != null) {
21843 clearTimeout(this.timeout);
21846 this.hoverState = 'in';
21847 //Roo.log("enter - show");
21848 if (!this.delay || !this.delay.show) {
21853 this.timeout = setTimeout(function () {
21854 if (_t.hoverState == 'in') {
21857 }, this.delay.show);
21861 clearTimeout(this.timeout);
21863 this.hoverState = 'out';
21864 if (!this.delay || !this.delay.hide) {
21870 this.timeout = setTimeout(function () {
21871 //Roo.log("leave - timeout");
21873 if (_t.hoverState == 'out') {
21875 Roo.bootstrap.Tooltip.currentEl = false;
21883 this.render(document.body);
21886 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21887 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21889 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21891 var placement = typeof this.placement == 'function' ?
21892 this.placement.call(this, this.el, on_el) :
21895 var autoToken = /\s?auto?\s?/i;
21896 var autoPlace = autoToken.test(placement);
21898 placement = placement.replace(autoToken, '') || 'top';
21902 //this.el.setXY([0,0]);
21904 //this.el.dom.style.display='block';
21905 this.el.addClass(placement);
21907 //this.el.appendTo(on_el);
21909 var p = this.getPosition();
21910 var box = this.el.getBox();
21915 var align = Roo.bootstrap.Tooltip.alignment[placement];
21916 this.el.alignTo(this.bindEl, align[0],align[1]);
21917 //var arrow = this.el.select('.arrow',true).first();
21918 //arrow.set(align[2],
21920 this.el.addClass('in fade');
21921 this.hoverState = null;
21923 if (this.el.hasClass('fade')) {
21934 //this.el.setXY([0,0]);
21935 this.el.removeClass('in');
21951 * @class Roo.bootstrap.LocationPicker
21952 * @extends Roo.bootstrap.Component
21953 * Bootstrap LocationPicker class
21954 * @cfg {Number} latitude Position when init default 0
21955 * @cfg {Number} longitude Position when init default 0
21956 * @cfg {Number} zoom default 15
21957 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21958 * @cfg {Boolean} mapTypeControl default false
21959 * @cfg {Boolean} disableDoubleClickZoom default false
21960 * @cfg {Boolean} scrollwheel default true
21961 * @cfg {Boolean} streetViewControl default false
21962 * @cfg {Number} radius default 0
21963 * @cfg {String} locationName
21964 * @cfg {Boolean} draggable default true
21965 * @cfg {Boolean} enableAutocomplete default false
21966 * @cfg {Boolean} enableReverseGeocode default true
21967 * @cfg {String} markerTitle
21970 * Create a new LocationPicker
21971 * @param {Object} config The config object
21975 Roo.bootstrap.LocationPicker = function(config){
21977 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21982 * Fires when the picker initialized.
21983 * @param {Roo.bootstrap.LocationPicker} this
21984 * @param {Google Location} location
21988 * @event positionchanged
21989 * Fires when the picker position changed.
21990 * @param {Roo.bootstrap.LocationPicker} this
21991 * @param {Google Location} location
21993 positionchanged : true,
21996 * Fires when the map resize.
21997 * @param {Roo.bootstrap.LocationPicker} this
22002 * Fires when the map show.
22003 * @param {Roo.bootstrap.LocationPicker} this
22008 * Fires when the map hide.
22009 * @param {Roo.bootstrap.LocationPicker} this
22014 * Fires when click the map.
22015 * @param {Roo.bootstrap.LocationPicker} this
22016 * @param {Map event} e
22020 * @event mapRightClick
22021 * Fires when right click the map.
22022 * @param {Roo.bootstrap.LocationPicker} this
22023 * @param {Map event} e
22025 mapRightClick : true,
22027 * @event markerClick
22028 * Fires when click the marker.
22029 * @param {Roo.bootstrap.LocationPicker} this
22030 * @param {Map event} e
22032 markerClick : true,
22034 * @event markerRightClick
22035 * Fires when right click the marker.
22036 * @param {Roo.bootstrap.LocationPicker} this
22037 * @param {Map event} e
22039 markerRightClick : true,
22041 * @event OverlayViewDraw
22042 * Fires when OverlayView Draw
22043 * @param {Roo.bootstrap.LocationPicker} this
22045 OverlayViewDraw : true,
22047 * @event OverlayViewOnAdd
22048 * Fires when OverlayView Draw
22049 * @param {Roo.bootstrap.LocationPicker} this
22051 OverlayViewOnAdd : true,
22053 * @event OverlayViewOnRemove
22054 * Fires when OverlayView Draw
22055 * @param {Roo.bootstrap.LocationPicker} this
22057 OverlayViewOnRemove : true,
22059 * @event OverlayViewShow
22060 * Fires when OverlayView Draw
22061 * @param {Roo.bootstrap.LocationPicker} this
22062 * @param {Pixel} cpx
22064 OverlayViewShow : true,
22066 * @event OverlayViewHide
22067 * Fires when OverlayView Draw
22068 * @param {Roo.bootstrap.LocationPicker} this
22070 OverlayViewHide : true
22075 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22077 gMapContext: false,
22083 mapTypeControl: false,
22084 disableDoubleClickZoom: false,
22086 streetViewControl: false,
22090 enableAutocomplete: false,
22091 enableReverseGeocode: true,
22094 getAutoCreate: function()
22099 cls: 'roo-location-picker'
22105 initEvents: function(ct, position)
22107 if(!this.el.getWidth() || this.isApplied()){
22111 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22116 initial: function()
22118 if(!this.mapTypeId){
22119 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22122 this.gMapContext = this.GMapContext();
22124 this.initOverlayView();
22126 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22130 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22131 _this.setPosition(_this.gMapContext.marker.position);
22134 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22135 _this.fireEvent('mapClick', this, event);
22139 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22140 _this.fireEvent('mapRightClick', this, event);
22144 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22145 _this.fireEvent('markerClick', this, event);
22149 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22150 _this.fireEvent('markerRightClick', this, event);
22154 this.setPosition(this.gMapContext.location);
22156 this.fireEvent('initial', this, this.gMapContext.location);
22159 initOverlayView: function()
22163 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22167 _this.fireEvent('OverlayViewDraw', _this);
22172 _this.fireEvent('OverlayViewOnAdd', _this);
22175 onRemove: function()
22177 _this.fireEvent('OverlayViewOnRemove', _this);
22180 show: function(cpx)
22182 _this.fireEvent('OverlayViewShow', _this, cpx);
22187 _this.fireEvent('OverlayViewHide', _this);
22193 fromLatLngToContainerPixel: function(event)
22195 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22198 isApplied: function()
22200 return this.getGmapContext() == false ? false : true;
22203 getGmapContext: function()
22205 return this.gMapContext
22208 GMapContext: function()
22210 var position = new google.maps.LatLng(this.latitude, this.longitude);
22212 var _map = new google.maps.Map(this.el.dom, {
22215 mapTypeId: this.mapTypeId,
22216 mapTypeControl: this.mapTypeControl,
22217 disableDoubleClickZoom: this.disableDoubleClickZoom,
22218 scrollwheel: this.scrollwheel,
22219 streetViewControl: this.streetViewControl,
22220 locationName: this.locationName,
22221 draggable: this.draggable,
22222 enableAutocomplete: this.enableAutocomplete,
22223 enableReverseGeocode: this.enableReverseGeocode
22226 var _marker = new google.maps.Marker({
22227 position: position,
22229 title: this.markerTitle,
22230 draggable: this.draggable
22237 location: position,
22238 radius: this.radius,
22239 locationName: this.locationName,
22240 addressComponents: {
22241 formatted_address: null,
22242 addressLine1: null,
22243 addressLine2: null,
22245 streetNumber: null,
22249 stateOrProvince: null
22252 domContainer: this.el.dom,
22253 geodecoder: new google.maps.Geocoder()
22257 drawCircle: function(center, radius, options)
22259 if (this.gMapContext.circle != null) {
22260 this.gMapContext.circle.setMap(null);
22264 options = Roo.apply({}, options, {
22265 strokeColor: "#0000FF",
22266 strokeOpacity: .35,
22268 fillColor: "#0000FF",
22272 options.map = this.gMapContext.map;
22273 options.radius = radius;
22274 options.center = center;
22275 this.gMapContext.circle = new google.maps.Circle(options);
22276 return this.gMapContext.circle;
22282 setPosition: function(location)
22284 this.gMapContext.location = location;
22285 this.gMapContext.marker.setPosition(location);
22286 this.gMapContext.map.panTo(location);
22287 this.drawCircle(location, this.gMapContext.radius, {});
22291 if (this.gMapContext.settings.enableReverseGeocode) {
22292 this.gMapContext.geodecoder.geocode({
22293 latLng: this.gMapContext.location
22294 }, function(results, status) {
22296 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22297 _this.gMapContext.locationName = results[0].formatted_address;
22298 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22300 _this.fireEvent('positionchanged', this, location);
22307 this.fireEvent('positionchanged', this, location);
22312 google.maps.event.trigger(this.gMapContext.map, "resize");
22314 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22316 this.fireEvent('resize', this);
22319 setPositionByLatLng: function(latitude, longitude)
22321 this.setPosition(new google.maps.LatLng(latitude, longitude));
22324 getCurrentPosition: function()
22327 latitude: this.gMapContext.location.lat(),
22328 longitude: this.gMapContext.location.lng()
22332 getAddressName: function()
22334 return this.gMapContext.locationName;
22337 getAddressComponents: function()
22339 return this.gMapContext.addressComponents;
22342 address_component_from_google_geocode: function(address_components)
22346 for (var i = 0; i < address_components.length; i++) {
22347 var component = address_components[i];
22348 if (component.types.indexOf("postal_code") >= 0) {
22349 result.postalCode = component.short_name;
22350 } else if (component.types.indexOf("street_number") >= 0) {
22351 result.streetNumber = component.short_name;
22352 } else if (component.types.indexOf("route") >= 0) {
22353 result.streetName = component.short_name;
22354 } else if (component.types.indexOf("neighborhood") >= 0) {
22355 result.city = component.short_name;
22356 } else if (component.types.indexOf("locality") >= 0) {
22357 result.city = component.short_name;
22358 } else if (component.types.indexOf("sublocality") >= 0) {
22359 result.district = component.short_name;
22360 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22361 result.stateOrProvince = component.short_name;
22362 } else if (component.types.indexOf("country") >= 0) {
22363 result.country = component.short_name;
22367 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22368 result.addressLine2 = "";
22372 setZoomLevel: function(zoom)
22374 this.gMapContext.map.setZoom(zoom);
22387 this.fireEvent('show', this);
22398 this.fireEvent('hide', this);
22403 Roo.apply(Roo.bootstrap.LocationPicker, {
22405 OverlayView : function(map, options)
22407 options = options || {};
22421 * @class Roo.bootstrap.Alert
22422 * @extends Roo.bootstrap.Component
22423 * Bootstrap Alert class
22424 * @cfg {String} title The title of alert
22425 * @cfg {String} html The content of alert
22426 * @cfg {String} weight ( success | info | warning | danger )
22427 * @cfg {String} faicon font-awesomeicon
22430 * Create a new alert
22431 * @param {Object} config The config object
22435 Roo.bootstrap.Alert = function(config){
22436 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22440 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22447 getAutoCreate : function()
22456 cls : 'roo-alert-icon'
22461 cls : 'roo-alert-title',
22466 cls : 'roo-alert-text',
22473 cfg.cn[0].cls += ' fa ' + this.faicon;
22477 cfg.cls += ' alert-' + this.weight;
22483 initEvents: function()
22485 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22488 setTitle : function(str)
22490 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22493 setText : function(str)
22495 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22498 setWeight : function(weight)
22501 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22504 this.weight = weight;
22506 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22509 setIcon : function(icon)
22512 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22517 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);