4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
33 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
36 allowDomMove : false, // to stop relocations in parent onRender...
46 * Initialize Events for the element
48 initEvents : function() { },
54 can_build_overlaid : true,
56 container_method : false,
63 // returns the parent component..
64 return Roo.ComponentMgr.get(this.parentId)
70 onRender : function(ct, position)
72 // Roo.log("Call onRender: " + this.xtype);
74 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
77 if (this.el.attr('xtype')) {
78 this.el.attr('xtypex', this.el.attr('xtype'));
79 this.el.dom.removeAttribute('xtype');
89 var cfg = Roo.apply({}, this.getAutoCreate());
92 // fill in the extra attributes
93 if (this.xattr && typeof(this.xattr) =='object') {
94 for (var i in this.xattr) {
95 cfg[i] = this.xattr[i];
100 cfg.dataId = this.dataId;
104 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
107 if (this.style) { // fixme needs to support more complex style data.
108 cfg.style = this.style;
112 cfg.name = this.name;
117 this.el = ct.createChild(cfg, position);
120 this.tooltipEl().attr('tooltip', this.tooltip);
123 if(this.tabIndex !== undefined){
124 this.el.dom.setAttribute('tabIndex', this.tabIndex);
131 * Fetch the element to add children to
132 * @return {Roo.Element} defaults to this.el
134 getChildContainer : function()
139 * Fetch the element to display the tooltip on.
140 * @return {Roo.Element} defaults to this.el
142 tooltipEl : function()
147 addxtype : function(tree,cntr)
151 cn = Roo.factory(tree);
153 cn.parentType = this.xtype; //??
154 cn.parentId = this.id;
156 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
157 if (typeof(cn.container_method) == 'string') {
158 cntr = cn.container_method;
162 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
164 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
166 var build_from_html = Roo.XComponent.build_from_html;
168 var is_body = (tree.xtype == 'Body') ;
170 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
172 var self_cntr_el = Roo.get(this[cntr](false));
174 // do not try and build conditional elements
175 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
179 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
180 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
181 return this.addxtypeChild(tree,cntr);
184 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
187 return this.addxtypeChild(Roo.apply({}, tree),cntr);
190 Roo.log('skipping render');
198 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
204 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
208 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
213 addxtypeChild : function (tree, cntr)
215 Roo.debug && Roo.log('addxtypeChild:' + cntr);
217 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
220 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
221 (typeof(tree['flexy:foreach']) != 'undefined');
225 skip_children = false;
226 // render the element if it's not BODY.
227 if (tree.xtype != 'Body') {
229 cn = Roo.factory(tree);
231 cn.parentType = this.xtype; //??
232 cn.parentId = this.id;
234 var build_from_html = Roo.XComponent.build_from_html;
237 // does the container contain child eleemnts with 'xtype' attributes.
238 // that match this xtype..
239 // note - when we render we create these as well..
240 // so we should check to see if body has xtype set.
241 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
243 var self_cntr_el = Roo.get(this[cntr](false));
244 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
247 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
248 // and are not displayed -this causes this to use up the wrong element when matching.
249 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
252 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
253 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
259 //echild.dom.removeAttribute('xtype');
261 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
262 Roo.debug && Roo.log(self_cntr_el);
263 Roo.debug && Roo.log(echild);
264 Roo.debug && Roo.log(cn);
270 // if object has flexy:if - then it may or may not be rendered.
271 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
272 // skip a flexy if element.
273 Roo.debug && Roo.log('skipping render');
274 Roo.debug && Roo.log(tree);
276 Roo.debug && Roo.log('skipping all children');
277 skip_children = true;
282 // actually if flexy:foreach is found, we really want to create
283 // multiple copies here...
285 //Roo.log(this[cntr]());
286 cn.render(this[cntr](true));
288 // then add the element..
296 if (typeof (tree.menu) != 'undefined') {
297 tree.menu.parentType = cn.xtype;
298 tree.menu.triggerEl = cn.el;
299 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
303 if (!tree.items || !tree.items.length) {
307 var items = tree.items;
310 //Roo.log(items.length);
312 if (!skip_children) {
313 for(var i =0;i < items.length;i++) {
314 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
336 * @class Roo.bootstrap.Body
337 * @extends Roo.bootstrap.Component
338 * Bootstrap Body class
342 * @param {Object} config The config object
345 Roo.bootstrap.Body = function(config){
346 Roo.bootstrap.Body.superclass.constructor.call(this, config);
347 this.el = Roo.get(document.body);
348 if (this.cls && this.cls.length) {
349 Roo.get(document.body).addClass(this.cls);
353 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
358 onRender : function(ct, position)
360 /* Roo.log("Roo.bootstrap.Body - onRender");
361 if (this.cls && this.cls.length) {
362 Roo.get(document.body).addClass(this.cls);
382 * @class Roo.bootstrap.ButtonGroup
383 * @extends Roo.bootstrap.Component
384 * Bootstrap ButtonGroup class
385 * @cfg {String} size lg | sm | xs (default empty normal)
386 * @cfg {String} align vertical | justified (default none)
387 * @cfg {String} direction up | down (default down)
388 * @cfg {Boolean} toolbar false | true
389 * @cfg {Boolean} btn true | false
394 * @param {Object} config The config object
397 Roo.bootstrap.ButtonGroup = function(config){
398 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
401 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
409 getAutoCreate : function(){
415 cfg.html = this.html || cfg.html;
426 if (['vertical','justified'].indexOf(this.align)!==-1) {
427 cfg.cls = 'btn-group-' + this.align;
429 if (this.align == 'justified') {
430 console.log(this.items);
434 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
435 cfg.cls += ' btn-group-' + this.size;
438 if (this.direction == 'up') {
439 cfg.cls += ' dropup' ;
455 * @class Roo.bootstrap.Button
456 * @extends Roo.bootstrap.Component
457 * Bootstrap Button class
458 * @cfg {String} html The button content
459 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
460 * @cfg {String} size ( lg | sm | xs)
461 * @cfg {String} tag ( a | input | submit)
462 * @cfg {String} href empty or href
463 * @cfg {Boolean} disabled default false;
464 * @cfg {Boolean} isClose default false;
465 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
466 * @cfg {String} badge text for badge
467 * @cfg {String} theme default
468 * @cfg {Boolean} inverse
469 * @cfg {Boolean} toggle
470 * @cfg {String} ontext text for on toggle state
471 * @cfg {String} offtext text for off toggle state
472 * @cfg {Boolean} defaulton
473 * @cfg {Boolean} preventDefault default true
474 * @cfg {Boolean} removeClass remove the standard class..
475 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
478 * Create a new button
479 * @param {Object} config The config object
483 Roo.bootstrap.Button = function(config){
484 Roo.bootstrap.Button.superclass.constructor.call(this, config);
489 * When a butotn is pressed
490 * @param {Roo.EventObject} e
495 * After the button has been toggles
496 * @param {Roo.EventObject} e
497 * @param {boolean} pressed (also available as button.pressed)
503 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
521 preventDefault: true,
530 getAutoCreate : function(){
538 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
539 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
544 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
546 if (this.toggle == true) {
549 cls: 'slider-frame roo-button',
554 'data-off-text':'OFF',
555 cls: 'slider-button',
561 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
562 cfg.cls += ' '+this.weight;
571 cfg["aria-hidden"] = true;
573 cfg.html = "×";
579 if (this.theme==='default') {
580 cfg.cls = 'btn roo-button';
582 //if (this.parentType != 'Navbar') {
583 this.weight = this.weight.length ? this.weight : 'default';
585 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
587 cfg.cls += ' btn-' + this.weight;
589 } else if (this.theme==='glow') {
592 cfg.cls = 'btn-glow roo-button';
594 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
596 cfg.cls += ' ' + this.weight;
602 this.cls += ' inverse';
607 cfg.cls += ' active';
611 cfg.disabled = 'disabled';
615 Roo.log('changing to ul' );
617 this.glyphicon = 'caret';
620 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
622 //gsRoo.log(this.parentType);
623 if (this.parentType === 'Navbar' && !this.parent().bar) {
624 Roo.log('changing to li?');
633 href : this.href || '#'
636 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
637 cfg.cls += ' dropdown';
644 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
646 if (this.glyphicon) {
647 cfg.html = ' ' + cfg.html;
652 cls: 'glyphicon glyphicon-' + this.glyphicon
662 // cfg.cls='btn roo-button';
666 var value = cfg.html;
671 cls: 'glyphicon glyphicon-' + this.glyphicon,
690 cfg.cls += ' dropdown';
691 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
694 if (cfg.tag !== 'a' && this.href !== '') {
695 throw "Tag must be a to set href.";
696 } else if (this.href.length > 0) {
697 cfg.href = this.href;
700 if(this.removeClass){
705 cfg.target = this.target;
710 initEvents: function() {
711 // Roo.log('init events?');
712 // Roo.log(this.el.dom);
715 if (typeof (this.menu) != 'undefined') {
716 this.menu.parentType = this.xtype;
717 this.menu.triggerEl = this.el;
718 this.addxtype(Roo.apply({}, this.menu));
722 if (this.el.hasClass('roo-button')) {
723 this.el.on('click', this.onClick, this);
725 this.el.select('.roo-button').on('click', this.onClick, this);
728 if(this.removeClass){
729 this.el.on('click', this.onClick, this);
732 this.el.enableDisplayMode();
735 onClick : function(e)
742 Roo.log('button on click ');
743 if(this.preventDefault){
746 if (this.pressed === true || this.pressed === false) {
747 this.pressed = !this.pressed;
748 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
749 this.fireEvent('toggle', this, e, this.pressed);
753 this.fireEvent('click', this, e);
757 * Enables this button
761 this.disabled = false;
762 this.el.removeClass('disabled');
766 * Disable this button
770 this.disabled = true;
771 this.el.addClass('disabled');
774 * sets the active state on/off,
775 * @param {Boolean} state (optional) Force a particular state
777 setActive : function(v) {
779 this.el[v ? 'addClass' : 'removeClass']('active');
782 * toggles the current active state
784 toggleActive : function()
786 var active = this.el.hasClass('active');
787 this.setActive(!active);
791 setText : function(str)
793 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
797 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
820 * @class Roo.bootstrap.Column
821 * @extends Roo.bootstrap.Component
822 * Bootstrap Column class
823 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
824 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
825 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
826 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
827 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
828 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
829 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
830 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
833 * @cfg {Boolean} hidden (true|false) hide the element
834 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
835 * @cfg {String} fa (ban|check|...) font awesome icon
836 * @cfg {Number} fasize (1|2|....) font awsome size
838 * @cfg {String} icon (info-sign|check|...) glyphicon name
840 * @cfg {String} html content of column.
843 * Create a new Column
844 * @param {Object} config The config object
847 Roo.bootstrap.Column = function(config){
848 Roo.bootstrap.Column.superclass.constructor.call(this, config);
851 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
869 getAutoCreate : function(){
870 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
878 ['xs','sm','md','lg'].map(function(size){
879 //Roo.log( size + ':' + settings[size]);
881 if (settings[size+'off'] !== false) {
882 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
885 if (settings[size] === false) {
888 Roo.log(settings[size]);
889 if (!settings[size]) { // 0 = hidden
890 cfg.cls += ' hidden-' + size;
893 cfg.cls += ' col-' + size + '-' + settings[size];
898 cfg.cls += ' hidden';
901 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
902 cfg.cls +=' alert alert-' + this.alert;
906 if (this.html.length) {
907 cfg.html = this.html;
911 if (this.fasize > 1) {
912 fasize = ' fa-' + this.fasize + 'x';
914 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
919 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
938 * @class Roo.bootstrap.Container
939 * @extends Roo.bootstrap.Component
940 * Bootstrap Container class
941 * @cfg {Boolean} jumbotron is it a jumbotron element
942 * @cfg {String} html content of element
943 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
944 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
945 * @cfg {String} header content of header (for panel)
946 * @cfg {String} footer content of footer (for panel)
947 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
948 * @cfg {String} tag (header|aside|section) type of HTML tag.
949 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
950 * @cfg {String} fa (ban|check|...) font awesome icon
951 * @cfg {String} icon (info-sign|check|...) glyphicon name
952 * @cfg {Boolean} hidden (true|false) hide the element
956 * Create a new Container
957 * @param {Object} config The config object
960 Roo.bootstrap.Container = function(config){
961 Roo.bootstrap.Container.superclass.constructor.call(this, config);
964 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
978 getChildContainer : function() {
984 if (this.panel.length) {
985 return this.el.select('.panel-body',true).first();
992 getAutoCreate : function(){
995 tag : this.tag || 'div',
999 if (this.jumbotron) {
1000 cfg.cls = 'jumbotron';
1005 // - this is applied by the parent..
1007 // cfg.cls = this.cls + '';
1010 if (this.sticky.length) {
1012 var bd = Roo.get(document.body);
1013 if (!bd.hasClass('bootstrap-sticky')) {
1014 bd.addClass('bootstrap-sticky');
1015 Roo.select('html',true).setStyle('height', '100%');
1018 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1022 if (this.well.length) {
1023 switch (this.well) {
1026 cfg.cls +=' well well-' +this.well;
1035 cfg.cls += ' hidden';
1039 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1040 cfg.cls +=' alert alert-' + this.alert;
1045 if (this.panel.length) {
1046 cfg.cls += ' panel panel-' + this.panel;
1048 if (this.header.length) {
1051 cls : 'panel-heading',
1054 cls : 'panel-title',
1067 if (this.footer.length) {
1069 cls : 'panel-footer',
1078 body.html = this.html || cfg.html;
1079 // prefix with the icons..
1081 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1084 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1089 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1090 cfg.cls = 'container';
1096 titleEl : function()
1098 if(!this.el || !this.panel.length || !this.header.length){
1102 return this.el.select('.panel-title',true).first();
1105 setTitle : function(v)
1107 var titleEl = this.titleEl();
1113 titleEl.dom.innerHTML = v;
1116 getTitle : function()
1119 var titleEl = this.titleEl();
1125 return titleEl.dom.innerHTML;
1129 this.el.removeClass('hidden');
1132 if (!this.el.hasClass('hidden')) {
1133 this.el.addClass('hidden');
1149 * @class Roo.bootstrap.Img
1150 * @extends Roo.bootstrap.Component
1151 * Bootstrap Img class
1152 * @cfg {Boolean} imgResponsive false | true
1153 * @cfg {String} border rounded | circle | thumbnail
1154 * @cfg {String} src image source
1155 * @cfg {String} alt image alternative text
1156 * @cfg {String} href a tag href
1157 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1160 * Create a new Input
1161 * @param {Object} config The config object
1164 Roo.bootstrap.Img = function(config){
1165 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1171 * The img click event for the img.
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1180 imgResponsive: true,
1186 getAutoCreate : function(){
1190 cls: (this.imgResponsive) ? 'img-responsive' : '',
1194 cfg.html = this.html || cfg.html;
1196 cfg.src = this.src || cfg.src;
1198 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1199 cfg.cls += ' img-' + this.border;
1216 a.target = this.target;
1222 return (this.href) ? a : cfg;
1225 initEvents: function() {
1228 this.el.on('click', this.onClick, this);
1232 onClick : function(e)
1234 Roo.log('img onclick');
1235 this.fireEvent('click', this, e);
1249 * @class Roo.bootstrap.Link
1250 * @extends Roo.bootstrap.Component
1251 * Bootstrap Link Class
1252 * @cfg {String} alt image alternative text
1253 * @cfg {String} href a tag href
1254 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1255 * @cfg {String} html the content of the link.
1256 * @cfg {String} anchor name for the anchor link
1258 * @cfg {Boolean} preventDefault (true | false) default false
1262 * Create a new Input
1263 * @param {Object} config The config object
1266 Roo.bootstrap.Link = function(config){
1267 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1273 * The img click event for the img.
1274 * @param {Roo.EventObject} e
1280 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1284 preventDefault: false,
1288 getAutoCreate : function()
1294 // anchor's do not require html/href...
1295 if (this.anchor === false) {
1296 cfg.html = this.html || 'html-missing';
1297 cfg.href = this.href || '#';
1299 cfg.name = this.anchor;
1300 if (this.html !== false) {
1301 cfg.html = this.html;
1303 if (this.href !== false) {
1304 cfg.href = this.href;
1308 if(this.alt !== false){
1313 if(this.target !== false) {
1314 cfg.target = this.target;
1320 initEvents: function() {
1322 if(!this.href || this.preventDefault){
1323 this.el.on('click', this.onClick, this);
1327 onClick : function(e)
1329 if(this.preventDefault){
1332 //Roo.log('img onclick');
1333 this.fireEvent('click', this, e);
1346 * @class Roo.bootstrap.Header
1347 * @extends Roo.bootstrap.Component
1348 * Bootstrap Header class
1349 * @cfg {String} html content of header
1350 * @cfg {Number} level (1|2|3|4|5|6) default 1
1353 * Create a new Header
1354 * @param {Object} config The config object
1358 Roo.bootstrap.Header = function(config){
1359 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1362 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1370 getAutoCreate : function(){
1373 tag: 'h' + (1 *this.level),
1374 html: this.html || 'fill in html'
1386 * Ext JS Library 1.1.1
1387 * Copyright(c) 2006-2007, Ext JS, LLC.
1389 * Originally Released Under LGPL - original licence link has changed is not relivant.
1392 * <script type="text/javascript">
1396 * @class Roo.bootstrap.MenuMgr
1397 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1400 Roo.bootstrap.MenuMgr = function(){
1401 var menus, active, groups = {}, attached = false, lastShow = new Date();
1403 // private - called when first menu is created
1406 active = new Roo.util.MixedCollection();
1407 Roo.get(document).addKeyListener(27, function(){
1408 if(active.length > 0){
1416 if(active && active.length > 0){
1417 var c = active.clone();
1427 if(active.length < 1){
1428 Roo.get(document).un("mouseup", onMouseDown);
1436 var last = active.last();
1437 lastShow = new Date();
1440 Roo.get(document).on("mouseup", onMouseDown);
1445 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1446 m.parentMenu.activeChild = m;
1447 }else if(last && last.isVisible()){
1448 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1453 function onBeforeHide(m){
1455 m.activeChild.hide();
1457 if(m.autoHideTimer){
1458 clearTimeout(m.autoHideTimer);
1459 delete m.autoHideTimer;
1464 function onBeforeShow(m){
1465 var pm = m.parentMenu;
1466 if(!pm && !m.allowOtherMenus){
1468 }else if(pm && pm.activeChild && active != m){
1469 pm.activeChild.hide();
1474 function onMouseDown(e){
1475 Roo.log("on MouseDown");
1476 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1484 function onBeforeCheck(mi, state){
1486 var g = groups[mi.group];
1487 for(var i = 0, l = g.length; i < l; i++){
1489 g[i].setChecked(false);
1498 * Hides all menus that are currently visible
1500 hideAll : function(){
1505 register : function(menu){
1509 menus[menu.id] = menu;
1510 menu.on("beforehide", onBeforeHide);
1511 menu.on("hide", onHide);
1512 menu.on("beforeshow", onBeforeShow);
1513 menu.on("show", onShow);
1515 if(g && menu.events["checkchange"]){
1519 groups[g].push(menu);
1520 menu.on("checkchange", onCheck);
1525 * Returns a {@link Roo.menu.Menu} object
1526 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1527 * be used to generate and return a new Menu instance.
1529 get : function(menu){
1530 if(typeof menu == "string"){ // menu id
1532 }else if(menu.events){ // menu instance
1535 /*else if(typeof menu.length == 'number'){ // array of menu items?
1536 return new Roo.bootstrap.Menu({items:menu});
1537 }else{ // otherwise, must be a config
1538 return new Roo.bootstrap.Menu(menu);
1545 unregister : function(menu){
1546 delete menus[menu.id];
1547 menu.un("beforehide", onBeforeHide);
1548 menu.un("hide", onHide);
1549 menu.un("beforeshow", onBeforeShow);
1550 menu.un("show", onShow);
1552 if(g && menu.events["checkchange"]){
1553 groups[g].remove(menu);
1554 menu.un("checkchange", onCheck);
1559 registerCheckable : function(menuItem){
1560 var g = menuItem.group;
1565 groups[g].push(menuItem);
1566 menuItem.on("beforecheckchange", onBeforeCheck);
1571 unregisterCheckable : function(menuItem){
1572 var g = menuItem.group;
1574 groups[g].remove(menuItem);
1575 menuItem.un("beforecheckchange", onBeforeCheck);
1587 * @class Roo.bootstrap.Menu
1588 * @extends Roo.bootstrap.Component
1589 * Bootstrap Menu class - container for MenuItems
1590 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1594 * @param {Object} config The config object
1598 Roo.bootstrap.Menu = function(config){
1599 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1600 if (this.registerMenu) {
1601 Roo.bootstrap.MenuMgr.register(this);
1606 * Fires before this menu is displayed
1607 * @param {Roo.menu.Menu} this
1612 * Fires before this menu is hidden
1613 * @param {Roo.menu.Menu} this
1618 * Fires after this menu is displayed
1619 * @param {Roo.menu.Menu} this
1624 * Fires after this menu is hidden
1625 * @param {Roo.menu.Menu} this
1630 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1631 * @param {Roo.menu.Menu} this
1632 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1633 * @param {Roo.EventObject} e
1638 * Fires when the mouse is hovering over this menu
1639 * @param {Roo.menu.Menu} this
1640 * @param {Roo.EventObject} e
1641 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1646 * Fires when the mouse exits this menu
1647 * @param {Roo.menu.Menu} this
1648 * @param {Roo.EventObject} e
1649 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1654 * Fires when a menu item contained in this menu is clicked
1655 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1656 * @param {Roo.EventObject} e
1660 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1663 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1667 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1670 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1672 registerMenu : true,
1674 menuItems :false, // stores the menu items..
1680 getChildContainer : function() {
1684 getAutoCreate : function(){
1686 //if (['right'].indexOf(this.align)!==-1) {
1687 // cfg.cn[1].cls += ' pull-right'
1693 cls : 'dropdown-menu' ,
1694 style : 'z-index:1000'
1698 if (this.type === 'submenu') {
1699 cfg.cls = 'submenu active';
1701 if (this.type === 'treeview') {
1702 cfg.cls = 'treeview-menu';
1707 initEvents : function() {
1709 // Roo.log("ADD event");
1710 // Roo.log(this.triggerEl.dom);
1711 this.triggerEl.on('click', this.onTriggerPress, this);
1712 this.triggerEl.addClass('dropdown-toggle');
1713 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1715 this.el.on("mouseover", this.onMouseOver, this);
1716 this.el.on("mouseout", this.onMouseOut, this);
1720 findTargetItem : function(e){
1721 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1725 //Roo.log(t); Roo.log(t.id);
1727 //Roo.log(this.menuitems);
1728 return this.menuitems.get(t.id);
1730 //return this.items.get(t.menuItemId);
1735 onClick : function(e){
1736 Roo.log("menu.onClick");
1737 var t = this.findTargetItem(e);
1738 if(!t || t.isContainer){
1743 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1744 if(t == this.activeItem && t.shouldDeactivate(e)){
1745 this.activeItem.deactivate();
1746 delete this.activeItem;
1750 this.setActiveItem(t, true);
1758 Roo.log('pass click event');
1762 this.fireEvent("click", this, t, e);
1766 onMouseOver : function(e){
1767 var t = this.findTargetItem(e);
1770 // if(t.canActivate && !t.disabled){
1771 // this.setActiveItem(t, true);
1775 this.fireEvent("mouseover", this, e, t);
1777 isVisible : function(){
1778 return !this.hidden;
1780 onMouseOut : function(e){
1781 var t = this.findTargetItem(e);
1784 // if(t == this.activeItem && t.shouldDeactivate(e)){
1785 // this.activeItem.deactivate();
1786 // delete this.activeItem;
1789 this.fireEvent("mouseout", this, e, t);
1794 * Displays this menu relative to another element
1795 * @param {String/HTMLElement/Roo.Element} element The element to align to
1796 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1797 * the element (defaults to this.defaultAlign)
1798 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1800 show : function(el, pos, parentMenu){
1801 this.parentMenu = parentMenu;
1805 this.fireEvent("beforeshow", this);
1806 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1809 * Displays this menu at a specific xy position
1810 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1811 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1813 showAt : function(xy, parentMenu, /* private: */_e){
1814 this.parentMenu = parentMenu;
1819 this.fireEvent("beforeshow", this);
1821 //xy = this.el.adjustForConstraints(xy);
1823 //this.el.setXY(xy);
1825 this.hideMenuItems();
1826 this.hidden = false;
1827 this.triggerEl.addClass('open');
1829 this.fireEvent("show", this);
1835 this.doFocus.defer(50, this);
1839 doFocus : function(){
1841 this.focusEl.focus();
1846 * Hides this menu and optionally all parent menus
1847 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1849 hide : function(deep){
1851 this.hideMenuItems();
1852 if(this.el && this.isVisible()){
1853 this.fireEvent("beforehide", this);
1854 if(this.activeItem){
1855 this.activeItem.deactivate();
1856 this.activeItem = null;
1858 this.triggerEl.removeClass('open');;
1860 this.fireEvent("hide", this);
1862 if(deep === true && this.parentMenu){
1863 this.parentMenu.hide(true);
1867 onTriggerPress : function(e)
1870 Roo.log('trigger press');
1871 //Roo.log(e.getTarget());
1872 // Roo.log(this.triggerEl.dom);
1873 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1876 if (this.isVisible()) {
1880 this.show(this.triggerEl, false, false);
1889 hideMenuItems : function()
1891 //$(backdrop).remove()
1892 Roo.select('.open',true).each(function(aa) {
1894 aa.removeClass('open');
1895 //var parent = getParent($(this))
1896 //var relatedTarget = { relatedTarget: this }
1898 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1899 //if (e.isDefaultPrevented()) return
1900 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1903 addxtypeChild : function (tree, cntr) {
1904 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1906 this.menuitems.add(comp);
1927 * @class Roo.bootstrap.MenuItem
1928 * @extends Roo.bootstrap.Component
1929 * Bootstrap MenuItem class
1930 * @cfg {String} html the menu label
1931 * @cfg {String} href the link
1932 * @cfg {Boolean} preventDefault (true | false) default true
1933 * @cfg {Boolean} isContainer (true | false) default false
1937 * Create a new MenuItem
1938 * @param {Object} config The config object
1942 Roo.bootstrap.MenuItem = function(config){
1943 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1948 * The raw click event for the entire grid.
1949 * @param {Roo.EventObject} e
1955 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1959 preventDefault: true,
1960 isContainer : false,
1962 getAutoCreate : function(){
1964 if(this.isContainer){
1967 cls: 'dropdown-menu-item'
1973 cls: 'dropdown-menu-item',
1982 if (this.parent().type == 'treeview') {
1983 cfg.cls = 'treeview-menu';
1986 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1987 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1991 initEvents: function() {
1993 //this.el.select('a').on('click', this.onClick, this);
1996 onClick : function(e)
1998 Roo.log('item on click ');
1999 //if(this.preventDefault){
2000 // e.preventDefault();
2002 //this.parent().hideMenuItems();
2004 this.fireEvent('click', this, e);
2023 * @class Roo.bootstrap.MenuSeparator
2024 * @extends Roo.bootstrap.Component
2025 * Bootstrap MenuSeparator class
2028 * Create a new MenuItem
2029 * @param {Object} config The config object
2033 Roo.bootstrap.MenuSeparator = function(config){
2034 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2037 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2039 getAutoCreate : function(){
2054 <div class="modal fade">
2055 <div class="modal-dialog">
2056 <div class="modal-content">
2057 <div class="modal-header">
2058 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
2059 <h4 class="modal-title">Modal title</h4>
2061 <div class="modal-body">
2062 <p>One fine body…</p>
2064 <div class="modal-footer">
2065 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2066 <button type="button" class="btn btn-primary">Save changes</button>
2068 </div><!-- /.modal-content -->
2069 </div><!-- /.modal-dialog -->
2070 </div><!-- /.modal -->
2080 * @class Roo.bootstrap.Modal
2081 * @extends Roo.bootstrap.Component
2082 * Bootstrap Modal class
2083 * @cfg {String} title Title of dialog
2084 * @cfg {Boolean} specificTitle default false
2085 * @cfg {Array} buttons Array of buttons or standard button set..
2086 * @cfg {String} buttonPosition (left|right|center) default right
2087 * @cfg {Boolean} animate default true
2088 * @cfg {Boolean} allow_close default true
2091 * Create a new Modal Dialog
2092 * @param {Object} config The config object
2095 Roo.bootstrap.Modal = function(config){
2096 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2101 * The raw btnclick event for the button
2102 * @param {Roo.EventObject} e
2106 this.buttons = this.buttons || [];
2109 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2111 title : 'test dialog',
2118 specificTitle: false,
2120 buttonPosition: 'right',
2126 onRender : function(ct, position)
2128 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2131 var cfg = Roo.apply({}, this.getAutoCreate());
2134 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2136 //if (!cfg.name.length) {
2140 cfg.cls += ' ' + this.cls;
2143 cfg.style = this.style;
2145 this.el = Roo.get(document.body).createChild(cfg, position);
2147 //var type = this.el.dom.type;
2149 if(this.tabIndex !== undefined){
2150 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2155 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2156 this.maskEl.enableDisplayMode("block");
2158 //this.el.addClass("x-dlg-modal");
2160 if (this.buttons.length) {
2161 Roo.each(this.buttons, function(bb) {
2162 b = Roo.apply({}, bb);
2163 b.xns = b.xns || Roo.bootstrap;
2164 b.xtype = b.xtype || 'Button';
2165 if (typeof(b.listeners) == 'undefined') {
2166 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2169 var btn = Roo.factory(b);
2171 btn.onRender(this.el.select('.modal-footer div').first());
2175 // render the children.
2178 if(typeof(this.items) != 'undefined'){
2179 var items = this.items;
2182 for(var i =0;i < items.length;i++) {
2183 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2187 this.items = nitems;
2189 this.body = this.el.select('.modal-body',true).first();
2190 this.close = this.el.select('.modal-header .close', true).first();
2191 this.footer = this.el.select('.modal-footer',true).first();
2193 //this.el.addClass([this.fieldClass, this.cls]);
2196 getAutoCreate : function(){
2201 html : this.html || ''
2206 cls : 'modal-title',
2210 if(this.specificTitle){
2216 if (this.allow_close) {
2227 style : 'display: none',
2230 cls: "modal-dialog",
2233 cls : "modal-content",
2236 cls : 'modal-header',
2241 cls : 'modal-footer',
2245 cls: 'btn-' + this.buttonPosition
2262 modal.cls += ' fade';
2268 getChildContainer : function() {
2270 return this.el.select('.modal-body',true).first();
2273 getButtonContainer : function() {
2274 return this.el.select('.modal-footer div',true).first();
2277 initEvents : function()
2279 this.el.select('.modal-header .close').on('click', this.hide, this);
2281 // this.addxtype(this);
2285 if (!this.rendered) {
2289 this.el.setStyle('display', 'block');
2293 (function(){ _this.el.addClass('in'); }).defer(50);
2295 this.el.addClass('in');
2298 Roo.get(document.body).addClass("x-body-masked");
2299 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2301 this.el.setStyle('zIndex', '10001');
2303 this.fireEvent('show', this);
2310 Roo.get(document.body).removeClass("x-body-masked");
2311 this.el.removeClass('in');
2315 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2317 this.el.setStyle('display', 'none');
2320 this.fireEvent('hide', this);
2323 addButton : function(str, cb)
2327 var b = Roo.apply({}, { html : str } );
2328 b.xns = b.xns || Roo.bootstrap;
2329 b.xtype = b.xtype || 'Button';
2330 if (typeof(b.listeners) == 'undefined') {
2331 b.listeners = { click : cb.createDelegate(this) };
2334 var btn = Roo.factory(b);
2336 btn.onRender(this.el.select('.modal-footer div').first());
2342 setDefaultButton : function(btn)
2344 //this.el.select('.modal-footer').()
2346 resizeTo: function(w,h)
2350 setContentSize : function(w, h)
2354 onButtonClick: function(btn,e)
2357 this.fireEvent('btnclick', btn.name, e);
2359 setTitle: function(str) {
2360 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2366 Roo.apply(Roo.bootstrap.Modal, {
2368 * Button config that displays a single OK button
2377 * Button config that displays Yes and No buttons
2393 * Button config that displays OK and Cancel buttons
2408 * Button config that displays Yes, No and Cancel buttons
2430 * messagebox - can be used as a replace
2434 * @class Roo.MessageBox
2435 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2439 Roo.Msg.alert('Status', 'Changes saved successfully.');
2441 // Prompt for user data:
2442 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2444 // process text value...
2448 // Show a dialog using config options:
2450 title:'Save Changes?',
2451 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2452 buttons: Roo.Msg.YESNOCANCEL,
2459 Roo.bootstrap.MessageBox = function(){
2460 var dlg, opt, mask, waitTimer;
2461 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2462 var buttons, activeTextEl, bwidth;
2466 var handleButton = function(button){
2468 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2472 var handleHide = function(){
2474 dlg.el.removeClass(opt.cls);
2477 // Roo.TaskMgr.stop(waitTimer);
2478 // waitTimer = null;
2483 var updateButtons = function(b){
2486 buttons["ok"].hide();
2487 buttons["cancel"].hide();
2488 buttons["yes"].hide();
2489 buttons["no"].hide();
2490 //dlg.footer.dom.style.display = 'none';
2493 dlg.footer.dom.style.display = '';
2494 for(var k in buttons){
2495 if(typeof buttons[k] != "function"){
2498 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2499 width += buttons[k].el.getWidth()+15;
2509 var handleEsc = function(d, k, e){
2510 if(opt && opt.closable !== false){
2520 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2521 * @return {Roo.BasicDialog} The BasicDialog element
2523 getDialog : function(){
2525 dlg = new Roo.bootstrap.Modal( {
2528 //constraintoviewport:false,
2530 //collapsible : false,
2535 //buttonAlign:"center",
2536 closeClick : function(){
2537 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2540 handleButton("cancel");
2545 dlg.on("hide", handleHide);
2547 //dlg.addKeyListener(27, handleEsc);
2549 this.buttons = buttons;
2550 var bt = this.buttonText;
2551 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2552 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2553 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2554 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2556 bodyEl = dlg.body.createChild({
2558 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2559 '<textarea class="roo-mb-textarea"></textarea>' +
2560 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2562 msgEl = bodyEl.dom.firstChild;
2563 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2564 textboxEl.enableDisplayMode();
2565 textboxEl.addKeyListener([10,13], function(){
2566 if(dlg.isVisible() && opt && opt.buttons){
2569 }else if(opt.buttons.yes){
2570 handleButton("yes");
2574 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2575 textareaEl.enableDisplayMode();
2576 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2577 progressEl.enableDisplayMode();
2578 var pf = progressEl.dom.firstChild;
2580 pp = Roo.get(pf.firstChild);
2581 pp.setHeight(pf.offsetHeight);
2589 * Updates the message box body text
2590 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2591 * the XHTML-compliant non-breaking space character '&#160;')
2592 * @return {Roo.MessageBox} This message box
2594 updateText : function(text){
2595 if(!dlg.isVisible() && !opt.width){
2596 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2598 msgEl.innerHTML = text || ' ';
2600 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2601 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2603 Math.min(opt.width || cw , this.maxWidth),
2604 Math.max(opt.minWidth || this.minWidth, bwidth)
2607 activeTextEl.setWidth(w);
2609 if(dlg.isVisible()){
2610 dlg.fixedcenter = false;
2612 // to big, make it scroll. = But as usual stupid IE does not support
2615 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2616 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2617 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2619 bodyEl.dom.style.height = '';
2620 bodyEl.dom.style.overflowY = '';
2623 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2625 bodyEl.dom.style.overflowX = '';
2628 dlg.setContentSize(w, bodyEl.getHeight());
2629 if(dlg.isVisible()){
2630 dlg.fixedcenter = true;
2636 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2637 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2638 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2639 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2640 * @return {Roo.MessageBox} This message box
2642 updateProgress : function(value, text){
2644 this.updateText(text);
2646 if (pp) { // weird bug on my firefox - for some reason this is not defined
2647 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2653 * Returns true if the message box is currently displayed
2654 * @return {Boolean} True if the message box is visible, else false
2656 isVisible : function(){
2657 return dlg && dlg.isVisible();
2661 * Hides the message box if it is displayed
2664 if(this.isVisible()){
2670 * Displays a new message box, or reinitializes an existing message box, based on the config options
2671 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2672 * The following config object properties are supported:
2674 Property Type Description
2675 ---------- --------------- ------------------------------------------------------------------------------------
2676 animEl String/Element An id or Element from which the message box should animate as it opens and
2677 closes (defaults to undefined)
2678 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2679 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2680 closable Boolean False to hide the top-right close button (defaults to true). Note that
2681 progress and wait dialogs will ignore this property and always hide the
2682 close button as they can only be closed programmatically.
2683 cls String A custom CSS class to apply to the message box element
2684 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2685 displayed (defaults to 75)
2686 fn Function A callback function to execute after closing the dialog. The arguments to the
2687 function will be btn (the name of the button that was clicked, if applicable,
2688 e.g. "ok"), and text (the value of the active text field, if applicable).
2689 Progress and wait dialogs will ignore this option since they do not respond to
2690 user actions and can only be closed programmatically, so any required function
2691 should be called by the same code after it closes the dialog.
2692 icon String A CSS class that provides a background image to be used as an icon for
2693 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2694 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2695 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2696 modal Boolean False to allow user interaction with the page while the message box is
2697 displayed (defaults to true)
2698 msg String A string that will replace the existing message box body text (defaults
2699 to the XHTML-compliant non-breaking space character ' ')
2700 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2701 progress Boolean True to display a progress bar (defaults to false)
2702 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2703 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2704 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2705 title String The title text
2706 value String The string value to set into the active textbox element if displayed
2707 wait Boolean True to display a progress bar (defaults to false)
2708 width Number The width of the dialog in pixels
2715 msg: 'Please enter your address:',
2717 buttons: Roo.MessageBox.OKCANCEL,
2720 animEl: 'addAddressBtn'
2723 * @param {Object} config Configuration options
2724 * @return {Roo.MessageBox} This message box
2726 show : function(options)
2729 // this causes nightmares if you show one dialog after another
2730 // especially on callbacks..
2732 if(this.isVisible()){
2735 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2736 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2737 Roo.log("New Dialog Message:" + options.msg )
2738 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2739 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2742 var d = this.getDialog();
2744 d.setTitle(opt.title || " ");
2745 d.close.setDisplayed(opt.closable !== false);
2746 activeTextEl = textboxEl;
2747 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2752 textareaEl.setHeight(typeof opt.multiline == "number" ?
2753 opt.multiline : this.defaultTextHeight);
2754 activeTextEl = textareaEl;
2763 progressEl.setDisplayed(opt.progress === true);
2764 this.updateProgress(0);
2765 activeTextEl.dom.value = opt.value || "";
2767 dlg.setDefaultButton(activeTextEl);
2769 var bs = opt.buttons;
2773 }else if(bs && bs.yes){
2774 db = buttons["yes"];
2776 dlg.setDefaultButton(db);
2778 bwidth = updateButtons(opt.buttons);
2779 this.updateText(opt.msg);
2781 d.el.addClass(opt.cls);
2783 d.proxyDrag = opt.proxyDrag === true;
2784 d.modal = opt.modal !== false;
2785 d.mask = opt.modal !== false ? mask : false;
2787 // force it to the end of the z-index stack so it gets a cursor in FF
2788 document.body.appendChild(dlg.el.dom);
2789 d.animateTarget = null;
2790 d.show(options.animEl);
2796 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2797 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2798 * and closing the message box when the process is complete.
2799 * @param {String} title The title bar text
2800 * @param {String} msg The message box body text
2801 * @return {Roo.MessageBox} This message box
2803 progress : function(title, msg){
2810 minWidth: this.minProgressWidth,
2817 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2818 * If a callback function is passed it will be called after the user clicks the button, and the
2819 * id of the button that was clicked will be passed as the only parameter to the callback
2820 * (could also be the top-right close button).
2821 * @param {String} title The title bar text
2822 * @param {String} msg The message box body text
2823 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2824 * @param {Object} scope (optional) The scope of the callback function
2825 * @return {Roo.MessageBox} This message box
2827 alert : function(title, msg, fn, scope){
2840 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2841 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2842 * You are responsible for closing the message box when the process is complete.
2843 * @param {String} msg The message box body text
2844 * @param {String} title (optional) The title bar text
2845 * @return {Roo.MessageBox} This message box
2847 wait : function(msg, title){
2858 waitTimer = Roo.TaskMgr.start({
2860 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2868 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2869 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2870 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2871 * @param {String} title The title bar text
2872 * @param {String} msg The message box body text
2873 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2874 * @param {Object} scope (optional) The scope of the callback function
2875 * @return {Roo.MessageBox} This message box
2877 confirm : function(title, msg, fn, scope){
2881 buttons: this.YESNO,
2890 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2891 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2892 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2893 * (could also be the top-right close button) and the text that was entered will be passed as the two
2894 * parameters to the callback.
2895 * @param {String} title The title bar text
2896 * @param {String} msg The message box body text
2897 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2898 * @param {Object} scope (optional) The scope of the callback function
2899 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2900 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2901 * @return {Roo.MessageBox} This message box
2903 prompt : function(title, msg, fn, scope, multiline){
2907 buttons: this.OKCANCEL,
2912 multiline: multiline,
2919 * Button config that displays a single OK button
2924 * Button config that displays Yes and No buttons
2927 YESNO : {yes:true, no:true},
2929 * Button config that displays OK and Cancel buttons
2932 OKCANCEL : {ok:true, cancel:true},
2934 * Button config that displays Yes, No and Cancel buttons
2937 YESNOCANCEL : {yes:true, no:true, cancel:true},
2940 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2943 defaultTextHeight : 75,
2945 * The maximum width in pixels of the message box (defaults to 600)
2950 * The minimum width in pixels of the message box (defaults to 100)
2955 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2956 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2959 minProgressWidth : 250,
2961 * An object containing the default button text strings that can be overriden for localized language support.
2962 * Supported properties are: ok, cancel, yes and no.
2963 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2976 * Shorthand for {@link Roo.MessageBox}
2978 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
2979 Roo.Msg = Roo.Msg || Roo.MessageBox;
2988 * @class Roo.bootstrap.Navbar
2989 * @extends Roo.bootstrap.Component
2990 * Bootstrap Navbar class
2993 * Create a new Navbar
2994 * @param {Object} config The config object
2998 Roo.bootstrap.Navbar = function(config){
2999 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3003 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3012 getAutoCreate : function(){
3015 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3019 initEvents :function ()
3021 //Roo.log(this.el.select('.navbar-toggle',true));
3022 this.el.select('.navbar-toggle',true).on('click', function() {
3023 // Roo.log('click');
3024 this.el.select('.navbar-collapse',true).toggleClass('in');
3032 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3034 var size = this.el.getSize();
3035 this.maskEl.setSize(size.width, size.height);
3036 this.maskEl.enableDisplayMode("block");
3045 getChildContainer : function()
3047 if (this.el.select('.collapse').getCount()) {
3048 return this.el.select('.collapse',true).first();
3081 * @class Roo.bootstrap.NavSimplebar
3082 * @extends Roo.bootstrap.Navbar
3083 * Bootstrap Sidebar class
3085 * @cfg {Boolean} inverse is inverted color
3087 * @cfg {String} type (nav | pills | tabs)
3088 * @cfg {Boolean} arrangement stacked | justified
3089 * @cfg {String} align (left | right) alignment
3091 * @cfg {Boolean} main (true|false) main nav bar? default false
3092 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3094 * @cfg {String} tag (header|footer|nav|div) default is nav
3100 * Create a new Sidebar
3101 * @param {Object} config The config object
3105 Roo.bootstrap.NavSimplebar = function(config){
3106 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3109 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3125 getAutoCreate : function(){
3129 tag : this.tag || 'div',
3142 this.type = this.type || 'nav';
3143 if (['tabs','pills'].indexOf(this.type)!==-1) {
3144 cfg.cn[0].cls += ' nav-' + this.type
3148 if (this.type!=='nav') {
3149 Roo.log('nav type must be nav/tabs/pills')
3151 cfg.cn[0].cls += ' navbar-nav'
3157 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3158 cfg.cn[0].cls += ' nav-' + this.arrangement;
3162 if (this.align === 'right') {
3163 cfg.cn[0].cls += ' navbar-right';
3167 cfg.cls += ' navbar-inverse';
3194 * @class Roo.bootstrap.NavHeaderbar
3195 * @extends Roo.bootstrap.NavSimplebar
3196 * Bootstrap Sidebar class
3198 * @cfg {String} brand what is brand
3199 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3200 * @cfg {String} brand_href href of the brand
3201 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3202 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3203 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3204 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3207 * Create a new Sidebar
3208 * @param {Object} config The config object
3212 Roo.bootstrap.NavHeaderbar = function(config){
3213 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3217 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3224 desktopCenter : false,
3227 getAutoCreate : function(){
3230 tag: this.nav || 'nav',
3237 if (this.desktopCenter) {
3238 cn.push({cls : 'container', cn : []});
3245 cls: 'navbar-header',
3250 cls: 'navbar-toggle',
3251 'data-toggle': 'collapse',
3256 html: 'Toggle navigation'
3278 cls: 'collapse navbar-collapse',
3282 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3284 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3285 cfg.cls += ' navbar-' + this.position;
3287 // tag can override this..
3289 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3292 if (this.brand !== '') {
3295 href: this.brand_href ? this.brand_href : '#',
3296 cls: 'navbar-brand',
3304 cfg.cls += ' main-nav';
3312 getHeaderChildContainer : function()
3314 if (this.el.select('.navbar-header').getCount()) {
3315 return this.el.select('.navbar-header',true).first();
3318 return this.getChildContainer();
3322 initEvents : function()
3324 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3326 if (this.autohide) {
3331 Roo.get(document).on('scroll',function(e) {
3332 var ns = Roo.get(document).getScroll().top;
3333 var os = prevScroll;
3337 ft.removeClass('slideDown');
3338 ft.addClass('slideUp');
3341 ft.removeClass('slideUp');
3342 ft.addClass('slideDown');
3366 * @class Roo.bootstrap.NavSidebar
3367 * @extends Roo.bootstrap.Navbar
3368 * Bootstrap Sidebar class
3371 * Create a new Sidebar
3372 * @param {Object} config The config object
3376 Roo.bootstrap.NavSidebar = function(config){
3377 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3380 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3382 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3384 getAutoCreate : function(){
3389 cls: 'sidebar sidebar-nav'
3411 * @class Roo.bootstrap.NavGroup
3412 * @extends Roo.bootstrap.Component
3413 * Bootstrap NavGroup class
3414 * @cfg {String} align left | right
3415 * @cfg {Boolean} inverse false | true
3416 * @cfg {String} type (nav|pills|tab) default nav
3417 * @cfg {String} navId - reference Id for navbar.
3421 * Create a new nav group
3422 * @param {Object} config The config object
3425 Roo.bootstrap.NavGroup = function(config){
3426 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3429 Roo.bootstrap.NavGroup.register(this);
3433 * Fires when the active item changes
3434 * @param {Roo.bootstrap.NavGroup} this
3435 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3436 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3443 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3454 getAutoCreate : function()
3456 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3463 if (['tabs','pills'].indexOf(this.type)!==-1) {
3464 cfg.cls += ' nav-' + this.type
3466 if (this.type!=='nav') {
3467 Roo.log('nav type must be nav/tabs/pills')
3469 cfg.cls += ' navbar-nav'
3472 if (this.parent().sidebar) {
3475 cls: 'dashboard-menu sidebar-menu'
3481 if (this.form === true) {
3487 if (this.align === 'right') {
3488 cfg.cls += ' navbar-right';
3490 cfg.cls += ' navbar-left';
3494 if (this.align === 'right') {
3495 cfg.cls += ' navbar-right';
3499 cfg.cls += ' navbar-inverse';
3507 * sets the active Navigation item
3508 * @param {Roo.bootstrap.NavItem} the new current navitem
3510 setActiveItem : function(item)
3513 Roo.each(this.navItems, function(v){
3518 v.setActive(false, true);
3525 item.setActive(true, true);
3526 this.fireEvent('changed', this, item, prev);
3531 * gets the active Navigation item
3532 * @return {Roo.bootstrap.NavItem} the current navitem
3534 getActive : function()
3538 Roo.each(this.navItems, function(v){
3549 indexOfNav : function()
3553 Roo.each(this.navItems, function(v,i){
3564 * adds a Navigation item
3565 * @param {Roo.bootstrap.NavItem} the navitem to add
3567 addItem : function(cfg)
3569 var cn = new Roo.bootstrap.NavItem(cfg);
3571 cn.parentId = this.id;
3572 cn.onRender(this.el, null);
3576 * register a Navigation item
3577 * @param {Roo.bootstrap.NavItem} the navitem to add
3579 register : function(item)
3581 this.navItems.push( item);
3582 item.navId = this.navId;
3587 * clear all the Navigation item
3590 clearAll : function()
3593 this.el.dom.innerHTML = '';
3596 getNavItem: function(tabId)
3599 Roo.each(this.navItems, function(e) {
3600 if (e.tabId == tabId) {
3610 setActiveNext : function()
3612 var i = this.indexOfNav(this.getActive());
3613 if (i > this.navItems.length) {
3616 this.setActiveItem(this.navItems[i+1]);
3618 setActivePrev : function()
3620 var i = this.indexOfNav(this.getActive());
3624 this.setActiveItem(this.navItems[i-1]);
3626 clearWasActive : function(except) {
3627 Roo.each(this.navItems, function(e) {
3628 if (e.tabId != except.tabId && e.was_active) {
3629 e.was_active = false;
3636 getWasActive : function ()
3639 Roo.each(this.navItems, function(e) {
3654 Roo.apply(Roo.bootstrap.NavGroup, {
3658 * register a Navigation Group
3659 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3661 register : function(navgrp)
3663 this.groups[navgrp.navId] = navgrp;
3667 * fetch a Navigation Group based on the navigation ID
3668 * @param {string} the navgroup to add
3669 * @returns {Roo.bootstrap.NavGroup} the navgroup
3671 get: function(navId) {
3672 if (typeof(this.groups[navId]) == 'undefined') {
3674 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3676 return this.groups[navId] ;
3691 * @class Roo.bootstrap.NavItem
3692 * @extends Roo.bootstrap.Component
3693 * Bootstrap Navbar.NavItem class
3694 * @cfg {String} href link to
3695 * @cfg {String} html content of button
3696 * @cfg {String} badge text inside badge
3697 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3698 * @cfg {String} glyphicon name of glyphicon
3699 * @cfg {String} icon name of font awesome icon
3700 * @cfg {Boolean} active Is item active
3701 * @cfg {Boolean} disabled Is item disabled
3703 * @cfg {Boolean} preventDefault (true | false) default false
3704 * @cfg {String} tabId the tab that this item activates.
3705 * @cfg {String} tagtype (a|span) render as a href or span?
3708 * Create a new Navbar Item
3709 * @param {Object} config The config object
3711 Roo.bootstrap.NavItem = function(config){
3712 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3717 * The raw click event for the entire grid.
3718 * @param {Roo.EventObject} e
3723 * Fires when the active item active state changes
3724 * @param {Roo.bootstrap.NavItem} this
3725 * @param {boolean} state the new state
3733 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3741 preventDefault : false,
3748 getAutoCreate : function(){
3756 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3758 if (this.disabled) {
3759 cfg.cls += ' disabled';
3762 if (this.href || this.html || this.glyphicon || this.icon) {
3766 href : this.href || "#",
3767 html: this.html || ''
3772 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3775 if(this.glyphicon) {
3776 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3781 cfg.cn[0].html += " <span class='caret'></span>";
3785 if (this.badge !== '') {
3787 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3795 initEvents: function()
3797 if (typeof (this.menu) != 'undefined') {
3798 this.menu.parentType = this.xtype;
3799 this.menu.triggerEl = this.el;
3800 this.menu = this.addxtype(Roo.apply({}, this.menu));
3803 this.el.select('a',true).on('click', this.onClick, this);
3805 if(this.tagtype == 'span'){
3806 this.el.select('span',true).on('click', this.onClick, this);
3809 // at this point parent should be available..
3810 this.parent().register(this);
3813 onClick : function(e)
3815 if(this.preventDefault || this.href == '#'){
3819 if (this.disabled) {
3823 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3824 if (tg && tg.transition) {
3825 Roo.log("waiting for the transitionend");
3829 Roo.log("fire event clicked");
3830 if(this.fireEvent('click', this, e) === false){
3834 if(this.tagtype == 'span'){
3838 var p = this.parent();
3839 if (['tabs','pills'].indexOf(p.type)!==-1) {
3840 if (typeof(p.setActiveItem) !== 'undefined') {
3841 p.setActiveItem(this);
3844 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3845 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3846 // remove the collapsed menu expand...
3847 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3852 isActive: function () {
3855 setActive : function(state, fire, is_was_active)
3857 if (this.active && !state & this.navId) {
3858 this.was_active = true;
3859 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3861 nv.clearWasActive(this);
3865 this.active = state;
3868 this.el.removeClass('active');
3869 } else if (!this.el.hasClass('active')) {
3870 this.el.addClass('active');
3873 this.fireEvent('changed', this, state);
3876 // show a panel if it's registered and related..
3878 if (!this.navId || !this.tabId || !state || is_was_active) {
3882 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3886 var pan = tg.getPanelByName(this.tabId);
3890 // if we can not flip to new panel - go back to old nav highlight..
3891 if (false == tg.showPanel(pan)) {
3892 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3894 var onav = nv.getWasActive();
3896 onav.setActive(true, false, true);
3905 // this should not be here...
3906 setDisabled : function(state)
3908 this.disabled = state;
3910 this.el.removeClass('disabled');
3911 } else if (!this.el.hasClass('disabled')) {
3912 this.el.addClass('disabled');
3918 * Fetch the element to display the tooltip on.
3919 * @return {Roo.Element} defaults to this.el
3921 tooltipEl : function()
3923 return this.el.select('' + this.tagtype + '', true).first();
3934 * <span> icon </span>
3935 * <span> text </span>
3936 * <span>badge </span>
3940 * @class Roo.bootstrap.NavSidebarItem
3941 * @extends Roo.bootstrap.NavItem
3942 * Bootstrap Navbar.NavSidebarItem class
3944 * Create a new Navbar Button
3945 * @param {Object} config The config object
3947 Roo.bootstrap.NavSidebarItem = function(config){
3948 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3953 * The raw click event for the entire grid.
3954 * @param {Roo.EventObject} e
3959 * Fires when the active item active state changes
3960 * @param {Roo.bootstrap.NavSidebarItem} this
3961 * @param {boolean} state the new state
3969 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3972 getAutoCreate : function(){
3977 href : this.href || '#',
3989 html : this.html || ''
3994 cfg.cls += ' active';
3998 if (this.glyphicon || this.icon) {
3999 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4000 a.cn.push({ tag : 'i', cls : c }) ;
4005 if (this.badge !== '') {
4006 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4010 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4011 a.cls += 'dropdown-toggle treeview' ;
4035 * @class Roo.bootstrap.Row
4036 * @extends Roo.bootstrap.Component
4037 * Bootstrap Row class (contains columns...)
4041 * @param {Object} config The config object
4044 Roo.bootstrap.Row = function(config){
4045 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4048 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4050 getAutoCreate : function(){
4069 * @class Roo.bootstrap.Element
4070 * @extends Roo.bootstrap.Component
4071 * Bootstrap Element class
4072 * @cfg {String} html contents of the element
4073 * @cfg {String} tag tag of the element
4074 * @cfg {String} cls class of the element
4077 * Create a new Element
4078 * @param {Object} config The config object
4081 Roo.bootstrap.Element = function(config){
4082 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4085 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4092 getAutoCreate : function(){
4117 * @class Roo.bootstrap.Pagination
4118 * @extends Roo.bootstrap.Component
4119 * Bootstrap Pagination class
4120 * @cfg {String} size xs | sm | md | lg
4121 * @cfg {Boolean} inverse false | true
4124 * Create a new Pagination
4125 * @param {Object} config The config object
4128 Roo.bootstrap.Pagination = function(config){
4129 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4132 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4138 getAutoCreate : function(){
4144 cfg.cls += ' inverse';
4150 cfg.cls += " " + this.cls;
4168 * @class Roo.bootstrap.PaginationItem
4169 * @extends Roo.bootstrap.Component
4170 * Bootstrap PaginationItem class
4171 * @cfg {String} html text
4172 * @cfg {String} href the link
4173 * @cfg {Boolean} preventDefault (true | false) default true
4174 * @cfg {Boolean} active (true | false) default false
4175 * @cfg {Boolean} disabled default false
4179 * Create a new PaginationItem
4180 * @param {Object} config The config object
4184 Roo.bootstrap.PaginationItem = function(config){
4185 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4190 * The raw click event for the entire grid.
4191 * @param {Roo.EventObject} e
4197 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4201 preventDefault: true,
4206 getAutoCreate : function(){
4212 href : this.href ? this.href : '#',
4213 html : this.html ? this.html : ''
4223 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4227 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4233 initEvents: function() {
4235 this.el.on('click', this.onClick, this);
4238 onClick : function(e)
4240 Roo.log('PaginationItem on click ');
4241 if(this.preventDefault){
4249 this.fireEvent('click', this, e);
4265 * @class Roo.bootstrap.Slider
4266 * @extends Roo.bootstrap.Component
4267 * Bootstrap Slider class
4270 * Create a new Slider
4271 * @param {Object} config The config object
4274 Roo.bootstrap.Slider = function(config){
4275 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4278 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4280 getAutoCreate : function(){
4284 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4288 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4300 * Ext JS Library 1.1.1
4301 * Copyright(c) 2006-2007, Ext JS, LLC.
4303 * Originally Released Under LGPL - original licence link has changed is not relivant.
4306 * <script type="text/javascript">
4311 * @class Roo.grid.ColumnModel
4312 * @extends Roo.util.Observable
4313 * This is the default implementation of a ColumnModel used by the Grid. It defines
4314 * the columns in the grid.
4317 var colModel = new Roo.grid.ColumnModel([
4318 {header: "Ticker", width: 60, sortable: true, locked: true},
4319 {header: "Company Name", width: 150, sortable: true},
4320 {header: "Market Cap.", width: 100, sortable: true},
4321 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4322 {header: "Employees", width: 100, sortable: true, resizable: false}
4327 * The config options listed for this class are options which may appear in each
4328 * individual column definition.
4329 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4331 * @param {Object} config An Array of column config objects. See this class's
4332 * config objects for details.
4334 Roo.grid.ColumnModel = function(config){
4336 * The config passed into the constructor
4338 this.config = config;
4341 // if no id, create one
4342 // if the column does not have a dataIndex mapping,
4343 // map it to the order it is in the config
4344 for(var i = 0, len = config.length; i < len; i++){
4346 if(typeof c.dataIndex == "undefined"){
4349 if(typeof c.renderer == "string"){
4350 c.renderer = Roo.util.Format[c.renderer];
4352 if(typeof c.id == "undefined"){
4355 if(c.editor && c.editor.xtype){
4356 c.editor = Roo.factory(c.editor, Roo.grid);
4358 if(c.editor && c.editor.isFormField){
4359 c.editor = new Roo.grid.GridEditor(c.editor);
4361 this.lookup[c.id] = c;
4365 * The width of columns which have no width specified (defaults to 100)
4368 this.defaultWidth = 100;
4371 * Default sortable of columns which have no sortable specified (defaults to false)
4374 this.defaultSortable = false;
4378 * @event widthchange
4379 * Fires when the width of a column changes.
4380 * @param {ColumnModel} this
4381 * @param {Number} columnIndex The column index
4382 * @param {Number} newWidth The new width
4384 "widthchange": true,
4386 * @event headerchange
4387 * Fires when the text of a header changes.
4388 * @param {ColumnModel} this
4389 * @param {Number} columnIndex The column index
4390 * @param {Number} newText The new header text
4392 "headerchange": true,
4394 * @event hiddenchange
4395 * Fires when a column is hidden or "unhidden".
4396 * @param {ColumnModel} this
4397 * @param {Number} columnIndex The column index
4398 * @param {Boolean} hidden true if hidden, false otherwise
4400 "hiddenchange": true,
4402 * @event columnmoved
4403 * Fires when a column is moved.
4404 * @param {ColumnModel} this
4405 * @param {Number} oldIndex
4406 * @param {Number} newIndex
4408 "columnmoved" : true,
4410 * @event columlockchange
4411 * Fires when a column's locked state is changed
4412 * @param {ColumnModel} this
4413 * @param {Number} colIndex
4414 * @param {Boolean} locked true if locked
4416 "columnlockchange" : true
4418 Roo.grid.ColumnModel.superclass.constructor.call(this);
4420 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4422 * @cfg {String} header The header text to display in the Grid view.
4425 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4426 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4427 * specified, the column's index is used as an index into the Record's data Array.
4430 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4431 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4434 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4435 * Defaults to the value of the {@link #defaultSortable} property.
4436 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4439 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4442 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4445 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4448 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4451 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4452 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4453 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4454 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4457 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4460 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4463 * @cfg {String} cursor (Optional)
4466 * @cfg {String} tooltip (Optional)
4469 * Returns the id of the column at the specified index.
4470 * @param {Number} index The column index
4471 * @return {String} the id
4473 getColumnId : function(index){
4474 return this.config[index].id;
4478 * Returns the column for a specified id.
4479 * @param {String} id The column id
4480 * @return {Object} the column
4482 getColumnById : function(id){
4483 return this.lookup[id];
4488 * Returns the column for a specified dataIndex.
4489 * @param {String} dataIndex The column dataIndex
4490 * @return {Object|Boolean} the column or false if not found
4492 getColumnByDataIndex: function(dataIndex){
4493 var index = this.findColumnIndex(dataIndex);
4494 return index > -1 ? this.config[index] : false;
4498 * Returns the index for a specified column id.
4499 * @param {String} id The column id
4500 * @return {Number} the index, or -1 if not found
4502 getIndexById : function(id){
4503 for(var i = 0, len = this.config.length; i < len; i++){
4504 if(this.config[i].id == id){
4512 * Returns the index for a specified column dataIndex.
4513 * @param {String} dataIndex The column dataIndex
4514 * @return {Number} the index, or -1 if not found
4517 findColumnIndex : function(dataIndex){
4518 for(var i = 0, len = this.config.length; i < len; i++){
4519 if(this.config[i].dataIndex == dataIndex){
4527 moveColumn : function(oldIndex, newIndex){
4528 var c = this.config[oldIndex];
4529 this.config.splice(oldIndex, 1);
4530 this.config.splice(newIndex, 0, c);
4531 this.dataMap = null;
4532 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4535 isLocked : function(colIndex){
4536 return this.config[colIndex].locked === true;
4539 setLocked : function(colIndex, value, suppressEvent){
4540 if(this.isLocked(colIndex) == value){
4543 this.config[colIndex].locked = value;
4545 this.fireEvent("columnlockchange", this, colIndex, value);
4549 getTotalLockedWidth : function(){
4551 for(var i = 0; i < this.config.length; i++){
4552 if(this.isLocked(i) && !this.isHidden(i)){
4553 this.totalWidth += this.getColumnWidth(i);
4559 getLockedCount : function(){
4560 for(var i = 0, len = this.config.length; i < len; i++){
4561 if(!this.isLocked(i)){
4568 * Returns the number of columns.
4571 getColumnCount : function(visibleOnly){
4572 if(visibleOnly === true){
4574 for(var i = 0, len = this.config.length; i < len; i++){
4575 if(!this.isHidden(i)){
4581 return this.config.length;
4585 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4586 * @param {Function} fn
4587 * @param {Object} scope (optional)
4588 * @return {Array} result
4590 getColumnsBy : function(fn, scope){
4592 for(var i = 0, len = this.config.length; i < len; i++){
4593 var c = this.config[i];
4594 if(fn.call(scope||this, c, i) === true){
4602 * Returns true if the specified column is sortable.
4603 * @param {Number} col The column index
4606 isSortable : function(col){
4607 if(typeof this.config[col].sortable == "undefined"){
4608 return this.defaultSortable;
4610 return this.config[col].sortable;
4614 * Returns the rendering (formatting) function defined for the column.
4615 * @param {Number} col The column index.
4616 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4618 getRenderer : function(col){
4619 if(!this.config[col].renderer){
4620 return Roo.grid.ColumnModel.defaultRenderer;
4622 return this.config[col].renderer;
4626 * Sets the rendering (formatting) function for a column.
4627 * @param {Number} col The column index
4628 * @param {Function} fn The function to use to process the cell's raw data
4629 * to return HTML markup for the grid view. The render function is called with
4630 * the following parameters:<ul>
4631 * <li>Data value.</li>
4632 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4633 * <li>css A CSS style string to apply to the table cell.</li>
4634 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4635 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4636 * <li>Row index</li>
4637 * <li>Column index</li>
4638 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4640 setRenderer : function(col, fn){
4641 this.config[col].renderer = fn;
4645 * Returns the width for the specified column.
4646 * @param {Number} col The column index
4649 getColumnWidth : function(col){
4650 return this.config[col].width * 1 || this.defaultWidth;
4654 * Sets the width for a column.
4655 * @param {Number} col The column index
4656 * @param {Number} width The new width
4658 setColumnWidth : function(col, width, suppressEvent){
4659 this.config[col].width = width;
4660 this.totalWidth = null;
4662 this.fireEvent("widthchange", this, col, width);
4667 * Returns the total width of all columns.
4668 * @param {Boolean} includeHidden True to include hidden column widths
4671 getTotalWidth : function(includeHidden){
4672 if(!this.totalWidth){
4673 this.totalWidth = 0;
4674 for(var i = 0, len = this.config.length; i < len; i++){
4675 if(includeHidden || !this.isHidden(i)){
4676 this.totalWidth += this.getColumnWidth(i);
4680 return this.totalWidth;
4684 * Returns the header for the specified column.
4685 * @param {Number} col The column index
4688 getColumnHeader : function(col){
4689 return this.config[col].header;
4693 * Sets the header for a column.
4694 * @param {Number} col The column index
4695 * @param {String} header The new header
4697 setColumnHeader : function(col, header){
4698 this.config[col].header = header;
4699 this.fireEvent("headerchange", this, col, header);
4703 * Returns the tooltip for the specified column.
4704 * @param {Number} col The column index
4707 getColumnTooltip : function(col){
4708 return this.config[col].tooltip;
4711 * Sets the tooltip for a column.
4712 * @param {Number} col The column index
4713 * @param {String} tooltip The new tooltip
4715 setColumnTooltip : function(col, tooltip){
4716 this.config[col].tooltip = tooltip;
4720 * Returns the dataIndex for the specified column.
4721 * @param {Number} col The column index
4724 getDataIndex : function(col){
4725 return this.config[col].dataIndex;
4729 * Sets the dataIndex for a column.
4730 * @param {Number} col The column index
4731 * @param {Number} dataIndex The new dataIndex
4733 setDataIndex : function(col, dataIndex){
4734 this.config[col].dataIndex = dataIndex;
4740 * Returns true if the cell is editable.
4741 * @param {Number} colIndex The column index
4742 * @param {Number} rowIndex The row index
4745 isCellEditable : function(colIndex, rowIndex){
4746 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4750 * Returns the editor defined for the cell/column.
4751 * return false or null to disable editing.
4752 * @param {Number} colIndex The column index
4753 * @param {Number} rowIndex The row index
4756 getCellEditor : function(colIndex, rowIndex){
4757 return this.config[colIndex].editor;
4761 * Sets if a column is editable.
4762 * @param {Number} col The column index
4763 * @param {Boolean} editable True if the column is editable
4765 setEditable : function(col, editable){
4766 this.config[col].editable = editable;
4771 * Returns true if the column is hidden.
4772 * @param {Number} colIndex The column index
4775 isHidden : function(colIndex){
4776 return this.config[colIndex].hidden;
4781 * Returns true if the column width cannot be changed
4783 isFixed : function(colIndex){
4784 return this.config[colIndex].fixed;
4788 * Returns true if the column can be resized
4791 isResizable : function(colIndex){
4792 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4795 * Sets if a column is hidden.
4796 * @param {Number} colIndex The column index
4797 * @param {Boolean} hidden True if the column is hidden
4799 setHidden : function(colIndex, hidden){
4800 this.config[colIndex].hidden = hidden;
4801 this.totalWidth = null;
4802 this.fireEvent("hiddenchange", this, colIndex, hidden);
4806 * Sets the editor for a column.
4807 * @param {Number} col The column index
4808 * @param {Object} editor The editor object
4810 setEditor : function(col, editor){
4811 this.config[col].editor = editor;
4815 Roo.grid.ColumnModel.defaultRenderer = function(value){
4816 if(typeof value == "string" && value.length < 1){
4822 // Alias for backwards compatibility
4823 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4826 * Ext JS Library 1.1.1
4827 * Copyright(c) 2006-2007, Ext JS, LLC.
4829 * Originally Released Under LGPL - original licence link has changed is not relivant.
4832 * <script type="text/javascript">
4836 * @class Roo.LoadMask
4837 * A simple utility class for generically masking elements while loading data. If the element being masked has
4838 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4839 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4840 * element's UpdateManager load indicator and will be destroyed after the initial load.
4842 * Create a new LoadMask
4843 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4844 * @param {Object} config The config object
4846 Roo.LoadMask = function(el, config){
4847 this.el = Roo.get(el);
4848 Roo.apply(this, config);
4850 this.store.on('beforeload', this.onBeforeLoad, this);
4851 this.store.on('load', this.onLoad, this);
4852 this.store.on('loadexception', this.onLoadException, this);
4853 this.removeMask = false;
4855 var um = this.el.getUpdateManager();
4856 um.showLoadIndicator = false; // disable the default indicator
4857 um.on('beforeupdate', this.onBeforeLoad, this);
4858 um.on('update', this.onLoad, this);
4859 um.on('failure', this.onLoad, this);
4860 this.removeMask = true;
4864 Roo.LoadMask.prototype = {
4866 * @cfg {Boolean} removeMask
4867 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4868 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4872 * The text to display in a centered loading message box (defaults to 'Loading...')
4876 * @cfg {String} msgCls
4877 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4879 msgCls : 'x-mask-loading',
4882 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4888 * Disables the mask to prevent it from being displayed
4890 disable : function(){
4891 this.disabled = true;
4895 * Enables the mask so that it can be displayed
4897 enable : function(){
4898 this.disabled = false;
4901 onLoadException : function()
4905 if (typeof(arguments[3]) != 'undefined') {
4906 Roo.MessageBox.alert("Error loading",arguments[3]);
4910 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4911 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4920 this.el.unmask(this.removeMask);
4925 this.el.unmask(this.removeMask);
4929 onBeforeLoad : function(){
4931 this.el.mask(this.msg, this.msgCls);
4936 destroy : function(){
4938 this.store.un('beforeload', this.onBeforeLoad, this);
4939 this.store.un('load', this.onLoad, this);
4940 this.store.un('loadexception', this.onLoadException, this);
4942 var um = this.el.getUpdateManager();
4943 um.un('beforeupdate', this.onBeforeLoad, this);
4944 um.un('update', this.onLoad, this);
4945 um.un('failure', this.onLoad, this);
4956 * @class Roo.bootstrap.Table
4957 * @extends Roo.bootstrap.Component
4958 * Bootstrap Table class
4959 * @cfg {String} cls table class
4960 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4961 * @cfg {String} bgcolor Specifies the background color for a table
4962 * @cfg {Number} border Specifies whether the table cells should have borders or not
4963 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4964 * @cfg {Number} cellspacing Specifies the space between cells
4965 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4966 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4967 * @cfg {String} sortable Specifies that the table should be sortable
4968 * @cfg {String} summary Specifies a summary of the content of a table
4969 * @cfg {Number} width Specifies the width of a table
4970 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4972 * @cfg {boolean} striped Should the rows be alternative striped
4973 * @cfg {boolean} bordered Add borders to the table
4974 * @cfg {boolean} hover Add hover highlighting
4975 * @cfg {boolean} condensed Format condensed
4976 * @cfg {boolean} responsive Format condensed
4977 * @cfg {Boolean} loadMask (true|false) default false
4978 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4979 * @cfg {Boolean} thead (true|false) generate thead, default true
4980 * @cfg {Boolean} RowSelection (true|false) default false
4981 * @cfg {Boolean} CellSelection (true|false) default false
4982 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4986 * Create a new Table
4987 * @param {Object} config The config object
4990 Roo.bootstrap.Table = function(config){
4991 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4994 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4995 this.sm = this.selModel;
4996 this.sm.xmodule = this.xmodule || false;
4998 if (this.cm && typeof(this.cm.config) == 'undefined') {
4999 this.colModel = new Roo.grid.ColumnModel(this.cm);
5000 this.cm = this.colModel;
5001 this.cm.xmodule = this.xmodule || false;
5004 this.store= Roo.factory(this.store, Roo.data);
5005 this.ds = this.store;
5006 this.ds.xmodule = this.xmodule || false;
5009 if (this.footer && this.store) {
5010 this.footer.dataSource = this.ds;
5011 this.footer = Roo.factory(this.footer);
5018 * Fires when a cell is clicked
5019 * @param {Roo.bootstrap.Table} this
5020 * @param {Roo.Element} el
5021 * @param {Number} rowIndex
5022 * @param {Number} columnIndex
5023 * @param {Roo.EventObject} e
5027 * @event celldblclick
5028 * Fires when a cell is double clicked
5029 * @param {Roo.bootstrap.Table} this
5030 * @param {Roo.Element} el
5031 * @param {Number} rowIndex
5032 * @param {Number} columnIndex
5033 * @param {Roo.EventObject} e
5035 "celldblclick" : true,
5038 * Fires when a row is clicked
5039 * @param {Roo.bootstrap.Table} this
5040 * @param {Roo.Element} el
5041 * @param {Number} rowIndex
5042 * @param {Roo.EventObject} e
5046 * @event rowdblclick
5047 * Fires when a row is double clicked
5048 * @param {Roo.bootstrap.Table} this
5049 * @param {Roo.Element} el
5050 * @param {Number} rowIndex
5051 * @param {Roo.EventObject} e
5053 "rowdblclick" : true,
5056 * Fires when a mouseover occur
5057 * @param {Roo.bootstrap.Table} this
5058 * @param {Roo.Element} el
5059 * @param {Number} rowIndex
5060 * @param {Number} columnIndex
5061 * @param {Roo.EventObject} e
5066 * Fires when a mouseout occur
5067 * @param {Roo.bootstrap.Table} this
5068 * @param {Roo.Element} el
5069 * @param {Number} rowIndex
5070 * @param {Number} columnIndex
5071 * @param {Roo.EventObject} e
5076 * Fires when a row is rendered, so you can change add a style to it.
5077 * @param {Roo.bootstrap.Table} this
5078 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5082 * @event rowsrendered
5083 * Fires when all the rows have been rendered
5084 * @param {Roo.bootstrap.Table} this
5086 'rowsrendered' : true
5091 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5115 RowSelection : false,
5116 CellSelection : false,
5119 // Roo.Element - the tbody
5122 getAutoCreate : function(){
5123 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5132 cfg.cls += ' table-striped';
5136 cfg.cls += ' table-hover';
5138 if (this.bordered) {
5139 cfg.cls += ' table-bordered';
5141 if (this.condensed) {
5142 cfg.cls += ' table-condensed';
5144 if (this.responsive) {
5145 cfg.cls += ' table-responsive';
5149 cfg.cls+= ' ' +this.cls;
5152 // this lot should be simplifed...
5155 cfg.align=this.align;
5158 cfg.bgcolor=this.bgcolor;
5161 cfg.border=this.border;
5163 if (this.cellpadding) {
5164 cfg.cellpadding=this.cellpadding;
5166 if (this.cellspacing) {
5167 cfg.cellspacing=this.cellspacing;
5170 cfg.frame=this.frame;
5173 cfg.rules=this.rules;
5175 if (this.sortable) {
5176 cfg.sortable=this.sortable;
5179 cfg.summary=this.summary;
5182 cfg.width=this.width;
5185 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5188 if(this.store || this.cm){
5190 cfg.cn.push(this.renderHeader());
5193 cfg.cn.push(this.renderBody());
5196 cfg.cn.push(this.renderFooter());
5199 cfg.cls+= ' TableGrid';
5202 return { cn : [ cfg ] };
5205 initEvents : function()
5207 if(!this.store || !this.cm){
5211 //Roo.log('initEvents with ds!!!!');
5213 this.mainBody = this.el.select('tbody', true).first();
5218 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5219 e.on('click', _this.sort, _this);
5222 this.el.on("click", this.onClick, this);
5223 this.el.on("dblclick", this.onDblClick, this);
5225 // why is this done????? = it breaks dialogs??
5226 //this.parent().el.setStyle('position', 'relative');
5230 this.footer.parentId = this.id;
5231 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5234 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5236 this.store.on('load', this.onLoad, this);
5237 this.store.on('beforeload', this.onBeforeLoad, this);
5238 this.store.on('update', this.onUpdate, this);
5239 this.store.on('add', this.onAdd, this);
5243 onMouseover : function(e, el)
5245 var cell = Roo.get(el);
5251 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5252 cell = cell.findParent('td', false, true);
5255 var row = cell.findParent('tr', false, true);
5256 var cellIndex = cell.dom.cellIndex;
5257 var rowIndex = row.dom.rowIndex - 1; // start from 0
5259 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5263 onMouseout : function(e, el)
5265 var cell = Roo.get(el);
5271 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5272 cell = cell.findParent('td', false, true);
5275 var row = cell.findParent('tr', false, true);
5276 var cellIndex = cell.dom.cellIndex;
5277 var rowIndex = row.dom.rowIndex - 1; // start from 0
5279 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5283 onClick : function(e, el)
5285 var cell = Roo.get(el);
5287 if(!cell || (!this.CellSelection && !this.RowSelection)){
5291 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5292 cell = cell.findParent('td', false, true);
5295 if(!cell || typeof(cell) == 'undefined'){
5299 var row = cell.findParent('tr', false, true);
5301 if(!row || typeof(row) == 'undefined'){
5305 var cellIndex = cell.dom.cellIndex;
5306 var rowIndex = this.getRowIndex(row);
5308 if(this.CellSelection){
5309 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5312 if(this.RowSelection){
5313 this.fireEvent('rowclick', this, row, rowIndex, e);
5319 onDblClick : function(e,el)
5321 var cell = Roo.get(el);
5323 if(!cell || (!this.CellSelection && !this.RowSelection)){
5327 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5328 cell = cell.findParent('td', false, true);
5331 if(!cell || typeof(cell) == 'undefined'){
5335 var row = cell.findParent('tr', false, true);
5337 if(!row || typeof(row) == 'undefined'){
5341 var cellIndex = cell.dom.cellIndex;
5342 var rowIndex = this.getRowIndex(row);
5344 if(this.CellSelection){
5345 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5348 if(this.RowSelection){
5349 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5353 sort : function(e,el)
5355 var col = Roo.get(el);
5357 if(!col.hasClass('sortable')){
5361 var sort = col.attr('sort');
5364 if(col.hasClass('glyphicon-arrow-up')){
5368 this.store.sortInfo = {field : sort, direction : dir};
5371 Roo.log("calling footer first");
5372 this.footer.onClick('first');
5375 this.store.load({ params : { start : 0 } });
5379 renderHeader : function()
5388 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5390 var config = cm.config[i];
5395 html: cm.getColumnHeader(i)
5398 if(typeof(config.tooltip) != 'undefined'){
5399 c.tooltip = config.tooltip;
5402 if(typeof(config.hidden) != 'undefined' && config.hidden){
5403 c.style += ' display:none;';
5406 if(typeof(config.dataIndex) != 'undefined'){
5407 c.sort = config.dataIndex;
5410 if(typeof(config.sortable) != 'undefined' && config.sortable){
5414 if(typeof(config.align) != 'undefined' && config.align.length){
5415 c.style += ' text-align:' + config.align + ';';
5418 if(typeof(config.width) != 'undefined'){
5419 c.style += ' width:' + config.width + 'px;';
5428 renderBody : function()
5438 colspan : this.cm.getColumnCount()
5448 renderFooter : function()
5458 colspan : this.cm.getColumnCount()
5472 Roo.log('ds onload');
5477 var ds = this.store;
5479 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5480 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5482 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5483 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5486 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5487 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5491 var tbody = this.mainBody;
5493 if(ds.getCount() > 0){
5494 ds.data.each(function(d,rowIndex){
5495 var row = this.renderRow(cm, ds, rowIndex);
5497 tbody.createChild(row);
5501 if(row.cellObjects.length){
5502 Roo.each(row.cellObjects, function(r){
5503 _this.renderCellObject(r);
5510 Roo.each(this.el.select('tbody td', true).elements, function(e){
5511 e.on('mouseover', _this.onMouseover, _this);
5514 Roo.each(this.el.select('tbody td', true).elements, function(e){
5515 e.on('mouseout', _this.onMouseout, _this);
5517 this.fireEvent('rowsrendered', this);
5518 //if(this.loadMask){
5519 // this.maskEl.hide();
5524 onUpdate : function(ds,record)
5526 this.refreshRow(record);
5529 onRemove : function(ds, record, index, isUpdate){
5530 if(isUpdate !== true){
5531 this.fireEvent("beforerowremoved", this, index, record);
5533 var bt = this.mainBody.dom;
5535 var rows = this.el.select('tbody > tr', true).elements;
5537 if(typeof(rows[index]) != 'undefined'){
5538 bt.removeChild(rows[index].dom);
5541 // if(bt.rows[index]){
5542 // bt.removeChild(bt.rows[index]);
5545 if(isUpdate !== true){
5546 //this.stripeRows(index);
5547 //this.syncRowHeights(index, index);
5549 this.fireEvent("rowremoved", this, index, record);
5553 onAdd : function(ds, records, rowIndex)
5555 //Roo.log('on Add called');
5556 // - note this does not handle multiple adding very well..
5557 var bt = this.mainBody.dom;
5558 for (var i =0 ; i < records.length;i++) {
5559 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5560 //Roo.log(records[i]);
5561 //Roo.log(this.store.getAt(rowIndex+i));
5562 this.insertRow(this.store, rowIndex + i, false);
5569 refreshRow : function(record){
5570 var ds = this.store, index;
5571 if(typeof record == 'number'){
5573 record = ds.getAt(index);
5575 index = ds.indexOf(record);
5577 this.insertRow(ds, index, true);
5578 this.onRemove(ds, record, index+1, true);
5579 //this.syncRowHeights(index, index);
5581 this.fireEvent("rowupdated", this, index, record);
5584 insertRow : function(dm, rowIndex, isUpdate){
5587 this.fireEvent("beforerowsinserted", this, rowIndex);
5589 //var s = this.getScrollState();
5590 var row = this.renderRow(this.cm, this.store, rowIndex);
5591 // insert before rowIndex..
5592 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5596 if(row.cellObjects.length){
5597 Roo.each(row.cellObjects, function(r){
5598 _this.renderCellObject(r);
5603 this.fireEvent("rowsinserted", this, rowIndex);
5604 //this.syncRowHeights(firstRow, lastRow);
5605 //this.stripeRows(firstRow);
5612 getRowDom : function(rowIndex)
5614 var rows = this.el.select('tbody > tr', true).elements;
5616 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5619 // returns the object tree for a tr..
5622 renderRow : function(cm, ds, rowIndex)
5625 var d = ds.getAt(rowIndex);
5632 var cellObjects = [];
5634 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5635 var config = cm.config[i];
5637 var renderer = cm.getRenderer(i);
5641 if(typeof(renderer) !== 'undefined'){
5642 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5644 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5645 // and are rendered into the cells after the row is rendered - using the id for the element.
5647 if(typeof(value) === 'object'){
5657 rowIndex : rowIndex,
5662 this.fireEvent('rowclass', this, rowcfg);
5666 cls : rowcfg.rowClass,
5668 html: (typeof(value) === 'object') ? '' : value
5675 if(typeof(config.hidden) != 'undefined' && config.hidden){
5676 td.style += ' display:none;';
5679 if(typeof(config.align) != 'undefined' && config.align.length){
5680 td.style += ' text-align:' + config.align + ';';
5683 if(typeof(config.width) != 'undefined'){
5684 td.style += ' width:' + config.width + 'px;';
5687 if(typeof(config.cursor) != 'undefined'){
5688 td.style += ' cursor:' + config.cursor + ';';
5695 row.cellObjects = cellObjects;
5703 onBeforeLoad : function()
5705 //Roo.log('ds onBeforeLoad');
5709 //if(this.loadMask){
5710 // this.maskEl.show();
5718 this.el.select('tbody', true).first().dom.innerHTML = '';
5721 * Show or hide a row.
5722 * @param {Number} rowIndex to show or hide
5723 * @param {Boolean} state hide
5725 setRowVisibility : function(rowIndex, state)
5727 var bt = this.mainBody.dom;
5729 var rows = this.el.select('tbody > tr', true).elements;
5731 if(typeof(rows[rowIndex]) == 'undefined'){
5734 rows[rowIndex].dom.style.display = state ? '' : 'none';
5738 getSelectionModel : function(){
5740 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5742 return this.selModel;
5745 * Render the Roo.bootstrap object from renderder
5747 renderCellObject : function(r)
5751 var t = r.cfg.render(r.container);
5754 Roo.each(r.cfg.cn, function(c){
5756 container: t.getChildContainer(),
5759 _this.renderCellObject(child);
5764 getRowIndex : function(row)
5768 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5791 * @class Roo.bootstrap.TableCell
5792 * @extends Roo.bootstrap.Component
5793 * Bootstrap TableCell class
5794 * @cfg {String} html cell contain text
5795 * @cfg {String} cls cell class
5796 * @cfg {String} tag cell tag (td|th) default td
5797 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5798 * @cfg {String} align Aligns the content in a cell
5799 * @cfg {String} axis Categorizes cells
5800 * @cfg {String} bgcolor Specifies the background color of a cell
5801 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5802 * @cfg {Number} colspan Specifies the number of columns a cell should span
5803 * @cfg {String} headers Specifies one or more header cells a cell is related to
5804 * @cfg {Number} height Sets the height of a cell
5805 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5806 * @cfg {Number} rowspan Sets the number of rows a cell should span
5807 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5808 * @cfg {String} valign Vertical aligns the content in a cell
5809 * @cfg {Number} width Specifies the width of a cell
5812 * Create a new TableCell
5813 * @param {Object} config The config object
5816 Roo.bootstrap.TableCell = function(config){
5817 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5820 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5840 getAutoCreate : function(){
5841 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5861 cfg.align=this.align
5867 cfg.bgcolor=this.bgcolor
5870 cfg.charoff=this.charoff
5873 cfg.colspan=this.colspan
5876 cfg.headers=this.headers
5879 cfg.height=this.height
5882 cfg.nowrap=this.nowrap
5885 cfg.rowspan=this.rowspan
5888 cfg.scope=this.scope
5891 cfg.valign=this.valign
5894 cfg.width=this.width
5913 * @class Roo.bootstrap.TableRow
5914 * @extends Roo.bootstrap.Component
5915 * Bootstrap TableRow class
5916 * @cfg {String} cls row class
5917 * @cfg {String} align Aligns the content in a table row
5918 * @cfg {String} bgcolor Specifies a background color for a table row
5919 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5920 * @cfg {String} valign Vertical aligns the content in a table row
5923 * Create a new TableRow
5924 * @param {Object} config The config object
5927 Roo.bootstrap.TableRow = function(config){
5928 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5931 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5939 getAutoCreate : function(){
5940 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5950 cfg.align = this.align;
5953 cfg.bgcolor = this.bgcolor;
5956 cfg.charoff = this.charoff;
5959 cfg.valign = this.valign;
5977 * @class Roo.bootstrap.TableBody
5978 * @extends Roo.bootstrap.Component
5979 * Bootstrap TableBody class
5980 * @cfg {String} cls element class
5981 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5982 * @cfg {String} align Aligns the content inside the element
5983 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5984 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5987 * Create a new TableBody
5988 * @param {Object} config The config object
5991 Roo.bootstrap.TableBody = function(config){
5992 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5995 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6003 getAutoCreate : function(){
6004 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6018 cfg.align = this.align;
6021 cfg.charoff = this.charoff;
6024 cfg.valign = this.valign;
6031 // initEvents : function()
6038 // this.store = Roo.factory(this.store, Roo.data);
6039 // this.store.on('load', this.onLoad, this);
6041 // this.store.load();
6045 // onLoad: function ()
6047 // this.fireEvent('load', this);
6057 * Ext JS Library 1.1.1
6058 * Copyright(c) 2006-2007, Ext JS, LLC.
6060 * Originally Released Under LGPL - original licence link has changed is not relivant.
6063 * <script type="text/javascript">
6066 // as we use this in bootstrap.
6067 Roo.namespace('Roo.form');
6069 * @class Roo.form.Action
6070 * Internal Class used to handle form actions
6072 * @param {Roo.form.BasicForm} el The form element or its id
6073 * @param {Object} config Configuration options
6078 // define the action interface
6079 Roo.form.Action = function(form, options){
6081 this.options = options || {};
6084 * Client Validation Failed
6087 Roo.form.Action.CLIENT_INVALID = 'client';
6089 * Server Validation Failed
6092 Roo.form.Action.SERVER_INVALID = 'server';
6094 * Connect to Server Failed
6097 Roo.form.Action.CONNECT_FAILURE = 'connect';
6099 * Reading Data from Server Failed
6102 Roo.form.Action.LOAD_FAILURE = 'load';
6104 Roo.form.Action.prototype = {
6106 failureType : undefined,
6107 response : undefined,
6111 run : function(options){
6116 success : function(response){
6121 handleResponse : function(response){
6125 // default connection failure
6126 failure : function(response){
6128 this.response = response;
6129 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6130 this.form.afterAction(this, false);
6133 processResponse : function(response){
6134 this.response = response;
6135 if(!response.responseText){
6138 this.result = this.handleResponse(response);
6142 // utility functions used internally
6143 getUrl : function(appendParams){
6144 var url = this.options.url || this.form.url || this.form.el.dom.action;
6146 var p = this.getParams();
6148 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6154 getMethod : function(){
6155 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6158 getParams : function(){
6159 var bp = this.form.baseParams;
6160 var p = this.options.params;
6162 if(typeof p == "object"){
6163 p = Roo.urlEncode(Roo.applyIf(p, bp));
6164 }else if(typeof p == 'string' && bp){
6165 p += '&' + Roo.urlEncode(bp);
6168 p = Roo.urlEncode(bp);
6173 createCallback : function(){
6175 success: this.success,
6176 failure: this.failure,
6178 timeout: (this.form.timeout*1000),
6179 upload: this.form.fileUpload ? this.success : undefined
6184 Roo.form.Action.Submit = function(form, options){
6185 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6188 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6191 haveProgress : false,
6192 uploadComplete : false,
6194 // uploadProgress indicator.
6195 uploadProgress : function()
6197 if (!this.form.progressUrl) {
6201 if (!this.haveProgress) {
6202 Roo.MessageBox.progress("Uploading", "Uploading");
6204 if (this.uploadComplete) {
6205 Roo.MessageBox.hide();
6209 this.haveProgress = true;
6211 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6213 var c = new Roo.data.Connection();
6215 url : this.form.progressUrl,
6220 success : function(req){
6221 //console.log(data);
6225 rdata = Roo.decode(req.responseText)
6227 Roo.log("Invalid data from server..");
6231 if (!rdata || !rdata.success) {
6233 Roo.MessageBox.alert(Roo.encode(rdata));
6236 var data = rdata.data;
6238 if (this.uploadComplete) {
6239 Roo.MessageBox.hide();
6244 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6245 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6248 this.uploadProgress.defer(2000,this);
6251 failure: function(data) {
6252 Roo.log('progress url failed ');
6263 // run get Values on the form, so it syncs any secondary forms.
6264 this.form.getValues();
6266 var o = this.options;
6267 var method = this.getMethod();
6268 var isPost = method == 'POST';
6269 if(o.clientValidation === false || this.form.isValid()){
6271 if (this.form.progressUrl) {
6272 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6273 (new Date() * 1) + '' + Math.random());
6278 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6279 form:this.form.el.dom,
6280 url:this.getUrl(!isPost),
6282 params:isPost ? this.getParams() : null,
6283 isUpload: this.form.fileUpload
6286 this.uploadProgress();
6288 }else if (o.clientValidation !== false){ // client validation failed
6289 this.failureType = Roo.form.Action.CLIENT_INVALID;
6290 this.form.afterAction(this, false);
6294 success : function(response)
6296 this.uploadComplete= true;
6297 if (this.haveProgress) {
6298 Roo.MessageBox.hide();
6302 var result = this.processResponse(response);
6303 if(result === true || result.success){
6304 this.form.afterAction(this, true);
6308 this.form.markInvalid(result.errors);
6309 this.failureType = Roo.form.Action.SERVER_INVALID;
6311 this.form.afterAction(this, false);
6313 failure : function(response)
6315 this.uploadComplete= true;
6316 if (this.haveProgress) {
6317 Roo.MessageBox.hide();
6320 this.response = response;
6321 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6322 this.form.afterAction(this, false);
6325 handleResponse : function(response){
6326 if(this.form.errorReader){
6327 var rs = this.form.errorReader.read(response);
6330 for(var i = 0, len = rs.records.length; i < len; i++) {
6331 var r = rs.records[i];
6335 if(errors.length < 1){
6339 success : rs.success,
6345 ret = Roo.decode(response.responseText);
6349 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6359 Roo.form.Action.Load = function(form, options){
6360 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6361 this.reader = this.form.reader;
6364 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6369 Roo.Ajax.request(Roo.apply(
6370 this.createCallback(), {
6371 method:this.getMethod(),
6372 url:this.getUrl(false),
6373 params:this.getParams()
6377 success : function(response){
6379 var result = this.processResponse(response);
6380 if(result === true || !result.success || !result.data){
6381 this.failureType = Roo.form.Action.LOAD_FAILURE;
6382 this.form.afterAction(this, false);
6385 this.form.clearInvalid();
6386 this.form.setValues(result.data);
6387 this.form.afterAction(this, true);
6390 handleResponse : function(response){
6391 if(this.form.reader){
6392 var rs = this.form.reader.read(response);
6393 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6395 success : rs.success,
6399 return Roo.decode(response.responseText);
6403 Roo.form.Action.ACTION_TYPES = {
6404 'load' : Roo.form.Action.Load,
6405 'submit' : Roo.form.Action.Submit
6414 * @class Roo.bootstrap.Form
6415 * @extends Roo.bootstrap.Component
6416 * Bootstrap Form class
6417 * @cfg {String} method GET | POST (default POST)
6418 * @cfg {String} labelAlign top | left (default top)
6419 * @cfg {String} align left | right - for navbars
6420 * @cfg {Boolean} loadMask load mask when submit (default true)
6425 * @param {Object} config The config object
6429 Roo.bootstrap.Form = function(config){
6430 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6433 * @event clientvalidation
6434 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6435 * @param {Form} this
6436 * @param {Boolean} valid true if the form has passed client-side validation
6438 clientvalidation: true,
6440 * @event beforeaction
6441 * Fires before any action is performed. Return false to cancel the action.
6442 * @param {Form} this
6443 * @param {Action} action The action to be performed
6447 * @event actionfailed
6448 * Fires when an action fails.
6449 * @param {Form} this
6450 * @param {Action} action The action that failed
6452 actionfailed : true,
6454 * @event actioncomplete
6455 * Fires when an action is completed.
6456 * @param {Form} this
6457 * @param {Action} action The action that completed
6459 actioncomplete : true
6464 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6467 * @cfg {String} method
6468 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6473 * The URL to use for form actions if one isn't supplied in the action options.
6476 * @cfg {Boolean} fileUpload
6477 * Set to true if this form is a file upload.
6481 * @cfg {Object} baseParams
6482 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6486 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6490 * @cfg {Sting} align (left|right) for navbar forms
6495 activeAction : null,
6498 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6499 * element by passing it or its id or mask the form itself by passing in true.
6502 waitMsgTarget : false,
6506 getAutoCreate : function(){
6510 method : this.method || 'POST',
6511 id : this.id || Roo.id(),
6514 if (this.parent().xtype.match(/^Nav/)) {
6515 cfg.cls = 'navbar-form navbar-' + this.align;
6519 if (this.labelAlign == 'left' ) {
6520 cfg.cls += ' form-horizontal';
6526 initEvents : function()
6528 this.el.on('submit', this.onSubmit, this);
6529 // this was added as random key presses on the form where triggering form submit.
6530 this.el.on('keypress', function(e) {
6531 if (e.getCharCode() != 13) {
6534 // we might need to allow it for textareas.. and some other items.
6535 // check e.getTarget().
6537 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6541 Roo.log("keypress blocked");
6549 onSubmit : function(e){
6554 * Returns true if client-side validation on the form is successful.
6557 isValid : function(){
6558 var items = this.getItems();
6560 items.each(function(f){
6569 * Returns true if any fields in this form have changed since their original load.
6572 isDirty : function(){
6574 var items = this.getItems();
6575 items.each(function(f){
6585 * Performs a predefined action (submit or load) or custom actions you define on this form.
6586 * @param {String} actionName The name of the action type
6587 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6588 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6589 * accept other config options):
6591 Property Type Description
6592 ---------------- --------------- ----------------------------------------------------------------------------------
6593 url String The url for the action (defaults to the form's url)
6594 method String The form method to use (defaults to the form's method, or POST if not defined)
6595 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6596 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6597 validate the form on the client (defaults to false)
6599 * @return {BasicForm} this
6601 doAction : function(action, options){
6602 if(typeof action == 'string'){
6603 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6605 if(this.fireEvent('beforeaction', this, action) !== false){
6606 this.beforeAction(action);
6607 action.run.defer(100, action);
6613 beforeAction : function(action){
6614 var o = action.options;
6617 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6619 // not really supported yet.. ??
6621 //if(this.waitMsgTarget === true){
6622 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6623 //}else if(this.waitMsgTarget){
6624 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6625 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6627 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6633 afterAction : function(action, success){
6634 this.activeAction = null;
6635 var o = action.options;
6637 //if(this.waitMsgTarget === true){
6639 //}else if(this.waitMsgTarget){
6640 // this.waitMsgTarget.unmask();
6642 // Roo.MessageBox.updateProgress(1);
6643 // Roo.MessageBox.hide();
6650 Roo.callback(o.success, o.scope, [this, action]);
6651 this.fireEvent('actioncomplete', this, action);
6655 // failure condition..
6656 // we have a scenario where updates need confirming.
6657 // eg. if a locking scenario exists..
6658 // we look for { errors : { needs_confirm : true }} in the response.
6660 (typeof(action.result) != 'undefined') &&
6661 (typeof(action.result.errors) != 'undefined') &&
6662 (typeof(action.result.errors.needs_confirm) != 'undefined')
6665 Roo.log("not supported yet");
6668 Roo.MessageBox.confirm(
6669 "Change requires confirmation",
6670 action.result.errorMsg,
6675 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6685 Roo.callback(o.failure, o.scope, [this, action]);
6686 // show an error message if no failed handler is set..
6687 if (!this.hasListener('actionfailed')) {
6688 Roo.log("need to add dialog support");
6690 Roo.MessageBox.alert("Error",
6691 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6692 action.result.errorMsg :
6693 "Saving Failed, please check your entries or try again"
6698 this.fireEvent('actionfailed', this, action);
6703 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6704 * @param {String} id The value to search for
6707 findField : function(id){
6708 var items = this.getItems();
6709 var field = items.get(id);
6711 items.each(function(f){
6712 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6719 return field || null;
6722 * Mark fields in this form invalid in bulk.
6723 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6724 * @return {BasicForm} this
6726 markInvalid : function(errors){
6727 if(errors instanceof Array){
6728 for(var i = 0, len = errors.length; i < len; i++){
6729 var fieldError = errors[i];
6730 var f = this.findField(fieldError.id);
6732 f.markInvalid(fieldError.msg);
6738 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6739 field.markInvalid(errors[id]);
6743 //Roo.each(this.childForms || [], function (f) {
6744 // f.markInvalid(errors);
6751 * Set values for fields in this form in bulk.
6752 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6753 * @return {BasicForm} this
6755 setValues : function(values){
6756 if(values instanceof Array){ // array of objects
6757 for(var i = 0, len = values.length; i < len; i++){
6759 var f = this.findField(v.id);
6761 f.setValue(v.value);
6762 if(this.trackResetOnLoad){
6763 f.originalValue = f.getValue();
6767 }else{ // object hash
6770 if(typeof values[id] != 'function' && (field = this.findField(id))){
6772 if (field.setFromData &&
6774 field.displayField &&
6775 // combos' with local stores can
6776 // be queried via setValue()
6777 // to set their value..
6778 (field.store && !field.store.isLocal)
6782 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6783 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6784 field.setFromData(sd);
6787 field.setValue(values[id]);
6791 if(this.trackResetOnLoad){
6792 field.originalValue = field.getValue();
6798 //Roo.each(this.childForms || [], function (f) {
6799 // f.setValues(values);
6806 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6807 * they are returned as an array.
6808 * @param {Boolean} asString
6811 getValues : function(asString){
6812 //if (this.childForms) {
6813 // copy values from the child forms
6814 // Roo.each(this.childForms, function (f) {
6815 // this.setValues(f.getValues());
6821 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6822 if(asString === true){
6825 return Roo.urlDecode(fs);
6829 * Returns the fields in this form as an object with key/value pairs.
6830 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6833 getFieldValues : function(with_hidden)
6835 var items = this.getItems();
6837 items.each(function(f){
6841 var v = f.getValue();
6842 if (f.inputType =='radio') {
6843 if (typeof(ret[f.getName()]) == 'undefined') {
6844 ret[f.getName()] = ''; // empty..
6847 if (!f.el.dom.checked) {
6855 // not sure if this supported any more..
6856 if ((typeof(v) == 'object') && f.getRawValue) {
6857 v = f.getRawValue() ; // dates..
6859 // combo boxes where name != hiddenName...
6860 if (f.name != f.getName()) {
6861 ret[f.name] = f.getRawValue();
6863 ret[f.getName()] = v;
6870 * Clears all invalid messages in this form.
6871 * @return {BasicForm} this
6873 clearInvalid : function(){
6874 var items = this.getItems();
6876 items.each(function(f){
6887 * @return {BasicForm} this
6890 var items = this.getItems();
6891 items.each(function(f){
6895 Roo.each(this.childForms || [], function (f) {
6902 getItems : function()
6904 var r=new Roo.util.MixedCollection(false, function(o){
6905 return o.id || (o.id = Roo.id());
6907 var iter = function(el) {
6914 Roo.each(el.items,function(e) {
6934 * Ext JS Library 1.1.1
6935 * Copyright(c) 2006-2007, Ext JS, LLC.
6937 * Originally Released Under LGPL - original licence link has changed is not relivant.
6940 * <script type="text/javascript">
6943 * @class Roo.form.VTypes
6944 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6947 Roo.form.VTypes = function(){
6948 // closure these in so they are only created once.
6949 var alpha = /^[a-zA-Z_]+$/;
6950 var alphanum = /^[a-zA-Z0-9_]+$/;
6951 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6952 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6954 // All these messages and functions are configurable
6957 * The function used to validate email addresses
6958 * @param {String} value The email address
6960 'email' : function(v){
6961 return email.test(v);
6964 * The error text to display when the email validation function returns false
6967 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6969 * The keystroke filter mask to be applied on email input
6972 'emailMask' : /[a-z0-9_\.\-@]/i,
6975 * The function used to validate URLs
6976 * @param {String} value The URL
6978 'url' : function(v){
6982 * The error text to display when the url validation function returns false
6985 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6988 * The function used to validate alpha values
6989 * @param {String} value The value
6991 'alpha' : function(v){
6992 return alpha.test(v);
6995 * The error text to display when the alpha validation function returns false
6998 'alphaText' : 'This field should only contain letters and _',
7000 * The keystroke filter mask to be applied on alpha input
7003 'alphaMask' : /[a-z_]/i,
7006 * The function used to validate alphanumeric values
7007 * @param {String} value The value
7009 'alphanum' : function(v){
7010 return alphanum.test(v);
7013 * The error text to display when the alphanumeric validation function returns false
7016 'alphanumText' : 'This field should only contain letters, numbers and _',
7018 * The keystroke filter mask to be applied on alphanumeric input
7021 'alphanumMask' : /[a-z0-9_]/i
7031 * @class Roo.bootstrap.Input
7032 * @extends Roo.bootstrap.Component
7033 * Bootstrap Input class
7034 * @cfg {Boolean} disabled is it disabled
7035 * @cfg {String} fieldLabel - the label associated
7036 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7037 * @cfg {String} name name of the input
7038 * @cfg {string} fieldLabel - the label associated
7039 * @cfg {string} inputType - input / file submit ...
7040 * @cfg {string} placeholder - placeholder to put in text.
7041 * @cfg {string} before - input group add on before
7042 * @cfg {string} after - input group add on after
7043 * @cfg {string} size - (lg|sm) or leave empty..
7044 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7045 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7046 * @cfg {Number} md colspan out of 12 for computer-sized screens
7047 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7048 * @cfg {string} value default value of the input
7049 * @cfg {Number} labelWidth set the width of label (0-12)
7050 * @cfg {String} labelAlign (top|left)
7051 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7052 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7054 * @cfg {String} align (left|center|right) Default left
7059 * Create a new Input
7060 * @param {Object} config The config object
7063 Roo.bootstrap.Input = function(config){
7064 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7069 * Fires when this field receives input focus.
7070 * @param {Roo.form.Field} this
7075 * Fires when this field loses input focus.
7076 * @param {Roo.form.Field} this
7081 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7082 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7083 * @param {Roo.form.Field} this
7084 * @param {Roo.EventObject} e The event object
7089 * Fires just before the field blurs if the field value has changed.
7090 * @param {Roo.form.Field} this
7091 * @param {Mixed} newValue The new value
7092 * @param {Mixed} oldValue The original value
7097 * Fires after the field has been marked as invalid.
7098 * @param {Roo.form.Field} this
7099 * @param {String} msg The validation message
7104 * Fires after the field has been validated with no errors.
7105 * @param {Roo.form.Field} this
7110 * Fires after the key up
7111 * @param {Roo.form.Field} this
7112 * @param {Roo.EventObject} e The event Object
7118 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7120 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7121 automatic validation (defaults to "keyup").
7123 validationEvent : "keyup",
7125 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7127 validateOnBlur : true,
7129 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7131 validationDelay : 250,
7133 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7135 focusClass : "x-form-focus", // not needed???
7139 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7141 invalidClass : "has-warning",
7144 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7146 validClass : "has-success",
7149 * @cfg {Boolean} hasFeedback (true|false) default true
7154 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7156 invalidFeedbackClass : "glyphicon-warning-sign",
7159 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7161 validFeedbackClass : "glyphicon-ok",
7164 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7166 selectOnFocus : false,
7169 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7173 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7178 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7180 disableKeyFilter : false,
7183 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7187 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7191 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7193 blankText : "This field is required",
7196 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7200 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7202 maxLength : Number.MAX_VALUE,
7204 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7206 minLengthText : "The minimum length for this field is {0}",
7208 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7210 maxLengthText : "The maximum length for this field is {0}",
7214 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7215 * If available, this function will be called only after the basic validators all return true, and will be passed the
7216 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7220 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7221 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7222 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7226 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7230 autocomplete: false,
7249 formatedValue : false,
7251 parentLabelAlign : function()
7254 while (parent.parent()) {
7255 parent = parent.parent();
7256 if (typeof(parent.labelAlign) !='undefined') {
7257 return parent.labelAlign;
7264 getAutoCreate : function(){
7266 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7272 if(this.inputType != 'hidden'){
7273 cfg.cls = 'form-group' //input-group
7279 type : this.inputType,
7281 cls : 'form-control',
7282 placeholder : this.placeholder || '',
7283 autocomplete : this.autocomplete || 'new-password'
7288 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7291 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7292 input.maxLength = this.maxLength;
7295 if (this.disabled) {
7296 input.disabled=true;
7299 if (this.readOnly) {
7300 input.readonly=true;
7304 input.name = this.name;
7307 input.cls += ' input-' + this.size;
7310 ['xs','sm','md','lg'].map(function(size){
7311 if (settings[size]) {
7312 cfg.cls += ' col-' + size + '-' + settings[size];
7316 var inputblock = input;
7318 if(this.hasFeedback && this.inputType != 'hidden'){
7322 cls: 'glyphicon form-control-feedback'
7326 cls : 'has-feedback',
7334 // var inputblock = input;
7336 if (this.before || this.after) {
7339 cls : 'input-group',
7343 if (this.before && typeof(this.before) == 'string') {
7345 inputblock.cn.push({
7347 cls : 'roo-input-before input-group-addon',
7351 if (this.before && typeof(this.before) == 'object') {
7352 this.before = Roo.factory(this.before);
7353 Roo.log(this.before);
7354 inputblock.cn.push({
7356 cls : 'roo-input-before input-group-' +
7357 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7361 inputblock.cn.push(input);
7363 if(this.hasFeedback && this.inputType != 'hidden'){
7364 inputblock.cls += ' has-feedback';
7365 inputblock.cn.push(feedback);
7368 if (this.after && typeof(this.after) == 'string') {
7369 inputblock.cn.push({
7371 cls : 'roo-input-after input-group-addon',
7375 if (this.after && typeof(this.after) == 'object') {
7376 this.after = Roo.factory(this.after);
7377 Roo.log(this.after);
7378 inputblock.cn.push({
7380 cls : 'roo-input-after input-group-' +
7381 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7386 if (align ==='left' && this.fieldLabel.length) {
7387 Roo.log("left and has label");
7393 cls : 'control-label col-sm-' + this.labelWidth,
7394 html : this.fieldLabel
7398 cls : "col-sm-" + (12 - this.labelWidth),
7405 } else if ( this.fieldLabel.length) {
7411 //cls : 'input-group-addon',
7412 html : this.fieldLabel
7422 Roo.log(" no label && no align");
7431 Roo.log('input-parentType: ' + this.parentType);
7433 if (this.parentType === 'Navbar' && this.parent().bar) {
7434 cfg.cls += ' navbar-form';
7442 * return the real input element.
7444 inputEl: function ()
7446 return this.el.select('input.form-control',true).first();
7449 tooltipEl : function()
7451 return this.inputEl();
7454 setDisabled : function(v)
7456 var i = this.inputEl().dom;
7458 i.removeAttribute('disabled');
7462 i.setAttribute('disabled','true');
7464 initEvents : function()
7467 this.inputEl().on("keydown" , this.fireKey, this);
7468 this.inputEl().on("focus", this.onFocus, this);
7469 this.inputEl().on("blur", this.onBlur, this);
7471 this.inputEl().relayEvent('keyup', this);
7473 // reference to original value for reset
7474 this.originalValue = this.getValue();
7475 //Roo.form.TextField.superclass.initEvents.call(this);
7476 if(this.validationEvent == 'keyup'){
7477 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7478 this.inputEl().on('keyup', this.filterValidation, this);
7480 else if(this.validationEvent !== false){
7481 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7484 if(this.selectOnFocus){
7485 this.on("focus", this.preFocus, this);
7488 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7489 this.inputEl().on("keypress", this.filterKeys, this);
7492 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7493 this.el.on("click", this.autoSize, this);
7496 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7497 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7500 if (typeof(this.before) == 'object') {
7501 this.before.render(this.el.select('.roo-input-before',true).first());
7503 if (typeof(this.after) == 'object') {
7504 this.after.render(this.el.select('.roo-input-after',true).first());
7509 filterValidation : function(e){
7510 if(!e.isNavKeyPress()){
7511 this.validationTask.delay(this.validationDelay);
7515 * Validates the field value
7516 * @return {Boolean} True if the value is valid, else false
7518 validate : function(){
7519 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7520 if(this.disabled || this.validateValue(this.getRawValue())){
7531 * Validates a value according to the field's validation rules and marks the field as invalid
7532 * if the validation fails
7533 * @param {Mixed} value The value to validate
7534 * @return {Boolean} True if the value is valid, else false
7536 validateValue : function(value){
7537 if(value.length < 1) { // if it's blank
7538 if(this.allowBlank){
7544 if(value.length < this.minLength){
7547 if(value.length > this.maxLength){
7551 var vt = Roo.form.VTypes;
7552 if(!vt[this.vtype](value, this)){
7556 if(typeof this.validator == "function"){
7557 var msg = this.validator(value);
7563 if(this.regex && !this.regex.test(value)){
7573 fireKey : function(e){
7574 //Roo.log('field ' + e.getKey());
7575 if(e.isNavKeyPress()){
7576 this.fireEvent("specialkey", this, e);
7579 focus : function (selectText){
7581 this.inputEl().focus();
7582 if(selectText === true){
7583 this.inputEl().dom.select();
7589 onFocus : function(){
7590 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7591 // this.el.addClass(this.focusClass);
7594 this.hasFocus = true;
7595 this.startValue = this.getValue();
7596 this.fireEvent("focus", this);
7600 beforeBlur : Roo.emptyFn,
7604 onBlur : function(){
7606 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7607 //this.el.removeClass(this.focusClass);
7609 this.hasFocus = false;
7610 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7613 var v = this.getValue();
7614 if(String(v) !== String(this.startValue)){
7615 this.fireEvent('change', this, v, this.startValue);
7617 this.fireEvent("blur", this);
7621 * Resets the current field value to the originally loaded value and clears any validation messages
7624 this.setValue(this.originalValue);
7628 * Returns the name of the field
7629 * @return {Mixed} name The name field
7631 getName: function(){
7635 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7636 * @return {Mixed} value The field value
7638 getValue : function(){
7640 var v = this.inputEl().getValue();
7645 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7646 * @return {Mixed} value The field value
7648 getRawValue : function(){
7649 var v = this.inputEl().getValue();
7655 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7656 * @param {Mixed} value The value to set
7658 setRawValue : function(v){
7659 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7662 selectText : function(start, end){
7663 var v = this.getRawValue();
7665 start = start === undefined ? 0 : start;
7666 end = end === undefined ? v.length : end;
7667 var d = this.inputEl().dom;
7668 if(d.setSelectionRange){
7669 d.setSelectionRange(start, end);
7670 }else if(d.createTextRange){
7671 var range = d.createTextRange();
7672 range.moveStart("character", start);
7673 range.moveEnd("character", v.length-end);
7680 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7681 * @param {Mixed} value The value to set
7683 setValue : function(v){
7686 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7692 processValue : function(value){
7693 if(this.stripCharsRe){
7694 var newValue = value.replace(this.stripCharsRe, '');
7695 if(newValue !== value){
7696 this.setRawValue(newValue);
7703 preFocus : function(){
7705 if(this.selectOnFocus){
7706 this.inputEl().dom.select();
7709 filterKeys : function(e){
7711 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7714 var c = e.getCharCode(), cc = String.fromCharCode(c);
7715 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7718 if(!this.maskRe.test(cc)){
7723 * Clear any invalid styles/messages for this field
7725 clearInvalid : function(){
7727 if(!this.el || this.preventMark){ // not rendered
7730 this.el.removeClass(this.invalidClass);
7732 this.fireEvent('valid', this);
7736 * Mark this field as valid
7738 markValid : function(){
7739 if(!this.el || this.preventMark){ // not rendered
7743 this.el.removeClass([this.invalidClass, this.validClass]);
7745 this.el.addClass(this.validClass);
7747 if(this.hasFeedback && this.inputType != 'hidden'){
7748 var feedback = this.el.select('.form-control-feedback', true).first();
7751 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7752 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7757 this.fireEvent('valid', this);
7761 * Mark this field as invalid
7762 * @param {String} msg The validation message
7764 markInvalid : function(msg){
7765 if(!this.el || this.preventMark){ // not rendered
7769 this.el.removeClass([this.invalidClass, this.validClass]);
7771 this.el.addClass(this.invalidClass);
7773 if(this.hasFeedback && this.inputType != 'hidden'){
7775 var feedback = this.el.select('.form-control-feedback', true).first();
7778 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7779 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7784 this.fireEvent('invalid', this, msg);
7787 SafariOnKeyDown : function(event)
7789 // this is a workaround for a password hang bug on chrome/ webkit.
7791 var isSelectAll = false;
7793 if(this.inputEl().dom.selectionEnd > 0){
7794 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7796 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7797 event.preventDefault();
7802 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7804 event.preventDefault();
7805 // this is very hacky as keydown always get's upper case.
7807 var cc = String.fromCharCode(event.getCharCode());
7808 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7812 adjustWidth : function(tag, w){
7813 tag = tag.toLowerCase();
7814 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7815 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7819 if(tag == 'textarea'){
7822 }else if(Roo.isOpera){
7826 if(tag == 'textarea'){
7845 * @class Roo.bootstrap.TextArea
7846 * @extends Roo.bootstrap.Input
7847 * Bootstrap TextArea class
7848 * @cfg {Number} cols Specifies the visible width of a text area
7849 * @cfg {Number} rows Specifies the visible number of lines in a text area
7850 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7851 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7852 * @cfg {string} html text
7855 * Create a new TextArea
7856 * @param {Object} config The config object
7859 Roo.bootstrap.TextArea = function(config){
7860 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7864 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7874 getAutoCreate : function(){
7876 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7887 value : this.value || '',
7888 html: this.html || '',
7889 cls : 'form-control',
7890 placeholder : this.placeholder || ''
7894 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7895 input.maxLength = this.maxLength;
7899 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7903 input.cols = this.cols;
7906 if (this.readOnly) {
7907 input.readonly = true;
7911 input.name = this.name;
7915 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7919 ['xs','sm','md','lg'].map(function(size){
7920 if (settings[size]) {
7921 cfg.cls += ' col-' + size + '-' + settings[size];
7925 var inputblock = input;
7927 if(this.hasFeedback){
7931 cls: 'glyphicon form-control-feedback'
7935 cls : 'has-feedback',
7944 if (this.before || this.after) {
7947 cls : 'input-group',
7951 inputblock.cn.push({
7953 cls : 'input-group-addon',
7958 inputblock.cn.push(input);
7960 if(this.hasFeedback){
7961 inputblock.cls += ' has-feedback';
7962 inputblock.cn.push(feedback);
7966 inputblock.cn.push({
7968 cls : 'input-group-addon',
7975 if (align ==='left' && this.fieldLabel.length) {
7976 Roo.log("left and has label");
7982 cls : 'control-label col-sm-' + this.labelWidth,
7983 html : this.fieldLabel
7987 cls : "col-sm-" + (12 - this.labelWidth),
7994 } else if ( this.fieldLabel.length) {
8000 //cls : 'input-group-addon',
8001 html : this.fieldLabel
8011 Roo.log(" no label && no align");
8021 if (this.disabled) {
8022 input.disabled=true;
8029 * return the real textarea element.
8031 inputEl: function ()
8033 return this.el.select('textarea.form-control',true).first();
8041 * trigger field - base class for combo..
8046 * @class Roo.bootstrap.TriggerField
8047 * @extends Roo.bootstrap.Input
8048 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8049 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8050 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8051 * for which you can provide a custom implementation. For example:
8053 var trigger = new Roo.bootstrap.TriggerField();
8054 trigger.onTriggerClick = myTriggerFn;
8055 trigger.applyTo('my-field');
8058 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8059 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8060 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8061 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8062 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8065 * Create a new TriggerField.
8066 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8067 * to the base TextField)
8069 Roo.bootstrap.TriggerField = function(config){
8070 this.mimicing = false;
8071 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8074 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8076 * @cfg {String} triggerClass A CSS class to apply to the trigger
8079 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8083 /** @cfg {Boolean} grow @hide */
8084 /** @cfg {Number} growMin @hide */
8085 /** @cfg {Number} growMax @hide */
8091 autoSize: Roo.emptyFn,
8098 actionMode : 'wrap',
8103 getAutoCreate : function(){
8105 var align = this.labelAlign || this.parentLabelAlign();
8110 cls: 'form-group' //input-group
8117 type : this.inputType,
8118 cls : 'form-control',
8119 autocomplete: 'new-password',
8120 placeholder : this.placeholder || ''
8124 input.name = this.name;
8127 input.cls += ' input-' + this.size;
8130 if (this.disabled) {
8131 input.disabled=true;
8134 var inputblock = input;
8136 if (this.before || this.after) {
8139 cls : 'input-group',
8143 inputblock.cn.push({
8145 cls : 'input-group-addon',
8149 inputblock.cn.push(input);
8151 inputblock.cn.push({
8153 cls : 'input-group-addon',
8166 cls: 'form-hidden-field'
8174 Roo.log('multiple');
8182 cls: 'form-hidden-field'
8186 cls: 'select2-choices',
8190 cls: 'select2-search-field',
8203 cls: 'select2-container input-group',
8208 // cls: 'typeahead typeahead-long dropdown-menu',
8209 // style: 'display:none'
8214 if(!this.multiple && this.showToggleBtn){
8220 if (this.caret != false) {
8223 cls: 'fa fa-' + this.caret
8230 cls : 'input-group-addon btn dropdown-toggle',
8235 cls: 'combobox-clear',
8249 combobox.cls += ' select2-container-multi';
8252 if (align ==='left' && this.fieldLabel.length) {
8254 Roo.log("left and has label");
8260 cls : 'control-label col-sm-' + this.labelWidth,
8261 html : this.fieldLabel
8265 cls : "col-sm-" + (12 - this.labelWidth),
8272 } else if ( this.fieldLabel.length) {
8278 //cls : 'input-group-addon',
8279 html : this.fieldLabel
8289 Roo.log(" no label && no align");
8296 ['xs','sm','md','lg'].map(function(size){
8297 if (settings[size]) {
8298 cfg.cls += ' col-' + size + '-' + settings[size];
8309 onResize : function(w, h){
8310 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8311 // if(typeof w == 'number'){
8312 // var x = w - this.trigger.getWidth();
8313 // this.inputEl().setWidth(this.adjustWidth('input', x));
8314 // this.trigger.setStyle('left', x+'px');
8319 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8322 getResizeEl : function(){
8323 return this.inputEl();
8327 getPositionEl : function(){
8328 return this.inputEl();
8332 alignErrorIcon : function(){
8333 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8337 initEvents : function(){
8341 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8342 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8343 if(!this.multiple && this.showToggleBtn){
8344 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8345 if(this.hideTrigger){
8346 this.trigger.setDisplayed(false);
8348 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8352 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8355 //this.trigger.addClassOnOver('x-form-trigger-over');
8356 //this.trigger.addClassOnClick('x-form-trigger-click');
8359 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8363 createList : function()
8365 this.list = Roo.get(document.body).createChild({
8367 cls: 'typeahead typeahead-long dropdown-menu',
8368 style: 'display:none'
8371 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8376 initTrigger : function(){
8381 onDestroy : function(){
8383 this.trigger.removeAllListeners();
8384 // this.trigger.remove();
8387 // this.wrap.remove();
8389 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8393 onFocus : function(){
8394 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8397 this.wrap.addClass('x-trigger-wrap-focus');
8398 this.mimicing = true;
8399 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8400 if(this.monitorTab){
8401 this.el.on("keydown", this.checkTab, this);
8408 checkTab : function(e){
8409 if(e.getKey() == e.TAB){
8415 onBlur : function(){
8420 mimicBlur : function(e, t){
8422 if(!this.wrap.contains(t) && this.validateBlur()){
8429 triggerBlur : function(){
8430 this.mimicing = false;
8431 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8432 if(this.monitorTab){
8433 this.el.un("keydown", this.checkTab, this);
8435 //this.wrap.removeClass('x-trigger-wrap-focus');
8436 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8440 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8441 validateBlur : function(e, t){
8446 onDisable : function(){
8447 this.inputEl().dom.disabled = true;
8448 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8450 // this.wrap.addClass('x-item-disabled');
8455 onEnable : function(){
8456 this.inputEl().dom.disabled = false;
8457 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8459 // this.el.removeClass('x-item-disabled');
8464 onShow : function(){
8465 var ae = this.getActionEl();
8468 ae.dom.style.display = '';
8469 ae.dom.style.visibility = 'visible';
8475 onHide : function(){
8476 var ae = this.getActionEl();
8477 ae.dom.style.display = 'none';
8481 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8482 * by an implementing function.
8484 * @param {EventObject} e
8486 onTriggerClick : Roo.emptyFn
8490 * Ext JS Library 1.1.1
8491 * Copyright(c) 2006-2007, Ext JS, LLC.
8493 * Originally Released Under LGPL - original licence link has changed is not relivant.
8496 * <script type="text/javascript">
8501 * @class Roo.data.SortTypes
8503 * Defines the default sorting (casting?) comparison functions used when sorting data.
8505 Roo.data.SortTypes = {
8507 * Default sort that does nothing
8508 * @param {Mixed} s The value being converted
8509 * @return {Mixed} The comparison value
8516 * The regular expression used to strip tags
8520 stripTagsRE : /<\/?[^>]+>/gi,
8523 * Strips all HTML tags to sort on text only
8524 * @param {Mixed} s The value being converted
8525 * @return {String} The comparison value
8527 asText : function(s){
8528 return String(s).replace(this.stripTagsRE, "");
8532 * Strips all HTML tags to sort on text only - Case insensitive
8533 * @param {Mixed} s The value being converted
8534 * @return {String} The comparison value
8536 asUCText : function(s){
8537 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8541 * Case insensitive string
8542 * @param {Mixed} s The value being converted
8543 * @return {String} The comparison value
8545 asUCString : function(s) {
8546 return String(s).toUpperCase();
8551 * @param {Mixed} s The value being converted
8552 * @return {Number} The comparison value
8554 asDate : function(s) {
8558 if(s instanceof Date){
8561 return Date.parse(String(s));
8566 * @param {Mixed} s The value being converted
8567 * @return {Float} The comparison value
8569 asFloat : function(s) {
8570 var val = parseFloat(String(s).replace(/,/g, ""));
8571 if(isNaN(val)) val = 0;
8577 * @param {Mixed} s The value being converted
8578 * @return {Number} The comparison value
8580 asInt : function(s) {
8581 var val = parseInt(String(s).replace(/,/g, ""));
8582 if(isNaN(val)) val = 0;
8587 * Ext JS Library 1.1.1
8588 * Copyright(c) 2006-2007, Ext JS, LLC.
8590 * Originally Released Under LGPL - original licence link has changed is not relivant.
8593 * <script type="text/javascript">
8597 * @class Roo.data.Record
8598 * Instances of this class encapsulate both record <em>definition</em> information, and record
8599 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8600 * to access Records cached in an {@link Roo.data.Store} object.<br>
8602 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8603 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8606 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8608 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8609 * {@link #create}. The parameters are the same.
8610 * @param {Array} data An associative Array of data values keyed by the field name.
8611 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8612 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8613 * not specified an integer id is generated.
8615 Roo.data.Record = function(data, id){
8616 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8621 * Generate a constructor for a specific record layout.
8622 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8623 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8624 * Each field definition object may contain the following properties: <ul>
8625 * <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,
8626 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8627 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8628 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8629 * is being used, then this is a string containing the javascript expression to reference the data relative to
8630 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8631 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8632 * this may be omitted.</p></li>
8633 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8634 * <ul><li>auto (Default, implies no conversion)</li>
8639 * <li>date</li></ul></p></li>
8640 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8641 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8642 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8643 * by the Reader into an object that will be stored in the Record. It is passed the
8644 * following parameters:<ul>
8645 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8647 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8649 * <br>usage:<br><pre><code>
8650 var TopicRecord = Roo.data.Record.create(
8651 {name: 'title', mapping: 'topic_title'},
8652 {name: 'author', mapping: 'username'},
8653 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8654 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8655 {name: 'lastPoster', mapping: 'user2'},
8656 {name: 'excerpt', mapping: 'post_text'}
8659 var myNewRecord = new TopicRecord({
8660 title: 'Do my job please',
8663 lastPost: new Date(),
8664 lastPoster: 'Animal',
8665 excerpt: 'No way dude!'
8667 myStore.add(myNewRecord);
8672 Roo.data.Record.create = function(o){
8674 f.superclass.constructor.apply(this, arguments);
8676 Roo.extend(f, Roo.data.Record);
8677 var p = f.prototype;
8678 p.fields = new Roo.util.MixedCollection(false, function(field){
8681 for(var i = 0, len = o.length; i < len; i++){
8682 p.fields.add(new Roo.data.Field(o[i]));
8684 f.getField = function(name){
8685 return p.fields.get(name);
8690 Roo.data.Record.AUTO_ID = 1000;
8691 Roo.data.Record.EDIT = 'edit';
8692 Roo.data.Record.REJECT = 'reject';
8693 Roo.data.Record.COMMIT = 'commit';
8695 Roo.data.Record.prototype = {
8697 * Readonly flag - true if this record has been modified.
8706 join : function(store){
8711 * Set the named field to the specified value.
8712 * @param {String} name The name of the field to set.
8713 * @param {Object} value The value to set the field to.
8715 set : function(name, value){
8716 if(this.data[name] == value){
8723 if(typeof this.modified[name] == 'undefined'){
8724 this.modified[name] = this.data[name];
8726 this.data[name] = value;
8727 if(!this.editing && this.store){
8728 this.store.afterEdit(this);
8733 * Get the value of the named field.
8734 * @param {String} name The name of the field to get the value of.
8735 * @return {Object} The value of the field.
8737 get : function(name){
8738 return this.data[name];
8742 beginEdit : function(){
8743 this.editing = true;
8748 cancelEdit : function(){
8749 this.editing = false;
8750 delete this.modified;
8754 endEdit : function(){
8755 this.editing = false;
8756 if(this.dirty && this.store){
8757 this.store.afterEdit(this);
8762 * Usually called by the {@link Roo.data.Store} which owns the Record.
8763 * Rejects all changes made to the Record since either creation, or the last commit operation.
8764 * Modified fields are reverted to their original values.
8766 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8767 * of reject operations.
8769 reject : function(){
8770 var m = this.modified;
8772 if(typeof m[n] != "function"){
8773 this.data[n] = m[n];
8777 delete this.modified;
8778 this.editing = false;
8780 this.store.afterReject(this);
8785 * Usually called by the {@link Roo.data.Store} which owns the Record.
8786 * Commits all changes made to the Record since either creation, or the last commit operation.
8788 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8789 * of commit operations.
8791 commit : function(){
8793 delete this.modified;
8794 this.editing = false;
8796 this.store.afterCommit(this);
8801 hasError : function(){
8802 return this.error != null;
8806 clearError : function(){
8811 * Creates a copy of this record.
8812 * @param {String} id (optional) A new record id if you don't want to use this record's id
8815 copy : function(newId) {
8816 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8820 * Ext JS Library 1.1.1
8821 * Copyright(c) 2006-2007, Ext JS, LLC.
8823 * Originally Released Under LGPL - original licence link has changed is not relivant.
8826 * <script type="text/javascript">
8832 * @class Roo.data.Store
8833 * @extends Roo.util.Observable
8834 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8835 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8837 * 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
8838 * has no knowledge of the format of the data returned by the Proxy.<br>
8840 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8841 * instances from the data object. These records are cached and made available through accessor functions.
8843 * Creates a new Store.
8844 * @param {Object} config A config object containing the objects needed for the Store to access data,
8845 * and read the data into Records.
8847 Roo.data.Store = function(config){
8848 this.data = new Roo.util.MixedCollection(false);
8849 this.data.getKey = function(o){
8852 this.baseParams = {};
8859 "multisort" : "_multisort"
8862 if(config && config.data){
8863 this.inlineData = config.data;
8867 Roo.apply(this, config);
8869 if(this.reader){ // reader passed
8870 this.reader = Roo.factory(this.reader, Roo.data);
8871 this.reader.xmodule = this.xmodule || false;
8872 if(!this.recordType){
8873 this.recordType = this.reader.recordType;
8875 if(this.reader.onMetaChange){
8876 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8880 if(this.recordType){
8881 this.fields = this.recordType.prototype.fields;
8887 * @event datachanged
8888 * Fires when the data cache has changed, and a widget which is using this Store
8889 * as a Record cache should refresh its view.
8890 * @param {Store} this
8895 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8896 * @param {Store} this
8897 * @param {Object} meta The JSON metadata
8902 * Fires when Records have been added to the Store
8903 * @param {Store} this
8904 * @param {Roo.data.Record[]} records The array of Records added
8905 * @param {Number} index The index at which the record(s) were added
8910 * Fires when a Record has been removed from the Store
8911 * @param {Store} this
8912 * @param {Roo.data.Record} record The Record that was removed
8913 * @param {Number} index The index at which the record was removed
8918 * Fires when a Record has been updated
8919 * @param {Store} this
8920 * @param {Roo.data.Record} record The Record that was updated
8921 * @param {String} operation The update operation being performed. Value may be one of:
8923 Roo.data.Record.EDIT
8924 Roo.data.Record.REJECT
8925 Roo.data.Record.COMMIT
8931 * Fires when the data cache has been cleared.
8932 * @param {Store} this
8937 * Fires before a request is made for a new data object. If the beforeload handler returns false
8938 * the load action will be canceled.
8939 * @param {Store} this
8940 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8944 * @event beforeloadadd
8945 * Fires after a new set of Records has been loaded.
8946 * @param {Store} this
8947 * @param {Roo.data.Record[]} records The Records that were loaded
8948 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8950 beforeloadadd : true,
8953 * Fires after a new set of Records has been loaded, before they are added to the store.
8954 * @param {Store} this
8955 * @param {Roo.data.Record[]} records The Records that were loaded
8956 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8957 * @params {Object} return from reader
8961 * @event loadexception
8962 * Fires if an exception occurs in the Proxy during loading.
8963 * Called with the signature of the Proxy's "loadexception" event.
8964 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8967 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8968 * @param {Object} load options
8969 * @param {Object} jsonData from your request (normally this contains the Exception)
8971 loadexception : true
8975 this.proxy = Roo.factory(this.proxy, Roo.data);
8976 this.proxy.xmodule = this.xmodule || false;
8977 this.relayEvents(this.proxy, ["loadexception"]);
8979 this.sortToggle = {};
8980 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8982 Roo.data.Store.superclass.constructor.call(this);
8984 if(this.inlineData){
8985 this.loadData(this.inlineData);
8986 delete this.inlineData;
8990 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8992 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8993 * without a remote query - used by combo/forms at present.
8997 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9000 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9003 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9004 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9007 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9008 * on any HTTP request
9011 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9014 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9018 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9019 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9024 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9025 * loaded or when a record is removed. (defaults to false).
9027 pruneModifiedRecords : false,
9033 * Add Records to the Store and fires the add event.
9034 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9036 add : function(records){
9037 records = [].concat(records);
9038 for(var i = 0, len = records.length; i < len; i++){
9039 records[i].join(this);
9041 var index = this.data.length;
9042 this.data.addAll(records);
9043 this.fireEvent("add", this, records, index);
9047 * Remove a Record from the Store and fires the remove event.
9048 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9050 remove : function(record){
9051 var index = this.data.indexOf(record);
9052 this.data.removeAt(index);
9053 if(this.pruneModifiedRecords){
9054 this.modified.remove(record);
9056 this.fireEvent("remove", this, record, index);
9060 * Remove all Records from the Store and fires the clear event.
9062 removeAll : function(){
9064 if(this.pruneModifiedRecords){
9067 this.fireEvent("clear", this);
9071 * Inserts Records to the Store at the given index and fires the add event.
9072 * @param {Number} index The start index at which to insert the passed Records.
9073 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9075 insert : function(index, records){
9076 records = [].concat(records);
9077 for(var i = 0, len = records.length; i < len; i++){
9078 this.data.insert(index, records[i]);
9079 records[i].join(this);
9081 this.fireEvent("add", this, records, index);
9085 * Get the index within the cache of the passed Record.
9086 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9087 * @return {Number} The index of the passed Record. Returns -1 if not found.
9089 indexOf : function(record){
9090 return this.data.indexOf(record);
9094 * Get the index within the cache of the Record with the passed id.
9095 * @param {String} id The id of the Record to find.
9096 * @return {Number} The index of the Record. Returns -1 if not found.
9098 indexOfId : function(id){
9099 return this.data.indexOfKey(id);
9103 * Get the Record with the specified id.
9104 * @param {String} id The id of the Record to find.
9105 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9107 getById : function(id){
9108 return this.data.key(id);
9112 * Get the Record at the specified index.
9113 * @param {Number} index The index of the Record to find.
9114 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9116 getAt : function(index){
9117 return this.data.itemAt(index);
9121 * Returns a range of Records between specified indices.
9122 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9123 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9124 * @return {Roo.data.Record[]} An array of Records
9126 getRange : function(start, end){
9127 return this.data.getRange(start, end);
9131 storeOptions : function(o){
9132 o = Roo.apply({}, o);
9135 this.lastOptions = o;
9139 * Loads the Record cache from the configured Proxy using the configured Reader.
9141 * If using remote paging, then the first load call must specify the <em>start</em>
9142 * and <em>limit</em> properties in the options.params property to establish the initial
9143 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9145 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9146 * and this call will return before the new data has been loaded. Perform any post-processing
9147 * in a callback function, or in a "load" event handler.</strong>
9149 * @param {Object} options An object containing properties which control loading options:<ul>
9150 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9151 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9152 * passed the following arguments:<ul>
9153 * <li>r : Roo.data.Record[]</li>
9154 * <li>options: Options object from the load call</li>
9155 * <li>success: Boolean success indicator</li></ul></li>
9156 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9157 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9160 load : function(options){
9161 options = options || {};
9162 if(this.fireEvent("beforeload", this, options) !== false){
9163 this.storeOptions(options);
9164 var p = Roo.apply(options.params || {}, this.baseParams);
9165 // if meta was not loaded from remote source.. try requesting it.
9166 if (!this.reader.metaFromRemote) {
9169 if(this.sortInfo && this.remoteSort){
9170 var pn = this.paramNames;
9171 p[pn["sort"]] = this.sortInfo.field;
9172 p[pn["dir"]] = this.sortInfo.direction;
9174 if (this.multiSort) {
9175 var pn = this.paramNames;
9176 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9179 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9184 * Reloads the Record cache from the configured Proxy using the configured Reader and
9185 * the options from the last load operation performed.
9186 * @param {Object} options (optional) An object containing properties which may override the options
9187 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9188 * the most recently used options are reused).
9190 reload : function(options){
9191 this.load(Roo.applyIf(options||{}, this.lastOptions));
9195 // Called as a callback by the Reader during a load operation.
9196 loadRecords : function(o, options, success){
9197 if(!o || success === false){
9198 if(success !== false){
9199 this.fireEvent("load", this, [], options, o);
9201 if(options.callback){
9202 options.callback.call(options.scope || this, [], options, false);
9206 // if data returned failure - throw an exception.
9207 if (o.success === false) {
9208 // show a message if no listener is registered.
9209 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9210 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9212 // loadmask wil be hooked into this..
9213 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9216 var r = o.records, t = o.totalRecords || r.length;
9218 this.fireEvent("beforeloadadd", this, r, options, o);
9220 if(!options || options.add !== true){
9221 if(this.pruneModifiedRecords){
9224 for(var i = 0, len = r.length; i < len; i++){
9228 this.data = this.snapshot;
9229 delete this.snapshot;
9232 this.data.addAll(r);
9233 this.totalLength = t;
9235 this.fireEvent("datachanged", this);
9237 this.totalLength = Math.max(t, this.data.length+r.length);
9240 this.fireEvent("load", this, r, options, o);
9241 if(options.callback){
9242 options.callback.call(options.scope || this, r, options, true);
9248 * Loads data from a passed data block. A Reader which understands the format of the data
9249 * must have been configured in the constructor.
9250 * @param {Object} data The data block from which to read the Records. The format of the data expected
9251 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9252 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9254 loadData : function(o, append){
9255 var r = this.reader.readRecords(o);
9256 this.loadRecords(r, {add: append}, true);
9260 * Gets the number of cached records.
9262 * <em>If using paging, this may not be the total size of the dataset. If the data object
9263 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9264 * the data set size</em>
9266 getCount : function(){
9267 return this.data.length || 0;
9271 * Gets the total number of records in the dataset as returned by the server.
9273 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9274 * the dataset size</em>
9276 getTotalCount : function(){
9277 return this.totalLength || 0;
9281 * Returns the sort state of the Store as an object with two properties:
9283 field {String} The name of the field by which the Records are sorted
9284 direction {String} The sort order, "ASC" or "DESC"
9287 getSortState : function(){
9288 return this.sortInfo;
9292 applySort : function(){
9293 if(this.sortInfo && !this.remoteSort){
9294 var s = this.sortInfo, f = s.field;
9295 var st = this.fields.get(f).sortType;
9296 var fn = function(r1, r2){
9297 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9298 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9300 this.data.sort(s.direction, fn);
9301 if(this.snapshot && this.snapshot != this.data){
9302 this.snapshot.sort(s.direction, fn);
9308 * Sets the default sort column and order to be used by the next load operation.
9309 * @param {String} fieldName The name of the field to sort by.
9310 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9312 setDefaultSort : function(field, dir){
9313 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9318 * If remote sorting is used, the sort is performed on the server, and the cache is
9319 * reloaded. If local sorting is used, the cache is sorted internally.
9320 * @param {String} fieldName The name of the field to sort by.
9321 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9323 sort : function(fieldName, dir){
9324 var f = this.fields.get(fieldName);
9326 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9328 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9329 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9334 this.sortToggle[f.name] = dir;
9335 this.sortInfo = {field: f.name, direction: dir};
9336 if(!this.remoteSort){
9338 this.fireEvent("datachanged", this);
9340 this.load(this.lastOptions);
9345 * Calls the specified function for each of the Records in the cache.
9346 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9347 * Returning <em>false</em> aborts and exits the iteration.
9348 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9350 each : function(fn, scope){
9351 this.data.each(fn, scope);
9355 * Gets all records modified since the last commit. Modified records are persisted across load operations
9356 * (e.g., during paging).
9357 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9359 getModifiedRecords : function(){
9360 return this.modified;
9364 createFilterFn : function(property, value, anyMatch){
9365 if(!value.exec){ // not a regex
9366 value = String(value);
9367 if(value.length == 0){
9370 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9373 return value.test(r.data[property]);
9378 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9379 * @param {String} property A field on your records
9380 * @param {Number} start The record index to start at (defaults to 0)
9381 * @param {Number} end The last record index to include (defaults to length - 1)
9382 * @return {Number} The sum
9384 sum : function(property, start, end){
9385 var rs = this.data.items, v = 0;
9387 end = (end || end === 0) ? end : rs.length-1;
9389 for(var i = start; i <= end; i++){
9390 v += (rs[i].data[property] || 0);
9396 * Filter the records by a specified property.
9397 * @param {String} field A field on your records
9398 * @param {String/RegExp} value Either a string that the field
9399 * should start with or a RegExp to test against the field
9400 * @param {Boolean} anyMatch True to match any part not just the beginning
9402 filter : function(property, value, anyMatch){
9403 var fn = this.createFilterFn(property, value, anyMatch);
9404 return fn ? this.filterBy(fn) : this.clearFilter();
9408 * Filter by a function. The specified function will be called with each
9409 * record in this data source. If the function returns true the record is included,
9410 * otherwise it is filtered.
9411 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9412 * @param {Object} scope (optional) The scope of the function (defaults to this)
9414 filterBy : function(fn, scope){
9415 this.snapshot = this.snapshot || this.data;
9416 this.data = this.queryBy(fn, scope||this);
9417 this.fireEvent("datachanged", this);
9421 * Query the records by a specified property.
9422 * @param {String} field A field on your records
9423 * @param {String/RegExp} value Either a string that the field
9424 * should start with or a RegExp to test against the field
9425 * @param {Boolean} anyMatch True to match any part not just the beginning
9426 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9428 query : function(property, value, anyMatch){
9429 var fn = this.createFilterFn(property, value, anyMatch);
9430 return fn ? this.queryBy(fn) : this.data.clone();
9434 * Query by a function. The specified function will be called with each
9435 * record in this data source. If the function returns true the record is included
9437 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9438 * @param {Object} scope (optional) The scope of the function (defaults to this)
9439 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9441 queryBy : function(fn, scope){
9442 var data = this.snapshot || this.data;
9443 return data.filterBy(fn, scope||this);
9447 * Collects unique values for a particular dataIndex from this store.
9448 * @param {String} dataIndex The property to collect
9449 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9450 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9451 * @return {Array} An array of the unique values
9453 collect : function(dataIndex, allowNull, bypassFilter){
9454 var d = (bypassFilter === true && this.snapshot) ?
9455 this.snapshot.items : this.data.items;
9456 var v, sv, r = [], l = {};
9457 for(var i = 0, len = d.length; i < len; i++){
9458 v = d[i].data[dataIndex];
9460 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9469 * Revert to a view of the Record cache with no filtering applied.
9470 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9472 clearFilter : function(suppressEvent){
9473 if(this.snapshot && this.snapshot != this.data){
9474 this.data = this.snapshot;
9475 delete this.snapshot;
9476 if(suppressEvent !== true){
9477 this.fireEvent("datachanged", this);
9483 afterEdit : function(record){
9484 if(this.modified.indexOf(record) == -1){
9485 this.modified.push(record);
9487 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9491 afterReject : function(record){
9492 this.modified.remove(record);
9493 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9497 afterCommit : function(record){
9498 this.modified.remove(record);
9499 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9503 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9504 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9506 commitChanges : function(){
9507 var m = this.modified.slice(0);
9509 for(var i = 0, len = m.length; i < len; i++){
9515 * Cancel outstanding changes on all changed records.
9517 rejectChanges : function(){
9518 var m = this.modified.slice(0);
9520 for(var i = 0, len = m.length; i < len; i++){
9525 onMetaChange : function(meta, rtype, o){
9526 this.recordType = rtype;
9527 this.fields = rtype.prototype.fields;
9528 delete this.snapshot;
9529 this.sortInfo = meta.sortInfo || this.sortInfo;
9531 this.fireEvent('metachange', this, this.reader.meta);
9534 moveIndex : function(data, type)
9536 var index = this.indexOf(data);
9538 var newIndex = index + type;
9542 this.insert(newIndex, data);
9547 * Ext JS Library 1.1.1
9548 * Copyright(c) 2006-2007, Ext JS, LLC.
9550 * Originally Released Under LGPL - original licence link has changed is not relivant.
9553 * <script type="text/javascript">
9557 * @class Roo.data.SimpleStore
9558 * @extends Roo.data.Store
9559 * Small helper class to make creating Stores from Array data easier.
9560 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9561 * @cfg {Array} fields An array of field definition objects, or field name strings.
9562 * @cfg {Array} data The multi-dimensional array of data
9564 * @param {Object} config
9566 Roo.data.SimpleStore = function(config){
9567 Roo.data.SimpleStore.superclass.constructor.call(this, {
9569 reader: new Roo.data.ArrayReader({
9572 Roo.data.Record.create(config.fields)
9574 proxy : new Roo.data.MemoryProxy(config.data)
9578 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9580 * Ext JS Library 1.1.1
9581 * Copyright(c) 2006-2007, Ext JS, LLC.
9583 * Originally Released Under LGPL - original licence link has changed is not relivant.
9586 * <script type="text/javascript">
9591 * @extends Roo.data.Store
9592 * @class Roo.data.JsonStore
9593 * Small helper class to make creating Stores for JSON data easier. <br/>
9595 var store = new Roo.data.JsonStore({
9596 url: 'get-images.php',
9598 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9601 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9602 * JsonReader and HttpProxy (unless inline data is provided).</b>
9603 * @cfg {Array} fields An array of field definition objects, or field name strings.
9605 * @param {Object} config
9607 Roo.data.JsonStore = function(c){
9608 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9609 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9610 reader: new Roo.data.JsonReader(c, c.fields)
9613 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9615 * Ext JS Library 1.1.1
9616 * Copyright(c) 2006-2007, Ext JS, LLC.
9618 * Originally Released Under LGPL - original licence link has changed is not relivant.
9621 * <script type="text/javascript">
9625 Roo.data.Field = function(config){
9626 if(typeof config == "string"){
9627 config = {name: config};
9629 Roo.apply(this, config);
9635 var st = Roo.data.SortTypes;
9636 // named sortTypes are supported, here we look them up
9637 if(typeof this.sortType == "string"){
9638 this.sortType = st[this.sortType];
9641 // set default sortType for strings and dates
9645 this.sortType = st.asUCString;
9648 this.sortType = st.asDate;
9651 this.sortType = st.none;
9656 var stripRe = /[\$,%]/g;
9658 // prebuilt conversion function for this field, instead of
9659 // switching every time we're reading a value
9661 var cv, dateFormat = this.dateFormat;
9666 cv = function(v){ return v; };
9669 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9673 return v !== undefined && v !== null && v !== '' ?
9674 parseInt(String(v).replace(stripRe, ""), 10) : '';
9679 return v !== undefined && v !== null && v !== '' ?
9680 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9685 cv = function(v){ return v === true || v === "true" || v == 1; };
9692 if(v instanceof Date){
9696 if(dateFormat == "timestamp"){
9697 return new Date(v*1000);
9699 return Date.parseDate(v, dateFormat);
9701 var parsed = Date.parse(v);
9702 return parsed ? new Date(parsed) : null;
9711 Roo.data.Field.prototype = {
9719 * Ext JS Library 1.1.1
9720 * Copyright(c) 2006-2007, Ext JS, LLC.
9722 * Originally Released Under LGPL - original licence link has changed is not relivant.
9725 * <script type="text/javascript">
9728 // Base class for reading structured data from a data source. This class is intended to be
9729 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9732 * @class Roo.data.DataReader
9733 * Base class for reading structured data from a data source. This class is intended to be
9734 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9737 Roo.data.DataReader = function(meta, recordType){
9741 this.recordType = recordType instanceof Array ?
9742 Roo.data.Record.create(recordType) : recordType;
9745 Roo.data.DataReader.prototype = {
9747 * Create an empty record
9748 * @param {Object} data (optional) - overlay some values
9749 * @return {Roo.data.Record} record created.
9751 newRow : function(d) {
9753 this.recordType.prototype.fields.each(function(c) {
9755 case 'int' : da[c.name] = 0; break;
9756 case 'date' : da[c.name] = new Date(); break;
9757 case 'float' : da[c.name] = 0.0; break;
9758 case 'boolean' : da[c.name] = false; break;
9759 default : da[c.name] = ""; break;
9763 return new this.recordType(Roo.apply(da, d));
9768 * Ext JS Library 1.1.1
9769 * Copyright(c) 2006-2007, Ext JS, LLC.
9771 * Originally Released Under LGPL - original licence link has changed is not relivant.
9774 * <script type="text/javascript">
9778 * @class Roo.data.DataProxy
9779 * @extends Roo.data.Observable
9780 * This class is an abstract base class for implementations which provide retrieval of
9781 * unformatted data objects.<br>
9783 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9784 * (of the appropriate type which knows how to parse the data object) to provide a block of
9785 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9787 * Custom implementations must implement the load method as described in
9788 * {@link Roo.data.HttpProxy#load}.
9790 Roo.data.DataProxy = function(){
9794 * Fires before a network request is made to retrieve a data object.
9795 * @param {Object} This DataProxy object.
9796 * @param {Object} params The params parameter to the load function.
9801 * Fires before the load method's callback is called.
9802 * @param {Object} This DataProxy object.
9803 * @param {Object} o The data object.
9804 * @param {Object} arg The callback argument object passed to the load function.
9808 * @event loadexception
9809 * Fires if an Exception occurs during data retrieval.
9810 * @param {Object} This DataProxy object.
9811 * @param {Object} o The data object.
9812 * @param {Object} arg The callback argument object passed to the load function.
9813 * @param {Object} e The Exception.
9815 loadexception : true
9817 Roo.data.DataProxy.superclass.constructor.call(this);
9820 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9823 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9827 * Ext JS Library 1.1.1
9828 * Copyright(c) 2006-2007, Ext JS, LLC.
9830 * Originally Released Under LGPL - original licence link has changed is not relivant.
9833 * <script type="text/javascript">
9836 * @class Roo.data.MemoryProxy
9837 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9838 * to the Reader when its load method is called.
9840 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9842 Roo.data.MemoryProxy = function(data){
9846 Roo.data.MemoryProxy.superclass.constructor.call(this);
9850 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9852 * Load data from the requested source (in this case an in-memory
9853 * data object passed to the constructor), read the data object into
9854 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9855 * process that block using the passed callback.
9856 * @param {Object} params This parameter is not used by the MemoryProxy class.
9857 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9858 * object into a block of Roo.data.Records.
9859 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9860 * The function must be passed <ul>
9861 * <li>The Record block object</li>
9862 * <li>The "arg" argument from the load function</li>
9863 * <li>A boolean success indicator</li>
9865 * @param {Object} scope The scope in which to call the callback
9866 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9868 load : function(params, reader, callback, scope, arg){
9869 params = params || {};
9872 result = reader.readRecords(this.data);
9874 this.fireEvent("loadexception", this, arg, null, e);
9875 callback.call(scope, null, arg, false);
9878 callback.call(scope, result, arg, true);
9882 update : function(params, records){
9887 * Ext JS Library 1.1.1
9888 * Copyright(c) 2006-2007, Ext JS, LLC.
9890 * Originally Released Under LGPL - original licence link has changed is not relivant.
9893 * <script type="text/javascript">
9896 * @class Roo.data.HttpProxy
9897 * @extends Roo.data.DataProxy
9898 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9899 * configured to reference a certain URL.<br><br>
9901 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9902 * from which the running page was served.<br><br>
9904 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9906 * Be aware that to enable the browser to parse an XML document, the server must set
9907 * the Content-Type header in the HTTP response to "text/xml".
9909 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9910 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9911 * will be used to make the request.
9913 Roo.data.HttpProxy = function(conn){
9914 Roo.data.HttpProxy.superclass.constructor.call(this);
9915 // is conn a conn config or a real conn?
9917 this.useAjax = !conn || !conn.events;
9921 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9922 // thse are take from connection...
9925 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9928 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9929 * extra parameters to each request made by this object. (defaults to undefined)
9932 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9933 * to each request made by this object. (defaults to undefined)
9936 * @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)
9939 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9942 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9948 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9952 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9953 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9954 * a finer-grained basis than the DataProxy events.
9956 getConnection : function(){
9957 return this.useAjax ? Roo.Ajax : this.conn;
9961 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9962 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9963 * process that block using the passed callback.
9964 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9965 * for the request to the remote server.
9966 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9967 * object into a block of Roo.data.Records.
9968 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9969 * The function must be passed <ul>
9970 * <li>The Record block object</li>
9971 * <li>The "arg" argument from the load function</li>
9972 * <li>A boolean success indicator</li>
9974 * @param {Object} scope The scope in which to call the callback
9975 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9977 load : function(params, reader, callback, scope, arg){
9978 if(this.fireEvent("beforeload", this, params) !== false){
9980 params : params || {},
9982 callback : callback,
9987 callback : this.loadResponse,
9991 Roo.applyIf(o, this.conn);
9992 if(this.activeRequest){
9993 Roo.Ajax.abort(this.activeRequest);
9995 this.activeRequest = Roo.Ajax.request(o);
9997 this.conn.request(o);
10000 callback.call(scope||this, null, arg, false);
10005 loadResponse : function(o, success, response){
10006 delete this.activeRequest;
10008 this.fireEvent("loadexception", this, o, response);
10009 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10014 result = o.reader.read(response);
10016 this.fireEvent("loadexception", this, o, response, e);
10017 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10021 this.fireEvent("load", this, o, o.request.arg);
10022 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10026 update : function(dataSet){
10031 updateResponse : function(dataSet){
10036 * Ext JS Library 1.1.1
10037 * Copyright(c) 2006-2007, Ext JS, LLC.
10039 * Originally Released Under LGPL - original licence link has changed is not relivant.
10042 * <script type="text/javascript">
10046 * @class Roo.data.ScriptTagProxy
10047 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10048 * other than the originating domain of the running page.<br><br>
10050 * <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
10051 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10053 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10054 * source code that is used as the source inside a <script> tag.<br><br>
10056 * In order for the browser to process the returned data, the server must wrap the data object
10057 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10058 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10059 * depending on whether the callback name was passed:
10062 boolean scriptTag = false;
10063 String cb = request.getParameter("callback");
10066 response.setContentType("text/javascript");
10068 response.setContentType("application/x-json");
10070 Writer out = response.getWriter();
10072 out.write(cb + "(");
10074 out.print(dataBlock.toJsonString());
10081 * @param {Object} config A configuration object.
10083 Roo.data.ScriptTagProxy = function(config){
10084 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10085 Roo.apply(this, config);
10086 this.head = document.getElementsByTagName("head")[0];
10089 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10091 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10093 * @cfg {String} url The URL from which to request the data object.
10096 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10100 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10101 * the server the name of the callback function set up by the load call to process the returned data object.
10102 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10103 * javascript output which calls this named function passing the data object as its only parameter.
10105 callbackParam : "callback",
10107 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10108 * name to the request.
10113 * Load data from the configured URL, read the data object into
10114 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10115 * process that block using the passed callback.
10116 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10117 * for the request to the remote server.
10118 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10119 * object into a block of Roo.data.Records.
10120 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10121 * The function must be passed <ul>
10122 * <li>The Record block object</li>
10123 * <li>The "arg" argument from the load function</li>
10124 * <li>A boolean success indicator</li>
10126 * @param {Object} scope The scope in which to call the callback
10127 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10129 load : function(params, reader, callback, scope, arg){
10130 if(this.fireEvent("beforeload", this, params) !== false){
10132 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10134 var url = this.url;
10135 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10137 url += "&_dc=" + (new Date().getTime());
10139 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10142 cb : "stcCallback"+transId,
10143 scriptId : "stcScript"+transId,
10147 callback : callback,
10153 window[trans.cb] = function(o){
10154 conn.handleResponse(o, trans);
10157 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10159 if(this.autoAbort !== false){
10163 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10165 var script = document.createElement("script");
10166 script.setAttribute("src", url);
10167 script.setAttribute("type", "text/javascript");
10168 script.setAttribute("id", trans.scriptId);
10169 this.head.appendChild(script);
10171 this.trans = trans;
10173 callback.call(scope||this, null, arg, false);
10178 isLoading : function(){
10179 return this.trans ? true : false;
10183 * Abort the current server request.
10185 abort : function(){
10186 if(this.isLoading()){
10187 this.destroyTrans(this.trans);
10192 destroyTrans : function(trans, isLoaded){
10193 this.head.removeChild(document.getElementById(trans.scriptId));
10194 clearTimeout(trans.timeoutId);
10196 window[trans.cb] = undefined;
10198 delete window[trans.cb];
10201 // if hasn't been loaded, wait for load to remove it to prevent script error
10202 window[trans.cb] = function(){
10203 window[trans.cb] = undefined;
10205 delete window[trans.cb];
10212 handleResponse : function(o, trans){
10213 this.trans = false;
10214 this.destroyTrans(trans, true);
10217 result = trans.reader.readRecords(o);
10219 this.fireEvent("loadexception", this, o, trans.arg, e);
10220 trans.callback.call(trans.scope||window, null, trans.arg, false);
10223 this.fireEvent("load", this, o, trans.arg);
10224 trans.callback.call(trans.scope||window, result, trans.arg, true);
10228 handleFailure : function(trans){
10229 this.trans = false;
10230 this.destroyTrans(trans, false);
10231 this.fireEvent("loadexception", this, null, trans.arg);
10232 trans.callback.call(trans.scope||window, null, trans.arg, false);
10236 * Ext JS Library 1.1.1
10237 * Copyright(c) 2006-2007, Ext JS, LLC.
10239 * Originally Released Under LGPL - original licence link has changed is not relivant.
10242 * <script type="text/javascript">
10246 * @class Roo.data.JsonReader
10247 * @extends Roo.data.DataReader
10248 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10249 * based on mappings in a provided Roo.data.Record constructor.
10251 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10252 * in the reply previously.
10257 var RecordDef = Roo.data.Record.create([
10258 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10259 {name: 'occupation'} // This field will use "occupation" as the mapping.
10261 var myReader = new Roo.data.JsonReader({
10262 totalProperty: "results", // The property which contains the total dataset size (optional)
10263 root: "rows", // The property which contains an Array of row objects
10264 id: "id" // The property within each row object that provides an ID for the record (optional)
10268 * This would consume a JSON file like this:
10270 { 'results': 2, 'rows': [
10271 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10272 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10275 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10276 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10277 * paged from the remote server.
10278 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10279 * @cfg {String} root name of the property which contains the Array of row objects.
10280 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10282 * Create a new JsonReader
10283 * @param {Object} meta Metadata configuration options
10284 * @param {Object} recordType Either an Array of field definition objects,
10285 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10287 Roo.data.JsonReader = function(meta, recordType){
10290 // set some defaults:
10291 Roo.applyIf(meta, {
10292 totalProperty: 'total',
10293 successProperty : 'success',
10298 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10300 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10303 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10304 * Used by Store query builder to append _requestMeta to params.
10307 metaFromRemote : false,
10309 * This method is only used by a DataProxy which has retrieved data from a remote server.
10310 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10311 * @return {Object} data A data block which is used by an Roo.data.Store object as
10312 * a cache of Roo.data.Records.
10314 read : function(response){
10315 var json = response.responseText;
10317 var o = /* eval:var:o */ eval("("+json+")");
10319 throw {message: "JsonReader.read: Json object not found"};
10325 this.metaFromRemote = true;
10326 this.meta = o.metaData;
10327 this.recordType = Roo.data.Record.create(o.metaData.fields);
10328 this.onMetaChange(this.meta, this.recordType, o);
10330 return this.readRecords(o);
10333 // private function a store will implement
10334 onMetaChange : function(meta, recordType, o){
10341 simpleAccess: function(obj, subsc) {
10348 getJsonAccessor: function(){
10350 return function(expr) {
10352 return(re.test(expr))
10353 ? new Function("obj", "return obj." + expr)
10358 return Roo.emptyFn;
10363 * Create a data block containing Roo.data.Records from an XML document.
10364 * @param {Object} o An object which contains an Array of row objects in the property specified
10365 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10366 * which contains the total size of the dataset.
10367 * @return {Object} data A data block which is used by an Roo.data.Store object as
10368 * a cache of Roo.data.Records.
10370 readRecords : function(o){
10372 * After any data loads, the raw JSON data is available for further custom processing.
10376 var s = this.meta, Record = this.recordType,
10377 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10379 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10381 if(s.totalProperty) {
10382 this.getTotal = this.getJsonAccessor(s.totalProperty);
10384 if(s.successProperty) {
10385 this.getSuccess = this.getJsonAccessor(s.successProperty);
10387 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10389 var g = this.getJsonAccessor(s.id);
10390 this.getId = function(rec) {
10392 return (r === undefined || r === "") ? null : r;
10395 this.getId = function(){return null;};
10398 for(var jj = 0; jj < fl; jj++){
10400 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10401 this.ef[jj] = this.getJsonAccessor(map);
10405 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10406 if(s.totalProperty){
10407 var vt = parseInt(this.getTotal(o), 10);
10412 if(s.successProperty){
10413 var vs = this.getSuccess(o);
10414 if(vs === false || vs === 'false'){
10419 for(var i = 0; i < c; i++){
10422 var id = this.getId(n);
10423 for(var j = 0; j < fl; j++){
10425 var v = this.ef[j](n);
10427 Roo.log('missing convert for ' + f.name);
10431 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10433 var record = new Record(values, id);
10435 records[i] = record;
10441 totalRecords : totalRecords
10446 * Ext JS Library 1.1.1
10447 * Copyright(c) 2006-2007, Ext JS, LLC.
10449 * Originally Released Under LGPL - original licence link has changed is not relivant.
10452 * <script type="text/javascript">
10456 * @class Roo.data.ArrayReader
10457 * @extends Roo.data.DataReader
10458 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10459 * Each element of that Array represents a row of data fields. The
10460 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10461 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10465 var RecordDef = Roo.data.Record.create([
10466 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10467 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10469 var myReader = new Roo.data.ArrayReader({
10470 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10474 * This would consume an Array like this:
10476 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10478 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10480 * Create a new JsonReader
10481 * @param {Object} meta Metadata configuration options.
10482 * @param {Object} recordType Either an Array of field definition objects
10483 * as specified to {@link Roo.data.Record#create},
10484 * or an {@link Roo.data.Record} object
10485 * created using {@link Roo.data.Record#create}.
10487 Roo.data.ArrayReader = function(meta, recordType){
10488 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10491 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10493 * Create a data block containing Roo.data.Records from an XML document.
10494 * @param {Object} o An Array of row objects which represents the dataset.
10495 * @return {Object} data A data block which is used by an Roo.data.Store object as
10496 * a cache of Roo.data.Records.
10498 readRecords : function(o){
10499 var sid = this.meta ? this.meta.id : null;
10500 var recordType = this.recordType, fields = recordType.prototype.fields;
10503 for(var i = 0; i < root.length; i++){
10506 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10507 for(var j = 0, jlen = fields.length; j < jlen; j++){
10508 var f = fields.items[j];
10509 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10510 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10512 values[f.name] = v;
10514 var record = new recordType(values, id);
10516 records[records.length] = record;
10520 totalRecords : records.length
10529 * @class Roo.bootstrap.ComboBox
10530 * @extends Roo.bootstrap.TriggerField
10531 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10532 * @cfg {Boolean} append (true|false) default false
10533 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10534 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10535 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10536 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10537 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10539 * Create a new ComboBox.
10540 * @param {Object} config Configuration options
10542 Roo.bootstrap.ComboBox = function(config){
10543 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10547 * Fires when the dropdown list is expanded
10548 * @param {Roo.bootstrap.ComboBox} combo This combo box
10553 * Fires when the dropdown list is collapsed
10554 * @param {Roo.bootstrap.ComboBox} combo This combo box
10558 * @event beforeselect
10559 * Fires before a list item is selected. Return false to cancel the selection.
10560 * @param {Roo.bootstrap.ComboBox} combo This combo box
10561 * @param {Roo.data.Record} record The data record returned from the underlying store
10562 * @param {Number} index The index of the selected item in the dropdown list
10564 'beforeselect' : true,
10567 * Fires when a list item is selected
10568 * @param {Roo.bootstrap.ComboBox} combo This combo box
10569 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10570 * @param {Number} index The index of the selected item in the dropdown list
10574 * @event beforequery
10575 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10576 * The event object passed has these properties:
10577 * @param {Roo.bootstrap.ComboBox} combo This combo box
10578 * @param {String} query The query
10579 * @param {Boolean} forceAll true to force "all" query
10580 * @param {Boolean} cancel true to cancel the query
10581 * @param {Object} e The query event object
10583 'beforequery': true,
10586 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10587 * @param {Roo.bootstrap.ComboBox} combo This combo box
10592 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10593 * @param {Roo.bootstrap.ComboBox} combo This combo box
10594 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10599 * Fires when the remove value from the combobox array
10600 * @param {Roo.bootstrap.ComboBox} combo This combo box
10607 this.tickItems = [];
10609 this.selectedIndex = -1;
10610 if(this.mode == 'local'){
10611 if(config.queryDelay === undefined){
10612 this.queryDelay = 10;
10614 if(config.minChars === undefined){
10620 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10623 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10624 * rendering into an Roo.Editor, defaults to false)
10627 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10628 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10631 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10634 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10635 * the dropdown list (defaults to undefined, with no header element)
10639 * @cfg {String/Roo.Template} tpl The template to use to render the output
10643 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10645 listWidth: undefined,
10647 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10648 * mode = 'remote' or 'text' if mode = 'local')
10650 displayField: undefined,
10652 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10653 * mode = 'remote' or 'value' if mode = 'local').
10654 * Note: use of a valueField requires the user make a selection
10655 * in order for a value to be mapped.
10657 valueField: undefined,
10661 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10662 * field's data value (defaults to the underlying DOM element's name)
10664 hiddenName: undefined,
10666 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10670 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10672 selectedClass: 'active',
10675 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10679 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10680 * anchor positions (defaults to 'tl-bl')
10682 listAlign: 'tl-bl?',
10684 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10688 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10689 * query specified by the allQuery config option (defaults to 'query')
10691 triggerAction: 'query',
10693 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10694 * (defaults to 4, does not apply if editable = false)
10698 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10699 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10703 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10704 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10708 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10709 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10713 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10714 * when editable = true (defaults to false)
10716 selectOnFocus:false,
10718 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10720 queryParam: 'query',
10722 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10723 * when mode = 'remote' (defaults to 'Loading...')
10725 loadingText: 'Loading...',
10727 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10731 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10735 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10736 * traditional select (defaults to true)
10740 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10744 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10748 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10749 * listWidth has a higher value)
10753 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10754 * allow the user to set arbitrary text into the field (defaults to false)
10756 forceSelection:false,
10758 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10759 * if typeAhead = true (defaults to 250)
10761 typeAheadDelay : 250,
10763 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10764 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10766 valueNotFoundText : undefined,
10768 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10770 blockFocus : false,
10773 * @cfg {Boolean} disableClear Disable showing of clear button.
10775 disableClear : false,
10777 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10779 alwaysQuery : false,
10782 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10796 btnPosition : 'right',
10797 triggerList : true,
10798 showToggleBtn : true,
10799 // element that contains real text value.. (when hidden is used..)
10801 getAutoCreate : function()
10808 if(!this.tickable){
10809 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10814 * ComboBox with tickable selections
10817 var align = this.labelAlign || this.parentLabelAlign();
10820 cls : 'form-group roo-combobox-tickable' //input-group
10826 cls : 'tickable-buttons',
10831 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10838 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10845 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10852 Roo.each(buttons.cn, function(c){
10854 c.cls += ' btn-' + _this.size;
10857 if (_this.disabled) {
10868 cls: 'form-hidden-field'
10872 cls: 'select2-choices',
10876 cls: 'select2-search-field',
10888 cls: 'select2-container input-group select2-container-multi',
10893 // cls: 'typeahead typeahead-long dropdown-menu',
10894 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10899 if (align ==='left' && this.fieldLabel.length) {
10901 Roo.log("left and has label");
10907 cls : 'control-label col-sm-' + this.labelWidth,
10908 html : this.fieldLabel
10912 cls : "col-sm-" + (12 - this.labelWidth),
10919 } else if ( this.fieldLabel.length) {
10925 //cls : 'input-group-addon',
10926 html : this.fieldLabel
10936 Roo.log(" no label && no align");
10943 ['xs','sm','md','lg'].map(function(size){
10944 if (settings[size]) {
10945 cfg.cls += ' col-' + size + '-' + settings[size];
10954 initEvents: function()
10958 throw "can not find store for combo";
10960 this.store = Roo.factory(this.store, Roo.data);
10963 this.initTickableEvents();
10967 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10969 if(this.hiddenName){
10971 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10973 this.hiddenField.dom.value =
10974 this.hiddenValue !== undefined ? this.hiddenValue :
10975 this.value !== undefined ? this.value : '';
10977 // prevent input submission
10978 this.el.dom.removeAttribute('name');
10979 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10984 // this.el.dom.setAttribute('autocomplete', 'off');
10987 var cls = 'x-combo-list';
10989 //this.list = new Roo.Layer({
10990 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10996 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10997 _this.list.setWidth(lw);
11000 this.list.on('mouseover', this.onViewOver, this);
11001 this.list.on('mousemove', this.onViewMove, this);
11003 this.list.on('scroll', this.onViewScroll, this);
11006 this.list.swallowEvent('mousewheel');
11007 this.assetHeight = 0;
11010 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11011 this.assetHeight += this.header.getHeight();
11014 this.innerList = this.list.createChild({cls:cls+'-inner'});
11015 this.innerList.on('mouseover', this.onViewOver, this);
11016 this.innerList.on('mousemove', this.onViewMove, this);
11017 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11019 if(this.allowBlank && !this.pageSize && !this.disableClear){
11020 this.footer = this.list.createChild({cls:cls+'-ft'});
11021 this.pageTb = new Roo.Toolbar(this.footer);
11025 this.footer = this.list.createChild({cls:cls+'-ft'});
11026 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11027 {pageSize: this.pageSize});
11031 if (this.pageTb && this.allowBlank && !this.disableClear) {
11033 this.pageTb.add(new Roo.Toolbar.Fill(), {
11034 cls: 'x-btn-icon x-btn-clear',
11036 handler: function()
11039 _this.clearValue();
11040 _this.onSelect(false, -1);
11045 this.assetHeight += this.footer.getHeight();
11050 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11053 this.view = new Roo.View(this.list, this.tpl, {
11054 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11056 //this.view.wrapEl.setDisplayed(false);
11057 this.view.on('click', this.onViewClick, this);
11061 this.store.on('beforeload', this.onBeforeLoad, this);
11062 this.store.on('load', this.onLoad, this);
11063 this.store.on('loadexception', this.onLoadException, this);
11065 if(this.resizable){
11066 this.resizer = new Roo.Resizable(this.list, {
11067 pinned:true, handles:'se'
11069 this.resizer.on('resize', function(r, w, h){
11070 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11071 this.listWidth = w;
11072 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11073 this.restrictHeight();
11075 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11078 if(!this.editable){
11079 this.editable = true;
11080 this.setEditable(false);
11085 if (typeof(this.events.add.listeners) != 'undefined') {
11087 this.addicon = this.wrap.createChild(
11088 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11090 this.addicon.on('click', function(e) {
11091 this.fireEvent('add', this);
11094 if (typeof(this.events.edit.listeners) != 'undefined') {
11096 this.editicon = this.wrap.createChild(
11097 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11098 if (this.addicon) {
11099 this.editicon.setStyle('margin-left', '40px');
11101 this.editicon.on('click', function(e) {
11103 // we fire even if inothing is selected..
11104 this.fireEvent('edit', this, this.lastData );
11110 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11111 "up" : function(e){
11112 this.inKeyMode = true;
11116 "down" : function(e){
11117 if(!this.isExpanded()){
11118 this.onTriggerClick();
11120 this.inKeyMode = true;
11125 "enter" : function(e){
11126 // this.onViewClick();
11130 if(this.fireEvent("specialkey", this, e)){
11131 this.onViewClick(false);
11137 "esc" : function(e){
11141 "tab" : function(e){
11144 if(this.fireEvent("specialkey", this, e)){
11145 this.onViewClick(false);
11153 doRelay : function(foo, bar, hname){
11154 if(hname == 'down' || this.scope.isExpanded()){
11155 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11164 this.queryDelay = Math.max(this.queryDelay || 10,
11165 this.mode == 'local' ? 10 : 250);
11168 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11170 if(this.typeAhead){
11171 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11173 if(this.editable !== false){
11174 this.inputEl().on("keyup", this.onKeyUp, this);
11176 if(this.forceSelection){
11177 this.inputEl().on('blur', this.doForce, this);
11181 this.choices = this.el.select('ul.select2-choices', true).first();
11182 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11186 initTickableEvents: function()
11190 if(this.hiddenName){
11192 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11194 this.hiddenField.dom.value =
11195 this.hiddenValue !== undefined ? this.hiddenValue :
11196 this.value !== undefined ? this.value : '';
11198 // prevent input submission
11199 this.el.dom.removeAttribute('name');
11200 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11205 // this.list = this.el.select('ul.dropdown-menu',true).first();
11207 this.choices = this.el.select('ul.select2-choices', true).first();
11208 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11209 if(this.triggerList){
11210 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11213 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11214 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11216 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11217 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11219 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11220 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11222 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11223 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11224 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11227 this.cancelBtn.hide();
11232 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11233 _this.list.setWidth(lw);
11236 this.list.on('mouseover', this.onViewOver, this);
11237 this.list.on('mousemove', this.onViewMove, this);
11239 this.list.on('scroll', this.onViewScroll, this);
11242 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>';
11245 this.view = new Roo.View(this.list, this.tpl, {
11246 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11249 //this.view.wrapEl.setDisplayed(false);
11250 this.view.on('click', this.onViewClick, this);
11254 this.store.on('beforeload', this.onBeforeLoad, this);
11255 this.store.on('load', this.onLoad, this);
11256 this.store.on('loadexception', this.onLoadException, this);
11258 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11259 // "up" : function(e){
11260 // this.inKeyMode = true;
11261 // this.selectPrev();
11264 // "down" : function(e){
11265 // if(!this.isExpanded()){
11266 // this.onTriggerClick();
11268 // this.inKeyMode = true;
11269 // this.selectNext();
11273 // "enter" : function(e){
11274 //// this.onViewClick();
11276 // this.collapse();
11278 // if(this.fireEvent("specialkey", this, e)){
11279 // this.onViewClick(false);
11285 // "esc" : function(e){
11286 // this.collapse();
11289 // "tab" : function(e){
11290 // this.collapse();
11292 // if(this.fireEvent("specialkey", this, e)){
11293 // this.onViewClick(false);
11301 // doRelay : function(foo, bar, hname){
11302 // if(hname == 'down' || this.scope.isExpanded()){
11303 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11308 // forceKeyDown: true
11312 this.queryDelay = Math.max(this.queryDelay || 10,
11313 this.mode == 'local' ? 10 : 250);
11316 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11318 if(this.typeAhead){
11319 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11324 onDestroy : function(){
11326 this.view.setStore(null);
11327 this.view.el.removeAllListeners();
11328 this.view.el.remove();
11329 this.view.purgeListeners();
11332 this.list.dom.innerHTML = '';
11336 this.store.un('beforeload', this.onBeforeLoad, this);
11337 this.store.un('load', this.onLoad, this);
11338 this.store.un('loadexception', this.onLoadException, this);
11340 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11344 fireKey : function(e){
11345 if(e.isNavKeyPress() && !this.list.isVisible()){
11346 this.fireEvent("specialkey", this, e);
11351 onResize: function(w, h){
11352 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11354 // if(typeof w != 'number'){
11355 // // we do not handle it!?!?
11358 // var tw = this.trigger.getWidth();
11359 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11360 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11362 // this.inputEl().setWidth( this.adjustWidth('input', x));
11364 // //this.trigger.setStyle('left', x+'px');
11366 // if(this.list && this.listWidth === undefined){
11367 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11368 // this.list.setWidth(lw);
11369 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11377 * Allow or prevent the user from directly editing the field text. If false is passed,
11378 * the user will only be able to select from the items defined in the dropdown list. This method
11379 * is the runtime equivalent of setting the 'editable' config option at config time.
11380 * @param {Boolean} value True to allow the user to directly edit the field text
11382 setEditable : function(value){
11383 if(value == this.editable){
11386 this.editable = value;
11388 this.inputEl().dom.setAttribute('readOnly', true);
11389 this.inputEl().on('mousedown', this.onTriggerClick, this);
11390 this.inputEl().addClass('x-combo-noedit');
11392 this.inputEl().dom.setAttribute('readOnly', false);
11393 this.inputEl().un('mousedown', this.onTriggerClick, this);
11394 this.inputEl().removeClass('x-combo-noedit');
11400 onBeforeLoad : function(combo,opts){
11401 if(!this.hasFocus){
11405 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11407 this.restrictHeight();
11408 this.selectedIndex = -1;
11412 onLoad : function(){
11414 this.hasQuery = false;
11416 if(!this.hasFocus){
11420 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11421 this.loading.hide();
11424 if(this.store.getCount() > 0){
11426 // this.restrictHeight();
11427 if(this.lastQuery == this.allQuery){
11428 if(this.editable && !this.tickable){
11429 this.inputEl().dom.select();
11433 !this.selectByValue(this.value, true) &&
11434 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11435 this.store.lastOptions.add != true)
11437 this.select(0, true);
11440 if(this.autoFocus){
11443 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11444 this.taTask.delay(this.typeAheadDelay);
11448 this.onEmptyResults();
11454 onLoadException : function()
11456 this.hasQuery = false;
11458 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11459 this.loading.hide();
11463 Roo.log(this.store.reader.jsonData);
11464 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11466 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11472 onTypeAhead : function(){
11473 if(this.store.getCount() > 0){
11474 var r = this.store.getAt(0);
11475 var newValue = r.data[this.displayField];
11476 var len = newValue.length;
11477 var selStart = this.getRawValue().length;
11479 if(selStart != len){
11480 this.setRawValue(newValue);
11481 this.selectText(selStart, newValue.length);
11487 onSelect : function(record, index){
11489 if(this.fireEvent('beforeselect', this, record, index) !== false){
11491 this.setFromData(index > -1 ? record.data : false);
11494 this.fireEvent('select', this, record, index);
11499 * Returns the currently selected field value or empty string if no value is set.
11500 * @return {String} value The selected value
11502 getValue : function(){
11505 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11508 if(this.valueField){
11509 return typeof this.value != 'undefined' ? this.value : '';
11511 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11516 * Clears any text/value currently set in the field
11518 clearValue : function(){
11519 if(this.hiddenField){
11520 this.hiddenField.dom.value = '';
11523 this.setRawValue('');
11524 this.lastSelectionText = '';
11525 this.lastData = false;
11530 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11531 * will be displayed in the field. If the value does not match the data value of an existing item,
11532 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11533 * Otherwise the field will be blank (although the value will still be set).
11534 * @param {String} value The value to match
11536 setValue : function(v){
11543 if(this.valueField){
11544 var r = this.findRecord(this.valueField, v);
11546 text = r.data[this.displayField];
11547 }else if(this.valueNotFoundText !== undefined){
11548 text = this.valueNotFoundText;
11551 this.lastSelectionText = text;
11552 if(this.hiddenField){
11553 this.hiddenField.dom.value = v;
11555 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11559 * @property {Object} the last set data for the element
11564 * Sets the value of the field based on a object which is related to the record format for the store.
11565 * @param {Object} value the value to set as. or false on reset?
11567 setFromData : function(o){
11574 var dv = ''; // display value
11575 var vv = ''; // value value..
11577 if (this.displayField) {
11578 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11580 // this is an error condition!!!
11581 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11584 if(this.valueField){
11585 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11588 if(this.hiddenField){
11589 this.hiddenField.dom.value = vv;
11591 this.lastSelectionText = dv;
11592 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11596 // no hidden field.. - we store the value in 'value', but still display
11597 // display field!!!!
11598 this.lastSelectionText = dv;
11599 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11605 reset : function(){
11606 // overridden so that last data is reset..
11607 this.setValue(this.originalValue);
11608 this.clearInvalid();
11609 this.lastData = false;
11611 this.view.clearSelections();
11615 findRecord : function(prop, value){
11617 if(this.store.getCount() > 0){
11618 this.store.each(function(r){
11619 if(r.data[prop] == value){
11629 getName: function()
11631 // returns hidden if it's set..
11632 if (!this.rendered) {return ''};
11633 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11637 onViewMove : function(e, t){
11638 this.inKeyMode = false;
11642 onViewOver : function(e, t){
11643 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11646 var item = this.view.findItemFromChild(t);
11649 var index = this.view.indexOf(item);
11650 this.select(index, false);
11655 onViewClick : function(view, doFocus, el, e)
11657 var index = this.view.getSelectedIndexes()[0];
11659 var r = this.store.getAt(index);
11663 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11670 Roo.each(this.tickItems, function(v,k){
11672 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11673 _this.tickItems.splice(k, 1);
11683 this.tickItems.push(r.data);
11688 this.onSelect(r, index);
11690 if(doFocus !== false && !this.blockFocus){
11691 this.inputEl().focus();
11696 restrictHeight : function(){
11697 //this.innerList.dom.style.height = '';
11698 //var inner = this.innerList.dom;
11699 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11700 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11701 //this.list.beginUpdate();
11702 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11703 this.list.alignTo(this.inputEl(), this.listAlign);
11704 this.list.alignTo(this.inputEl(), this.listAlign);
11705 //this.list.endUpdate();
11709 onEmptyResults : function(){
11714 * Returns true if the dropdown list is expanded, else false.
11716 isExpanded : function(){
11717 return this.list.isVisible();
11721 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11722 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11723 * @param {String} value The data value of the item to select
11724 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11725 * selected item if it is not currently in view (defaults to true)
11726 * @return {Boolean} True if the value matched an item in the list, else false
11728 selectByValue : function(v, scrollIntoView){
11729 if(v !== undefined && v !== null){
11730 var r = this.findRecord(this.valueField || this.displayField, v);
11732 this.select(this.store.indexOf(r), scrollIntoView);
11740 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11741 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11742 * @param {Number} index The zero-based index of the list item to select
11743 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11744 * selected item if it is not currently in view (defaults to true)
11746 select : function(index, scrollIntoView){
11747 this.selectedIndex = index;
11748 this.view.select(index);
11749 if(scrollIntoView !== false){
11750 var el = this.view.getNode(index);
11751 if(el && !this.multiple && !this.tickable){
11752 this.list.scrollChildIntoView(el, false);
11758 selectNext : function(){
11759 var ct = this.store.getCount();
11761 if(this.selectedIndex == -1){
11763 }else if(this.selectedIndex < ct-1){
11764 this.select(this.selectedIndex+1);
11770 selectPrev : function(){
11771 var ct = this.store.getCount();
11773 if(this.selectedIndex == -1){
11775 }else if(this.selectedIndex != 0){
11776 this.select(this.selectedIndex-1);
11782 onKeyUp : function(e){
11783 if(this.editable !== false && !e.isSpecialKey()){
11784 this.lastKey = e.getKey();
11785 this.dqTask.delay(this.queryDelay);
11790 validateBlur : function(){
11791 return !this.list || !this.list.isVisible();
11795 initQuery : function(){
11796 this.doQuery(this.getRawValue());
11800 doForce : function(){
11801 if(this.inputEl().dom.value.length > 0){
11802 this.inputEl().dom.value =
11803 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11809 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11810 * query allowing the query action to be canceled if needed.
11811 * @param {String} query The SQL query to execute
11812 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11813 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11814 * saved in the current store (defaults to false)
11816 doQuery : function(q, forceAll){
11818 if(q === undefined || q === null){
11823 forceAll: forceAll,
11827 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11832 forceAll = qe.forceAll;
11833 if(forceAll === true || (q.length >= this.minChars)){
11835 this.hasQuery = true;
11837 if(this.lastQuery != q || this.alwaysQuery){
11838 this.lastQuery = q;
11839 if(this.mode == 'local'){
11840 this.selectedIndex = -1;
11842 this.store.clearFilter();
11844 this.store.filter(this.displayField, q);
11848 this.store.baseParams[this.queryParam] = q;
11850 var options = {params : this.getParams(q)};
11853 options.add = true;
11854 options.params.start = this.page * this.pageSize;
11857 this.store.load(options);
11859 * this code will make the page width larger, at the beginning, the list not align correctly,
11860 * we should expand the list on onLoad
11861 * so command out it
11866 this.selectedIndex = -1;
11871 this.loadNext = false;
11875 getParams : function(q){
11877 //p[this.queryParam] = q;
11881 p.limit = this.pageSize;
11887 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11889 collapse : function(){
11890 if(!this.isExpanded()){
11897 this.hasFocus = false;
11899 this.cancelBtn.hide();
11900 this.trigger.show();
11903 Roo.get(document).un('mousedown', this.collapseIf, this);
11904 Roo.get(document).un('mousewheel', this.collapseIf, this);
11905 if (!this.editable) {
11906 Roo.get(document).un('keydown', this.listKeyPress, this);
11908 this.fireEvent('collapse', this);
11912 collapseIf : function(e){
11913 var in_combo = e.within(this.el);
11914 var in_list = e.within(this.list);
11915 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11917 if (in_combo || in_list || is_list) {
11918 //e.stopPropagation();
11923 this.onTickableFooterButtonClick(e, false, false);
11931 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11933 expand : function(){
11935 if(this.isExpanded() || !this.hasFocus){
11939 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11940 this.list.setWidth(lw);
11947 this.restrictHeight();
11951 this.tickItems = Roo.apply([], this.item);
11954 this.cancelBtn.show();
11955 this.trigger.hide();
11959 Roo.get(document).on('mousedown', this.collapseIf, this);
11960 Roo.get(document).on('mousewheel', this.collapseIf, this);
11961 if (!this.editable) {
11962 Roo.get(document).on('keydown', this.listKeyPress, this);
11965 this.fireEvent('expand', this);
11969 // Implements the default empty TriggerField.onTriggerClick function
11970 onTriggerClick : function(e)
11972 Roo.log('trigger click');
11974 if(this.disabled || !this.triggerList){
11979 this.loadNext = false;
11981 if(this.isExpanded()){
11983 if (!this.blockFocus) {
11984 this.inputEl().focus();
11988 this.hasFocus = true;
11989 if(this.triggerAction == 'all') {
11990 this.doQuery(this.allQuery, true);
11992 this.doQuery(this.getRawValue());
11994 if (!this.blockFocus) {
11995 this.inputEl().focus();
12000 onTickableTriggerClick : function(e)
12007 this.loadNext = false;
12008 this.hasFocus = true;
12010 if(this.triggerAction == 'all') {
12011 this.doQuery(this.allQuery, true);
12013 this.doQuery(this.getRawValue());
12017 onSearchFieldClick : function(e)
12019 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12020 this.onTickableFooterButtonClick(e, false, false);
12024 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12029 this.loadNext = false;
12030 this.hasFocus = true;
12032 if(this.triggerAction == 'all') {
12033 this.doQuery(this.allQuery, true);
12035 this.doQuery(this.getRawValue());
12039 listKeyPress : function(e)
12041 //Roo.log('listkeypress');
12042 // scroll to first matching element based on key pres..
12043 if (e.isSpecialKey()) {
12046 var k = String.fromCharCode(e.getKey()).toUpperCase();
12049 var csel = this.view.getSelectedNodes();
12050 var cselitem = false;
12052 var ix = this.view.indexOf(csel[0]);
12053 cselitem = this.store.getAt(ix);
12054 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12060 this.store.each(function(v) {
12062 // start at existing selection.
12063 if (cselitem.id == v.id) {
12069 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12070 match = this.store.indexOf(v);
12076 if (match === false) {
12077 return true; // no more action?
12080 this.view.select(match);
12081 var sn = Roo.get(this.view.getSelectedNodes()[0])
12082 sn.scrollIntoView(sn.dom.parentNode, false);
12085 onViewScroll : function(e, t){
12087 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){
12091 this.hasQuery = true;
12093 this.loading = this.list.select('.loading', true).first();
12095 if(this.loading === null){
12096 this.list.createChild({
12098 cls: 'loading select2-more-results select2-active',
12099 html: 'Loading more results...'
12102 this.loading = this.list.select('.loading', true).first();
12104 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12106 this.loading.hide();
12109 this.loading.show();
12114 this.loadNext = true;
12116 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12121 addItem : function(o)
12123 var dv = ''; // display value
12125 if (this.displayField) {
12126 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12128 // this is an error condition!!!
12129 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12136 var choice = this.choices.createChild({
12138 cls: 'select2-search-choice',
12147 cls: 'select2-search-choice-close',
12152 }, this.searchField);
12154 var close = choice.select('a.select2-search-choice-close', true).first()
12156 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12164 this.inputEl().dom.value = '';
12168 onRemoveItem : function(e, _self, o)
12170 e.preventDefault();
12172 this.lastItem = Roo.apply([], this.item);
12174 var index = this.item.indexOf(o.data) * 1;
12177 Roo.log('not this item?!');
12181 this.item.splice(index, 1);
12186 this.fireEvent('remove', this, e);
12190 syncValue : function()
12192 if(!this.item.length){
12199 Roo.each(this.item, function(i){
12200 if(_this.valueField){
12201 value.push(i[_this.valueField]);
12208 this.value = value.join(',');
12210 if(this.hiddenField){
12211 this.hiddenField.dom.value = this.value;
12215 clearItem : function()
12217 if(!this.multiple){
12223 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12230 inputEl: function ()
12233 return this.searchField;
12235 return this.el.select('input.form-control',true).first();
12239 onTickableFooterButtonClick : function(e, btn, el)
12241 e.preventDefault();
12243 this.lastItem = Roo.apply([], this.item);
12245 if(btn && btn.name == 'cancel'){
12246 this.tickItems = Roo.apply([], this.item);
12255 Roo.each(this.tickItems, function(o){
12263 validate : function()
12265 var v = this.getRawValue();
12268 v = this.getValue();
12271 if(this.disabled || this.validateValue(v)){
12272 this.clearInvalid();
12281 * @cfg {Boolean} grow
12285 * @cfg {Number} growMin
12289 * @cfg {Number} growMax
12299 * Ext JS Library 1.1.1
12300 * Copyright(c) 2006-2007, Ext JS, LLC.
12302 * Originally Released Under LGPL - original licence link has changed is not relivant.
12305 * <script type="text/javascript">
12310 * @extends Roo.util.Observable
12311 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12312 * This class also supports single and multi selection modes. <br>
12313 * Create a data model bound view:
12315 var store = new Roo.data.Store(...);
12317 var view = new Roo.View({
12319 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12321 singleSelect: true,
12322 selectedClass: "ydataview-selected",
12326 // listen for node click?
12327 view.on("click", function(vw, index, node, e){
12328 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12332 dataModel.load("foobar.xml");
12334 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12336 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12337 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12339 * Note: old style constructor is still suported (container, template, config)
12342 * Create a new View
12343 * @param {Object} config The config object
12346 Roo.View = function(config, depreciated_tpl, depreciated_config){
12348 this.parent = false;
12350 if (typeof(depreciated_tpl) == 'undefined') {
12351 // new way.. - universal constructor.
12352 Roo.apply(this, config);
12353 this.el = Roo.get(this.el);
12356 this.el = Roo.get(config);
12357 this.tpl = depreciated_tpl;
12358 Roo.apply(this, depreciated_config);
12360 this.wrapEl = this.el.wrap().wrap();
12361 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12364 if(typeof(this.tpl) == "string"){
12365 this.tpl = new Roo.Template(this.tpl);
12367 // support xtype ctors..
12368 this.tpl = new Roo.factory(this.tpl, Roo);
12372 this.tpl.compile();
12377 * @event beforeclick
12378 * Fires before a click is processed. Returns false to cancel the default action.
12379 * @param {Roo.View} this
12380 * @param {Number} index The index of the target node
12381 * @param {HTMLElement} node The target node
12382 * @param {Roo.EventObject} e The raw event object
12384 "beforeclick" : true,
12387 * Fires when a template node is clicked.
12388 * @param {Roo.View} this
12389 * @param {Number} index The index of the target node
12390 * @param {HTMLElement} node The target node
12391 * @param {Roo.EventObject} e The raw event object
12396 * Fires when a template node is double clicked.
12397 * @param {Roo.View} this
12398 * @param {Number} index The index of the target node
12399 * @param {HTMLElement} node The target node
12400 * @param {Roo.EventObject} e The raw event object
12404 * @event contextmenu
12405 * Fires when a template node is right clicked.
12406 * @param {Roo.View} this
12407 * @param {Number} index The index of the target node
12408 * @param {HTMLElement} node The target node
12409 * @param {Roo.EventObject} e The raw event object
12411 "contextmenu" : true,
12413 * @event selectionchange
12414 * Fires when the selected nodes change.
12415 * @param {Roo.View} this
12416 * @param {Array} selections Array of the selected nodes
12418 "selectionchange" : true,
12421 * @event beforeselect
12422 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12423 * @param {Roo.View} this
12424 * @param {HTMLElement} node The node to be selected
12425 * @param {Array} selections Array of currently selected nodes
12427 "beforeselect" : true,
12429 * @event preparedata
12430 * Fires on every row to render, to allow you to change the data.
12431 * @param {Roo.View} this
12432 * @param {Object} data to be rendered (change this)
12434 "preparedata" : true
12442 "click": this.onClick,
12443 "dblclick": this.onDblClick,
12444 "contextmenu": this.onContextMenu,
12448 this.selections = [];
12450 this.cmp = new Roo.CompositeElementLite([]);
12452 this.store = Roo.factory(this.store, Roo.data);
12453 this.setStore(this.store, true);
12456 if ( this.footer && this.footer.xtype) {
12458 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12460 this.footer.dataSource = this.store
12461 this.footer.container = fctr;
12462 this.footer = Roo.factory(this.footer, Roo);
12463 fctr.insertFirst(this.el);
12465 // this is a bit insane - as the paging toolbar seems to detach the el..
12466 // dom.parentNode.parentNode.parentNode
12467 // they get detached?
12471 Roo.View.superclass.constructor.call(this);
12476 Roo.extend(Roo.View, Roo.util.Observable, {
12479 * @cfg {Roo.data.Store} store Data store to load data from.
12484 * @cfg {String|Roo.Element} el The container element.
12489 * @cfg {String|Roo.Template} tpl The template used by this View
12493 * @cfg {String} dataName the named area of the template to use as the data area
12494 * Works with domtemplates roo-name="name"
12498 * @cfg {String} selectedClass The css class to add to selected nodes
12500 selectedClass : "x-view-selected",
12502 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12507 * @cfg {String} text to display on mask (default Loading)
12511 * @cfg {Boolean} multiSelect Allow multiple selection
12513 multiSelect : false,
12515 * @cfg {Boolean} singleSelect Allow single selection
12517 singleSelect: false,
12520 * @cfg {Boolean} toggleSelect - selecting
12522 toggleSelect : false,
12525 * @cfg {Boolean} tickable - selecting
12530 * Returns the element this view is bound to.
12531 * @return {Roo.Element}
12533 getEl : function(){
12534 return this.wrapEl;
12540 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12542 refresh : function(){
12543 //Roo.log('refresh');
12546 // if we are using something like 'domtemplate', then
12547 // the what gets used is:
12548 // t.applySubtemplate(NAME, data, wrapping data..)
12549 // the outer template then get' applied with
12550 // the store 'extra data'
12551 // and the body get's added to the
12552 // roo-name="data" node?
12553 // <span class='roo-tpl-{name}'></span> ?????
12557 this.clearSelections();
12558 this.el.update("");
12560 var records = this.store.getRange();
12561 if(records.length < 1) {
12563 // is this valid?? = should it render a template??
12565 this.el.update(this.emptyText);
12569 if (this.dataName) {
12570 this.el.update(t.apply(this.store.meta)); //????
12571 el = this.el.child('.roo-tpl-' + this.dataName);
12574 for(var i = 0, len = records.length; i < len; i++){
12575 var data = this.prepareData(records[i].data, i, records[i]);
12576 this.fireEvent("preparedata", this, data, i, records[i]);
12578 var d = Roo.apply({}, data);
12581 Roo.apply(d, {'roo-id' : Roo.id()});
12585 Roo.each(this.parent.item, function(item){
12586 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12589 Roo.apply(d, {'roo-data-checked' : 'checked'});
12593 html[html.length] = Roo.util.Format.trim(
12595 t.applySubtemplate(this.dataName, d, this.store.meta) :
12602 el.update(html.join(""));
12603 this.nodes = el.dom.childNodes;
12604 this.updateIndexes(0);
12609 * Function to override to reformat the data that is sent to
12610 * the template for each node.
12611 * DEPRICATED - use the preparedata event handler.
12612 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12613 * a JSON object for an UpdateManager bound view).
12615 prepareData : function(data, index, record)
12617 this.fireEvent("preparedata", this, data, index, record);
12621 onUpdate : function(ds, record){
12622 // Roo.log('on update');
12623 this.clearSelections();
12624 var index = this.store.indexOf(record);
12625 var n = this.nodes[index];
12626 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12627 n.parentNode.removeChild(n);
12628 this.updateIndexes(index, index);
12634 onAdd : function(ds, records, index)
12636 //Roo.log(['on Add', ds, records, index] );
12637 this.clearSelections();
12638 if(this.nodes.length == 0){
12642 var n = this.nodes[index];
12643 for(var i = 0, len = records.length; i < len; i++){
12644 var d = this.prepareData(records[i].data, i, records[i]);
12646 this.tpl.insertBefore(n, d);
12649 this.tpl.append(this.el, d);
12652 this.updateIndexes(index);
12655 onRemove : function(ds, record, index){
12656 // Roo.log('onRemove');
12657 this.clearSelections();
12658 var el = this.dataName ?
12659 this.el.child('.roo-tpl-' + this.dataName) :
12662 el.dom.removeChild(this.nodes[index]);
12663 this.updateIndexes(index);
12667 * Refresh an individual node.
12668 * @param {Number} index
12670 refreshNode : function(index){
12671 this.onUpdate(this.store, this.store.getAt(index));
12674 updateIndexes : function(startIndex, endIndex){
12675 var ns = this.nodes;
12676 startIndex = startIndex || 0;
12677 endIndex = endIndex || ns.length - 1;
12678 for(var i = startIndex; i <= endIndex; i++){
12679 ns[i].nodeIndex = i;
12684 * Changes the data store this view uses and refresh the view.
12685 * @param {Store} store
12687 setStore : function(store, initial){
12688 if(!initial && this.store){
12689 this.store.un("datachanged", this.refresh);
12690 this.store.un("add", this.onAdd);
12691 this.store.un("remove", this.onRemove);
12692 this.store.un("update", this.onUpdate);
12693 this.store.un("clear", this.refresh);
12694 this.store.un("beforeload", this.onBeforeLoad);
12695 this.store.un("load", this.onLoad);
12696 this.store.un("loadexception", this.onLoad);
12700 store.on("datachanged", this.refresh, this);
12701 store.on("add", this.onAdd, this);
12702 store.on("remove", this.onRemove, this);
12703 store.on("update", this.onUpdate, this);
12704 store.on("clear", this.refresh, this);
12705 store.on("beforeload", this.onBeforeLoad, this);
12706 store.on("load", this.onLoad, this);
12707 store.on("loadexception", this.onLoad, this);
12715 * onbeforeLoad - masks the loading area.
12718 onBeforeLoad : function(store,opts)
12720 //Roo.log('onBeforeLoad');
12722 this.el.update("");
12724 this.el.mask(this.mask ? this.mask : "Loading" );
12726 onLoad : function ()
12733 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12734 * @param {HTMLElement} node
12735 * @return {HTMLElement} The template node
12737 findItemFromChild : function(node){
12738 var el = this.dataName ?
12739 this.el.child('.roo-tpl-' + this.dataName,true) :
12742 if(!node || node.parentNode == el){
12745 var p = node.parentNode;
12746 while(p && p != el){
12747 if(p.parentNode == el){
12756 onClick : function(e){
12757 var item = this.findItemFromChild(e.getTarget());
12759 var index = this.indexOf(item);
12760 if(this.onItemClick(item, index, e) !== false){
12761 this.fireEvent("click", this, index, item, e);
12764 this.clearSelections();
12769 onContextMenu : function(e){
12770 var item = this.findItemFromChild(e.getTarget());
12772 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12777 onDblClick : function(e){
12778 var item = this.findItemFromChild(e.getTarget());
12780 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12784 onItemClick : function(item, index, e)
12786 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12789 if (this.toggleSelect) {
12790 var m = this.isSelected(item) ? 'unselect' : 'select';
12793 _t[m](item, true, false);
12796 if(this.multiSelect || this.singleSelect){
12797 if(this.multiSelect && e.shiftKey && this.lastSelection){
12798 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12800 this.select(item, this.multiSelect && e.ctrlKey);
12801 this.lastSelection = item;
12804 if(!this.tickable){
12805 e.preventDefault();
12813 * Get the number of selected nodes.
12816 getSelectionCount : function(){
12817 return this.selections.length;
12821 * Get the currently selected nodes.
12822 * @return {Array} An array of HTMLElements
12824 getSelectedNodes : function(){
12825 return this.selections;
12829 * Get the indexes of the selected nodes.
12832 getSelectedIndexes : function(){
12833 var indexes = [], s = this.selections;
12834 for(var i = 0, len = s.length; i < len; i++){
12835 indexes.push(s[i].nodeIndex);
12841 * Clear all selections
12842 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12844 clearSelections : function(suppressEvent){
12845 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12846 this.cmp.elements = this.selections;
12847 this.cmp.removeClass(this.selectedClass);
12848 this.selections = [];
12849 if(!suppressEvent){
12850 this.fireEvent("selectionchange", this, this.selections);
12856 * Returns true if the passed node is selected
12857 * @param {HTMLElement/Number} node The node or node index
12858 * @return {Boolean}
12860 isSelected : function(node){
12861 var s = this.selections;
12865 node = this.getNode(node);
12866 return s.indexOf(node) !== -1;
12871 * @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
12872 * @param {Boolean} keepExisting (optional) true to keep existing selections
12873 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12875 select : function(nodeInfo, keepExisting, suppressEvent){
12876 if(nodeInfo instanceof Array){
12878 this.clearSelections(true);
12880 for(var i = 0, len = nodeInfo.length; i < len; i++){
12881 this.select(nodeInfo[i], true, true);
12885 var node = this.getNode(nodeInfo);
12886 if(!node || this.isSelected(node)){
12887 return; // already selected.
12890 this.clearSelections(true);
12893 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12894 Roo.fly(node).addClass(this.selectedClass);
12895 this.selections.push(node);
12896 if(!suppressEvent){
12897 this.fireEvent("selectionchange", this, this.selections);
12905 * @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
12906 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12907 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12909 unselect : function(nodeInfo, keepExisting, suppressEvent)
12911 if(nodeInfo instanceof Array){
12912 Roo.each(this.selections, function(s) {
12913 this.unselect(s, nodeInfo);
12917 var node = this.getNode(nodeInfo);
12918 if(!node || !this.isSelected(node)){
12919 //Roo.log("not selected");
12920 return; // not selected.
12924 Roo.each(this.selections, function(s) {
12926 Roo.fly(node).removeClass(this.selectedClass);
12933 this.selections= ns;
12934 this.fireEvent("selectionchange", this, this.selections);
12938 * Gets a template node.
12939 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12940 * @return {HTMLElement} The node or null if it wasn't found
12942 getNode : function(nodeInfo){
12943 if(typeof nodeInfo == "string"){
12944 return document.getElementById(nodeInfo);
12945 }else if(typeof nodeInfo == "number"){
12946 return this.nodes[nodeInfo];
12952 * Gets a range template nodes.
12953 * @param {Number} startIndex
12954 * @param {Number} endIndex
12955 * @return {Array} An array of nodes
12957 getNodes : function(start, end){
12958 var ns = this.nodes;
12959 start = start || 0;
12960 end = typeof end == "undefined" ? ns.length - 1 : end;
12963 for(var i = start; i <= end; i++){
12967 for(var i = start; i >= end; i--){
12975 * Finds the index of the passed node
12976 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12977 * @return {Number} The index of the node or -1
12979 indexOf : function(node){
12980 node = this.getNode(node);
12981 if(typeof node.nodeIndex == "number"){
12982 return node.nodeIndex;
12984 var ns = this.nodes;
12985 for(var i = 0, len = ns.length; i < len; i++){
12996 * based on jquery fullcalendar
13000 Roo.bootstrap = Roo.bootstrap || {};
13002 * @class Roo.bootstrap.Calendar
13003 * @extends Roo.bootstrap.Component
13004 * Bootstrap Calendar class
13005 * @cfg {Boolean} loadMask (true|false) default false
13006 * @cfg {Object} header generate the user specific header of the calendar, default false
13009 * Create a new Container
13010 * @param {Object} config The config object
13015 Roo.bootstrap.Calendar = function(config){
13016 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13020 * Fires when a date is selected
13021 * @param {DatePicker} this
13022 * @param {Date} date The selected date
13026 * @event monthchange
13027 * Fires when the displayed month changes
13028 * @param {DatePicker} this
13029 * @param {Date} date The selected month
13031 'monthchange': true,
13033 * @event evententer
13034 * Fires when mouse over an event
13035 * @param {Calendar} this
13036 * @param {event} Event
13038 'evententer': true,
13040 * @event eventleave
13041 * Fires when the mouse leaves an
13042 * @param {Calendar} this
13045 'eventleave': true,
13047 * @event eventclick
13048 * Fires when the mouse click an
13049 * @param {Calendar} this
13058 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13061 * @cfg {Number} startDay
13062 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13070 getAutoCreate : function(){
13073 var fc_button = function(name, corner, style, content ) {
13074 return Roo.apply({},{
13076 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13078 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13081 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13092 style : 'width:100%',
13099 cls : 'fc-header-left',
13101 fc_button('prev', 'left', 'arrow', '‹' ),
13102 fc_button('next', 'right', 'arrow', '›' ),
13103 { tag: 'span', cls: 'fc-header-space' },
13104 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13112 cls : 'fc-header-center',
13116 cls: 'fc-header-title',
13119 html : 'month / year'
13127 cls : 'fc-header-right',
13129 /* fc_button('month', 'left', '', 'month' ),
13130 fc_button('week', '', '', 'week' ),
13131 fc_button('day', 'right', '', 'day' )
13143 header = this.header;
13146 var cal_heads = function() {
13148 // fixme - handle this.
13150 for (var i =0; i < Date.dayNames.length; i++) {
13151 var d = Date.dayNames[i];
13154 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13155 html : d.substring(0,3)
13159 ret[0].cls += ' fc-first';
13160 ret[6].cls += ' fc-last';
13163 var cal_cell = function(n) {
13166 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13171 cls: 'fc-day-number',
13175 cls: 'fc-day-content',
13179 style: 'position: relative;' // height: 17px;
13191 var cal_rows = function() {
13194 for (var r = 0; r < 6; r++) {
13201 for (var i =0; i < Date.dayNames.length; i++) {
13202 var d = Date.dayNames[i];
13203 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13206 row.cn[0].cls+=' fc-first';
13207 row.cn[0].cn[0].style = 'min-height:90px';
13208 row.cn[6].cls+=' fc-last';
13212 ret[0].cls += ' fc-first';
13213 ret[4].cls += ' fc-prev-last';
13214 ret[5].cls += ' fc-last';
13221 cls: 'fc-border-separate',
13222 style : 'width:100%',
13230 cls : 'fc-first fc-last',
13248 cls : 'fc-content',
13249 style : "position: relative;",
13252 cls : 'fc-view fc-view-month fc-grid',
13253 style : 'position: relative',
13254 unselectable : 'on',
13257 cls : 'fc-event-container',
13258 style : 'position:absolute;z-index:8;top:0;left:0;'
13276 initEvents : function()
13279 throw "can not find store for calendar";
13285 style: "text-align:center",
13289 style: "background-color:white;width:50%;margin:250 auto",
13293 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13304 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13306 var size = this.el.select('.fc-content', true).first().getSize();
13307 this.maskEl.setSize(size.width, size.height);
13308 this.maskEl.enableDisplayMode("block");
13309 if(!this.loadMask){
13310 this.maskEl.hide();
13313 this.store = Roo.factory(this.store, Roo.data);
13314 this.store.on('load', this.onLoad, this);
13315 this.store.on('beforeload', this.onBeforeLoad, this);
13319 this.cells = this.el.select('.fc-day',true);
13320 //Roo.log(this.cells);
13321 this.textNodes = this.el.query('.fc-day-number');
13322 this.cells.addClassOnOver('fc-state-hover');
13324 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13325 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13326 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13327 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13329 this.on('monthchange', this.onMonthChange, this);
13331 this.update(new Date().clearTime());
13334 resize : function() {
13335 var sz = this.el.getSize();
13337 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13338 this.el.select('.fc-day-content div',true).setHeight(34);
13343 showPrevMonth : function(e){
13344 this.update(this.activeDate.add("mo", -1));
13346 showToday : function(e){
13347 this.update(new Date().clearTime());
13350 showNextMonth : function(e){
13351 this.update(this.activeDate.add("mo", 1));
13355 showPrevYear : function(){
13356 this.update(this.activeDate.add("y", -1));
13360 showNextYear : function(){
13361 this.update(this.activeDate.add("y", 1));
13366 update : function(date)
13368 var vd = this.activeDate;
13369 this.activeDate = date;
13370 // if(vd && this.el){
13371 // var t = date.getTime();
13372 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13373 // Roo.log('using add remove');
13375 // this.fireEvent('monthchange', this, date);
13377 // this.cells.removeClass("fc-state-highlight");
13378 // this.cells.each(function(c){
13379 // if(c.dateValue == t){
13380 // c.addClass("fc-state-highlight");
13381 // setTimeout(function(){
13382 // try{c.dom.firstChild.focus();}catch(e){}
13392 var days = date.getDaysInMonth();
13394 var firstOfMonth = date.getFirstDateOfMonth();
13395 var startingPos = firstOfMonth.getDay()-this.startDay;
13397 if(startingPos < this.startDay){
13401 var pm = date.add(Date.MONTH, -1);
13402 var prevStart = pm.getDaysInMonth()-startingPos;
13404 this.cells = this.el.select('.fc-day',true);
13405 this.textNodes = this.el.query('.fc-day-number');
13406 this.cells.addClassOnOver('fc-state-hover');
13408 var cells = this.cells.elements;
13409 var textEls = this.textNodes;
13411 Roo.each(cells, function(cell){
13412 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13415 days += startingPos;
13417 // convert everything to numbers so it's fast
13418 var day = 86400000;
13419 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13422 //Roo.log(prevStart);
13424 var today = new Date().clearTime().getTime();
13425 var sel = date.clearTime().getTime();
13426 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13427 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13428 var ddMatch = this.disabledDatesRE;
13429 var ddText = this.disabledDatesText;
13430 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13431 var ddaysText = this.disabledDaysText;
13432 var format = this.format;
13434 var setCellClass = function(cal, cell){
13438 //Roo.log('set Cell Class');
13440 var t = d.getTime();
13444 cell.dateValue = t;
13446 cell.className += " fc-today";
13447 cell.className += " fc-state-highlight";
13448 cell.title = cal.todayText;
13451 // disable highlight in other month..
13452 //cell.className += " fc-state-highlight";
13457 cell.className = " fc-state-disabled";
13458 cell.title = cal.minText;
13462 cell.className = " fc-state-disabled";
13463 cell.title = cal.maxText;
13467 if(ddays.indexOf(d.getDay()) != -1){
13468 cell.title = ddaysText;
13469 cell.className = " fc-state-disabled";
13472 if(ddMatch && format){
13473 var fvalue = d.dateFormat(format);
13474 if(ddMatch.test(fvalue)){
13475 cell.title = ddText.replace("%0", fvalue);
13476 cell.className = " fc-state-disabled";
13480 if (!cell.initialClassName) {
13481 cell.initialClassName = cell.dom.className;
13484 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13489 for(; i < startingPos; i++) {
13490 textEls[i].innerHTML = (++prevStart);
13491 d.setDate(d.getDate()+1);
13493 cells[i].className = "fc-past fc-other-month";
13494 setCellClass(this, cells[i]);
13499 for(; i < days; i++){
13500 intDay = i - startingPos + 1;
13501 textEls[i].innerHTML = (intDay);
13502 d.setDate(d.getDate()+1);
13504 cells[i].className = ''; // "x-date-active";
13505 setCellClass(this, cells[i]);
13509 for(; i < 42; i++) {
13510 textEls[i].innerHTML = (++extraDays);
13511 d.setDate(d.getDate()+1);
13513 cells[i].className = "fc-future fc-other-month";
13514 setCellClass(this, cells[i]);
13517 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13519 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13521 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13522 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13524 if(totalRows != 6){
13525 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13526 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13529 this.fireEvent('monthchange', this, date);
13533 if(!this.internalRender){
13534 var main = this.el.dom.firstChild;
13535 var w = main.offsetWidth;
13536 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13537 Roo.fly(main).setWidth(w);
13538 this.internalRender = true;
13539 // opera does not respect the auto grow header center column
13540 // then, after it gets a width opera refuses to recalculate
13541 // without a second pass
13542 if(Roo.isOpera && !this.secondPass){
13543 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13544 this.secondPass = true;
13545 this.update.defer(10, this, [date]);
13552 findCell : function(dt) {
13553 dt = dt.clearTime().getTime();
13555 this.cells.each(function(c){
13556 //Roo.log("check " +c.dateValue + '?=' + dt);
13557 if(c.dateValue == dt){
13567 findCells : function(ev) {
13568 var s = ev.start.clone().clearTime().getTime();
13570 var e= ev.end.clone().clearTime().getTime();
13573 this.cells.each(function(c){
13574 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13576 if(c.dateValue > e){
13579 if(c.dateValue < s){
13588 // findBestRow: function(cells)
13592 // for (var i =0 ; i < cells.length;i++) {
13593 // ret = Math.max(cells[i].rows || 0,ret);
13600 addItem : function(ev)
13602 // look for vertical location slot in
13603 var cells = this.findCells(ev);
13605 // ev.row = this.findBestRow(cells);
13607 // work out the location.
13611 for(var i =0; i < cells.length; i++) {
13613 cells[i].row = cells[0].row;
13616 cells[i].row = cells[i].row + 1;
13626 if (crow.start.getY() == cells[i].getY()) {
13628 crow.end = cells[i];
13645 cells[0].events.push(ev);
13647 this.calevents.push(ev);
13650 clearEvents: function() {
13652 if(!this.calevents){
13656 Roo.each(this.cells.elements, function(c){
13662 Roo.each(this.calevents, function(e) {
13663 Roo.each(e.els, function(el) {
13664 el.un('mouseenter' ,this.onEventEnter, this);
13665 el.un('mouseleave' ,this.onEventLeave, this);
13670 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13676 renderEvents: function()
13680 this.cells.each(function(c) {
13689 if(c.row != c.events.length){
13690 r = 4 - (4 - (c.row - c.events.length));
13693 c.events = ev.slice(0, r);
13694 c.more = ev.slice(r);
13696 if(c.more.length && c.more.length == 1){
13697 c.events.push(c.more.pop());
13700 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13704 this.cells.each(function(c) {
13706 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13709 for (var e = 0; e < c.events.length; e++){
13710 var ev = c.events[e];
13711 var rows = ev.rows;
13713 for(var i = 0; i < rows.length; i++) {
13715 // how many rows should it span..
13718 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13719 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13721 unselectable : "on",
13724 cls: 'fc-event-inner',
13728 // cls: 'fc-event-time',
13729 // html : cells.length > 1 ? '' : ev.time
13733 cls: 'fc-event-title',
13734 html : String.format('{0}', ev.title)
13741 cls: 'ui-resizable-handle ui-resizable-e',
13742 html : '  '
13749 cfg.cls += ' fc-event-start';
13751 if ((i+1) == rows.length) {
13752 cfg.cls += ' fc-event-end';
13755 var ctr = _this.el.select('.fc-event-container',true).first();
13756 var cg = ctr.createChild(cfg);
13758 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13759 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13761 var r = (c.more.length) ? 1 : 0;
13762 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13763 cg.setWidth(ebox.right - sbox.x -2);
13765 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13766 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13767 cg.on('click', _this.onEventClick, _this, ev);
13778 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13779 style : 'position: absolute',
13780 unselectable : "on",
13783 cls: 'fc-event-inner',
13787 cls: 'fc-event-title',
13795 cls: 'ui-resizable-handle ui-resizable-e',
13796 html : '  '
13802 var ctr = _this.el.select('.fc-event-container',true).first();
13803 var cg = ctr.createChild(cfg);
13805 var sbox = c.select('.fc-day-content',true).first().getBox();
13806 var ebox = c.select('.fc-day-content',true).first().getBox();
13808 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13809 cg.setWidth(ebox.right - sbox.x -2);
13811 cg.on('click', _this.onMoreEventClick, _this, c.more);
13821 onEventEnter: function (e, el,event,d) {
13822 this.fireEvent('evententer', this, el, event);
13825 onEventLeave: function (e, el,event,d) {
13826 this.fireEvent('eventleave', this, el, event);
13829 onEventClick: function (e, el,event,d) {
13830 this.fireEvent('eventclick', this, el, event);
13833 onMonthChange: function () {
13837 onMoreEventClick: function(e, el, more)
13841 this.calpopover.placement = 'right';
13842 this.calpopover.setTitle('More');
13844 this.calpopover.setContent('');
13846 var ctr = this.calpopover.el.select('.popover-content', true).first();
13848 Roo.each(more, function(m){
13850 cls : 'fc-event-hori fc-event-draggable',
13853 var cg = ctr.createChild(cfg);
13855 cg.on('click', _this.onEventClick, _this, m);
13858 this.calpopover.show(el);
13863 onLoad: function ()
13865 this.calevents = [];
13868 if(this.store.getCount() > 0){
13869 this.store.data.each(function(d){
13872 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13873 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13874 time : d.data.start_time,
13875 title : d.data.title,
13876 description : d.data.description,
13877 venue : d.data.venue
13882 this.renderEvents();
13884 if(this.calevents.length && this.loadMask){
13885 this.maskEl.hide();
13889 onBeforeLoad: function()
13891 this.clearEvents();
13893 this.maskEl.show();
13907 * @class Roo.bootstrap.Popover
13908 * @extends Roo.bootstrap.Component
13909 * Bootstrap Popover class
13910 * @cfg {String} html contents of the popover (or false to use children..)
13911 * @cfg {String} title of popover (or false to hide)
13912 * @cfg {String} placement how it is placed
13913 * @cfg {String} trigger click || hover (or false to trigger manually)
13914 * @cfg {String} over what (parent or false to trigger manually.)
13915 * @cfg {Number} delay - delay before showing
13918 * Create a new Popover
13919 * @param {Object} config The config object
13922 Roo.bootstrap.Popover = function(config){
13923 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13926 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13928 title: 'Fill in a title',
13931 placement : 'right',
13932 trigger : 'hover', // hover
13938 can_build_overlaid : false,
13940 getChildContainer : function()
13942 return this.el.select('.popover-content',true).first();
13945 getAutoCreate : function(){
13946 Roo.log('make popover?');
13948 cls : 'popover roo-dynamic',
13949 style: 'display:block',
13955 cls : 'popover-inner',
13959 cls: 'popover-title',
13963 cls : 'popover-content',
13974 setTitle: function(str)
13976 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13978 setContent: function(str)
13980 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13982 // as it get's added to the bottom of the page.
13983 onRender : function(ct, position)
13985 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13987 var cfg = Roo.apply({}, this.getAutoCreate());
13991 cfg.cls += ' ' + this.cls;
13994 cfg.style = this.style;
13996 Roo.log("adding to ")
13997 this.el = Roo.get(document.body).createChild(cfg, position);
14003 initEvents : function()
14005 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14006 this.el.enableDisplayMode('block');
14008 if (this.over === false) {
14011 if (this.triggers === false) {
14014 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14015 var triggers = this.trigger ? this.trigger.split(' ') : [];
14016 Roo.each(triggers, function(trigger) {
14018 if (trigger == 'click') {
14019 on_el.on('click', this.toggle, this);
14020 } else if (trigger != 'manual') {
14021 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14022 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14024 on_el.on(eventIn ,this.enter, this);
14025 on_el.on(eventOut, this.leave, this);
14036 toggle : function () {
14037 this.hoverState == 'in' ? this.leave() : this.enter();
14040 enter : function () {
14043 clearTimeout(this.timeout);
14045 this.hoverState = 'in';
14047 if (!this.delay || !this.delay.show) {
14052 this.timeout = setTimeout(function () {
14053 if (_t.hoverState == 'in') {
14056 }, this.delay.show)
14058 leave : function() {
14059 clearTimeout(this.timeout);
14061 this.hoverState = 'out';
14063 if (!this.delay || !this.delay.hide) {
14068 this.timeout = setTimeout(function () {
14069 if (_t.hoverState == 'out') {
14072 }, this.delay.hide)
14075 show : function (on_el)
14078 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14081 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14082 if (this.html !== false) {
14083 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14085 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14086 if (!this.title.length) {
14087 this.el.select('.popover-title',true).hide();
14090 var placement = typeof this.placement == 'function' ?
14091 this.placement.call(this, this.el, on_el) :
14094 var autoToken = /\s?auto?\s?/i;
14095 var autoPlace = autoToken.test(placement);
14097 placement = placement.replace(autoToken, '') || 'top';
14101 //this.el.setXY([0,0]);
14103 this.el.dom.style.display='block';
14104 this.el.addClass(placement);
14106 //this.el.appendTo(on_el);
14108 var p = this.getPosition();
14109 var box = this.el.getBox();
14114 var align = Roo.bootstrap.Popover.alignment[placement];
14115 this.el.alignTo(on_el, align[0],align[1]);
14116 //var arrow = this.el.select('.arrow',true).first();
14117 //arrow.set(align[2],
14119 this.el.addClass('in');
14120 this.hoverState = null;
14122 if (this.el.hasClass('fade')) {
14129 this.el.setXY([0,0]);
14130 this.el.removeClass('in');
14137 Roo.bootstrap.Popover.alignment = {
14138 'left' : ['r-l', [-10,0], 'right'],
14139 'right' : ['l-r', [10,0], 'left'],
14140 'bottom' : ['t-b', [0,10], 'top'],
14141 'top' : [ 'b-t', [0,-10], 'bottom']
14152 * @class Roo.bootstrap.Progress
14153 * @extends Roo.bootstrap.Component
14154 * Bootstrap Progress class
14155 * @cfg {Boolean} striped striped of the progress bar
14156 * @cfg {Boolean} active animated of the progress bar
14160 * Create a new Progress
14161 * @param {Object} config The config object
14164 Roo.bootstrap.Progress = function(config){
14165 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14168 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14173 getAutoCreate : function(){
14181 cfg.cls += ' progress-striped';
14185 cfg.cls += ' active';
14204 * @class Roo.bootstrap.ProgressBar
14205 * @extends Roo.bootstrap.Component
14206 * Bootstrap ProgressBar class
14207 * @cfg {Number} aria_valuenow aria-value now
14208 * @cfg {Number} aria_valuemin aria-value min
14209 * @cfg {Number} aria_valuemax aria-value max
14210 * @cfg {String} label label for the progress bar
14211 * @cfg {String} panel (success | info | warning | danger )
14212 * @cfg {String} role role of the progress bar
14213 * @cfg {String} sr_only text
14217 * Create a new ProgressBar
14218 * @param {Object} config The config object
14221 Roo.bootstrap.ProgressBar = function(config){
14222 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14225 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14229 aria_valuemax : 100,
14235 getAutoCreate : function()
14240 cls: 'progress-bar',
14241 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14253 cfg.role = this.role;
14256 if(this.aria_valuenow){
14257 cfg['aria-valuenow'] = this.aria_valuenow;
14260 if(this.aria_valuemin){
14261 cfg['aria-valuemin'] = this.aria_valuemin;
14264 if(this.aria_valuemax){
14265 cfg['aria-valuemax'] = this.aria_valuemax;
14268 if(this.label && !this.sr_only){
14269 cfg.html = this.label;
14273 cfg.cls += ' progress-bar-' + this.panel;
14279 update : function(aria_valuenow)
14281 this.aria_valuenow = aria_valuenow;
14283 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14298 * @class Roo.bootstrap.TabGroup
14299 * @extends Roo.bootstrap.Column
14300 * Bootstrap Column class
14301 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14302 * @cfg {Boolean} carousel true to make the group behave like a carousel
14305 * Create a new TabGroup
14306 * @param {Object} config The config object
14309 Roo.bootstrap.TabGroup = function(config){
14310 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14312 this.navId = Roo.id();
14315 Roo.bootstrap.TabGroup.register(this);
14319 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14322 transition : false,
14324 getAutoCreate : function()
14326 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14328 cfg.cls += ' tab-content';
14330 if (this.carousel) {
14331 cfg.cls += ' carousel slide';
14333 cls : 'carousel-inner'
14340 getChildContainer : function()
14342 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14346 * register a Navigation item
14347 * @param {Roo.bootstrap.NavItem} the navitem to add
14349 register : function(item)
14351 this.tabs.push( item);
14352 item.navId = this.navId; // not really needed..
14356 getActivePanel : function()
14359 Roo.each(this.tabs, function(t) {
14369 getPanelByName : function(n)
14372 Roo.each(this.tabs, function(t) {
14373 if (t.tabId == n) {
14381 indexOfPanel : function(p)
14384 Roo.each(this.tabs, function(t,i) {
14385 if (t.tabId == p.tabId) {
14394 * show a specific panel
14395 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14396 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14398 showPanel : function (pan)
14401 if (typeof(pan) == 'number') {
14402 pan = this.tabs[pan];
14404 if (typeof(pan) == 'string') {
14405 pan = this.getPanelByName(pan);
14407 if (pan.tabId == this.getActivePanel().tabId) {
14410 var cur = this.getActivePanel();
14412 if (false === cur.fireEvent('beforedeactivate')) {
14416 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14418 this.transition = true;
14419 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14420 var lr = dir == 'next' ? 'left' : 'right';
14421 pan.el.addClass(dir); // or prev
14422 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14423 cur.el.addClass(lr); // or right
14424 pan.el.addClass(lr);
14427 cur.el.on('transitionend', function() {
14428 Roo.log("trans end?");
14430 pan.el.removeClass([lr,dir]);
14431 pan.setActive(true);
14433 cur.el.removeClass([lr]);
14434 cur.setActive(false);
14436 _this.transition = false;
14438 }, this, { single: true } );
14442 cur.setActive(false);
14443 pan.setActive(true);
14447 showPanelNext : function()
14449 var i = this.indexOfPanel(this.getActivePanel());
14450 if (i > this.tabs.length) {
14453 this.showPanel(this.tabs[i+1]);
14455 showPanelPrev : function()
14457 var i = this.indexOfPanel(this.getActivePanel());
14461 this.showPanel(this.tabs[i-1]);
14472 Roo.apply(Roo.bootstrap.TabGroup, {
14476 * register a Navigation Group
14477 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14479 register : function(navgrp)
14481 this.groups[navgrp.navId] = navgrp;
14485 * fetch a Navigation Group based on the navigation ID
14486 * if one does not exist , it will get created.
14487 * @param {string} the navgroup to add
14488 * @returns {Roo.bootstrap.NavGroup} the navgroup
14490 get: function(navId) {
14491 if (typeof(this.groups[navId]) == 'undefined') {
14492 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14494 return this.groups[navId] ;
14509 * @class Roo.bootstrap.TabPanel
14510 * @extends Roo.bootstrap.Component
14511 * Bootstrap TabPanel class
14512 * @cfg {Boolean} active panel active
14513 * @cfg {String} html panel content
14514 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14515 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14519 * Create a new TabPanel
14520 * @param {Object} config The config object
14523 Roo.bootstrap.TabPanel = function(config){
14524 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14528 * Fires when the active status changes
14529 * @param {Roo.bootstrap.TabPanel} this
14530 * @param {Boolean} state the new state
14535 * @event beforedeactivate
14536 * Fires before a tab is de-activated - can be used to do validation on a form.
14537 * @param {Roo.bootstrap.TabPanel} this
14538 * @return {Boolean} false if there is an error
14541 'beforedeactivate': true
14544 this.tabId = this.tabId || Roo.id();
14548 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14555 getAutoCreate : function(){
14558 // item is needed for carousel - not sure if it has any effect otherwise
14559 cls: 'tab-pane item',
14560 html: this.html || ''
14564 cfg.cls += ' active';
14568 cfg.tabId = this.tabId;
14575 initEvents: function()
14577 Roo.log('-------- init events on tab panel ---------');
14579 var p = this.parent();
14580 this.navId = this.navId || p.navId;
14582 if (typeof(this.navId) != 'undefined') {
14583 // not really needed.. but just in case.. parent should be a NavGroup.
14584 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14585 Roo.log(['register', tg, this]);
14591 onRender : function(ct, position)
14593 // Roo.log("Call onRender: " + this.xtype);
14595 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14603 setActive: function(state)
14605 Roo.log("panel - set active " + this.tabId + "=" + state);
14607 this.active = state;
14609 this.el.removeClass('active');
14611 } else if (!this.el.hasClass('active')) {
14612 this.el.addClass('active');
14614 this.fireEvent('changed', this, state);
14631 * @class Roo.bootstrap.DateField
14632 * @extends Roo.bootstrap.Input
14633 * Bootstrap DateField class
14634 * @cfg {Number} weekStart default 0
14635 * @cfg {String} viewMode default empty, (months|years)
14636 * @cfg {String} minViewMode default empty, (months|years)
14637 * @cfg {Number} startDate default -Infinity
14638 * @cfg {Number} endDate default Infinity
14639 * @cfg {Boolean} todayHighlight default false
14640 * @cfg {Boolean} todayBtn default false
14641 * @cfg {Boolean} calendarWeeks default false
14642 * @cfg {Object} daysOfWeekDisabled default empty
14643 * @cfg {Boolean} singleMode default false (true | false)
14645 * @cfg {Boolean} keyboardNavigation default true
14646 * @cfg {String} language default en
14649 * Create a new DateField
14650 * @param {Object} config The config object
14653 Roo.bootstrap.DateField = function(config){
14654 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14658 * Fires when this field show.
14659 * @param {Roo.bootstrap.DateField} this
14660 * @param {Mixed} date The date value
14665 * Fires when this field hide.
14666 * @param {Roo.bootstrap.DateField} this
14667 * @param {Mixed} date The date value
14672 * Fires when select a date.
14673 * @param {Roo.bootstrap.DateField} this
14674 * @param {Mixed} date The date value
14680 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14683 * @cfg {String} format
14684 * The default date format string which can be overriden for localization support. The format must be
14685 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14689 * @cfg {String} altFormats
14690 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14691 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14693 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14701 todayHighlight : false,
14707 keyboardNavigation: true,
14709 calendarWeeks: false,
14711 startDate: -Infinity,
14715 daysOfWeekDisabled: [],
14719 singleMode : false,
14721 UTCDate: function()
14723 return new Date(Date.UTC.apply(Date, arguments));
14726 UTCToday: function()
14728 var today = new Date();
14729 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14732 getDate: function() {
14733 var d = this.getUTCDate();
14734 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14737 getUTCDate: function() {
14741 setDate: function(d) {
14742 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14745 setUTCDate: function(d) {
14747 this.setValue(this.formatDate(this.date));
14750 onRender: function(ct, position)
14753 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14755 this.language = this.language || 'en';
14756 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14757 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14759 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14760 this.format = this.format || 'm/d/y';
14761 this.isInline = false;
14762 this.isInput = true;
14763 this.component = this.el.select('.add-on', true).first() || false;
14764 this.component = (this.component && this.component.length === 0) ? false : this.component;
14765 this.hasInput = this.component && this.inputEL().length;
14767 if (typeof(this.minViewMode === 'string')) {
14768 switch (this.minViewMode) {
14770 this.minViewMode = 1;
14773 this.minViewMode = 2;
14776 this.minViewMode = 0;
14781 if (typeof(this.viewMode === 'string')) {
14782 switch (this.viewMode) {
14795 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14797 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14799 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14801 this.picker().on('mousedown', this.onMousedown, this);
14802 this.picker().on('click', this.onClick, this);
14804 this.picker().addClass('datepicker-dropdown');
14806 this.startViewMode = this.viewMode;
14808 if(this.singleMode){
14809 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14810 v.setVisibilityMode(Roo.Element.DISPLAY)
14814 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14815 v.setStyle('width', '189px');
14819 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14820 if(!this.calendarWeeks){
14825 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14826 v.attr('colspan', function(i, val){
14827 return parseInt(val) + 1;
14832 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14834 this.setStartDate(this.startDate);
14835 this.setEndDate(this.endDate);
14837 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14844 if(this.isInline) {
14849 picker : function()
14851 return this.pickerEl;
14852 // return this.el.select('.datepicker', true).first();
14855 fillDow: function()
14857 var dowCnt = this.weekStart;
14866 if(this.calendarWeeks){
14874 while (dowCnt < this.weekStart + 7) {
14878 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14882 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14885 fillMonths: function()
14888 var months = this.picker().select('>.datepicker-months td', true).first();
14890 months.dom.innerHTML = '';
14896 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14899 months.createChild(month);
14906 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;
14908 if (this.date < this.startDate) {
14909 this.viewDate = new Date(this.startDate);
14910 } else if (this.date > this.endDate) {
14911 this.viewDate = new Date(this.endDate);
14913 this.viewDate = new Date(this.date);
14921 var d = new Date(this.viewDate),
14922 year = d.getUTCFullYear(),
14923 month = d.getUTCMonth(),
14924 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14925 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14926 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14927 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14928 currentDate = this.date && this.date.valueOf(),
14929 today = this.UTCToday();
14931 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14933 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14935 // this.picker.select('>tfoot th.today').
14936 // .text(dates[this.language].today)
14937 // .toggle(this.todayBtn !== false);
14939 this.updateNavArrows();
14942 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14944 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14946 prevMonth.setUTCDate(day);
14948 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14950 var nextMonth = new Date(prevMonth);
14952 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14954 nextMonth = nextMonth.valueOf();
14956 var fillMonths = false;
14958 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14960 while(prevMonth.valueOf() < nextMonth) {
14963 if (prevMonth.getUTCDay() === this.weekStart) {
14965 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14973 if(this.calendarWeeks){
14974 // ISO 8601: First week contains first thursday.
14975 // ISO also states week starts on Monday, but we can be more abstract here.
14977 // Start of current week: based on weekstart/current date
14978 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14979 // Thursday of this week
14980 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14981 // First Thursday of year, year from thursday
14982 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14983 // Calendar week: ms between thursdays, div ms per day, div 7 days
14984 calWeek = (th - yth) / 864e5 / 7 + 1;
14986 fillMonths.cn.push({
14994 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14996 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14999 if (this.todayHighlight &&
15000 prevMonth.getUTCFullYear() == today.getFullYear() &&
15001 prevMonth.getUTCMonth() == today.getMonth() &&
15002 prevMonth.getUTCDate() == today.getDate()) {
15003 clsName += ' today';
15006 if (currentDate && prevMonth.valueOf() === currentDate) {
15007 clsName += ' active';
15010 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15011 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15012 clsName += ' disabled';
15015 fillMonths.cn.push({
15017 cls: 'day ' + clsName,
15018 html: prevMonth.getDate()
15021 prevMonth.setDate(prevMonth.getDate()+1);
15024 var currentYear = this.date && this.date.getUTCFullYear();
15025 var currentMonth = this.date && this.date.getUTCMonth();
15027 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15029 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15030 v.removeClass('active');
15032 if(currentYear === year && k === currentMonth){
15033 v.addClass('active');
15036 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15037 v.addClass('disabled');
15043 year = parseInt(year/10, 10) * 10;
15045 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15047 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15050 for (var i = -1; i < 11; i++) {
15051 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15053 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15061 showMode: function(dir)
15064 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15067 Roo.each(this.picker().select('>div',true).elements, function(v){
15068 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15071 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15076 if(this.isInline) return;
15078 this.picker().removeClass(['bottom', 'top']);
15080 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15082 * place to the top of element!
15086 this.picker().addClass('top');
15087 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15092 this.picker().addClass('bottom');
15094 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15097 parseDate : function(value)
15099 if(!value || value instanceof Date){
15102 var v = Date.parseDate(value, this.format);
15103 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15104 v = Date.parseDate(value, 'Y-m-d');
15106 if(!v && this.altFormats){
15107 if(!this.altFormatsArray){
15108 this.altFormatsArray = this.altFormats.split("|");
15110 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15111 v = Date.parseDate(value, this.altFormatsArray[i]);
15117 formatDate : function(date, fmt)
15119 return (!date || !(date instanceof Date)) ?
15120 date : date.dateFormat(fmt || this.format);
15123 onFocus : function()
15125 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15129 onBlur : function()
15131 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15133 var d = this.inputEl().getValue();
15142 this.picker().show();
15146 this.fireEvent('show', this, this.date);
15151 if(this.isInline) return;
15152 this.picker().hide();
15153 this.viewMode = this.startViewMode;
15156 this.fireEvent('hide', this, this.date);
15160 onMousedown: function(e)
15162 e.stopPropagation();
15163 e.preventDefault();
15168 Roo.bootstrap.DateField.superclass.keyup.call(this);
15172 setValue: function(v)
15175 // v can be a string or a date..
15178 var d = new Date(this.parseDate(v) ).clearTime();
15180 if(isNaN(d.getTime())){
15181 this.date = this.viewDate = '';
15182 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15186 v = this.formatDate(d);
15188 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15190 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15194 this.fireEvent('select', this, this.date);
15198 getValue: function()
15200 return this.formatDate(this.date);
15203 fireKey: function(e)
15205 if (!this.picker().isVisible()){
15206 if (e.keyCode == 27) // allow escape to hide and re-show picker
15211 var dateChanged = false,
15213 newDate, newViewDate;
15218 e.preventDefault();
15222 if (!this.keyboardNavigation) break;
15223 dir = e.keyCode == 37 ? -1 : 1;
15226 newDate = this.moveYear(this.date, dir);
15227 newViewDate = this.moveYear(this.viewDate, dir);
15228 } else if (e.shiftKey){
15229 newDate = this.moveMonth(this.date, dir);
15230 newViewDate = this.moveMonth(this.viewDate, dir);
15232 newDate = new Date(this.date);
15233 newDate.setUTCDate(this.date.getUTCDate() + dir);
15234 newViewDate = new Date(this.viewDate);
15235 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15237 if (this.dateWithinRange(newDate)){
15238 this.date = newDate;
15239 this.viewDate = newViewDate;
15240 this.setValue(this.formatDate(this.date));
15242 e.preventDefault();
15243 dateChanged = true;
15248 if (!this.keyboardNavigation) break;
15249 dir = e.keyCode == 38 ? -1 : 1;
15251 newDate = this.moveYear(this.date, dir);
15252 newViewDate = this.moveYear(this.viewDate, dir);
15253 } else if (e.shiftKey){
15254 newDate = this.moveMonth(this.date, dir);
15255 newViewDate = this.moveMonth(this.viewDate, dir);
15257 newDate = new Date(this.date);
15258 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15259 newViewDate = new Date(this.viewDate);
15260 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15262 if (this.dateWithinRange(newDate)){
15263 this.date = newDate;
15264 this.viewDate = newViewDate;
15265 this.setValue(this.formatDate(this.date));
15267 e.preventDefault();
15268 dateChanged = true;
15272 this.setValue(this.formatDate(this.date));
15274 e.preventDefault();
15277 this.setValue(this.formatDate(this.date));
15291 onClick: function(e)
15293 e.stopPropagation();
15294 e.preventDefault();
15296 var target = e.getTarget();
15298 if(target.nodeName.toLowerCase() === 'i'){
15299 target = Roo.get(target).dom.parentNode;
15302 var nodeName = target.nodeName;
15303 var className = target.className;
15304 var html = target.innerHTML;
15305 //Roo.log(nodeName);
15307 switch(nodeName.toLowerCase()) {
15309 switch(className) {
15315 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15316 switch(this.viewMode){
15318 this.viewDate = this.moveMonth(this.viewDate, dir);
15322 this.viewDate = this.moveYear(this.viewDate, dir);
15328 var date = new Date();
15329 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15331 this.setValue(this.formatDate(this.date));
15338 if (className.indexOf('disabled') < 0) {
15339 this.viewDate.setUTCDate(1);
15340 if (className.indexOf('month') > -1) {
15341 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15343 var year = parseInt(html, 10) || 0;
15344 this.viewDate.setUTCFullYear(year);
15348 if(this.singleMode){
15349 this.setValue(this.formatDate(this.viewDate));
15360 //Roo.log(className);
15361 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15362 var day = parseInt(html, 10) || 1;
15363 var year = this.viewDate.getUTCFullYear(),
15364 month = this.viewDate.getUTCMonth();
15366 if (className.indexOf('old') > -1) {
15373 } else if (className.indexOf('new') > -1) {
15381 //Roo.log([year,month,day]);
15382 this.date = this.UTCDate(year, month, day,0,0,0,0);
15383 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15385 //Roo.log(this.formatDate(this.date));
15386 this.setValue(this.formatDate(this.date));
15393 setStartDate: function(startDate)
15395 this.startDate = startDate || -Infinity;
15396 if (this.startDate !== -Infinity) {
15397 this.startDate = this.parseDate(this.startDate);
15400 this.updateNavArrows();
15403 setEndDate: function(endDate)
15405 this.endDate = endDate || Infinity;
15406 if (this.endDate !== Infinity) {
15407 this.endDate = this.parseDate(this.endDate);
15410 this.updateNavArrows();
15413 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15415 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15416 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15417 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15419 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15420 return parseInt(d, 10);
15423 this.updateNavArrows();
15426 updateNavArrows: function()
15428 if(this.singleMode){
15432 var d = new Date(this.viewDate),
15433 year = d.getUTCFullYear(),
15434 month = d.getUTCMonth();
15436 Roo.each(this.picker().select('.prev', true).elements, function(v){
15438 switch (this.viewMode) {
15441 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15447 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15454 Roo.each(this.picker().select('.next', true).elements, function(v){
15456 switch (this.viewMode) {
15459 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15465 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15473 moveMonth: function(date, dir)
15475 if (!dir) return date;
15476 var new_date = new Date(date.valueOf()),
15477 day = new_date.getUTCDate(),
15478 month = new_date.getUTCMonth(),
15479 mag = Math.abs(dir),
15481 dir = dir > 0 ? 1 : -1;
15484 // If going back one month, make sure month is not current month
15485 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15487 return new_date.getUTCMonth() == month;
15489 // If going forward one month, make sure month is as expected
15490 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15492 return new_date.getUTCMonth() != new_month;
15494 new_month = month + dir;
15495 new_date.setUTCMonth(new_month);
15496 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15497 if (new_month < 0 || new_month > 11)
15498 new_month = (new_month + 12) % 12;
15500 // For magnitudes >1, move one month at a time...
15501 for (var i=0; i<mag; i++)
15502 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15503 new_date = this.moveMonth(new_date, dir);
15504 // ...then reset the day, keeping it in the new month
15505 new_month = new_date.getUTCMonth();
15506 new_date.setUTCDate(day);
15508 return new_month != new_date.getUTCMonth();
15511 // Common date-resetting loop -- if date is beyond end of month, make it
15514 new_date.setUTCDate(--day);
15515 new_date.setUTCMonth(new_month);
15520 moveYear: function(date, dir)
15522 return this.moveMonth(date, dir*12);
15525 dateWithinRange: function(date)
15527 return date >= this.startDate && date <= this.endDate;
15533 this.picker().remove();
15538 Roo.apply(Roo.bootstrap.DateField, {
15549 html: '<i class="fa fa-arrow-left"/>'
15559 html: '<i class="fa fa-arrow-right"/>'
15601 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15602 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15603 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15604 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15605 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15618 navFnc: 'FullYear',
15623 navFnc: 'FullYear',
15628 Roo.apply(Roo.bootstrap.DateField, {
15632 cls: 'datepicker dropdown-menu roo-dynamic',
15636 cls: 'datepicker-days',
15640 cls: 'table-condensed',
15642 Roo.bootstrap.DateField.head,
15646 Roo.bootstrap.DateField.footer
15653 cls: 'datepicker-months',
15657 cls: 'table-condensed',
15659 Roo.bootstrap.DateField.head,
15660 Roo.bootstrap.DateField.content,
15661 Roo.bootstrap.DateField.footer
15668 cls: 'datepicker-years',
15672 cls: 'table-condensed',
15674 Roo.bootstrap.DateField.head,
15675 Roo.bootstrap.DateField.content,
15676 Roo.bootstrap.DateField.footer
15695 * @class Roo.bootstrap.TimeField
15696 * @extends Roo.bootstrap.Input
15697 * Bootstrap DateField class
15701 * Create a new TimeField
15702 * @param {Object} config The config object
15705 Roo.bootstrap.TimeField = function(config){
15706 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15710 * Fires when this field show.
15711 * @param {Roo.bootstrap.DateField} thisthis
15712 * @param {Mixed} date The date value
15717 * Fires when this field hide.
15718 * @param {Roo.bootstrap.DateField} this
15719 * @param {Mixed} date The date value
15724 * Fires when select a date.
15725 * @param {Roo.bootstrap.DateField} this
15726 * @param {Mixed} date The date value
15732 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15735 * @cfg {String} format
15736 * The default time format string which can be overriden for localization support. The format must be
15737 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15741 onRender: function(ct, position)
15744 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15746 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15748 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15750 this.pop = this.picker().select('>.datepicker-time',true).first();
15751 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15753 this.picker().on('mousedown', this.onMousedown, this);
15754 this.picker().on('click', this.onClick, this);
15756 this.picker().addClass('datepicker-dropdown');
15761 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15762 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15763 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15764 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15765 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15766 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15770 fireKey: function(e){
15771 if (!this.picker().isVisible()){
15772 if (e.keyCode == 27) { // allow escape to hide and re-show picker
15778 e.preventDefault();
15786 this.onTogglePeriod();
15789 this.onIncrementMinutes();
15792 this.onDecrementMinutes();
15801 onClick: function(e) {
15802 e.stopPropagation();
15803 e.preventDefault();
15806 picker : function()
15808 return this.el.select('.datepicker', true).first();
15811 fillTime: function()
15813 var time = this.pop.select('tbody', true).first();
15815 time.dom.innerHTML = '';
15830 cls: 'hours-up glyphicon glyphicon-chevron-up'
15850 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15871 cls: 'timepicker-hour',
15886 cls: 'timepicker-minute',
15901 cls: 'btn btn-primary period',
15923 cls: 'hours-down glyphicon glyphicon-chevron-down'
15943 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15961 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15968 var hours = this.time.getHours();
15969 var minutes = this.time.getMinutes();
15982 hours = hours - 12;
15986 hours = '0' + hours;
15990 minutes = '0' + minutes;
15993 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15994 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15995 this.pop.select('button', true).first().dom.innerHTML = period;
16001 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16003 var cls = ['bottom'];
16005 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16012 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16017 this.picker().addClass(cls.join('-'));
16021 Roo.each(cls, function(c){
16023 _this.picker().setTop(_this.inputEl().getHeight());
16027 _this.picker().setTop(0 - _this.picker().getHeight());
16032 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16036 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16043 onFocus : function()
16045 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16049 onBlur : function()
16051 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16057 this.picker().show();
16062 this.fireEvent('show', this, this.date);
16067 this.picker().hide();
16070 this.fireEvent('hide', this, this.date);
16073 setTime : function()
16076 this.setValue(this.time.format(this.format));
16078 this.fireEvent('select', this, this.date);
16083 onMousedown: function(e){
16084 e.stopPropagation();
16085 e.preventDefault();
16088 onIncrementHours: function()
16090 Roo.log('onIncrementHours');
16091 this.time = this.time.add(Date.HOUR, 1);
16096 onDecrementHours: function()
16098 Roo.log('onDecrementHours');
16099 this.time = this.time.add(Date.HOUR, -1);
16103 onIncrementMinutes: function()
16105 Roo.log('onIncrementMinutes');
16106 this.time = this.time.add(Date.MINUTE, 1);
16110 onDecrementMinutes: function()
16112 Roo.log('onDecrementMinutes');
16113 this.time = this.time.add(Date.MINUTE, -1);
16117 onTogglePeriod: function()
16119 Roo.log('onTogglePeriod');
16120 this.time = this.time.add(Date.HOUR, 12);
16127 Roo.apply(Roo.bootstrap.TimeField, {
16157 cls: 'btn btn-info ok',
16169 Roo.apply(Roo.bootstrap.TimeField, {
16173 cls: 'datepicker dropdown-menu',
16177 cls: 'datepicker-time',
16181 cls: 'table-condensed',
16183 Roo.bootstrap.TimeField.content,
16184 Roo.bootstrap.TimeField.footer
16203 * @class Roo.bootstrap.MonthField
16204 * @extends Roo.bootstrap.Input
16205 * Bootstrap MonthField class
16207 * @cfg {String} language default en
16210 * Create a new MonthField
16211 * @param {Object} config The config object
16214 Roo.bootstrap.MonthField = function(config){
16215 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16220 * Fires when this field show.
16221 * @param {Roo.bootstrap.MonthField} this
16222 * @param {Mixed} date The date value
16227 * Fires when this field hide.
16228 * @param {Roo.bootstrap.MonthField} this
16229 * @param {Mixed} date The date value
16234 * Fires when select a date.
16235 * @param {Roo.bootstrap.MonthField} this
16236 * @param {Mixed} date The date value
16242 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16244 onRender: function(ct, position)
16247 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16249 this.language = this.language || 'en';
16250 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16251 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16253 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16254 this.isInline = false;
16255 this.isInput = true;
16256 this.component = this.el.select('.add-on', true).first() || false;
16257 this.component = (this.component && this.component.length === 0) ? false : this.component;
16258 this.hasInput = this.component && this.inputEL().length;
16260 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16262 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16264 this.picker().on('mousedown', this.onMousedown, this);
16265 this.picker().on('click', this.onClick, this);
16267 this.picker().addClass('datepicker-dropdown');
16269 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16270 v.setStyle('width', '189px');
16277 if(this.isInline) {
16283 setValue: function(v)
16285 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16289 this.fireEvent('select', this, this.date);
16293 getValue: function()
16298 onClick: function(e)
16300 e.stopPropagation();
16301 e.preventDefault();
16303 var target = e.getTarget();
16305 if(target.nodeName.toLowerCase() === 'i'){
16306 target = Roo.get(target).dom.parentNode;
16309 var nodeName = target.nodeName;
16310 var className = target.className;
16311 var html = target.innerHTML;
16313 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16317 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16319 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16325 picker : function()
16327 return this.pickerEl;
16330 fillMonths: function()
16333 var months = this.picker().select('>.datepicker-months td', true).first();
16335 months.dom.innerHTML = '';
16341 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16344 months.createChild(month);
16353 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16354 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16357 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16358 e.removeClass('active');
16360 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16361 e.addClass('active');
16368 if(this.isInline) return;
16370 this.picker().removeClass(['bottom', 'top']);
16372 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16374 * place to the top of element!
16378 this.picker().addClass('top');
16379 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16384 this.picker().addClass('bottom');
16386 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16389 onFocus : function()
16391 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16395 onBlur : function()
16397 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16399 var d = this.inputEl().getValue();
16408 this.picker().show();
16409 this.picker().select('>.datepicker-months', true).first().show();
16413 this.fireEvent('show', this, this.date);
16418 if(this.isInline) return;
16419 this.picker().hide();
16420 this.fireEvent('hide', this, this.date);
16424 onMousedown: function(e)
16426 e.stopPropagation();
16427 e.preventDefault();
16432 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16436 fireKey: function(e)
16438 if (!this.picker().isVisible()){
16439 if (e.keyCode == 27) // allow escape to hide and re-show picker
16449 e.preventDefault();
16453 dir = e.keyCode == 37 ? -1 : 1;
16455 this.vIndex = this.vIndex + dir;
16457 if(this.vIndex < 0){
16461 if(this.vIndex > 11){
16465 if(isNaN(this.vIndex)){
16469 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16475 dir = e.keyCode == 38 ? -1 : 1;
16477 this.vIndex = this.vIndex + dir * 4;
16479 if(this.vIndex < 0){
16483 if(this.vIndex > 11){
16487 if(isNaN(this.vIndex)){
16491 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16496 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16497 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16501 e.preventDefault();
16504 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16505 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16521 this.picker().remove();
16526 Roo.apply(Roo.bootstrap.MonthField, {
16545 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16546 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16551 Roo.apply(Roo.bootstrap.MonthField, {
16555 cls: 'datepicker dropdown-menu roo-dynamic',
16559 cls: 'datepicker-months',
16563 cls: 'table-condensed',
16565 Roo.bootstrap.DateField.content
16585 * @class Roo.bootstrap.CheckBox
16586 * @extends Roo.bootstrap.Input
16587 * Bootstrap CheckBox class
16589 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16590 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16591 * @cfg {String} boxLabel The text that appears beside the checkbox
16592 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16593 * @cfg {Boolean} checked initnal the element
16594 * @cfg {Boolean} inline inline the element (default false)
16595 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16598 * Create a new CheckBox
16599 * @param {Object} config The config object
16602 Roo.bootstrap.CheckBox = function(config){
16603 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16608 * Fires when the element is checked or unchecked.
16609 * @param {Roo.bootstrap.CheckBox} this This input
16610 * @param {Boolean} checked The new checked value
16617 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16619 invalidClass : "has-warning",
16620 validClass : "has-success",
16621 inputType: 'checkbox',
16629 getAutoCreate : function()
16631 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16637 cfg.cls = 'form-group ' + this.inputType; //input-group
16640 cfg.cls += ' ' + this.inputType + '-inline';
16646 type : this.inputType,
16647 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16648 cls : 'roo-' + this.inputType, //'form-box',
16649 placeholder : this.placeholder || ''
16653 if (this.weight) { // Validity check?
16654 cfg.cls += " " + this.inputType + "-" + this.weight;
16657 if (this.disabled) {
16658 input.disabled=true;
16662 input.checked = this.checked;
16666 input.name = this.name;
16670 input.cls += ' input-' + this.size;
16675 ['xs','sm','md','lg'].map(function(size){
16676 if (settings[size]) {
16677 cfg.cls += ' col-' + size + '-' + settings[size];
16681 var inputblock = input;
16683 if (this.before || this.after) {
16686 cls : 'input-group',
16691 inputblock.cn.push({
16693 cls : 'input-group-addon',
16698 inputblock.cn.push(input);
16701 inputblock.cn.push({
16703 cls : 'input-group-addon',
16710 if (align ==='left' && this.fieldLabel.length) {
16711 Roo.log("left and has label");
16717 cls : 'control-label col-md-' + this.labelWidth,
16718 html : this.fieldLabel
16722 cls : "col-md-" + (12 - this.labelWidth),
16729 } else if ( this.fieldLabel.length) {
16734 tag: this.boxLabel ? 'span' : 'label',
16736 cls: 'control-label box-input-label',
16737 //cls : 'input-group-addon',
16738 html : this.fieldLabel
16748 Roo.log(" no label && no align");
16749 cfg.cn = [ inputblock ] ;
16754 var boxLabelCfg = {
16756 //'for': id, // box label is handled by onclick - so no for...
16758 html: this.boxLabel
16762 boxLabelCfg.tooltip = this.tooltip;
16765 cfg.cn.push(boxLabelCfg);
16775 * return the real input element.
16777 inputEl: function ()
16779 return this.el.select('input.roo-' + this.inputType,true).first();
16782 labelEl: function()
16784 return this.el.select('label.control-label',true).first();
16786 /* depricated... */
16790 return this.labelEl();
16793 initEvents : function()
16795 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16797 this.inputEl().on('click', this.onClick, this);
16799 if (this.boxLabel) {
16800 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16803 this.startValue = this.getValue();
16806 Roo.bootstrap.CheckBox.register(this);
16810 onClick : function()
16812 this.setChecked(!this.checked);
16815 setChecked : function(state,suppressEvent)
16817 this.startValue = this.getValue();
16819 if(this.inputType == 'radio'){
16821 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16822 e.dom.checked = false;
16825 this.inputEl().dom.checked = true;
16827 this.inputEl().dom.value = this.inputValue;
16829 if(suppressEvent !== true){
16830 this.fireEvent('check', this, true);
16836 this.checked = state;
16838 this.inputEl().dom.checked = state;
16840 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16842 if(suppressEvent !== true){
16843 this.fireEvent('check', this, state);
16847 getValue : function()
16849 if(this.inputType == 'radio'){
16850 return this.getGroupValue();
16853 return this.inputEl().getValue();
16857 getGroupValue : function()
16859 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16863 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16866 setValue : function(v,suppressEvent)
16868 if(this.inputType == 'radio'){
16869 this.setGroupValue(v, suppressEvent);
16874 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16878 setGroupValue : function(v, suppressEvent)
16880 this.startValue = this.getValue();
16882 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16883 e.dom.checked = false;
16885 if(e.dom.value == v){
16886 e.dom.checked = true;
16890 if(suppressEvent !== true){
16891 this.fireEvent('check', this, true);
16897 validate : function()
16901 (this.inputType == 'radio' && this.getValue().length) ||
16902 (this.inputType == 'checkbox' && this.validateGroup())
16908 this.markInvalid();
16912 validateGroup : function()
16915 return (this.getValue() == this.inputValue) ? true : false;
16918 var group = Roo.bootstrap.CheckBox.get(this.groupId);
16926 for(var i in group){
16931 r = (group[i].getValue() == group[i].inputValue) ? true : false;
16938 * Mark this field as valid
16940 markValid : function()
16944 this.fireEvent('valid', this);
16946 if(this.inputType == 'radio'){
16947 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16948 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
16949 e.findParent('.form-group', false, true).addClass(_this.validClass);
16956 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
16957 this.el.findParent('.form-group', false, true).addClass(this.validClass);
16961 var group = Roo.bootstrap.CheckBox.get(this.groupId);
16967 for(var i in group){
16968 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
16969 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
16974 * Mark this field as invalid
16975 * @param {String} msg The validation message
16977 markInvalid : function(msg)
16981 this.fireEvent('invalid', this, msg);
16983 if(this.inputType == 'radio'){
16984 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16985 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
16986 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
16993 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
16994 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
16998 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17004 for(var i in group){
17005 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17006 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17013 Roo.apply(Roo.bootstrap.CheckBox, {
17018 * register a CheckBox Group
17019 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17021 register : function(checkbox)
17023 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17024 this.groups[checkbox.groupId] = {};
17027 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17031 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17035 * fetch a CheckBox Group based on the group ID
17036 * @param {string} the group ID
17037 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17039 get: function(groupId) {
17040 if (typeof(this.groups[groupId]) == 'undefined') {
17044 return this.groups[groupId] ;
17056 *<div class="radio">
17058 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17059 Option one is this and that—be sure to include why it's great
17066 *<label class="radio-inline">fieldLabel</label>
17067 *<label class="radio-inline">
17068 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17076 * @class Roo.bootstrap.Radio
17077 * @extends Roo.bootstrap.CheckBox
17078 * Bootstrap Radio class
17081 * Create a new Radio
17082 * @param {Object} config The config object
17085 Roo.bootstrap.Radio = function(config){
17086 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17090 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17092 inputType: 'radio',
17096 getAutoCreate : function()
17098 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17099 align = align || 'left'; // default...
17106 tag : this.inline ? 'span' : 'div',
17111 var inline = this.inline ? ' radio-inline' : '';
17115 // does not need for, as we wrap the input with it..
17117 cls : 'control-label box-label' + inline,
17120 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17124 //cls : 'control-label' + inline,
17125 html : this.fieldLabel,
17126 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17135 type : this.inputType,
17136 //value : (!this.checked) ? this.valueOff : this.inputValue,
17137 value : this.inputValue,
17139 placeholder : this.placeholder || '' // ?? needed????
17142 if (this.weight) { // Validity check?
17143 input.cls += " radio-" + this.weight;
17145 if (this.disabled) {
17146 input.disabled=true;
17150 input.checked = this.checked;
17154 input.name = this.name;
17158 input.cls += ' input-' + this.size;
17161 //?? can span's inline have a width??
17164 ['xs','sm','md','lg'].map(function(size){
17165 if (settings[size]) {
17166 cfg.cls += ' col-' + size + '-' + settings[size];
17170 var inputblock = input;
17172 if (this.before || this.after) {
17175 cls : 'input-group',
17180 inputblock.cn.push({
17182 cls : 'input-group-addon',
17186 inputblock.cn.push(input);
17188 inputblock.cn.push({
17190 cls : 'input-group-addon',
17198 if (this.fieldLabel && this.fieldLabel.length) {
17199 cfg.cn.push(fieldLabel);
17202 // normal bootstrap puts the input inside the label.
17203 // however with our styled version - it has to go after the input.
17205 //lbl.cn.push(inputblock);
17209 cls: 'radio' + inline,
17216 cfg.cn.push( lblwrap);
17221 html: this.boxLabel
17230 initEvents : function()
17232 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17234 this.inputEl().on('click', this.onClick, this);
17235 if (this.boxLabel) {
17236 Roo.log('find label')
17237 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17242 inputEl: function ()
17244 return this.el.select('input.roo-radio',true).first();
17246 onClick : function()
17249 this.setChecked(true);
17252 setChecked : function(state,suppressEvent)
17255 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17256 v.dom.checked = false;
17259 Roo.log(this.inputEl().dom);
17260 this.checked = state;
17261 this.inputEl().dom.checked = state;
17263 if(suppressEvent !== true){
17264 this.fireEvent('check', this, state);
17267 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17271 getGroupValue : function()
17274 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17275 if(v.dom.checked == true){
17276 value = v.dom.value;
17284 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17285 * @return {Mixed} value The field value
17287 getValue : function(){
17288 return this.getGroupValue();
17294 //<script type="text/javascript">
17297 * Based Ext JS Library 1.1.1
17298 * Copyright(c) 2006-2007, Ext JS, LLC.
17304 * @class Roo.HtmlEditorCore
17305 * @extends Roo.Component
17306 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17308 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17311 Roo.HtmlEditorCore = function(config){
17314 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17319 * @event initialize
17320 * Fires when the editor is fully initialized (including the iframe)
17321 * @param {Roo.HtmlEditorCore} this
17326 * Fires when the editor is first receives the focus. Any insertion must wait
17327 * until after this event.
17328 * @param {Roo.HtmlEditorCore} this
17332 * @event beforesync
17333 * Fires before the textarea is updated with content from the editor iframe. Return false
17334 * to cancel the sync.
17335 * @param {Roo.HtmlEditorCore} this
17336 * @param {String} html
17340 * @event beforepush
17341 * Fires before the iframe editor is updated with content from the textarea. Return false
17342 * to cancel the push.
17343 * @param {Roo.HtmlEditorCore} this
17344 * @param {String} html
17349 * Fires when the textarea is updated with content from the editor iframe.
17350 * @param {Roo.HtmlEditorCore} this
17351 * @param {String} html
17356 * Fires when the iframe editor is updated with content from the textarea.
17357 * @param {Roo.HtmlEditorCore} this
17358 * @param {String} html
17363 * @event editorevent
17364 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17365 * @param {Roo.HtmlEditorCore} this
17371 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17373 // defaults : white / black...
17374 this.applyBlacklists();
17381 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17385 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17391 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17396 * @cfg {Number} height (in pixels)
17400 * @cfg {Number} width (in pixels)
17405 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17408 stylesheets: false,
17413 // private properties
17414 validationEvent : false,
17416 initialized : false,
17418 sourceEditMode : false,
17419 onFocus : Roo.emptyFn,
17421 hideMode:'offsets',
17425 // blacklist + whitelisted elements..
17432 * Protected method that will not generally be called directly. It
17433 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17434 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17436 getDocMarkup : function(){
17440 // inherit styels from page...??
17441 if (this.stylesheets === false) {
17443 Roo.get(document.head).select('style').each(function(node) {
17444 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17447 Roo.get(document.head).select('link').each(function(node) {
17448 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17451 } else if (!this.stylesheets.length) {
17453 st = '<style type="text/css">' +
17454 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17460 st += '<style type="text/css">' +
17461 'IMG { cursor: pointer } ' +
17465 return '<html><head>' + st +
17466 //<style type="text/css">' +
17467 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17469 ' </head><body class="roo-htmleditor-body"></body></html>';
17473 onRender : function(ct, position)
17476 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17477 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17480 this.el.dom.style.border = '0 none';
17481 this.el.dom.setAttribute('tabIndex', -1);
17482 this.el.addClass('x-hidden hide');
17486 if(Roo.isIE){ // fix IE 1px bogus margin
17487 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17491 this.frameId = Roo.id();
17495 var iframe = this.owner.wrap.createChild({
17497 cls: 'form-control', // bootstrap..
17499 name: this.frameId,
17500 frameBorder : 'no',
17501 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17506 this.iframe = iframe.dom;
17508 this.assignDocWin();
17510 this.doc.designMode = 'on';
17513 this.doc.write(this.getDocMarkup());
17517 var task = { // must defer to wait for browser to be ready
17519 //console.log("run task?" + this.doc.readyState);
17520 this.assignDocWin();
17521 if(this.doc.body || this.doc.readyState == 'complete'){
17523 this.doc.designMode="on";
17527 Roo.TaskMgr.stop(task);
17528 this.initEditor.defer(10, this);
17535 Roo.TaskMgr.start(task);
17540 onResize : function(w, h)
17542 Roo.log('resize: ' +w + ',' + h );
17543 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17547 if(typeof w == 'number'){
17549 this.iframe.style.width = w + 'px';
17551 if(typeof h == 'number'){
17553 this.iframe.style.height = h + 'px';
17555 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17562 * Toggles the editor between standard and source edit mode.
17563 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17565 toggleSourceEdit : function(sourceEditMode){
17567 this.sourceEditMode = sourceEditMode === true;
17569 if(this.sourceEditMode){
17571 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17574 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17575 //this.iframe.className = '';
17578 //this.setSize(this.owner.wrap.getSize());
17579 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17586 * Protected method that will not generally be called directly. If you need/want
17587 * custom HTML cleanup, this is the method you should override.
17588 * @param {String} html The HTML to be cleaned
17589 * return {String} The cleaned HTML
17591 cleanHtml : function(html){
17592 html = String(html);
17593 if(html.length > 5){
17594 if(Roo.isSafari){ // strip safari nonsense
17595 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17598 if(html == ' '){
17605 * HTML Editor -> Textarea
17606 * Protected method that will not generally be called directly. Syncs the contents
17607 * of the editor iframe with the textarea.
17609 syncValue : function(){
17610 if(this.initialized){
17611 var bd = (this.doc.body || this.doc.documentElement);
17612 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17613 var html = bd.innerHTML;
17615 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17616 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17618 html = '<div style="'+m[0]+'">' + html + '</div>';
17621 html = this.cleanHtml(html);
17622 // fix up the special chars.. normaly like back quotes in word...
17623 // however we do not want to do this with chinese..
17624 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17625 var cc = b.charCodeAt();
17627 (cc >= 0x4E00 && cc < 0xA000 ) ||
17628 (cc >= 0x3400 && cc < 0x4E00 ) ||
17629 (cc >= 0xf900 && cc < 0xfb00 )
17635 if(this.owner.fireEvent('beforesync', this, html) !== false){
17636 this.el.dom.value = html;
17637 this.owner.fireEvent('sync', this, html);
17643 * Protected method that will not generally be called directly. Pushes the value of the textarea
17644 * into the iframe editor.
17646 pushValue : function(){
17647 if(this.initialized){
17648 var v = this.el.dom.value.trim();
17650 // if(v.length < 1){
17654 if(this.owner.fireEvent('beforepush', this, v) !== false){
17655 var d = (this.doc.body || this.doc.documentElement);
17657 this.cleanUpPaste();
17658 this.el.dom.value = d.innerHTML;
17659 this.owner.fireEvent('push', this, v);
17665 deferFocus : function(){
17666 this.focus.defer(10, this);
17670 focus : function(){
17671 if(this.win && !this.sourceEditMode){
17678 assignDocWin: function()
17680 var iframe = this.iframe;
17683 this.doc = iframe.contentWindow.document;
17684 this.win = iframe.contentWindow;
17686 // if (!Roo.get(this.frameId)) {
17689 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17690 // this.win = Roo.get(this.frameId).dom.contentWindow;
17692 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17696 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17697 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17702 initEditor : function(){
17703 //console.log("INIT EDITOR");
17704 this.assignDocWin();
17708 this.doc.designMode="on";
17710 this.doc.write(this.getDocMarkup());
17713 var dbody = (this.doc.body || this.doc.documentElement);
17714 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17715 // this copies styles from the containing element into thsi one..
17716 // not sure why we need all of this..
17717 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17719 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17720 //ss['background-attachment'] = 'fixed'; // w3c
17721 dbody.bgProperties = 'fixed'; // ie
17722 //Roo.DomHelper.applyStyles(dbody, ss);
17723 Roo.EventManager.on(this.doc, {
17724 //'mousedown': this.onEditorEvent,
17725 'mouseup': this.onEditorEvent,
17726 'dblclick': this.onEditorEvent,
17727 'click': this.onEditorEvent,
17728 'keyup': this.onEditorEvent,
17733 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17735 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17736 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17738 this.initialized = true;
17740 this.owner.fireEvent('initialize', this);
17745 onDestroy : function(){
17751 //for (var i =0; i < this.toolbars.length;i++) {
17752 // // fixme - ask toolbars for heights?
17753 // this.toolbars[i].onDestroy();
17756 //this.wrap.dom.innerHTML = '';
17757 //this.wrap.remove();
17762 onFirstFocus : function(){
17764 this.assignDocWin();
17767 this.activated = true;
17770 if(Roo.isGecko){ // prevent silly gecko errors
17772 var s = this.win.getSelection();
17773 if(!s.focusNode || s.focusNode.nodeType != 3){
17774 var r = s.getRangeAt(0);
17775 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17780 this.execCmd('useCSS', true);
17781 this.execCmd('styleWithCSS', false);
17784 this.owner.fireEvent('activate', this);
17788 adjustFont: function(btn){
17789 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17790 //if(Roo.isSafari){ // safari
17793 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17794 if(Roo.isSafari){ // safari
17795 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17796 v = (v < 10) ? 10 : v;
17797 v = (v > 48) ? 48 : v;
17798 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17803 v = Math.max(1, v+adjust);
17805 this.execCmd('FontSize', v );
17808 onEditorEvent : function(e){
17809 this.owner.fireEvent('editorevent', this, e);
17810 // this.updateToolbar();
17811 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17814 insertTag : function(tg)
17816 // could be a bit smarter... -> wrap the current selected tRoo..
17817 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17819 range = this.createRange(this.getSelection());
17820 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17821 wrappingNode.appendChild(range.extractContents());
17822 range.insertNode(wrappingNode);
17829 this.execCmd("formatblock", tg);
17833 insertText : function(txt)
17837 var range = this.createRange();
17838 range.deleteContents();
17839 //alert(Sender.getAttribute('label'));
17841 range.insertNode(this.doc.createTextNode(txt));
17847 * Executes a Midas editor command on the editor document and performs necessary focus and
17848 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17849 * @param {String} cmd The Midas command
17850 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17852 relayCmd : function(cmd, value){
17854 this.execCmd(cmd, value);
17855 this.owner.fireEvent('editorevent', this);
17856 //this.updateToolbar();
17857 this.owner.deferFocus();
17861 * Executes a Midas editor command directly on the editor document.
17862 * For visual commands, you should use {@link #relayCmd} instead.
17863 * <b>This should only be called after the editor is initialized.</b>
17864 * @param {String} cmd The Midas command
17865 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17867 execCmd : function(cmd, value){
17868 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17875 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17877 * @param {String} text | dom node..
17879 insertAtCursor : function(text)
17884 if(!this.activated){
17890 var r = this.doc.selection.createRange();
17901 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17905 // from jquery ui (MIT licenced)
17907 var win = this.win;
17909 if (win.getSelection && win.getSelection().getRangeAt) {
17910 range = win.getSelection().getRangeAt(0);
17911 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17912 range.insertNode(node);
17913 } else if (win.document.selection && win.document.selection.createRange) {
17914 // no firefox support
17915 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17916 win.document.selection.createRange().pasteHTML(txt);
17918 // no firefox support
17919 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17920 this.execCmd('InsertHTML', txt);
17929 mozKeyPress : function(e){
17931 var c = e.getCharCode(), cmd;
17934 c = String.fromCharCode(c).toLowerCase();
17948 this.cleanUpPaste.defer(100, this);
17956 e.preventDefault();
17964 fixKeys : function(){ // load time branching for fastest keydown performance
17966 return function(e){
17967 var k = e.getKey(), r;
17970 r = this.doc.selection.createRange();
17973 r.pasteHTML('    ');
17980 r = this.doc.selection.createRange();
17982 var target = r.parentElement();
17983 if(!target || target.tagName.toLowerCase() != 'li'){
17985 r.pasteHTML('<br />');
17991 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17992 this.cleanUpPaste.defer(100, this);
17998 }else if(Roo.isOpera){
17999 return function(e){
18000 var k = e.getKey();
18004 this.execCmd('InsertHTML','    ');
18007 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18008 this.cleanUpPaste.defer(100, this);
18013 }else if(Roo.isSafari){
18014 return function(e){
18015 var k = e.getKey();
18019 this.execCmd('InsertText','\t');
18023 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18024 this.cleanUpPaste.defer(100, this);
18032 getAllAncestors: function()
18034 var p = this.getSelectedNode();
18037 a.push(p); // push blank onto stack..
18038 p = this.getParentElement();
18042 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18046 a.push(this.doc.body);
18050 lastSelNode : false,
18053 getSelection : function()
18055 this.assignDocWin();
18056 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18059 getSelectedNode: function()
18061 // this may only work on Gecko!!!
18063 // should we cache this!!!!
18068 var range = this.createRange(this.getSelection()).cloneRange();
18071 var parent = range.parentElement();
18073 var testRange = range.duplicate();
18074 testRange.moveToElementText(parent);
18075 if (testRange.inRange(range)) {
18078 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18081 parent = parent.parentElement;
18086 // is ancestor a text element.
18087 var ac = range.commonAncestorContainer;
18088 if (ac.nodeType == 3) {
18089 ac = ac.parentNode;
18092 var ar = ac.childNodes;
18095 var other_nodes = [];
18096 var has_other_nodes = false;
18097 for (var i=0;i<ar.length;i++) {
18098 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18101 // fullly contained node.
18103 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18108 // probably selected..
18109 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18110 other_nodes.push(ar[i]);
18114 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18119 has_other_nodes = true;
18121 if (!nodes.length && other_nodes.length) {
18122 nodes= other_nodes;
18124 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18130 createRange: function(sel)
18132 // this has strange effects when using with
18133 // top toolbar - not sure if it's a great idea.
18134 //this.editor.contentWindow.focus();
18135 if (typeof sel != "undefined") {
18137 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18139 return this.doc.createRange();
18142 return this.doc.createRange();
18145 getParentElement: function()
18148 this.assignDocWin();
18149 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18151 var range = this.createRange(sel);
18154 var p = range.commonAncestorContainer;
18155 while (p.nodeType == 3) { // text node
18166 * Range intersection.. the hard stuff...
18170 * [ -- selected range --- ]
18174 * if end is before start or hits it. fail.
18175 * if start is after end or hits it fail.
18177 * if either hits (but other is outside. - then it's not
18183 // @see http://www.thismuchiknow.co.uk/?p=64.
18184 rangeIntersectsNode : function(range, node)
18186 var nodeRange = node.ownerDocument.createRange();
18188 nodeRange.selectNode(node);
18190 nodeRange.selectNodeContents(node);
18193 var rangeStartRange = range.cloneRange();
18194 rangeStartRange.collapse(true);
18196 var rangeEndRange = range.cloneRange();
18197 rangeEndRange.collapse(false);
18199 var nodeStartRange = nodeRange.cloneRange();
18200 nodeStartRange.collapse(true);
18202 var nodeEndRange = nodeRange.cloneRange();
18203 nodeEndRange.collapse(false);
18205 return rangeStartRange.compareBoundaryPoints(
18206 Range.START_TO_START, nodeEndRange) == -1 &&
18207 rangeEndRange.compareBoundaryPoints(
18208 Range.START_TO_START, nodeStartRange) == 1;
18212 rangeCompareNode : function(range, node)
18214 var nodeRange = node.ownerDocument.createRange();
18216 nodeRange.selectNode(node);
18218 nodeRange.selectNodeContents(node);
18222 range.collapse(true);
18224 nodeRange.collapse(true);
18226 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18227 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18229 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18231 var nodeIsBefore = ss == 1;
18232 var nodeIsAfter = ee == -1;
18234 if (nodeIsBefore && nodeIsAfter)
18236 if (!nodeIsBefore && nodeIsAfter)
18237 return 1; //right trailed.
18239 if (nodeIsBefore && !nodeIsAfter)
18240 return 2; // left trailed.
18245 // private? - in a new class?
18246 cleanUpPaste : function()
18248 // cleans up the whole document..
18249 Roo.log('cleanuppaste');
18251 this.cleanUpChildren(this.doc.body);
18252 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18253 if (clean != this.doc.body.innerHTML) {
18254 this.doc.body.innerHTML = clean;
18259 cleanWordChars : function(input) {// change the chars to hex code
18260 var he = Roo.HtmlEditorCore;
18262 var output = input;
18263 Roo.each(he.swapCodes, function(sw) {
18264 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18266 output = output.replace(swapper, sw[1]);
18273 cleanUpChildren : function (n)
18275 if (!n.childNodes.length) {
18278 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18279 this.cleanUpChild(n.childNodes[i]);
18286 cleanUpChild : function (node)
18289 //console.log(node);
18290 if (node.nodeName == "#text") {
18291 // clean up silly Windows -- stuff?
18294 if (node.nodeName == "#comment") {
18295 node.parentNode.removeChild(node);
18296 // clean up silly Windows -- stuff?
18299 var lcname = node.tagName.toLowerCase();
18300 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18301 // whitelist of tags..
18303 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18305 node.parentNode.removeChild(node);
18310 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18312 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18313 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18315 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18316 // remove_keep_children = true;
18319 if (remove_keep_children) {
18320 this.cleanUpChildren(node);
18321 // inserts everything just before this node...
18322 while (node.childNodes.length) {
18323 var cn = node.childNodes[0];
18324 node.removeChild(cn);
18325 node.parentNode.insertBefore(cn, node);
18327 node.parentNode.removeChild(node);
18331 if (!node.attributes || !node.attributes.length) {
18332 this.cleanUpChildren(node);
18336 function cleanAttr(n,v)
18339 if (v.match(/^\./) || v.match(/^\//)) {
18342 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18345 if (v.match(/^#/)) {
18348 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18349 node.removeAttribute(n);
18353 var cwhite = this.cwhite;
18354 var cblack = this.cblack;
18356 function cleanStyle(n,v)
18358 if (v.match(/expression/)) { //XSS?? should we even bother..
18359 node.removeAttribute(n);
18363 var parts = v.split(/;/);
18366 Roo.each(parts, function(p) {
18367 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18371 var l = p.split(':').shift().replace(/\s+/g,'');
18372 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18374 if ( cwhite.length && cblack.indexOf(l) > -1) {
18375 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18376 //node.removeAttribute(n);
18380 // only allow 'c whitelisted system attributes'
18381 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18382 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18383 //node.removeAttribute(n);
18393 if (clean.length) {
18394 node.setAttribute(n, clean.join(';'));
18396 node.removeAttribute(n);
18402 for (var i = node.attributes.length-1; i > -1 ; i--) {
18403 var a = node.attributes[i];
18406 if (a.name.toLowerCase().substr(0,2)=='on') {
18407 node.removeAttribute(a.name);
18410 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18411 node.removeAttribute(a.name);
18414 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18415 cleanAttr(a.name,a.value); // fixme..
18418 if (a.name == 'style') {
18419 cleanStyle(a.name,a.value);
18422 /// clean up MS crap..
18423 // tecnically this should be a list of valid class'es..
18426 if (a.name == 'class') {
18427 if (a.value.match(/^Mso/)) {
18428 node.className = '';
18431 if (a.value.match(/body/)) {
18432 node.className = '';
18443 this.cleanUpChildren(node);
18448 * Clean up MS wordisms...
18450 cleanWord : function(node)
18453 var cleanWordChildren = function()
18455 if (!node.childNodes.length) {
18458 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18459 _t.cleanWord(node.childNodes[i]);
18465 this.cleanWord(this.doc.body);
18468 if (node.nodeName == "#text") {
18469 // clean up silly Windows -- stuff?
18472 if (node.nodeName == "#comment") {
18473 node.parentNode.removeChild(node);
18474 // clean up silly Windows -- stuff?
18478 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18479 node.parentNode.removeChild(node);
18483 // remove - but keep children..
18484 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18485 while (node.childNodes.length) {
18486 var cn = node.childNodes[0];
18487 node.removeChild(cn);
18488 node.parentNode.insertBefore(cn, node);
18490 node.parentNode.removeChild(node);
18491 cleanWordChildren();
18495 if (node.className.length) {
18497 var cn = node.className.split(/\W+/);
18499 Roo.each(cn, function(cls) {
18500 if (cls.match(/Mso[a-zA-Z]+/)) {
18505 node.className = cna.length ? cna.join(' ') : '';
18507 node.removeAttribute("class");
18511 if (node.hasAttribute("lang")) {
18512 node.removeAttribute("lang");
18515 if (node.hasAttribute("style")) {
18517 var styles = node.getAttribute("style").split(";");
18519 Roo.each(styles, function(s) {
18520 if (!s.match(/:/)) {
18523 var kv = s.split(":");
18524 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18527 // what ever is left... we allow.
18530 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18531 if (!nstyle.length) {
18532 node.removeAttribute('style');
18536 cleanWordChildren();
18540 domToHTML : function(currentElement, depth, nopadtext) {
18542 depth = depth || 0;
18543 nopadtext = nopadtext || false;
18545 if (!currentElement) {
18546 return this.domToHTML(this.doc.body);
18549 //Roo.log(currentElement);
18551 var allText = false;
18552 var nodeName = currentElement.nodeName;
18553 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18555 if (nodeName == '#text') {
18557 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18562 if (nodeName != 'BODY') {
18565 // Prints the node tagName, such as <A>, <IMG>, etc
18568 for(i = 0; i < currentElement.attributes.length;i++) {
18570 var aname = currentElement.attributes.item(i).name;
18571 if (!currentElement.attributes.item(i).value.length) {
18574 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18577 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18586 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18589 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18594 // Traverse the tree
18596 var currentElementChild = currentElement.childNodes.item(i);
18597 var allText = true;
18598 var innerHTML = '';
18600 while (currentElementChild) {
18601 // Formatting code (indent the tree so it looks nice on the screen)
18602 var nopad = nopadtext;
18603 if (lastnode == 'SPAN') {
18607 if (currentElementChild.nodeName == '#text') {
18608 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18609 toadd = nopadtext ? toadd : toadd.trim();
18610 if (!nopad && toadd.length > 80) {
18611 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18613 innerHTML += toadd;
18616 currentElementChild = currentElement.childNodes.item(i);
18622 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18624 // Recursively traverse the tree structure of the child node
18625 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18626 lastnode = currentElementChild.nodeName;
18628 currentElementChild=currentElement.childNodes.item(i);
18634 // The remaining code is mostly for formatting the tree
18635 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18640 ret+= "</"+tagName+">";
18646 applyBlacklists : function()
18648 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18649 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18653 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18654 if (b.indexOf(tag) > -1) {
18657 this.white.push(tag);
18661 Roo.each(w, function(tag) {
18662 if (b.indexOf(tag) > -1) {
18665 if (this.white.indexOf(tag) > -1) {
18668 this.white.push(tag);
18673 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18674 if (w.indexOf(tag) > -1) {
18677 this.black.push(tag);
18681 Roo.each(b, function(tag) {
18682 if (w.indexOf(tag) > -1) {
18685 if (this.black.indexOf(tag) > -1) {
18688 this.black.push(tag);
18693 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18694 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18698 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18699 if (b.indexOf(tag) > -1) {
18702 this.cwhite.push(tag);
18706 Roo.each(w, function(tag) {
18707 if (b.indexOf(tag) > -1) {
18710 if (this.cwhite.indexOf(tag) > -1) {
18713 this.cwhite.push(tag);
18718 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18719 if (w.indexOf(tag) > -1) {
18722 this.cblack.push(tag);
18726 Roo.each(b, function(tag) {
18727 if (w.indexOf(tag) > -1) {
18730 if (this.cblack.indexOf(tag) > -1) {
18733 this.cblack.push(tag);
18738 setStylesheets : function(stylesheets)
18740 if(typeof(stylesheets) == 'string'){
18741 Roo.get(this.iframe.contentDocument.head).createChild({
18743 rel : 'stylesheet',
18752 Roo.each(stylesheets, function(s) {
18757 Roo.get(_this.iframe.contentDocument.head).createChild({
18759 rel : 'stylesheet',
18768 removeStylesheets : function()
18772 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18777 // hide stuff that is not compatible
18791 * @event specialkey
18795 * @cfg {String} fieldClass @hide
18798 * @cfg {String} focusClass @hide
18801 * @cfg {String} autoCreate @hide
18804 * @cfg {String} inputType @hide
18807 * @cfg {String} invalidClass @hide
18810 * @cfg {String} invalidText @hide
18813 * @cfg {String} msgFx @hide
18816 * @cfg {String} validateOnBlur @hide
18820 Roo.HtmlEditorCore.white = [
18821 'area', 'br', 'img', 'input', 'hr', 'wbr',
18823 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18824 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18825 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18826 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18827 'table', 'ul', 'xmp',
18829 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18832 'dir', 'menu', 'ol', 'ul', 'dl',
18838 Roo.HtmlEditorCore.black = [
18839 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18841 'base', 'basefont', 'bgsound', 'blink', 'body',
18842 'frame', 'frameset', 'head', 'html', 'ilayer',
18843 'iframe', 'layer', 'link', 'meta', 'object',
18844 'script', 'style' ,'title', 'xml' // clean later..
18846 Roo.HtmlEditorCore.clean = [
18847 'script', 'style', 'title', 'xml'
18849 Roo.HtmlEditorCore.remove = [
18854 Roo.HtmlEditorCore.ablack = [
18858 Roo.HtmlEditorCore.aclean = [
18859 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18863 Roo.HtmlEditorCore.pwhite= [
18864 'http', 'https', 'mailto'
18867 // white listed style attributes.
18868 Roo.HtmlEditorCore.cwhite= [
18869 // 'text-align', /// default is to allow most things..
18875 // black listed style attributes.
18876 Roo.HtmlEditorCore.cblack= [
18877 // 'font-size' -- this can be set by the project
18881 Roo.HtmlEditorCore.swapCodes =[
18900 * @class Roo.bootstrap.HtmlEditor
18901 * @extends Roo.bootstrap.TextArea
18902 * Bootstrap HtmlEditor class
18905 * Create a new HtmlEditor
18906 * @param {Object} config The config object
18909 Roo.bootstrap.HtmlEditor = function(config){
18910 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18911 if (!this.toolbars) {
18912 this.toolbars = [];
18914 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18917 * @event initialize
18918 * Fires when the editor is fully initialized (including the iframe)
18919 * @param {HtmlEditor} this
18924 * Fires when the editor is first receives the focus. Any insertion must wait
18925 * until after this event.
18926 * @param {HtmlEditor} this
18930 * @event beforesync
18931 * Fires before the textarea is updated with content from the editor iframe. Return false
18932 * to cancel the sync.
18933 * @param {HtmlEditor} this
18934 * @param {String} html
18938 * @event beforepush
18939 * Fires before the iframe editor is updated with content from the textarea. Return false
18940 * to cancel the push.
18941 * @param {HtmlEditor} this
18942 * @param {String} html
18947 * Fires when the textarea is updated with content from the editor iframe.
18948 * @param {HtmlEditor} this
18949 * @param {String} html
18954 * Fires when the iframe editor is updated with content from the textarea.
18955 * @param {HtmlEditor} this
18956 * @param {String} html
18960 * @event editmodechange
18961 * Fires when the editor switches edit modes
18962 * @param {HtmlEditor} this
18963 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18965 editmodechange: true,
18967 * @event editorevent
18968 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18969 * @param {HtmlEditor} this
18973 * @event firstfocus
18974 * Fires when on first focus - needed by toolbars..
18975 * @param {HtmlEditor} this
18980 * Auto save the htmlEditor value as a file into Events
18981 * @param {HtmlEditor} this
18985 * @event savedpreview
18986 * preview the saved version of htmlEditor
18987 * @param {HtmlEditor} this
18994 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18998 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19003 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19008 * @cfg {Number} height (in pixels)
19012 * @cfg {Number} width (in pixels)
19017 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19020 stylesheets: false,
19025 // private properties
19026 validationEvent : false,
19028 initialized : false,
19031 onFocus : Roo.emptyFn,
19033 hideMode:'offsets',
19036 tbContainer : false,
19038 toolbarContainer :function() {
19039 return this.wrap.select('.x-html-editor-tb',true).first();
19043 * Protected method that will not generally be called directly. It
19044 * is called when the editor creates its toolbar. Override this method if you need to
19045 * add custom toolbar buttons.
19046 * @param {HtmlEditor} editor
19048 createToolbar : function(){
19050 Roo.log("create toolbars");
19052 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19053 this.toolbars[0].render(this.toolbarContainer());
19057 // if (!editor.toolbars || !editor.toolbars.length) {
19058 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19061 // for (var i =0 ; i < editor.toolbars.length;i++) {
19062 // editor.toolbars[i] = Roo.factory(
19063 // typeof(editor.toolbars[i]) == 'string' ?
19064 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19065 // Roo.bootstrap.HtmlEditor);
19066 // editor.toolbars[i].init(editor);
19072 onRender : function(ct, position)
19074 // Roo.log("Call onRender: " + this.xtype);
19076 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19078 this.wrap = this.inputEl().wrap({
19079 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19082 this.editorcore.onRender(ct, position);
19084 if (this.resizable) {
19085 this.resizeEl = new Roo.Resizable(this.wrap, {
19089 minHeight : this.height,
19090 height: this.height,
19091 handles : this.resizable,
19094 resize : function(r, w, h) {
19095 _t.onResize(w,h); // -something
19101 this.createToolbar(this);
19104 if(!this.width && this.resizable){
19105 this.setSize(this.wrap.getSize());
19107 if (this.resizeEl) {
19108 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19109 // should trigger onReize..
19115 onResize : function(w, h)
19117 Roo.log('resize: ' +w + ',' + h );
19118 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19122 if(this.inputEl() ){
19123 if(typeof w == 'number'){
19124 var aw = w - this.wrap.getFrameWidth('lr');
19125 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19128 if(typeof h == 'number'){
19129 var tbh = -11; // fixme it needs to tool bar size!
19130 for (var i =0; i < this.toolbars.length;i++) {
19131 // fixme - ask toolbars for heights?
19132 tbh += this.toolbars[i].el.getHeight();
19133 //if (this.toolbars[i].footer) {
19134 // tbh += this.toolbars[i].footer.el.getHeight();
19142 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19143 ah -= 5; // knock a few pixes off for look..
19144 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19148 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19149 this.editorcore.onResize(ew,eh);
19154 * Toggles the editor between standard and source edit mode.
19155 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19157 toggleSourceEdit : function(sourceEditMode)
19159 this.editorcore.toggleSourceEdit(sourceEditMode);
19161 if(this.editorcore.sourceEditMode){
19162 Roo.log('editor - showing textarea');
19165 // Roo.log(this.syncValue());
19167 this.inputEl().removeClass(['hide', 'x-hidden']);
19168 this.inputEl().dom.removeAttribute('tabIndex');
19169 this.inputEl().focus();
19171 Roo.log('editor - hiding textarea');
19173 // Roo.log(this.pushValue());
19176 this.inputEl().addClass(['hide', 'x-hidden']);
19177 this.inputEl().dom.setAttribute('tabIndex', -1);
19178 //this.deferFocus();
19181 if(this.resizable){
19182 this.setSize(this.wrap.getSize());
19185 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19188 // private (for BoxComponent)
19189 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19191 // private (for BoxComponent)
19192 getResizeEl : function(){
19196 // private (for BoxComponent)
19197 getPositionEl : function(){
19202 initEvents : function(){
19203 this.originalValue = this.getValue();
19207 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19210 // markInvalid : Roo.emptyFn,
19212 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19215 // clearInvalid : Roo.emptyFn,
19217 setValue : function(v){
19218 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19219 this.editorcore.pushValue();
19224 deferFocus : function(){
19225 this.focus.defer(10, this);
19229 focus : function(){
19230 this.editorcore.focus();
19236 onDestroy : function(){
19242 for (var i =0; i < this.toolbars.length;i++) {
19243 // fixme - ask toolbars for heights?
19244 this.toolbars[i].onDestroy();
19247 this.wrap.dom.innerHTML = '';
19248 this.wrap.remove();
19253 onFirstFocus : function(){
19254 //Roo.log("onFirstFocus");
19255 this.editorcore.onFirstFocus();
19256 for (var i =0; i < this.toolbars.length;i++) {
19257 this.toolbars[i].onFirstFocus();
19263 syncValue : function()
19265 this.editorcore.syncValue();
19268 pushValue : function()
19270 this.editorcore.pushValue();
19274 // hide stuff that is not compatible
19288 * @event specialkey
19292 * @cfg {String} fieldClass @hide
19295 * @cfg {String} focusClass @hide
19298 * @cfg {String} autoCreate @hide
19301 * @cfg {String} inputType @hide
19304 * @cfg {String} invalidClass @hide
19307 * @cfg {String} invalidText @hide
19310 * @cfg {String} msgFx @hide
19313 * @cfg {String} validateOnBlur @hide
19322 Roo.namespace('Roo.bootstrap.htmleditor');
19324 * @class Roo.bootstrap.HtmlEditorToolbar1
19329 new Roo.bootstrap.HtmlEditor({
19332 new Roo.bootstrap.HtmlEditorToolbar1({
19333 disable : { fonts: 1 , format: 1, ..., ... , ...],
19339 * @cfg {Object} disable List of elements to disable..
19340 * @cfg {Array} btns List of additional buttons.
19344 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19347 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19350 Roo.apply(this, config);
19352 // default disabled, based on 'good practice'..
19353 this.disable = this.disable || {};
19354 Roo.applyIf(this.disable, {
19357 specialElements : true
19359 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19361 this.editor = config.editor;
19362 this.editorcore = config.editor.editorcore;
19364 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19366 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19367 // dont call parent... till later.
19369 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19374 editorcore : false,
19379 "h1","h2","h3","h4","h5","h6",
19381 "abbr", "acronym", "address", "cite", "samp", "var",
19385 onRender : function(ct, position)
19387 // Roo.log("Call onRender: " + this.xtype);
19389 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19391 this.el.dom.style.marginBottom = '0';
19393 var editorcore = this.editorcore;
19394 var editor= this.editor;
19397 var btn = function(id,cmd , toggle, handler){
19399 var event = toggle ? 'toggle' : 'click';
19404 xns: Roo.bootstrap,
19407 enableToggle:toggle !== false,
19409 pressed : toggle ? false : null,
19412 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19413 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19422 xns: Roo.bootstrap,
19423 glyphicon : 'font',
19427 xns: Roo.bootstrap,
19431 Roo.each(this.formats, function(f) {
19432 style.menu.items.push({
19434 xns: Roo.bootstrap,
19435 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19440 editorcore.insertTag(this.tagname);
19447 children.push(style);
19450 btn('bold',false,true);
19451 btn('italic',false,true);
19452 btn('align-left', 'justifyleft',true);
19453 btn('align-center', 'justifycenter',true);
19454 btn('align-right' , 'justifyright',true);
19455 btn('link', false, false, function(btn) {
19456 //Roo.log("create link?");
19457 var url = prompt(this.createLinkText, this.defaultLinkValue);
19458 if(url && url != 'http:/'+'/'){
19459 this.editorcore.relayCmd('createlink', url);
19462 btn('list','insertunorderedlist',true);
19463 btn('pencil', false,true, function(btn){
19466 this.toggleSourceEdit(btn.pressed);
19472 xns: Roo.bootstrap,
19477 xns: Roo.bootstrap,
19482 cog.menu.items.push({
19484 xns: Roo.bootstrap,
19485 html : Clean styles,
19490 editorcore.insertTag(this.tagname);
19499 this.xtype = 'NavSimplebar';
19501 for(var i=0;i< children.length;i++) {
19503 this.buttons.add(this.addxtypeChild(children[i]));
19507 editor.on('editorevent', this.updateToolbar, this);
19509 onBtnClick : function(id)
19511 this.editorcore.relayCmd(id);
19512 this.editorcore.focus();
19516 * Protected method that will not generally be called directly. It triggers
19517 * a toolbar update by reading the markup state of the current selection in the editor.
19519 updateToolbar: function(){
19521 if(!this.editorcore.activated){
19522 this.editor.onFirstFocus(); // is this neeed?
19526 var btns = this.buttons;
19527 var doc = this.editorcore.doc;
19528 btns.get('bold').setActive(doc.queryCommandState('bold'));
19529 btns.get('italic').setActive(doc.queryCommandState('italic'));
19530 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19532 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19533 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19534 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19536 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19537 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19540 var ans = this.editorcore.getAllAncestors();
19541 if (this.formatCombo) {
19544 var store = this.formatCombo.store;
19545 this.formatCombo.setValue("");
19546 for (var i =0; i < ans.length;i++) {
19547 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19549 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19557 // hides menus... - so this cant be on a menu...
19558 Roo.bootstrap.MenuMgr.hideAll();
19560 Roo.bootstrap.MenuMgr.hideAll();
19561 //this.editorsyncValue();
19563 onFirstFocus: function() {
19564 this.buttons.each(function(item){
19568 toggleSourceEdit : function(sourceEditMode){
19571 if(sourceEditMode){
19572 Roo.log("disabling buttons");
19573 this.buttons.each( function(item){
19574 if(item.cmd != 'pencil'){
19580 Roo.log("enabling buttons");
19581 if(this.editorcore.initialized){
19582 this.buttons.each( function(item){
19588 Roo.log("calling toggole on editor");
19589 // tell the editor that it's been pressed..
19590 this.editor.toggleSourceEdit(sourceEditMode);
19600 * @class Roo.bootstrap.Table.AbstractSelectionModel
19601 * @extends Roo.util.Observable
19602 * Abstract base class for grid SelectionModels. It provides the interface that should be
19603 * implemented by descendant classes. This class should not be directly instantiated.
19606 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19607 this.locked = false;
19608 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19612 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19613 /** @ignore Called by the grid automatically. Do not call directly. */
19614 init : function(grid){
19620 * Locks the selections.
19623 this.locked = true;
19627 * Unlocks the selections.
19629 unlock : function(){
19630 this.locked = false;
19634 * Returns true if the selections are locked.
19635 * @return {Boolean}
19637 isLocked : function(){
19638 return this.locked;
19642 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19643 * @class Roo.bootstrap.Table.RowSelectionModel
19644 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19645 * It supports multiple selections and keyboard selection/navigation.
19647 * @param {Object} config
19650 Roo.bootstrap.Table.RowSelectionModel = function(config){
19651 Roo.apply(this, config);
19652 this.selections = new Roo.util.MixedCollection(false, function(o){
19657 this.lastActive = false;
19661 * @event selectionchange
19662 * Fires when the selection changes
19663 * @param {SelectionModel} this
19665 "selectionchange" : true,
19667 * @event afterselectionchange
19668 * Fires after the selection changes (eg. by key press or clicking)
19669 * @param {SelectionModel} this
19671 "afterselectionchange" : true,
19673 * @event beforerowselect
19674 * Fires when a row is selected being selected, return false to cancel.
19675 * @param {SelectionModel} this
19676 * @param {Number} rowIndex The selected index
19677 * @param {Boolean} keepExisting False if other selections will be cleared
19679 "beforerowselect" : true,
19682 * Fires when a row is selected.
19683 * @param {SelectionModel} this
19684 * @param {Number} rowIndex The selected index
19685 * @param {Roo.data.Record} r The record
19687 "rowselect" : true,
19689 * @event rowdeselect
19690 * Fires when a row is deselected.
19691 * @param {SelectionModel} this
19692 * @param {Number} rowIndex The selected index
19694 "rowdeselect" : true
19696 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19697 this.locked = false;
19700 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19702 * @cfg {Boolean} singleSelect
19703 * True to allow selection of only one row at a time (defaults to false)
19705 singleSelect : false,
19708 initEvents : function(){
19710 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19711 this.grid.on("mousedown", this.handleMouseDown, this);
19712 }else{ // allow click to work like normal
19713 this.grid.on("rowclick", this.handleDragableRowClick, this);
19716 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19717 "up" : function(e){
19719 this.selectPrevious(e.shiftKey);
19720 }else if(this.last !== false && this.lastActive !== false){
19721 var last = this.last;
19722 this.selectRange(this.last, this.lastActive-1);
19723 this.grid.getView().focusRow(this.lastActive);
19724 if(last !== false){
19728 this.selectFirstRow();
19730 this.fireEvent("afterselectionchange", this);
19732 "down" : function(e){
19734 this.selectNext(e.shiftKey);
19735 }else if(this.last !== false && this.lastActive !== false){
19736 var last = this.last;
19737 this.selectRange(this.last, this.lastActive+1);
19738 this.grid.getView().focusRow(this.lastActive);
19739 if(last !== false){
19743 this.selectFirstRow();
19745 this.fireEvent("afterselectionchange", this);
19750 var view = this.grid.view;
19751 view.on("refresh", this.onRefresh, this);
19752 view.on("rowupdated", this.onRowUpdated, this);
19753 view.on("rowremoved", this.onRemove, this);
19757 onRefresh : function(){
19758 var ds = this.grid.dataSource, i, v = this.grid.view;
19759 var s = this.selections;
19760 s.each(function(r){
19761 if((i = ds.indexOfId(r.id)) != -1){
19770 onRemove : function(v, index, r){
19771 this.selections.remove(r);
19775 onRowUpdated : function(v, index, r){
19776 if(this.isSelected(r)){
19777 v.onRowSelect(index);
19783 * @param {Array} records The records to select
19784 * @param {Boolean} keepExisting (optional) True to keep existing selections
19786 selectRecords : function(records, keepExisting){
19788 this.clearSelections();
19790 var ds = this.grid.dataSource;
19791 for(var i = 0, len = records.length; i < len; i++){
19792 this.selectRow(ds.indexOf(records[i]), true);
19797 * Gets the number of selected rows.
19800 getCount : function(){
19801 return this.selections.length;
19805 * Selects the first row in the grid.
19807 selectFirstRow : function(){
19812 * Select the last row.
19813 * @param {Boolean} keepExisting (optional) True to keep existing selections
19815 selectLastRow : function(keepExisting){
19816 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19820 * Selects the row immediately following the last selected row.
19821 * @param {Boolean} keepExisting (optional) True to keep existing selections
19823 selectNext : function(keepExisting){
19824 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19825 this.selectRow(this.last+1, keepExisting);
19826 this.grid.getView().focusRow(this.last);
19831 * Selects the row that precedes the last selected row.
19832 * @param {Boolean} keepExisting (optional) True to keep existing selections
19834 selectPrevious : function(keepExisting){
19836 this.selectRow(this.last-1, keepExisting);
19837 this.grid.getView().focusRow(this.last);
19842 * Returns the selected records
19843 * @return {Array} Array of selected records
19845 getSelections : function(){
19846 return [].concat(this.selections.items);
19850 * Returns the first selected record.
19853 getSelected : function(){
19854 return this.selections.itemAt(0);
19859 * Clears all selections.
19861 clearSelections : function(fast){
19862 if(this.locked) return;
19864 var ds = this.grid.dataSource;
19865 var s = this.selections;
19866 s.each(function(r){
19867 this.deselectRow(ds.indexOfId(r.id));
19871 this.selections.clear();
19878 * Selects all rows.
19880 selectAll : function(){
19881 if(this.locked) return;
19882 this.selections.clear();
19883 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19884 this.selectRow(i, true);
19889 * Returns True if there is a selection.
19890 * @return {Boolean}
19892 hasSelection : function(){
19893 return this.selections.length > 0;
19897 * Returns True if the specified row is selected.
19898 * @param {Number/Record} record The record or index of the record to check
19899 * @return {Boolean}
19901 isSelected : function(index){
19902 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19903 return (r && this.selections.key(r.id) ? true : false);
19907 * Returns True if the specified record id is selected.
19908 * @param {String} id The id of record to check
19909 * @return {Boolean}
19911 isIdSelected : function(id){
19912 return (this.selections.key(id) ? true : false);
19916 handleMouseDown : function(e, t){
19917 var view = this.grid.getView(), rowIndex;
19918 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19921 if(e.shiftKey && this.last !== false){
19922 var last = this.last;
19923 this.selectRange(last, rowIndex, e.ctrlKey);
19924 this.last = last; // reset the last
19925 view.focusRow(rowIndex);
19927 var isSelected = this.isSelected(rowIndex);
19928 if(e.button !== 0 && isSelected){
19929 view.focusRow(rowIndex);
19930 }else if(e.ctrlKey && isSelected){
19931 this.deselectRow(rowIndex);
19932 }else if(!isSelected){
19933 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19934 view.focusRow(rowIndex);
19937 this.fireEvent("afterselectionchange", this);
19940 handleDragableRowClick : function(grid, rowIndex, e)
19942 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19943 this.selectRow(rowIndex, false);
19944 grid.view.focusRow(rowIndex);
19945 this.fireEvent("afterselectionchange", this);
19950 * Selects multiple rows.
19951 * @param {Array} rows Array of the indexes of the row to select
19952 * @param {Boolean} keepExisting (optional) True to keep existing selections
19954 selectRows : function(rows, keepExisting){
19956 this.clearSelections();
19958 for(var i = 0, len = rows.length; i < len; i++){
19959 this.selectRow(rows[i], true);
19964 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19965 * @param {Number} startRow The index of the first row in the range
19966 * @param {Number} endRow The index of the last row in the range
19967 * @param {Boolean} keepExisting (optional) True to retain existing selections
19969 selectRange : function(startRow, endRow, keepExisting){
19970 if(this.locked) return;
19972 this.clearSelections();
19974 if(startRow <= endRow){
19975 for(var i = startRow; i <= endRow; i++){
19976 this.selectRow(i, true);
19979 for(var i = startRow; i >= endRow; i--){
19980 this.selectRow(i, true);
19986 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19987 * @param {Number} startRow The index of the first row in the range
19988 * @param {Number} endRow The index of the last row in the range
19990 deselectRange : function(startRow, endRow, preventViewNotify){
19991 if(this.locked) return;
19992 for(var i = startRow; i <= endRow; i++){
19993 this.deselectRow(i, preventViewNotify);
19999 * @param {Number} row The index of the row to select
20000 * @param {Boolean} keepExisting (optional) True to keep existing selections
20002 selectRow : function(index, keepExisting, preventViewNotify){
20003 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20004 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20005 if(!keepExisting || this.singleSelect){
20006 this.clearSelections();
20008 var r = this.grid.dataSource.getAt(index);
20009 this.selections.add(r);
20010 this.last = this.lastActive = index;
20011 if(!preventViewNotify){
20012 this.grid.getView().onRowSelect(index);
20014 this.fireEvent("rowselect", this, index, r);
20015 this.fireEvent("selectionchange", this);
20021 * @param {Number} row The index of the row to deselect
20023 deselectRow : function(index, preventViewNotify){
20024 if(this.locked) return;
20025 if(this.last == index){
20028 if(this.lastActive == index){
20029 this.lastActive = false;
20031 var r = this.grid.dataSource.getAt(index);
20032 this.selections.remove(r);
20033 if(!preventViewNotify){
20034 this.grid.getView().onRowDeselect(index);
20036 this.fireEvent("rowdeselect", this, index);
20037 this.fireEvent("selectionchange", this);
20041 restoreLast : function(){
20043 this.last = this._last;
20048 acceptsNav : function(row, col, cm){
20049 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20053 onEditorKey : function(field, e){
20054 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20059 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20061 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20063 }else if(k == e.ENTER && !e.ctrlKey){
20067 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20069 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20071 }else if(k == e.ESC){
20075 g.startEditing(newCell[0], newCell[1]);
20080 * Ext JS Library 1.1.1
20081 * Copyright(c) 2006-2007, Ext JS, LLC.
20083 * Originally Released Under LGPL - original licence link has changed is not relivant.
20086 * <script type="text/javascript">
20090 * @class Roo.bootstrap.PagingToolbar
20092 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20094 * Create a new PagingToolbar
20095 * @param {Object} config The config object
20097 Roo.bootstrap.PagingToolbar = function(config)
20099 // old args format still supported... - xtype is prefered..
20100 // created from xtype...
20101 var ds = config.dataSource;
20102 this.toolbarItems = [];
20103 if (config.items) {
20104 this.toolbarItems = config.items;
20105 // config.items = [];
20108 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20115 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20119 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20121 * @cfg {Roo.data.Store} dataSource
20122 * The underlying data store providing the paged data
20125 * @cfg {String/HTMLElement/Element} container
20126 * container The id or element that will contain the toolbar
20129 * @cfg {Boolean} displayInfo
20130 * True to display the displayMsg (defaults to false)
20133 * @cfg {Number} pageSize
20134 * The number of records to display per page (defaults to 20)
20138 * @cfg {String} displayMsg
20139 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20141 displayMsg : 'Displaying {0} - {1} of {2}',
20143 * @cfg {String} emptyMsg
20144 * The message to display when no records are found (defaults to "No data to display")
20146 emptyMsg : 'No data to display',
20148 * Customizable piece of the default paging text (defaults to "Page")
20151 beforePageText : "Page",
20153 * Customizable piece of the default paging text (defaults to "of %0")
20156 afterPageText : "of {0}",
20158 * Customizable piece of the default paging text (defaults to "First Page")
20161 firstText : "First Page",
20163 * Customizable piece of the default paging text (defaults to "Previous Page")
20166 prevText : "Previous Page",
20168 * Customizable piece of the default paging text (defaults to "Next Page")
20171 nextText : "Next Page",
20173 * Customizable piece of the default paging text (defaults to "Last Page")
20176 lastText : "Last Page",
20178 * Customizable piece of the default paging text (defaults to "Refresh")
20181 refreshText : "Refresh",
20185 onRender : function(ct, position)
20187 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20188 this.navgroup.parentId = this.id;
20189 this.navgroup.onRender(this.el, null);
20190 // add the buttons to the navgroup
20192 if(this.displayInfo){
20193 Roo.log(this.el.select('ul.navbar-nav',true).first());
20194 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20195 this.displayEl = this.el.select('.x-paging-info', true).first();
20196 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20197 // this.displayEl = navel.el.select('span',true).first();
20203 Roo.each(_this.buttons, function(e){
20204 Roo.factory(e).onRender(_this.el, null);
20208 Roo.each(_this.toolbarItems, function(e) {
20209 _this.navgroup.addItem(e);
20213 this.first = this.navgroup.addItem({
20214 tooltip: this.firstText,
20216 icon : 'fa fa-backward',
20218 preventDefault: true,
20219 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20222 this.prev = this.navgroup.addItem({
20223 tooltip: this.prevText,
20225 icon : 'fa fa-step-backward',
20227 preventDefault: true,
20228 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20230 //this.addSeparator();
20233 var field = this.navgroup.addItem( {
20235 cls : 'x-paging-position',
20237 html : this.beforePageText +
20238 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20239 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20242 this.field = field.el.select('input', true).first();
20243 this.field.on("keydown", this.onPagingKeydown, this);
20244 this.field.on("focus", function(){this.dom.select();});
20247 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20248 //this.field.setHeight(18);
20249 //this.addSeparator();
20250 this.next = this.navgroup.addItem({
20251 tooltip: this.nextText,
20253 html : ' <i class="fa fa-step-forward">',
20255 preventDefault: true,
20256 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20258 this.last = this.navgroup.addItem({
20259 tooltip: this.lastText,
20260 icon : 'fa fa-forward',
20263 preventDefault: true,
20264 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20266 //this.addSeparator();
20267 this.loading = this.navgroup.addItem({
20268 tooltip: this.refreshText,
20269 icon: 'fa fa-refresh',
20270 preventDefault: true,
20271 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20277 updateInfo : function(){
20278 if(this.displayEl){
20279 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20280 var msg = count == 0 ?
20284 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20286 this.displayEl.update(msg);
20291 onLoad : function(ds, r, o){
20292 this.cursor = o.params ? o.params.start : 0;
20293 var d = this.getPageData(),
20297 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20298 this.field.dom.value = ap;
20299 this.first.setDisabled(ap == 1);
20300 this.prev.setDisabled(ap == 1);
20301 this.next.setDisabled(ap == ps);
20302 this.last.setDisabled(ap == ps);
20303 this.loading.enable();
20308 getPageData : function(){
20309 var total = this.ds.getTotalCount();
20312 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20313 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20318 onLoadError : function(){
20319 this.loading.enable();
20323 onPagingKeydown : function(e){
20324 var k = e.getKey();
20325 var d = this.getPageData();
20327 var v = this.field.dom.value, pageNum;
20328 if(!v || isNaN(pageNum = parseInt(v, 10))){
20329 this.field.dom.value = d.activePage;
20332 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20333 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20336 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))
20338 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20339 this.field.dom.value = pageNum;
20340 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20343 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20345 var v = this.field.dom.value, pageNum;
20346 var increment = (e.shiftKey) ? 10 : 1;
20347 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20349 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20350 this.field.dom.value = d.activePage;
20353 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20355 this.field.dom.value = parseInt(v, 10) + increment;
20356 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20357 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20364 beforeLoad : function(){
20366 this.loading.disable();
20371 onClick : function(which){
20380 ds.load({params:{start: 0, limit: this.pageSize}});
20383 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20386 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20389 var total = ds.getTotalCount();
20390 var extra = total % this.pageSize;
20391 var lastStart = extra ? (total - extra) : total-this.pageSize;
20392 ds.load({params:{start: lastStart, limit: this.pageSize}});
20395 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20401 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20402 * @param {Roo.data.Store} store The data store to unbind
20404 unbind : function(ds){
20405 ds.un("beforeload", this.beforeLoad, this);
20406 ds.un("load", this.onLoad, this);
20407 ds.un("loadexception", this.onLoadError, this);
20408 ds.un("remove", this.updateInfo, this);
20409 ds.un("add", this.updateInfo, this);
20410 this.ds = undefined;
20414 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20415 * @param {Roo.data.Store} store The data store to bind
20417 bind : function(ds){
20418 ds.on("beforeload", this.beforeLoad, this);
20419 ds.on("load", this.onLoad, this);
20420 ds.on("loadexception", this.onLoadError, this);
20421 ds.on("remove", this.updateInfo, this);
20422 ds.on("add", this.updateInfo, this);
20433 * @class Roo.bootstrap.MessageBar
20434 * @extends Roo.bootstrap.Component
20435 * Bootstrap MessageBar class
20436 * @cfg {String} html contents of the MessageBar
20437 * @cfg {String} weight (info | success | warning | danger) default info
20438 * @cfg {String} beforeClass insert the bar before the given class
20439 * @cfg {Boolean} closable (true | false) default false
20440 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20443 * Create a new Element
20444 * @param {Object} config The config object
20447 Roo.bootstrap.MessageBar = function(config){
20448 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20451 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20457 beforeClass: 'bootstrap-sticky-wrap',
20459 getAutoCreate : function(){
20463 cls: 'alert alert-dismissable alert-' + this.weight,
20468 html: this.html || ''
20474 cfg.cls += ' alert-messages-fixed';
20488 onRender : function(ct, position)
20490 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20493 var cfg = Roo.apply({}, this.getAutoCreate());
20497 cfg.cls += ' ' + this.cls;
20500 cfg.style = this.style;
20502 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20504 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20507 this.el.select('>button.close').on('click', this.hide, this);
20513 if (!this.rendered) {
20519 this.fireEvent('show', this);
20525 if (!this.rendered) {
20531 this.fireEvent('hide', this);
20534 update : function()
20536 // var e = this.el.dom.firstChild;
20538 // if(this.closable){
20539 // e = e.nextSibling;
20542 // e.data = this.html || '';
20544 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20560 * @class Roo.bootstrap.Graph
20561 * @extends Roo.bootstrap.Component
20562 * Bootstrap Graph class
20566 @cfg {String} graphtype bar | vbar | pie
20567 @cfg {number} g_x coodinator | centre x (pie)
20568 @cfg {number} g_y coodinator | centre y (pie)
20569 @cfg {number} g_r radius (pie)
20570 @cfg {number} g_height height of the chart (respected by all elements in the set)
20571 @cfg {number} g_width width of the chart (respected by all elements in the set)
20572 @cfg {Object} title The title of the chart
20575 -opts (object) options for the chart
20577 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20578 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20580 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.
20581 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20583 o stretch (boolean)
20585 -opts (object) options for the pie
20588 o startAngle (number)
20589 o endAngle (number)
20593 * Create a new Input
20594 * @param {Object} config The config object
20597 Roo.bootstrap.Graph = function(config){
20598 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20604 * The img click event for the img.
20605 * @param {Roo.EventObject} e
20611 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20622 //g_colors: this.colors,
20629 getAutoCreate : function(){
20640 onRender : function(ct,position){
20641 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20642 this.raphael = Raphael(this.el.dom);
20644 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20645 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20646 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20647 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20649 r.text(160, 10, "Single Series Chart").attr(txtattr);
20650 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20651 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20652 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20654 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20655 r.barchart(330, 10, 300, 220, data1);
20656 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20657 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20660 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20661 // r.barchart(30, 30, 560, 250, xdata, {
20662 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20663 // axis : "0 0 1 1",
20664 // axisxlabels : xdata
20665 // //yvalues : cols,
20668 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20670 // this.load(null,xdata,{
20671 // axis : "0 0 1 1",
20672 // axisxlabels : xdata
20677 load : function(graphtype,xdata,opts){
20678 this.raphael.clear();
20680 graphtype = this.graphtype;
20685 var r = this.raphael,
20686 fin = function () {
20687 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20689 fout = function () {
20690 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20692 pfin = function() {
20693 this.sector.stop();
20694 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20697 this.label[0].stop();
20698 this.label[0].attr({ r: 7.5 });
20699 this.label[1].attr({ "font-weight": 800 });
20702 pfout = function() {
20703 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20706 this.label[0].animate({ r: 5 }, 500, "bounce");
20707 this.label[1].attr({ "font-weight": 400 });
20713 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20716 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20719 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20720 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20722 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20729 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20734 setTitle: function(o)
20739 initEvents: function() {
20742 this.el.on('click', this.onClick, this);
20746 onClick : function(e)
20748 Roo.log('img onclick');
20749 this.fireEvent('click', this, e);
20761 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20764 * @class Roo.bootstrap.dash.NumberBox
20765 * @extends Roo.bootstrap.Component
20766 * Bootstrap NumberBox class
20767 * @cfg {String} headline Box headline
20768 * @cfg {String} content Box content
20769 * @cfg {String} icon Box icon
20770 * @cfg {String} footer Footer text
20771 * @cfg {String} fhref Footer href
20774 * Create a new NumberBox
20775 * @param {Object} config The config object
20779 Roo.bootstrap.dash.NumberBox = function(config){
20780 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20784 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20793 getAutoCreate : function(){
20797 cls : 'small-box ',
20805 cls : 'roo-headline',
20806 html : this.headline
20810 cls : 'roo-content',
20811 html : this.content
20825 cls : 'ion ' + this.icon
20834 cls : 'small-box-footer',
20835 href : this.fhref || '#',
20839 cfg.cn.push(footer);
20846 onRender : function(ct,position){
20847 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20854 setHeadline: function (value)
20856 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20859 setFooter: function (value, href)
20861 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20864 this.el.select('a.small-box-footer',true).first().attr('href', href);
20869 setContent: function (value)
20871 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20874 initEvents: function()
20888 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20891 * @class Roo.bootstrap.dash.TabBox
20892 * @extends Roo.bootstrap.Component
20893 * Bootstrap TabBox class
20894 * @cfg {String} title Title of the TabBox
20895 * @cfg {String} icon Icon of the TabBox
20896 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20897 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20900 * Create a new TabBox
20901 * @param {Object} config The config object
20905 Roo.bootstrap.dash.TabBox = function(config){
20906 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20911 * When a pane is added
20912 * @param {Roo.bootstrap.dash.TabPane} pane
20916 * @event activatepane
20917 * When a pane is activated
20918 * @param {Roo.bootstrap.dash.TabPane} pane
20920 "activatepane" : true
20928 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20933 tabScrollable : false,
20935 getChildContainer : function()
20937 return this.el.select('.tab-content', true).first();
20940 getAutoCreate : function(){
20944 cls: 'pull-left header',
20952 cls: 'fa ' + this.icon
20958 cls: 'nav nav-tabs pull-right',
20964 if(this.tabScrollable){
20971 cls: 'nav nav-tabs pull-right',
20982 cls: 'nav-tabs-custom',
20987 cls: 'tab-content no-padding',
20995 initEvents : function()
20997 //Roo.log('add add pane handler');
20998 this.on('addpane', this.onAddPane, this);
21001 * Updates the box title
21002 * @param {String} html to set the title to.
21004 setTitle : function(value)
21006 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21008 onAddPane : function(pane)
21010 this.panes.push(pane);
21011 //Roo.log('addpane');
21013 // tabs are rendere left to right..
21014 if(!this.showtabs){
21018 var ctr = this.el.select('.nav-tabs', true).first();
21021 var existing = ctr.select('.nav-tab',true);
21022 var qty = existing.getCount();;
21025 var tab = ctr.createChild({
21027 cls : 'nav-tab' + (qty ? '' : ' active'),
21035 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21038 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21040 pane.el.addClass('active');
21045 onTabClick : function(ev,un,ob,pane)
21047 //Roo.log('tab - prev default');
21048 ev.preventDefault();
21051 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21052 pane.tab.addClass('active');
21053 //Roo.log(pane.title);
21054 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21055 // technically we should have a deactivate event.. but maybe add later.
21056 // and it should not de-activate the selected tab...
21057 this.fireEvent('activatepane', pane);
21058 pane.el.addClass('active');
21059 pane.fireEvent('activate');
21064 getActivePane : function()
21067 Roo.each(this.panes, function(p) {
21068 if(p.el.hasClass('active')){
21089 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21091 * @class Roo.bootstrap.TabPane
21092 * @extends Roo.bootstrap.Component
21093 * Bootstrap TabPane class
21094 * @cfg {Boolean} active (false | true) Default false
21095 * @cfg {String} title title of panel
21099 * Create a new TabPane
21100 * @param {Object} config The config object
21103 Roo.bootstrap.dash.TabPane = function(config){
21104 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21110 * When a pane is activated
21111 * @param {Roo.bootstrap.dash.TabPane} pane
21118 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21123 // the tabBox that this is attached to.
21126 getAutoCreate : function()
21134 cfg.cls += ' active';
21139 initEvents : function()
21141 //Roo.log('trigger add pane handler');
21142 this.parent().fireEvent('addpane', this)
21146 * Updates the tab title
21147 * @param {String} html to set the title to.
21149 setTitle: function(str)
21155 this.tab.select('a', true).first().dom.innerHTML = str;
21172 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21175 * @class Roo.bootstrap.menu.Menu
21176 * @extends Roo.bootstrap.Component
21177 * Bootstrap Menu class - container for Menu
21178 * @cfg {String} html Text of the menu
21179 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21180 * @cfg {String} icon Font awesome icon
21181 * @cfg {String} pos Menu align to (top | bottom) default bottom
21185 * Create a new Menu
21186 * @param {Object} config The config object
21190 Roo.bootstrap.menu.Menu = function(config){
21191 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21195 * @event beforeshow
21196 * Fires before this menu is displayed
21197 * @param {Roo.bootstrap.menu.Menu} this
21201 * @event beforehide
21202 * Fires before this menu is hidden
21203 * @param {Roo.bootstrap.menu.Menu} this
21208 * Fires after this menu is displayed
21209 * @param {Roo.bootstrap.menu.Menu} this
21214 * Fires after this menu is hidden
21215 * @param {Roo.bootstrap.menu.Menu} this
21220 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21221 * @param {Roo.bootstrap.menu.Menu} this
21222 * @param {Roo.EventObject} e
21229 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21233 weight : 'default',
21238 getChildContainer : function() {
21239 if(this.isSubMenu){
21243 return this.el.select('ul.dropdown-menu', true).first();
21246 getAutoCreate : function()
21251 cls : 'roo-menu-text',
21259 cls : 'fa ' + this.icon
21270 cls : 'dropdown-button btn btn-' + this.weight,
21275 cls : 'dropdown-toggle btn btn-' + this.weight,
21285 cls : 'dropdown-menu'
21291 if(this.pos == 'top'){
21292 cfg.cls += ' dropup';
21295 if(this.isSubMenu){
21298 cls : 'dropdown-menu'
21305 onRender : function(ct, position)
21307 this.isSubMenu = ct.hasClass('dropdown-submenu');
21309 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21312 initEvents : function()
21314 if(this.isSubMenu){
21318 this.hidden = true;
21320 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21321 this.triggerEl.on('click', this.onTriggerPress, this);
21323 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21324 this.buttonEl.on('click', this.onClick, this);
21330 if(this.isSubMenu){
21334 return this.el.select('ul.dropdown-menu', true).first();
21337 onClick : function(e)
21339 this.fireEvent("click", this, e);
21342 onTriggerPress : function(e)
21344 if (this.isVisible()) {
21351 isVisible : function(){
21352 return !this.hidden;
21357 this.fireEvent("beforeshow", this);
21359 this.hidden = false;
21360 this.el.addClass('open');
21362 Roo.get(document).on("mouseup", this.onMouseUp, this);
21364 this.fireEvent("show", this);
21371 this.fireEvent("beforehide", this);
21373 this.hidden = true;
21374 this.el.removeClass('open');
21376 Roo.get(document).un("mouseup", this.onMouseUp);
21378 this.fireEvent("hide", this);
21381 onMouseUp : function()
21395 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21398 * @class Roo.bootstrap.menu.Item
21399 * @extends Roo.bootstrap.Component
21400 * Bootstrap MenuItem class
21401 * @cfg {Boolean} submenu (true | false) default false
21402 * @cfg {String} html text of the item
21403 * @cfg {String} href the link
21404 * @cfg {Boolean} disable (true | false) default false
21405 * @cfg {Boolean} preventDefault (true | false) default true
21406 * @cfg {String} icon Font awesome icon
21407 * @cfg {String} pos Submenu align to (left | right) default right
21411 * Create a new Item
21412 * @param {Object} config The config object
21416 Roo.bootstrap.menu.Item = function(config){
21417 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21421 * Fires when the mouse is hovering over this menu
21422 * @param {Roo.bootstrap.menu.Item} this
21423 * @param {Roo.EventObject} e
21428 * Fires when the mouse exits this menu
21429 * @param {Roo.bootstrap.menu.Item} this
21430 * @param {Roo.EventObject} e
21436 * The raw click event for the entire grid.
21437 * @param {Roo.EventObject} e
21443 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21448 preventDefault: true,
21453 getAutoCreate : function()
21458 cls : 'roo-menu-item-text',
21466 cls : 'fa ' + this.icon
21475 href : this.href || '#',
21482 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21486 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21488 if(this.pos == 'left'){
21489 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21496 initEvents : function()
21498 this.el.on('mouseover', this.onMouseOver, this);
21499 this.el.on('mouseout', this.onMouseOut, this);
21501 this.el.select('a', true).first().on('click', this.onClick, this);
21505 onClick : function(e)
21507 if(this.preventDefault){
21508 e.preventDefault();
21511 this.fireEvent("click", this, e);
21514 onMouseOver : function(e)
21516 if(this.submenu && this.pos == 'left'){
21517 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21520 this.fireEvent("mouseover", this, e);
21523 onMouseOut : function(e)
21525 this.fireEvent("mouseout", this, e);
21537 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21540 * @class Roo.bootstrap.menu.Separator
21541 * @extends Roo.bootstrap.Component
21542 * Bootstrap Separator class
21545 * Create a new Separator
21546 * @param {Object} config The config object
21550 Roo.bootstrap.menu.Separator = function(config){
21551 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21554 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21556 getAutoCreate : function(){
21577 * @class Roo.bootstrap.Tooltip
21578 * Bootstrap Tooltip class
21579 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21580 * to determine which dom element triggers the tooltip.
21582 * It needs to add support for additional attributes like tooltip-position
21585 * Create a new Toolti
21586 * @param {Object} config The config object
21589 Roo.bootstrap.Tooltip = function(config){
21590 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21593 Roo.apply(Roo.bootstrap.Tooltip, {
21595 * @function init initialize tooltip monitoring.
21599 currentTip : false,
21600 currentRegion : false,
21606 Roo.get(document).on('mouseover', this.enter ,this);
21607 Roo.get(document).on('mouseout', this.leave, this);
21610 this.currentTip = new Roo.bootstrap.Tooltip();
21613 enter : function(ev)
21615 var dom = ev.getTarget();
21616 //Roo.log(['enter',dom]);
21617 var el = Roo.fly(dom);
21618 if (this.currentEl) {
21620 //Roo.log(this.currentEl);
21621 //Roo.log(this.currentEl.contains(dom));
21622 if (this.currentEl == el) {
21625 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21633 if (this.currentTip.el) {
21634 this.currentTip.el.hide(); // force hiding...
21637 if (!el.attr('tooltip')) { // parents who have tip?
21640 this.currentEl = el;
21641 this.currentTip.bind(el);
21642 this.currentRegion = Roo.lib.Region.getRegion(dom);
21643 this.currentTip.enter();
21646 leave : function(ev)
21648 var dom = ev.getTarget();
21649 //Roo.log(['leave',dom]);
21650 if (!this.currentEl) {
21655 if (dom != this.currentEl.dom) {
21658 var xy = ev.getXY();
21659 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21662 // only activate leave if mouse cursor is outside... bounding box..
21667 if (this.currentTip) {
21668 this.currentTip.leave();
21670 //Roo.log('clear currentEl');
21671 this.currentEl = false;
21676 'left' : ['r-l', [-2,0], 'right'],
21677 'right' : ['l-r', [2,0], 'left'],
21678 'bottom' : ['t-b', [0,2], 'top'],
21679 'top' : [ 'b-t', [0,-2], 'bottom']
21685 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21690 delay : null, // can be { show : 300 , hide: 500}
21694 hoverState : null, //???
21696 placement : 'bottom',
21698 getAutoCreate : function(){
21705 cls : 'tooltip-arrow'
21708 cls : 'tooltip-inner'
21715 bind : function(el)
21721 enter : function () {
21723 if (this.timeout != null) {
21724 clearTimeout(this.timeout);
21727 this.hoverState = 'in';
21728 //Roo.log("enter - show");
21729 if (!this.delay || !this.delay.show) {
21734 this.timeout = setTimeout(function () {
21735 if (_t.hoverState == 'in') {
21738 }, this.delay.show);
21742 clearTimeout(this.timeout);
21744 this.hoverState = 'out';
21745 if (!this.delay || !this.delay.hide) {
21751 this.timeout = setTimeout(function () {
21752 //Roo.log("leave - timeout");
21754 if (_t.hoverState == 'out') {
21756 Roo.bootstrap.Tooltip.currentEl = false;
21764 this.render(document.body);
21767 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21768 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21770 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21772 var placement = typeof this.placement == 'function' ?
21773 this.placement.call(this, this.el, on_el) :
21776 var autoToken = /\s?auto?\s?/i;
21777 var autoPlace = autoToken.test(placement);
21779 placement = placement.replace(autoToken, '') || 'top';
21783 //this.el.setXY([0,0]);
21785 //this.el.dom.style.display='block';
21786 this.el.addClass(placement);
21788 //this.el.appendTo(on_el);
21790 var p = this.getPosition();
21791 var box = this.el.getBox();
21796 var align = Roo.bootstrap.Tooltip.alignment[placement];
21797 this.el.alignTo(this.bindEl, align[0],align[1]);
21798 //var arrow = this.el.select('.arrow',true).first();
21799 //arrow.set(align[2],
21801 this.el.addClass('in fade');
21802 this.hoverState = null;
21804 if (this.el.hasClass('fade')) {
21815 //this.el.setXY([0,0]);
21816 this.el.removeClass('in');
21832 * @class Roo.bootstrap.LocationPicker
21833 * @extends Roo.bootstrap.Component
21834 * Bootstrap LocationPicker class
21835 * @cfg {Number} latitude Position when init default 0
21836 * @cfg {Number} longitude Position when init default 0
21837 * @cfg {Number} zoom default 15
21838 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21839 * @cfg {Boolean} mapTypeControl default false
21840 * @cfg {Boolean} disableDoubleClickZoom default false
21841 * @cfg {Boolean} scrollwheel default true
21842 * @cfg {Boolean} streetViewControl default false
21843 * @cfg {Number} radius default 0
21844 * @cfg {String} locationName
21845 * @cfg {Boolean} draggable default true
21846 * @cfg {Boolean} enableAutocomplete default false
21847 * @cfg {Boolean} enableReverseGeocode default true
21848 * @cfg {String} markerTitle
21851 * Create a new LocationPicker
21852 * @param {Object} config The config object
21856 Roo.bootstrap.LocationPicker = function(config){
21858 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21863 * Fires when the picker initialized.
21864 * @param {Roo.bootstrap.LocationPicker} this
21865 * @param {Google Location} location
21869 * @event positionchanged
21870 * Fires when the picker position changed.
21871 * @param {Roo.bootstrap.LocationPicker} this
21872 * @param {Google Location} location
21874 positionchanged : true,
21877 * Fires when the map resize.
21878 * @param {Roo.bootstrap.LocationPicker} this
21883 * Fires when the map show.
21884 * @param {Roo.bootstrap.LocationPicker} this
21889 * Fires when the map hide.
21890 * @param {Roo.bootstrap.LocationPicker} this
21895 * Fires when click the map.
21896 * @param {Roo.bootstrap.LocationPicker} this
21897 * @param {Map event} e
21901 * @event mapRightClick
21902 * Fires when right click the map.
21903 * @param {Roo.bootstrap.LocationPicker} this
21904 * @param {Map event} e
21906 mapRightClick : true,
21908 * @event markerClick
21909 * Fires when click the marker.
21910 * @param {Roo.bootstrap.LocationPicker} this
21911 * @param {Map event} e
21913 markerClick : true,
21915 * @event markerRightClick
21916 * Fires when right click the marker.
21917 * @param {Roo.bootstrap.LocationPicker} this
21918 * @param {Map event} e
21920 markerRightClick : true,
21922 * @event OverlayViewDraw
21923 * Fires when OverlayView Draw
21924 * @param {Roo.bootstrap.LocationPicker} this
21926 OverlayViewDraw : true,
21928 * @event OverlayViewOnAdd
21929 * Fires when OverlayView Draw
21930 * @param {Roo.bootstrap.LocationPicker} this
21932 OverlayViewOnAdd : true,
21934 * @event OverlayViewOnRemove
21935 * Fires when OverlayView Draw
21936 * @param {Roo.bootstrap.LocationPicker} this
21938 OverlayViewOnRemove : true,
21940 * @event OverlayViewShow
21941 * Fires when OverlayView Draw
21942 * @param {Roo.bootstrap.LocationPicker} this
21943 * @param {Pixel} cpx
21945 OverlayViewShow : true,
21947 * @event OverlayViewHide
21948 * Fires when OverlayView Draw
21949 * @param {Roo.bootstrap.LocationPicker} this
21951 OverlayViewHide : true
21956 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
21958 gMapContext: false,
21964 mapTypeControl: false,
21965 disableDoubleClickZoom: false,
21967 streetViewControl: false,
21971 enableAutocomplete: false,
21972 enableReverseGeocode: true,
21975 getAutoCreate: function()
21980 cls: 'roo-location-picker'
21986 initEvents: function(ct, position)
21988 if(!this.el.getWidth() || this.isApplied()){
21992 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21997 initial: function()
21999 if(!this.mapTypeId){
22000 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22003 this.gMapContext = this.GMapContext();
22005 this.initOverlayView();
22007 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22011 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22012 _this.setPosition(_this.gMapContext.marker.position);
22015 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22016 _this.fireEvent('mapClick', this, event);
22020 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22021 _this.fireEvent('mapRightClick', this, event);
22025 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22026 _this.fireEvent('markerClick', this, event);
22030 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22031 _this.fireEvent('markerRightClick', this, event);
22035 this.setPosition(this.gMapContext.location);
22037 this.fireEvent('initial', this, this.gMapContext.location);
22040 initOverlayView: function()
22044 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22048 _this.fireEvent('OverlayViewDraw', _this);
22053 _this.fireEvent('OverlayViewOnAdd', _this);
22056 onRemove: function()
22058 _this.fireEvent('OverlayViewOnRemove', _this);
22061 show: function(cpx)
22063 _this.fireEvent('OverlayViewShow', _this, cpx);
22068 _this.fireEvent('OverlayViewHide', _this);
22074 fromLatLngToContainerPixel: function(event)
22076 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22079 isApplied: function()
22081 return this.getGmapContext() == false ? false : true;
22084 getGmapContext: function()
22086 return this.gMapContext
22089 GMapContext: function()
22091 var _map = new google.maps.Map(this.el.dom, this);
22092 var _marker = new google.maps.Marker({
22093 position: new google.maps.LatLng(this.latitude, this.longitude),
22095 title: this.markerTitle,
22096 draggable: this.draggable
22103 location: _marker.position,
22104 radius: this.radius,
22105 locationName: this.locationName,
22106 addressComponents: {
22107 formatted_address: null,
22108 addressLine1: null,
22109 addressLine2: null,
22111 streetNumber: null,
22115 stateOrProvince: null
22118 domContainer: this.el.dom,
22119 geodecoder: new google.maps.Geocoder()
22123 drawCircle: function(center, radius, options)
22125 if (this.gMapContext.circle != null) {
22126 this.gMapContext.circle.setMap(null);
22130 options = Roo.apply({}, options, {
22131 strokeColor: "#0000FF",
22132 strokeOpacity: .35,
22134 fillColor: "#0000FF",
22138 options.map = this.gMapContext.map;
22139 options.radius = radius;
22140 options.center = center;
22141 this.gMapContext.circle = new google.maps.Circle(options);
22142 return this.gMapContext.circle;
22148 setPosition: function(location)
22150 this.gMapContext.location = location;
22151 this.gMapContext.marker.setPosition(location);
22152 this.gMapContext.map.panTo(location);
22153 this.drawCircle(location, this.gMapContext.radius, {});
22157 if (this.gMapContext.settings.enableReverseGeocode) {
22158 this.gMapContext.geodecoder.geocode({
22159 latLng: this.gMapContext.location
22160 }, function(results, status) {
22162 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22163 _this.gMapContext.locationName = results[0].formatted_address;
22164 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22166 _this.fireEvent('positionchanged', this, location);
22173 this.fireEvent('positionchanged', this, location);
22178 google.maps.event.trigger(this.gMapContext.map, "resize");
22180 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22182 this.fireEvent('resize', this);
22185 setPositionByLatLng: function(latitude, longitude)
22187 this.setPosition(new google.maps.LatLng(latitude, longitude));
22190 getCurrentPosition: function()
22193 latitude: this.gMapContext.location.lat(),
22194 longitude: this.gMapContext.location.lng()
22198 getAddressName: function()
22200 return this.gMapContext.locationName;
22203 getAddressComponents: function()
22205 return this.gMapContext.addressComponents;
22208 address_component_from_google_geocode: function(address_components)
22212 for (var i = 0; i < address_components.length; i++) {
22213 var component = address_components[i];
22214 if (component.types.indexOf("postal_code") >= 0) {
22215 result.postalCode = component.short_name;
22216 } else if (component.types.indexOf("street_number") >= 0) {
22217 result.streetNumber = component.short_name;
22218 } else if (component.types.indexOf("route") >= 0) {
22219 result.streetName = component.short_name;
22220 } else if (component.types.indexOf("neighborhood") >= 0) {
22221 result.city = component.short_name;
22222 } else if (component.types.indexOf("locality") >= 0) {
22223 result.city = component.short_name;
22224 } else if (component.types.indexOf("sublocality") >= 0) {
22225 result.district = component.short_name;
22226 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22227 result.stateOrProvince = component.short_name;
22228 } else if (component.types.indexOf("country") >= 0) {
22229 result.country = component.short_name;
22233 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22234 result.addressLine2 = "";
22238 setZoomLevel: function(zoom)
22240 this.gMapContext.map.setZoom(zoom);
22253 this.fireEvent('show', this);
22264 this.fireEvent('hide', this);
22269 Roo.apply(Roo.bootstrap.LocationPicker, {
22271 OverlayView : function(map, options)
22273 options = options || {};
22287 * @class Roo.bootstrap.Alert
22288 * @extends Roo.bootstrap.Component
22289 * Bootstrap Alert class
22290 * @cfg {String} title The title of alert
22291 * @cfg {String} html The content of alert
22292 * @cfg {String} weight ( success | info | warning | danger )
22293 * @cfg {String} faicon font-awesomeicon
22296 * Create a new alert
22297 * @param {Object} config The config object
22301 Roo.bootstrap.Alert = function(config){
22302 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22306 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22313 getAutoCreate : function()
22322 cls : 'roo-alert-icon'
22327 cls : 'roo-alert-title',
22332 cls : 'roo-alert-text',
22339 cfg.cn[0].cls += ' fa ' + this.faicon;
22343 cfg.cls += ' alert-' + this.weight;
22349 initEvents: function()
22351 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22354 setTitle : function(str)
22356 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22359 setText : function(str)
22361 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22364 setWeight : function(weight)
22367 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22370 this.weight = weight;
22372 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22375 setIcon : function(icon)
22378 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22383 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);