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.hasFeedback){
8140 cls: 'glyphicon form-control-feedback'
8144 cls : 'has-feedback',
8152 if (this.before || this.after) {
8155 cls : 'input-group',
8159 inputblock.cn.push({
8161 cls : 'input-group-addon',
8166 inputblock.cn.push(input);
8168 if(this.hasFeedback){
8169 inputblock.cls += ' has-feedback';
8170 inputblock.cn.push(feedback);
8174 inputblock.cn.push({
8176 cls : 'input-group-addon',
8189 cls: 'form-hidden-field'
8197 Roo.log('multiple');
8205 cls: 'form-hidden-field'
8209 cls: 'select2-choices',
8213 cls: 'select2-search-field',
8226 cls: 'select2-container input-group',
8231 // cls: 'typeahead typeahead-long dropdown-menu',
8232 // style: 'display:none'
8237 if(!this.multiple && this.showToggleBtn){
8243 if (this.caret != false) {
8246 cls: 'fa fa-' + this.caret
8253 cls : 'input-group-addon btn dropdown-toggle',
8258 cls: 'combobox-clear',
8272 combobox.cls += ' select2-container-multi';
8275 if (align ==='left' && this.fieldLabel.length) {
8277 Roo.log("left and has label");
8283 cls : 'control-label col-sm-' + this.labelWidth,
8284 html : this.fieldLabel
8288 cls : "col-sm-" + (12 - this.labelWidth),
8295 } else if ( this.fieldLabel.length) {
8301 //cls : 'input-group-addon',
8302 html : this.fieldLabel
8312 Roo.log(" no label && no align");
8319 ['xs','sm','md','lg'].map(function(size){
8320 if (settings[size]) {
8321 cfg.cls += ' col-' + size + '-' + settings[size];
8332 onResize : function(w, h){
8333 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8334 // if(typeof w == 'number'){
8335 // var x = w - this.trigger.getWidth();
8336 // this.inputEl().setWidth(this.adjustWidth('input', x));
8337 // this.trigger.setStyle('left', x+'px');
8342 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8345 getResizeEl : function(){
8346 return this.inputEl();
8350 getPositionEl : function(){
8351 return this.inputEl();
8355 alignErrorIcon : function(){
8356 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8360 initEvents : function(){
8364 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8365 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8366 if(!this.multiple && this.showToggleBtn){
8367 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8368 if(this.hideTrigger){
8369 this.trigger.setDisplayed(false);
8371 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8375 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8378 //this.trigger.addClassOnOver('x-form-trigger-over');
8379 //this.trigger.addClassOnClick('x-form-trigger-click');
8382 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8386 createList : function()
8388 this.list = Roo.get(document.body).createChild({
8390 cls: 'typeahead typeahead-long dropdown-menu',
8391 style: 'display:none'
8394 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8399 initTrigger : function(){
8404 onDestroy : function(){
8406 this.trigger.removeAllListeners();
8407 // this.trigger.remove();
8410 // this.wrap.remove();
8412 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8416 onFocus : function(){
8417 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8420 this.wrap.addClass('x-trigger-wrap-focus');
8421 this.mimicing = true;
8422 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8423 if(this.monitorTab){
8424 this.el.on("keydown", this.checkTab, this);
8431 checkTab : function(e){
8432 if(e.getKey() == e.TAB){
8438 onBlur : function(){
8443 mimicBlur : function(e, t){
8445 if(!this.wrap.contains(t) && this.validateBlur()){
8452 triggerBlur : function(){
8453 this.mimicing = false;
8454 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8455 if(this.monitorTab){
8456 this.el.un("keydown", this.checkTab, this);
8458 //this.wrap.removeClass('x-trigger-wrap-focus');
8459 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8463 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8464 validateBlur : function(e, t){
8469 onDisable : function(){
8470 this.inputEl().dom.disabled = true;
8471 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8473 // this.wrap.addClass('x-item-disabled');
8478 onEnable : function(){
8479 this.inputEl().dom.disabled = false;
8480 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8482 // this.el.removeClass('x-item-disabled');
8487 onShow : function(){
8488 var ae = this.getActionEl();
8491 ae.dom.style.display = '';
8492 ae.dom.style.visibility = 'visible';
8498 onHide : function(){
8499 var ae = this.getActionEl();
8500 ae.dom.style.display = 'none';
8504 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8505 * by an implementing function.
8507 * @param {EventObject} e
8509 onTriggerClick : Roo.emptyFn
8513 * Ext JS Library 1.1.1
8514 * Copyright(c) 2006-2007, Ext JS, LLC.
8516 * Originally Released Under LGPL - original licence link has changed is not relivant.
8519 * <script type="text/javascript">
8524 * @class Roo.data.SortTypes
8526 * Defines the default sorting (casting?) comparison functions used when sorting data.
8528 Roo.data.SortTypes = {
8530 * Default sort that does nothing
8531 * @param {Mixed} s The value being converted
8532 * @return {Mixed} The comparison value
8539 * The regular expression used to strip tags
8543 stripTagsRE : /<\/?[^>]+>/gi,
8546 * Strips all HTML tags to sort on text only
8547 * @param {Mixed} s The value being converted
8548 * @return {String} The comparison value
8550 asText : function(s){
8551 return String(s).replace(this.stripTagsRE, "");
8555 * Strips all HTML tags to sort on text only - Case insensitive
8556 * @param {Mixed} s The value being converted
8557 * @return {String} The comparison value
8559 asUCText : function(s){
8560 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8564 * Case insensitive string
8565 * @param {Mixed} s The value being converted
8566 * @return {String} The comparison value
8568 asUCString : function(s) {
8569 return String(s).toUpperCase();
8574 * @param {Mixed} s The value being converted
8575 * @return {Number} The comparison value
8577 asDate : function(s) {
8581 if(s instanceof Date){
8584 return Date.parse(String(s));
8589 * @param {Mixed} s The value being converted
8590 * @return {Float} The comparison value
8592 asFloat : function(s) {
8593 var val = parseFloat(String(s).replace(/,/g, ""));
8594 if(isNaN(val)) val = 0;
8600 * @param {Mixed} s The value being converted
8601 * @return {Number} The comparison value
8603 asInt : function(s) {
8604 var val = parseInt(String(s).replace(/,/g, ""));
8605 if(isNaN(val)) val = 0;
8610 * Ext JS Library 1.1.1
8611 * Copyright(c) 2006-2007, Ext JS, LLC.
8613 * Originally Released Under LGPL - original licence link has changed is not relivant.
8616 * <script type="text/javascript">
8620 * @class Roo.data.Record
8621 * Instances of this class encapsulate both record <em>definition</em> information, and record
8622 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8623 * to access Records cached in an {@link Roo.data.Store} object.<br>
8625 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8626 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8629 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8631 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8632 * {@link #create}. The parameters are the same.
8633 * @param {Array} data An associative Array of data values keyed by the field name.
8634 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8635 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8636 * not specified an integer id is generated.
8638 Roo.data.Record = function(data, id){
8639 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8644 * Generate a constructor for a specific record layout.
8645 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8646 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8647 * Each field definition object may contain the following properties: <ul>
8648 * <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,
8649 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8650 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8651 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8652 * is being used, then this is a string containing the javascript expression to reference the data relative to
8653 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8654 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8655 * this may be omitted.</p></li>
8656 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8657 * <ul><li>auto (Default, implies no conversion)</li>
8662 * <li>date</li></ul></p></li>
8663 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8664 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8665 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8666 * by the Reader into an object that will be stored in the Record. It is passed the
8667 * following parameters:<ul>
8668 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8670 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8672 * <br>usage:<br><pre><code>
8673 var TopicRecord = Roo.data.Record.create(
8674 {name: 'title', mapping: 'topic_title'},
8675 {name: 'author', mapping: 'username'},
8676 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8677 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8678 {name: 'lastPoster', mapping: 'user2'},
8679 {name: 'excerpt', mapping: 'post_text'}
8682 var myNewRecord = new TopicRecord({
8683 title: 'Do my job please',
8686 lastPost: new Date(),
8687 lastPoster: 'Animal',
8688 excerpt: 'No way dude!'
8690 myStore.add(myNewRecord);
8695 Roo.data.Record.create = function(o){
8697 f.superclass.constructor.apply(this, arguments);
8699 Roo.extend(f, Roo.data.Record);
8700 var p = f.prototype;
8701 p.fields = new Roo.util.MixedCollection(false, function(field){
8704 for(var i = 0, len = o.length; i < len; i++){
8705 p.fields.add(new Roo.data.Field(o[i]));
8707 f.getField = function(name){
8708 return p.fields.get(name);
8713 Roo.data.Record.AUTO_ID = 1000;
8714 Roo.data.Record.EDIT = 'edit';
8715 Roo.data.Record.REJECT = 'reject';
8716 Roo.data.Record.COMMIT = 'commit';
8718 Roo.data.Record.prototype = {
8720 * Readonly flag - true if this record has been modified.
8729 join : function(store){
8734 * Set the named field to the specified value.
8735 * @param {String} name The name of the field to set.
8736 * @param {Object} value The value to set the field to.
8738 set : function(name, value){
8739 if(this.data[name] == value){
8746 if(typeof this.modified[name] == 'undefined'){
8747 this.modified[name] = this.data[name];
8749 this.data[name] = value;
8750 if(!this.editing && this.store){
8751 this.store.afterEdit(this);
8756 * Get the value of the named field.
8757 * @param {String} name The name of the field to get the value of.
8758 * @return {Object} The value of the field.
8760 get : function(name){
8761 return this.data[name];
8765 beginEdit : function(){
8766 this.editing = true;
8771 cancelEdit : function(){
8772 this.editing = false;
8773 delete this.modified;
8777 endEdit : function(){
8778 this.editing = false;
8779 if(this.dirty && this.store){
8780 this.store.afterEdit(this);
8785 * Usually called by the {@link Roo.data.Store} which owns the Record.
8786 * Rejects all changes made to the Record since either creation, or the last commit operation.
8787 * Modified fields are reverted to their original values.
8789 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8790 * of reject operations.
8792 reject : function(){
8793 var m = this.modified;
8795 if(typeof m[n] != "function"){
8796 this.data[n] = m[n];
8800 delete this.modified;
8801 this.editing = false;
8803 this.store.afterReject(this);
8808 * Usually called by the {@link Roo.data.Store} which owns the Record.
8809 * Commits all changes made to the Record since either creation, or the last commit operation.
8811 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8812 * of commit operations.
8814 commit : function(){
8816 delete this.modified;
8817 this.editing = false;
8819 this.store.afterCommit(this);
8824 hasError : function(){
8825 return this.error != null;
8829 clearError : function(){
8834 * Creates a copy of this record.
8835 * @param {String} id (optional) A new record id if you don't want to use this record's id
8838 copy : function(newId) {
8839 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8843 * Ext JS Library 1.1.1
8844 * Copyright(c) 2006-2007, Ext JS, LLC.
8846 * Originally Released Under LGPL - original licence link has changed is not relivant.
8849 * <script type="text/javascript">
8855 * @class Roo.data.Store
8856 * @extends Roo.util.Observable
8857 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8858 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8860 * 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
8861 * has no knowledge of the format of the data returned by the Proxy.<br>
8863 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8864 * instances from the data object. These records are cached and made available through accessor functions.
8866 * Creates a new Store.
8867 * @param {Object} config A config object containing the objects needed for the Store to access data,
8868 * and read the data into Records.
8870 Roo.data.Store = function(config){
8871 this.data = new Roo.util.MixedCollection(false);
8872 this.data.getKey = function(o){
8875 this.baseParams = {};
8882 "multisort" : "_multisort"
8885 if(config && config.data){
8886 this.inlineData = config.data;
8890 Roo.apply(this, config);
8892 if(this.reader){ // reader passed
8893 this.reader = Roo.factory(this.reader, Roo.data);
8894 this.reader.xmodule = this.xmodule || false;
8895 if(!this.recordType){
8896 this.recordType = this.reader.recordType;
8898 if(this.reader.onMetaChange){
8899 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8903 if(this.recordType){
8904 this.fields = this.recordType.prototype.fields;
8910 * @event datachanged
8911 * Fires when the data cache has changed, and a widget which is using this Store
8912 * as a Record cache should refresh its view.
8913 * @param {Store} this
8918 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8919 * @param {Store} this
8920 * @param {Object} meta The JSON metadata
8925 * Fires when Records have been added to the Store
8926 * @param {Store} this
8927 * @param {Roo.data.Record[]} records The array of Records added
8928 * @param {Number} index The index at which the record(s) were added
8933 * Fires when a Record has been removed from the Store
8934 * @param {Store} this
8935 * @param {Roo.data.Record} record The Record that was removed
8936 * @param {Number} index The index at which the record was removed
8941 * Fires when a Record has been updated
8942 * @param {Store} this
8943 * @param {Roo.data.Record} record The Record that was updated
8944 * @param {String} operation The update operation being performed. Value may be one of:
8946 Roo.data.Record.EDIT
8947 Roo.data.Record.REJECT
8948 Roo.data.Record.COMMIT
8954 * Fires when the data cache has been cleared.
8955 * @param {Store} this
8960 * Fires before a request is made for a new data object. If the beforeload handler returns false
8961 * the load action will be canceled.
8962 * @param {Store} this
8963 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8967 * @event beforeloadadd
8968 * Fires after a new set of Records has been loaded.
8969 * @param {Store} this
8970 * @param {Roo.data.Record[]} records The Records that were loaded
8971 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8973 beforeloadadd : true,
8976 * Fires after a new set of Records has been loaded, before they are added to the store.
8977 * @param {Store} this
8978 * @param {Roo.data.Record[]} records The Records that were loaded
8979 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8980 * @params {Object} return from reader
8984 * @event loadexception
8985 * Fires if an exception occurs in the Proxy during loading.
8986 * Called with the signature of the Proxy's "loadexception" event.
8987 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8990 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8991 * @param {Object} load options
8992 * @param {Object} jsonData from your request (normally this contains the Exception)
8994 loadexception : true
8998 this.proxy = Roo.factory(this.proxy, Roo.data);
8999 this.proxy.xmodule = this.xmodule || false;
9000 this.relayEvents(this.proxy, ["loadexception"]);
9002 this.sortToggle = {};
9003 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9005 Roo.data.Store.superclass.constructor.call(this);
9007 if(this.inlineData){
9008 this.loadData(this.inlineData);
9009 delete this.inlineData;
9013 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9015 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9016 * without a remote query - used by combo/forms at present.
9020 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9023 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9026 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9027 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9030 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9031 * on any HTTP request
9034 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9037 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9041 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9042 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9047 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9048 * loaded or when a record is removed. (defaults to false).
9050 pruneModifiedRecords : false,
9056 * Add Records to the Store and fires the add event.
9057 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9059 add : function(records){
9060 records = [].concat(records);
9061 for(var i = 0, len = records.length; i < len; i++){
9062 records[i].join(this);
9064 var index = this.data.length;
9065 this.data.addAll(records);
9066 this.fireEvent("add", this, records, index);
9070 * Remove a Record from the Store and fires the remove event.
9071 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9073 remove : function(record){
9074 var index = this.data.indexOf(record);
9075 this.data.removeAt(index);
9076 if(this.pruneModifiedRecords){
9077 this.modified.remove(record);
9079 this.fireEvent("remove", this, record, index);
9083 * Remove all Records from the Store and fires the clear event.
9085 removeAll : function(){
9087 if(this.pruneModifiedRecords){
9090 this.fireEvent("clear", this);
9094 * Inserts Records to the Store at the given index and fires the add event.
9095 * @param {Number} index The start index at which to insert the passed Records.
9096 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9098 insert : function(index, records){
9099 records = [].concat(records);
9100 for(var i = 0, len = records.length; i < len; i++){
9101 this.data.insert(index, records[i]);
9102 records[i].join(this);
9104 this.fireEvent("add", this, records, index);
9108 * Get the index within the cache of the passed Record.
9109 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9110 * @return {Number} The index of the passed Record. Returns -1 if not found.
9112 indexOf : function(record){
9113 return this.data.indexOf(record);
9117 * Get the index within the cache of the Record with the passed id.
9118 * @param {String} id The id of the Record to find.
9119 * @return {Number} The index of the Record. Returns -1 if not found.
9121 indexOfId : function(id){
9122 return this.data.indexOfKey(id);
9126 * Get the Record with the specified id.
9127 * @param {String} id The id of the Record to find.
9128 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9130 getById : function(id){
9131 return this.data.key(id);
9135 * Get the Record at the specified index.
9136 * @param {Number} index The index of the Record to find.
9137 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9139 getAt : function(index){
9140 return this.data.itemAt(index);
9144 * Returns a range of Records between specified indices.
9145 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9146 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9147 * @return {Roo.data.Record[]} An array of Records
9149 getRange : function(start, end){
9150 return this.data.getRange(start, end);
9154 storeOptions : function(o){
9155 o = Roo.apply({}, o);
9158 this.lastOptions = o;
9162 * Loads the Record cache from the configured Proxy using the configured Reader.
9164 * If using remote paging, then the first load call must specify the <em>start</em>
9165 * and <em>limit</em> properties in the options.params property to establish the initial
9166 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9168 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9169 * and this call will return before the new data has been loaded. Perform any post-processing
9170 * in a callback function, or in a "load" event handler.</strong>
9172 * @param {Object} options An object containing properties which control loading options:<ul>
9173 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9174 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9175 * passed the following arguments:<ul>
9176 * <li>r : Roo.data.Record[]</li>
9177 * <li>options: Options object from the load call</li>
9178 * <li>success: Boolean success indicator</li></ul></li>
9179 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9180 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9183 load : function(options){
9184 options = options || {};
9185 if(this.fireEvent("beforeload", this, options) !== false){
9186 this.storeOptions(options);
9187 var p = Roo.apply(options.params || {}, this.baseParams);
9188 // if meta was not loaded from remote source.. try requesting it.
9189 if (!this.reader.metaFromRemote) {
9192 if(this.sortInfo && this.remoteSort){
9193 var pn = this.paramNames;
9194 p[pn["sort"]] = this.sortInfo.field;
9195 p[pn["dir"]] = this.sortInfo.direction;
9197 if (this.multiSort) {
9198 var pn = this.paramNames;
9199 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9202 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9207 * Reloads the Record cache from the configured Proxy using the configured Reader and
9208 * the options from the last load operation performed.
9209 * @param {Object} options (optional) An object containing properties which may override the options
9210 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9211 * the most recently used options are reused).
9213 reload : function(options){
9214 this.load(Roo.applyIf(options||{}, this.lastOptions));
9218 // Called as a callback by the Reader during a load operation.
9219 loadRecords : function(o, options, success){
9220 if(!o || success === false){
9221 if(success !== false){
9222 this.fireEvent("load", this, [], options, o);
9224 if(options.callback){
9225 options.callback.call(options.scope || this, [], options, false);
9229 // if data returned failure - throw an exception.
9230 if (o.success === false) {
9231 // show a message if no listener is registered.
9232 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9233 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9235 // loadmask wil be hooked into this..
9236 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9239 var r = o.records, t = o.totalRecords || r.length;
9241 this.fireEvent("beforeloadadd", this, r, options, o);
9243 if(!options || options.add !== true){
9244 if(this.pruneModifiedRecords){
9247 for(var i = 0, len = r.length; i < len; i++){
9251 this.data = this.snapshot;
9252 delete this.snapshot;
9255 this.data.addAll(r);
9256 this.totalLength = t;
9258 this.fireEvent("datachanged", this);
9260 this.totalLength = Math.max(t, this.data.length+r.length);
9263 this.fireEvent("load", this, r, options, o);
9264 if(options.callback){
9265 options.callback.call(options.scope || this, r, options, true);
9271 * Loads data from a passed data block. A Reader which understands the format of the data
9272 * must have been configured in the constructor.
9273 * @param {Object} data The data block from which to read the Records. The format of the data expected
9274 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9275 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9277 loadData : function(o, append){
9278 var r = this.reader.readRecords(o);
9279 this.loadRecords(r, {add: append}, true);
9283 * Gets the number of cached records.
9285 * <em>If using paging, this may not be the total size of the dataset. If the data object
9286 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9287 * the data set size</em>
9289 getCount : function(){
9290 return this.data.length || 0;
9294 * Gets the total number of records in the dataset as returned by the server.
9296 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9297 * the dataset size</em>
9299 getTotalCount : function(){
9300 return this.totalLength || 0;
9304 * Returns the sort state of the Store as an object with two properties:
9306 field {String} The name of the field by which the Records are sorted
9307 direction {String} The sort order, "ASC" or "DESC"
9310 getSortState : function(){
9311 return this.sortInfo;
9315 applySort : function(){
9316 if(this.sortInfo && !this.remoteSort){
9317 var s = this.sortInfo, f = s.field;
9318 var st = this.fields.get(f).sortType;
9319 var fn = function(r1, r2){
9320 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9321 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9323 this.data.sort(s.direction, fn);
9324 if(this.snapshot && this.snapshot != this.data){
9325 this.snapshot.sort(s.direction, fn);
9331 * Sets the default sort column and order to be used by the next load operation.
9332 * @param {String} fieldName The name of the field to sort by.
9333 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9335 setDefaultSort : function(field, dir){
9336 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9341 * If remote sorting is used, the sort is performed on the server, and the cache is
9342 * reloaded. If local sorting is used, the cache is sorted internally.
9343 * @param {String} fieldName The name of the field to sort by.
9344 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9346 sort : function(fieldName, dir){
9347 var f = this.fields.get(fieldName);
9349 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9351 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9352 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9357 this.sortToggle[f.name] = dir;
9358 this.sortInfo = {field: f.name, direction: dir};
9359 if(!this.remoteSort){
9361 this.fireEvent("datachanged", this);
9363 this.load(this.lastOptions);
9368 * Calls the specified function for each of the Records in the cache.
9369 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9370 * Returning <em>false</em> aborts and exits the iteration.
9371 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9373 each : function(fn, scope){
9374 this.data.each(fn, scope);
9378 * Gets all records modified since the last commit. Modified records are persisted across load operations
9379 * (e.g., during paging).
9380 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9382 getModifiedRecords : function(){
9383 return this.modified;
9387 createFilterFn : function(property, value, anyMatch){
9388 if(!value.exec){ // not a regex
9389 value = String(value);
9390 if(value.length == 0){
9393 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9396 return value.test(r.data[property]);
9401 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9402 * @param {String} property A field on your records
9403 * @param {Number} start The record index to start at (defaults to 0)
9404 * @param {Number} end The last record index to include (defaults to length - 1)
9405 * @return {Number} The sum
9407 sum : function(property, start, end){
9408 var rs = this.data.items, v = 0;
9410 end = (end || end === 0) ? end : rs.length-1;
9412 for(var i = start; i <= end; i++){
9413 v += (rs[i].data[property] || 0);
9419 * Filter the records by a specified property.
9420 * @param {String} field A field on your records
9421 * @param {String/RegExp} value Either a string that the field
9422 * should start with or a RegExp to test against the field
9423 * @param {Boolean} anyMatch True to match any part not just the beginning
9425 filter : function(property, value, anyMatch){
9426 var fn = this.createFilterFn(property, value, anyMatch);
9427 return fn ? this.filterBy(fn) : this.clearFilter();
9431 * Filter by a function. The specified function will be called with each
9432 * record in this data source. If the function returns true the record is included,
9433 * otherwise it is filtered.
9434 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9435 * @param {Object} scope (optional) The scope of the function (defaults to this)
9437 filterBy : function(fn, scope){
9438 this.snapshot = this.snapshot || this.data;
9439 this.data = this.queryBy(fn, scope||this);
9440 this.fireEvent("datachanged", this);
9444 * Query the records by a specified property.
9445 * @param {String} field A field on your records
9446 * @param {String/RegExp} value Either a string that the field
9447 * should start with or a RegExp to test against the field
9448 * @param {Boolean} anyMatch True to match any part not just the beginning
9449 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9451 query : function(property, value, anyMatch){
9452 var fn = this.createFilterFn(property, value, anyMatch);
9453 return fn ? this.queryBy(fn) : this.data.clone();
9457 * Query by a function. The specified function will be called with each
9458 * record in this data source. If the function returns true the record is included
9460 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9461 * @param {Object} scope (optional) The scope of the function (defaults to this)
9462 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9464 queryBy : function(fn, scope){
9465 var data = this.snapshot || this.data;
9466 return data.filterBy(fn, scope||this);
9470 * Collects unique values for a particular dataIndex from this store.
9471 * @param {String} dataIndex The property to collect
9472 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9473 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9474 * @return {Array} An array of the unique values
9476 collect : function(dataIndex, allowNull, bypassFilter){
9477 var d = (bypassFilter === true && this.snapshot) ?
9478 this.snapshot.items : this.data.items;
9479 var v, sv, r = [], l = {};
9480 for(var i = 0, len = d.length; i < len; i++){
9481 v = d[i].data[dataIndex];
9483 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9492 * Revert to a view of the Record cache with no filtering applied.
9493 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9495 clearFilter : function(suppressEvent){
9496 if(this.snapshot && this.snapshot != this.data){
9497 this.data = this.snapshot;
9498 delete this.snapshot;
9499 if(suppressEvent !== true){
9500 this.fireEvent("datachanged", this);
9506 afterEdit : function(record){
9507 if(this.modified.indexOf(record) == -1){
9508 this.modified.push(record);
9510 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9514 afterReject : function(record){
9515 this.modified.remove(record);
9516 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9520 afterCommit : function(record){
9521 this.modified.remove(record);
9522 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9526 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9527 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9529 commitChanges : function(){
9530 var m = this.modified.slice(0);
9532 for(var i = 0, len = m.length; i < len; i++){
9538 * Cancel outstanding changes on all changed records.
9540 rejectChanges : function(){
9541 var m = this.modified.slice(0);
9543 for(var i = 0, len = m.length; i < len; i++){
9548 onMetaChange : function(meta, rtype, o){
9549 this.recordType = rtype;
9550 this.fields = rtype.prototype.fields;
9551 delete this.snapshot;
9552 this.sortInfo = meta.sortInfo || this.sortInfo;
9554 this.fireEvent('metachange', this, this.reader.meta);
9557 moveIndex : function(data, type)
9559 var index = this.indexOf(data);
9561 var newIndex = index + type;
9565 this.insert(newIndex, data);
9570 * Ext JS Library 1.1.1
9571 * Copyright(c) 2006-2007, Ext JS, LLC.
9573 * Originally Released Under LGPL - original licence link has changed is not relivant.
9576 * <script type="text/javascript">
9580 * @class Roo.data.SimpleStore
9581 * @extends Roo.data.Store
9582 * Small helper class to make creating Stores from Array data easier.
9583 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9584 * @cfg {Array} fields An array of field definition objects, or field name strings.
9585 * @cfg {Array} data The multi-dimensional array of data
9587 * @param {Object} config
9589 Roo.data.SimpleStore = function(config){
9590 Roo.data.SimpleStore.superclass.constructor.call(this, {
9592 reader: new Roo.data.ArrayReader({
9595 Roo.data.Record.create(config.fields)
9597 proxy : new Roo.data.MemoryProxy(config.data)
9601 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9603 * Ext JS Library 1.1.1
9604 * Copyright(c) 2006-2007, Ext JS, LLC.
9606 * Originally Released Under LGPL - original licence link has changed is not relivant.
9609 * <script type="text/javascript">
9614 * @extends Roo.data.Store
9615 * @class Roo.data.JsonStore
9616 * Small helper class to make creating Stores for JSON data easier. <br/>
9618 var store = new Roo.data.JsonStore({
9619 url: 'get-images.php',
9621 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9624 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9625 * JsonReader and HttpProxy (unless inline data is provided).</b>
9626 * @cfg {Array} fields An array of field definition objects, or field name strings.
9628 * @param {Object} config
9630 Roo.data.JsonStore = function(c){
9631 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9632 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9633 reader: new Roo.data.JsonReader(c, c.fields)
9636 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9638 * Ext JS Library 1.1.1
9639 * Copyright(c) 2006-2007, Ext JS, LLC.
9641 * Originally Released Under LGPL - original licence link has changed is not relivant.
9644 * <script type="text/javascript">
9648 Roo.data.Field = function(config){
9649 if(typeof config == "string"){
9650 config = {name: config};
9652 Roo.apply(this, config);
9658 var st = Roo.data.SortTypes;
9659 // named sortTypes are supported, here we look them up
9660 if(typeof this.sortType == "string"){
9661 this.sortType = st[this.sortType];
9664 // set default sortType for strings and dates
9668 this.sortType = st.asUCString;
9671 this.sortType = st.asDate;
9674 this.sortType = st.none;
9679 var stripRe = /[\$,%]/g;
9681 // prebuilt conversion function for this field, instead of
9682 // switching every time we're reading a value
9684 var cv, dateFormat = this.dateFormat;
9689 cv = function(v){ return v; };
9692 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9696 return v !== undefined && v !== null && v !== '' ?
9697 parseInt(String(v).replace(stripRe, ""), 10) : '';
9702 return v !== undefined && v !== null && v !== '' ?
9703 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9708 cv = function(v){ return v === true || v === "true" || v == 1; };
9715 if(v instanceof Date){
9719 if(dateFormat == "timestamp"){
9720 return new Date(v*1000);
9722 return Date.parseDate(v, dateFormat);
9724 var parsed = Date.parse(v);
9725 return parsed ? new Date(parsed) : null;
9734 Roo.data.Field.prototype = {
9742 * Ext JS Library 1.1.1
9743 * Copyright(c) 2006-2007, Ext JS, LLC.
9745 * Originally Released Under LGPL - original licence link has changed is not relivant.
9748 * <script type="text/javascript">
9751 // Base class for reading structured data from a data source. This class is intended to be
9752 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9755 * @class Roo.data.DataReader
9756 * Base class for reading structured data from a data source. This class is intended to be
9757 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9760 Roo.data.DataReader = function(meta, recordType){
9764 this.recordType = recordType instanceof Array ?
9765 Roo.data.Record.create(recordType) : recordType;
9768 Roo.data.DataReader.prototype = {
9770 * Create an empty record
9771 * @param {Object} data (optional) - overlay some values
9772 * @return {Roo.data.Record} record created.
9774 newRow : function(d) {
9776 this.recordType.prototype.fields.each(function(c) {
9778 case 'int' : da[c.name] = 0; break;
9779 case 'date' : da[c.name] = new Date(); break;
9780 case 'float' : da[c.name] = 0.0; break;
9781 case 'boolean' : da[c.name] = false; break;
9782 default : da[c.name] = ""; break;
9786 return new this.recordType(Roo.apply(da, d));
9791 * Ext JS Library 1.1.1
9792 * Copyright(c) 2006-2007, Ext JS, LLC.
9794 * Originally Released Under LGPL - original licence link has changed is not relivant.
9797 * <script type="text/javascript">
9801 * @class Roo.data.DataProxy
9802 * @extends Roo.data.Observable
9803 * This class is an abstract base class for implementations which provide retrieval of
9804 * unformatted data objects.<br>
9806 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9807 * (of the appropriate type which knows how to parse the data object) to provide a block of
9808 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9810 * Custom implementations must implement the load method as described in
9811 * {@link Roo.data.HttpProxy#load}.
9813 Roo.data.DataProxy = function(){
9817 * Fires before a network request is made to retrieve a data object.
9818 * @param {Object} This DataProxy object.
9819 * @param {Object} params The params parameter to the load function.
9824 * Fires before the load method's callback is called.
9825 * @param {Object} This DataProxy object.
9826 * @param {Object} o The data object.
9827 * @param {Object} arg The callback argument object passed to the load function.
9831 * @event loadexception
9832 * Fires if an Exception occurs during data retrieval.
9833 * @param {Object} This DataProxy object.
9834 * @param {Object} o The data object.
9835 * @param {Object} arg The callback argument object passed to the load function.
9836 * @param {Object} e The Exception.
9838 loadexception : true
9840 Roo.data.DataProxy.superclass.constructor.call(this);
9843 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9846 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9850 * Ext JS Library 1.1.1
9851 * Copyright(c) 2006-2007, Ext JS, LLC.
9853 * Originally Released Under LGPL - original licence link has changed is not relivant.
9856 * <script type="text/javascript">
9859 * @class Roo.data.MemoryProxy
9860 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9861 * to the Reader when its load method is called.
9863 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9865 Roo.data.MemoryProxy = function(data){
9869 Roo.data.MemoryProxy.superclass.constructor.call(this);
9873 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9875 * Load data from the requested source (in this case an in-memory
9876 * data object passed to the constructor), read the data object into
9877 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9878 * process that block using the passed callback.
9879 * @param {Object} params This parameter is not used by the MemoryProxy class.
9880 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9881 * object into a block of Roo.data.Records.
9882 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9883 * The function must be passed <ul>
9884 * <li>The Record block object</li>
9885 * <li>The "arg" argument from the load function</li>
9886 * <li>A boolean success indicator</li>
9888 * @param {Object} scope The scope in which to call the callback
9889 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9891 load : function(params, reader, callback, scope, arg){
9892 params = params || {};
9895 result = reader.readRecords(this.data);
9897 this.fireEvent("loadexception", this, arg, null, e);
9898 callback.call(scope, null, arg, false);
9901 callback.call(scope, result, arg, true);
9905 update : function(params, records){
9910 * Ext JS Library 1.1.1
9911 * Copyright(c) 2006-2007, Ext JS, LLC.
9913 * Originally Released Under LGPL - original licence link has changed is not relivant.
9916 * <script type="text/javascript">
9919 * @class Roo.data.HttpProxy
9920 * @extends Roo.data.DataProxy
9921 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9922 * configured to reference a certain URL.<br><br>
9924 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9925 * from which the running page was served.<br><br>
9927 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9929 * Be aware that to enable the browser to parse an XML document, the server must set
9930 * the Content-Type header in the HTTP response to "text/xml".
9932 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9933 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9934 * will be used to make the request.
9936 Roo.data.HttpProxy = function(conn){
9937 Roo.data.HttpProxy.superclass.constructor.call(this);
9938 // is conn a conn config or a real conn?
9940 this.useAjax = !conn || !conn.events;
9944 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9945 // thse are take from connection...
9948 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9951 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9952 * extra parameters to each request made by this object. (defaults to undefined)
9955 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9956 * to each request made by this object. (defaults to undefined)
9959 * @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)
9962 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9965 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9971 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9975 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9976 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9977 * a finer-grained basis than the DataProxy events.
9979 getConnection : function(){
9980 return this.useAjax ? Roo.Ajax : this.conn;
9984 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9985 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9986 * process that block using the passed callback.
9987 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9988 * for the request to the remote server.
9989 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9990 * object into a block of Roo.data.Records.
9991 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9992 * The function must be passed <ul>
9993 * <li>The Record block object</li>
9994 * <li>The "arg" argument from the load function</li>
9995 * <li>A boolean success indicator</li>
9997 * @param {Object} scope The scope in which to call the callback
9998 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10000 load : function(params, reader, callback, scope, arg){
10001 if(this.fireEvent("beforeload", this, params) !== false){
10003 params : params || {},
10005 callback : callback,
10010 callback : this.loadResponse,
10014 Roo.applyIf(o, this.conn);
10015 if(this.activeRequest){
10016 Roo.Ajax.abort(this.activeRequest);
10018 this.activeRequest = Roo.Ajax.request(o);
10020 this.conn.request(o);
10023 callback.call(scope||this, null, arg, false);
10028 loadResponse : function(o, success, response){
10029 delete this.activeRequest;
10031 this.fireEvent("loadexception", this, o, response);
10032 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10037 result = o.reader.read(response);
10039 this.fireEvent("loadexception", this, o, response, e);
10040 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10044 this.fireEvent("load", this, o, o.request.arg);
10045 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10049 update : function(dataSet){
10054 updateResponse : function(dataSet){
10059 * Ext JS Library 1.1.1
10060 * Copyright(c) 2006-2007, Ext JS, LLC.
10062 * Originally Released Under LGPL - original licence link has changed is not relivant.
10065 * <script type="text/javascript">
10069 * @class Roo.data.ScriptTagProxy
10070 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10071 * other than the originating domain of the running page.<br><br>
10073 * <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
10074 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10076 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10077 * source code that is used as the source inside a <script> tag.<br><br>
10079 * In order for the browser to process the returned data, the server must wrap the data object
10080 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10081 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10082 * depending on whether the callback name was passed:
10085 boolean scriptTag = false;
10086 String cb = request.getParameter("callback");
10089 response.setContentType("text/javascript");
10091 response.setContentType("application/x-json");
10093 Writer out = response.getWriter();
10095 out.write(cb + "(");
10097 out.print(dataBlock.toJsonString());
10104 * @param {Object} config A configuration object.
10106 Roo.data.ScriptTagProxy = function(config){
10107 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10108 Roo.apply(this, config);
10109 this.head = document.getElementsByTagName("head")[0];
10112 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10114 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10116 * @cfg {String} url The URL from which to request the data object.
10119 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10123 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10124 * the server the name of the callback function set up by the load call to process the returned data object.
10125 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10126 * javascript output which calls this named function passing the data object as its only parameter.
10128 callbackParam : "callback",
10130 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10131 * name to the request.
10136 * Load data from the configured URL, read the data object into
10137 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10138 * process that block using the passed callback.
10139 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10140 * for the request to the remote server.
10141 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10142 * object into a block of Roo.data.Records.
10143 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10144 * The function must be passed <ul>
10145 * <li>The Record block object</li>
10146 * <li>The "arg" argument from the load function</li>
10147 * <li>A boolean success indicator</li>
10149 * @param {Object} scope The scope in which to call the callback
10150 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10152 load : function(params, reader, callback, scope, arg){
10153 if(this.fireEvent("beforeload", this, params) !== false){
10155 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10157 var url = this.url;
10158 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10160 url += "&_dc=" + (new Date().getTime());
10162 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10165 cb : "stcCallback"+transId,
10166 scriptId : "stcScript"+transId,
10170 callback : callback,
10176 window[trans.cb] = function(o){
10177 conn.handleResponse(o, trans);
10180 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10182 if(this.autoAbort !== false){
10186 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10188 var script = document.createElement("script");
10189 script.setAttribute("src", url);
10190 script.setAttribute("type", "text/javascript");
10191 script.setAttribute("id", trans.scriptId);
10192 this.head.appendChild(script);
10194 this.trans = trans;
10196 callback.call(scope||this, null, arg, false);
10201 isLoading : function(){
10202 return this.trans ? true : false;
10206 * Abort the current server request.
10208 abort : function(){
10209 if(this.isLoading()){
10210 this.destroyTrans(this.trans);
10215 destroyTrans : function(trans, isLoaded){
10216 this.head.removeChild(document.getElementById(trans.scriptId));
10217 clearTimeout(trans.timeoutId);
10219 window[trans.cb] = undefined;
10221 delete window[trans.cb];
10224 // if hasn't been loaded, wait for load to remove it to prevent script error
10225 window[trans.cb] = function(){
10226 window[trans.cb] = undefined;
10228 delete window[trans.cb];
10235 handleResponse : function(o, trans){
10236 this.trans = false;
10237 this.destroyTrans(trans, true);
10240 result = trans.reader.readRecords(o);
10242 this.fireEvent("loadexception", this, o, trans.arg, e);
10243 trans.callback.call(trans.scope||window, null, trans.arg, false);
10246 this.fireEvent("load", this, o, trans.arg);
10247 trans.callback.call(trans.scope||window, result, trans.arg, true);
10251 handleFailure : function(trans){
10252 this.trans = false;
10253 this.destroyTrans(trans, false);
10254 this.fireEvent("loadexception", this, null, trans.arg);
10255 trans.callback.call(trans.scope||window, null, trans.arg, false);
10259 * Ext JS Library 1.1.1
10260 * Copyright(c) 2006-2007, Ext JS, LLC.
10262 * Originally Released Under LGPL - original licence link has changed is not relivant.
10265 * <script type="text/javascript">
10269 * @class Roo.data.JsonReader
10270 * @extends Roo.data.DataReader
10271 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10272 * based on mappings in a provided Roo.data.Record constructor.
10274 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10275 * in the reply previously.
10280 var RecordDef = Roo.data.Record.create([
10281 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10282 {name: 'occupation'} // This field will use "occupation" as the mapping.
10284 var myReader = new Roo.data.JsonReader({
10285 totalProperty: "results", // The property which contains the total dataset size (optional)
10286 root: "rows", // The property which contains an Array of row objects
10287 id: "id" // The property within each row object that provides an ID for the record (optional)
10291 * This would consume a JSON file like this:
10293 { 'results': 2, 'rows': [
10294 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10295 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10298 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10299 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10300 * paged from the remote server.
10301 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10302 * @cfg {String} root name of the property which contains the Array of row objects.
10303 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10305 * Create a new JsonReader
10306 * @param {Object} meta Metadata configuration options
10307 * @param {Object} recordType Either an Array of field definition objects,
10308 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10310 Roo.data.JsonReader = function(meta, recordType){
10313 // set some defaults:
10314 Roo.applyIf(meta, {
10315 totalProperty: 'total',
10316 successProperty : 'success',
10321 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10323 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10326 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10327 * Used by Store query builder to append _requestMeta to params.
10330 metaFromRemote : false,
10332 * This method is only used by a DataProxy which has retrieved data from a remote server.
10333 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10334 * @return {Object} data A data block which is used by an Roo.data.Store object as
10335 * a cache of Roo.data.Records.
10337 read : function(response){
10338 var json = response.responseText;
10340 var o = /* eval:var:o */ eval("("+json+")");
10342 throw {message: "JsonReader.read: Json object not found"};
10348 this.metaFromRemote = true;
10349 this.meta = o.metaData;
10350 this.recordType = Roo.data.Record.create(o.metaData.fields);
10351 this.onMetaChange(this.meta, this.recordType, o);
10353 return this.readRecords(o);
10356 // private function a store will implement
10357 onMetaChange : function(meta, recordType, o){
10364 simpleAccess: function(obj, subsc) {
10371 getJsonAccessor: function(){
10373 return function(expr) {
10375 return(re.test(expr))
10376 ? new Function("obj", "return obj." + expr)
10381 return Roo.emptyFn;
10386 * Create a data block containing Roo.data.Records from an XML document.
10387 * @param {Object} o An object which contains an Array of row objects in the property specified
10388 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10389 * which contains the total size of the dataset.
10390 * @return {Object} data A data block which is used by an Roo.data.Store object as
10391 * a cache of Roo.data.Records.
10393 readRecords : function(o){
10395 * After any data loads, the raw JSON data is available for further custom processing.
10399 var s = this.meta, Record = this.recordType,
10400 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10402 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10404 if(s.totalProperty) {
10405 this.getTotal = this.getJsonAccessor(s.totalProperty);
10407 if(s.successProperty) {
10408 this.getSuccess = this.getJsonAccessor(s.successProperty);
10410 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10412 var g = this.getJsonAccessor(s.id);
10413 this.getId = function(rec) {
10415 return (r === undefined || r === "") ? null : r;
10418 this.getId = function(){return null;};
10421 for(var jj = 0; jj < fl; jj++){
10423 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10424 this.ef[jj] = this.getJsonAccessor(map);
10428 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10429 if(s.totalProperty){
10430 var vt = parseInt(this.getTotal(o), 10);
10435 if(s.successProperty){
10436 var vs = this.getSuccess(o);
10437 if(vs === false || vs === 'false'){
10442 for(var i = 0; i < c; i++){
10445 var id = this.getId(n);
10446 for(var j = 0; j < fl; j++){
10448 var v = this.ef[j](n);
10450 Roo.log('missing convert for ' + f.name);
10454 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10456 var record = new Record(values, id);
10458 records[i] = record;
10464 totalRecords : totalRecords
10469 * Ext JS Library 1.1.1
10470 * Copyright(c) 2006-2007, Ext JS, LLC.
10472 * Originally Released Under LGPL - original licence link has changed is not relivant.
10475 * <script type="text/javascript">
10479 * @class Roo.data.ArrayReader
10480 * @extends Roo.data.DataReader
10481 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10482 * Each element of that Array represents a row of data fields. The
10483 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10484 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10488 var RecordDef = Roo.data.Record.create([
10489 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10490 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10492 var myReader = new Roo.data.ArrayReader({
10493 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10497 * This would consume an Array like this:
10499 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10501 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10503 * Create a new JsonReader
10504 * @param {Object} meta Metadata configuration options.
10505 * @param {Object} recordType Either an Array of field definition objects
10506 * as specified to {@link Roo.data.Record#create},
10507 * or an {@link Roo.data.Record} object
10508 * created using {@link Roo.data.Record#create}.
10510 Roo.data.ArrayReader = function(meta, recordType){
10511 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10514 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10516 * Create a data block containing Roo.data.Records from an XML document.
10517 * @param {Object} o An Array of row objects which represents the dataset.
10518 * @return {Object} data A data block which is used by an Roo.data.Store object as
10519 * a cache of Roo.data.Records.
10521 readRecords : function(o){
10522 var sid = this.meta ? this.meta.id : null;
10523 var recordType = this.recordType, fields = recordType.prototype.fields;
10526 for(var i = 0; i < root.length; i++){
10529 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10530 for(var j = 0, jlen = fields.length; j < jlen; j++){
10531 var f = fields.items[j];
10532 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10533 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10535 values[f.name] = v;
10537 var record = new recordType(values, id);
10539 records[records.length] = record;
10543 totalRecords : records.length
10552 * @class Roo.bootstrap.ComboBox
10553 * @extends Roo.bootstrap.TriggerField
10554 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10555 * @cfg {Boolean} append (true|false) default false
10556 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10557 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10558 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10559 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10560 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10562 * Create a new ComboBox.
10563 * @param {Object} config Configuration options
10565 Roo.bootstrap.ComboBox = function(config){
10566 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10570 * Fires when the dropdown list is expanded
10571 * @param {Roo.bootstrap.ComboBox} combo This combo box
10576 * Fires when the dropdown list is collapsed
10577 * @param {Roo.bootstrap.ComboBox} combo This combo box
10581 * @event beforeselect
10582 * Fires before a list item is selected. Return false to cancel the selection.
10583 * @param {Roo.bootstrap.ComboBox} combo This combo box
10584 * @param {Roo.data.Record} record The data record returned from the underlying store
10585 * @param {Number} index The index of the selected item in the dropdown list
10587 'beforeselect' : true,
10590 * Fires when a list item is selected
10591 * @param {Roo.bootstrap.ComboBox} combo This combo box
10592 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10593 * @param {Number} index The index of the selected item in the dropdown list
10597 * @event beforequery
10598 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10599 * The event object passed has these properties:
10600 * @param {Roo.bootstrap.ComboBox} combo This combo box
10601 * @param {String} query The query
10602 * @param {Boolean} forceAll true to force "all" query
10603 * @param {Boolean} cancel true to cancel the query
10604 * @param {Object} e The query event object
10606 'beforequery': true,
10609 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10610 * @param {Roo.bootstrap.ComboBox} combo This combo box
10615 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10616 * @param {Roo.bootstrap.ComboBox} combo This combo box
10617 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10622 * Fires when the remove value from the combobox array
10623 * @param {Roo.bootstrap.ComboBox} combo This combo box
10630 this.tickItems = [];
10632 this.selectedIndex = -1;
10633 if(this.mode == 'local'){
10634 if(config.queryDelay === undefined){
10635 this.queryDelay = 10;
10637 if(config.minChars === undefined){
10643 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10646 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10647 * rendering into an Roo.Editor, defaults to false)
10650 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10651 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10654 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10657 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10658 * the dropdown list (defaults to undefined, with no header element)
10662 * @cfg {String/Roo.Template} tpl The template to use to render the output
10666 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10668 listWidth: undefined,
10670 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10671 * mode = 'remote' or 'text' if mode = 'local')
10673 displayField: undefined,
10675 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10676 * mode = 'remote' or 'value' if mode = 'local').
10677 * Note: use of a valueField requires the user make a selection
10678 * in order for a value to be mapped.
10680 valueField: undefined,
10684 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10685 * field's data value (defaults to the underlying DOM element's name)
10687 hiddenName: undefined,
10689 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10693 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10695 selectedClass: 'active',
10698 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10702 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10703 * anchor positions (defaults to 'tl-bl')
10705 listAlign: 'tl-bl?',
10707 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10711 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10712 * query specified by the allQuery config option (defaults to 'query')
10714 triggerAction: 'query',
10716 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10717 * (defaults to 4, does not apply if editable = false)
10721 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10722 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10726 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10727 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10731 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10732 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10736 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10737 * when editable = true (defaults to false)
10739 selectOnFocus:false,
10741 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10743 queryParam: 'query',
10745 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10746 * when mode = 'remote' (defaults to 'Loading...')
10748 loadingText: 'Loading...',
10750 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10754 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10758 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10759 * traditional select (defaults to true)
10763 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10767 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10771 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10772 * listWidth has a higher value)
10776 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10777 * allow the user to set arbitrary text into the field (defaults to false)
10779 forceSelection:false,
10781 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10782 * if typeAhead = true (defaults to 250)
10784 typeAheadDelay : 250,
10786 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10787 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10789 valueNotFoundText : undefined,
10791 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10793 blockFocus : false,
10796 * @cfg {Boolean} disableClear Disable showing of clear button.
10798 disableClear : false,
10800 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10802 alwaysQuery : false,
10805 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10810 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10812 invalidClass : "has-warning",
10815 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10817 validClass : "has-success",
10829 btnPosition : 'right',
10830 triggerList : true,
10831 showToggleBtn : true,
10832 // element that contains real text value.. (when hidden is used..)
10834 getAutoCreate : function()
10841 if(!this.tickable){
10842 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10847 * ComboBox with tickable selections
10850 var align = this.labelAlign || this.parentLabelAlign();
10853 cls : 'form-group roo-combobox-tickable' //input-group
10859 cls : 'tickable-buttons',
10864 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10871 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10878 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10885 Roo.each(buttons.cn, function(c){
10887 c.cls += ' btn-' + _this.size;
10890 if (_this.disabled) {
10901 cls: 'form-hidden-field'
10905 cls: 'select2-choices',
10909 cls: 'select2-search-field',
10921 cls: 'select2-container input-group select2-container-multi',
10926 // cls: 'typeahead typeahead-long dropdown-menu',
10927 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10932 if (align ==='left' && this.fieldLabel.length) {
10934 Roo.log("left and has label");
10940 cls : 'control-label col-sm-' + this.labelWidth,
10941 html : this.fieldLabel
10945 cls : "col-sm-" + (12 - this.labelWidth),
10952 } else if ( this.fieldLabel.length) {
10958 //cls : 'input-group-addon',
10959 html : this.fieldLabel
10969 Roo.log(" no label && no align");
10976 ['xs','sm','md','lg'].map(function(size){
10977 if (settings[size]) {
10978 cfg.cls += ' col-' + size + '-' + settings[size];
10987 initEvents: function()
10991 throw "can not find store for combo";
10993 this.store = Roo.factory(this.store, Roo.data);
10996 this.initTickableEvents();
11000 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11002 if(this.hiddenName){
11004 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11006 this.hiddenField.dom.value =
11007 this.hiddenValue !== undefined ? this.hiddenValue :
11008 this.value !== undefined ? this.value : '';
11010 // prevent input submission
11011 this.el.dom.removeAttribute('name');
11012 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11017 // this.el.dom.setAttribute('autocomplete', 'off');
11020 var cls = 'x-combo-list';
11022 //this.list = new Roo.Layer({
11023 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11029 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11030 _this.list.setWidth(lw);
11033 this.list.on('mouseover', this.onViewOver, this);
11034 this.list.on('mousemove', this.onViewMove, this);
11036 this.list.on('scroll', this.onViewScroll, this);
11039 this.list.swallowEvent('mousewheel');
11040 this.assetHeight = 0;
11043 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11044 this.assetHeight += this.header.getHeight();
11047 this.innerList = this.list.createChild({cls:cls+'-inner'});
11048 this.innerList.on('mouseover', this.onViewOver, this);
11049 this.innerList.on('mousemove', this.onViewMove, this);
11050 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11052 if(this.allowBlank && !this.pageSize && !this.disableClear){
11053 this.footer = this.list.createChild({cls:cls+'-ft'});
11054 this.pageTb = new Roo.Toolbar(this.footer);
11058 this.footer = this.list.createChild({cls:cls+'-ft'});
11059 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11060 {pageSize: this.pageSize});
11064 if (this.pageTb && this.allowBlank && !this.disableClear) {
11066 this.pageTb.add(new Roo.Toolbar.Fill(), {
11067 cls: 'x-btn-icon x-btn-clear',
11069 handler: function()
11072 _this.clearValue();
11073 _this.onSelect(false, -1);
11078 this.assetHeight += this.footer.getHeight();
11083 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11086 this.view = new Roo.View(this.list, this.tpl, {
11087 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11089 //this.view.wrapEl.setDisplayed(false);
11090 this.view.on('click', this.onViewClick, this);
11094 this.store.on('beforeload', this.onBeforeLoad, this);
11095 this.store.on('load', this.onLoad, this);
11096 this.store.on('loadexception', this.onLoadException, this);
11098 if(this.resizable){
11099 this.resizer = new Roo.Resizable(this.list, {
11100 pinned:true, handles:'se'
11102 this.resizer.on('resize', function(r, w, h){
11103 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11104 this.listWidth = w;
11105 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11106 this.restrictHeight();
11108 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11111 if(!this.editable){
11112 this.editable = true;
11113 this.setEditable(false);
11118 if (typeof(this.events.add.listeners) != 'undefined') {
11120 this.addicon = this.wrap.createChild(
11121 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11123 this.addicon.on('click', function(e) {
11124 this.fireEvent('add', this);
11127 if (typeof(this.events.edit.listeners) != 'undefined') {
11129 this.editicon = this.wrap.createChild(
11130 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11131 if (this.addicon) {
11132 this.editicon.setStyle('margin-left', '40px');
11134 this.editicon.on('click', function(e) {
11136 // we fire even if inothing is selected..
11137 this.fireEvent('edit', this, this.lastData );
11143 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11144 "up" : function(e){
11145 this.inKeyMode = true;
11149 "down" : function(e){
11150 if(!this.isExpanded()){
11151 this.onTriggerClick();
11153 this.inKeyMode = true;
11158 "enter" : function(e){
11159 // this.onViewClick();
11163 if(this.fireEvent("specialkey", this, e)){
11164 this.onViewClick(false);
11170 "esc" : function(e){
11174 "tab" : function(e){
11177 if(this.fireEvent("specialkey", this, e)){
11178 this.onViewClick(false);
11186 doRelay : function(foo, bar, hname){
11187 if(hname == 'down' || this.scope.isExpanded()){
11188 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11197 this.queryDelay = Math.max(this.queryDelay || 10,
11198 this.mode == 'local' ? 10 : 250);
11201 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11203 if(this.typeAhead){
11204 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11206 if(this.editable !== false){
11207 this.inputEl().on("keyup", this.onKeyUp, this);
11209 if(this.forceSelection){
11210 this.inputEl().on('blur', this.doForce, this);
11214 this.choices = this.el.select('ul.select2-choices', true).first();
11215 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11219 initTickableEvents: function()
11223 if(this.hiddenName){
11225 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11227 this.hiddenField.dom.value =
11228 this.hiddenValue !== undefined ? this.hiddenValue :
11229 this.value !== undefined ? this.value : '';
11231 // prevent input submission
11232 this.el.dom.removeAttribute('name');
11233 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11238 // this.list = this.el.select('ul.dropdown-menu',true).first();
11240 this.choices = this.el.select('ul.select2-choices', true).first();
11241 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11242 if(this.triggerList){
11243 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11246 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11247 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11249 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11250 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11252 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11253 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11255 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11256 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11257 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11260 this.cancelBtn.hide();
11265 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11266 _this.list.setWidth(lw);
11269 this.list.on('mouseover', this.onViewOver, this);
11270 this.list.on('mousemove', this.onViewMove, this);
11272 this.list.on('scroll', this.onViewScroll, this);
11275 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>';
11278 this.view = new Roo.View(this.list, this.tpl, {
11279 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11282 //this.view.wrapEl.setDisplayed(false);
11283 this.view.on('click', this.onViewClick, this);
11287 this.store.on('beforeload', this.onBeforeLoad, this);
11288 this.store.on('load', this.onLoad, this);
11289 this.store.on('loadexception', this.onLoadException, this);
11291 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11292 // "up" : function(e){
11293 // this.inKeyMode = true;
11294 // this.selectPrev();
11297 // "down" : function(e){
11298 // if(!this.isExpanded()){
11299 // this.onTriggerClick();
11301 // this.inKeyMode = true;
11302 // this.selectNext();
11306 // "enter" : function(e){
11307 //// this.onViewClick();
11309 // this.collapse();
11311 // if(this.fireEvent("specialkey", this, e)){
11312 // this.onViewClick(false);
11318 // "esc" : function(e){
11319 // this.collapse();
11322 // "tab" : function(e){
11323 // this.collapse();
11325 // if(this.fireEvent("specialkey", this, e)){
11326 // this.onViewClick(false);
11334 // doRelay : function(foo, bar, hname){
11335 // if(hname == 'down' || this.scope.isExpanded()){
11336 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11341 // forceKeyDown: true
11345 this.queryDelay = Math.max(this.queryDelay || 10,
11346 this.mode == 'local' ? 10 : 250);
11349 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11351 if(this.typeAhead){
11352 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11357 onDestroy : function(){
11359 this.view.setStore(null);
11360 this.view.el.removeAllListeners();
11361 this.view.el.remove();
11362 this.view.purgeListeners();
11365 this.list.dom.innerHTML = '';
11369 this.store.un('beforeload', this.onBeforeLoad, this);
11370 this.store.un('load', this.onLoad, this);
11371 this.store.un('loadexception', this.onLoadException, this);
11373 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11377 fireKey : function(e){
11378 if(e.isNavKeyPress() && !this.list.isVisible()){
11379 this.fireEvent("specialkey", this, e);
11384 onResize: function(w, h){
11385 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11387 // if(typeof w != 'number'){
11388 // // we do not handle it!?!?
11391 // var tw = this.trigger.getWidth();
11392 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11393 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11395 // this.inputEl().setWidth( this.adjustWidth('input', x));
11397 // //this.trigger.setStyle('left', x+'px');
11399 // if(this.list && this.listWidth === undefined){
11400 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11401 // this.list.setWidth(lw);
11402 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11410 * Allow or prevent the user from directly editing the field text. If false is passed,
11411 * the user will only be able to select from the items defined in the dropdown list. This method
11412 * is the runtime equivalent of setting the 'editable' config option at config time.
11413 * @param {Boolean} value True to allow the user to directly edit the field text
11415 setEditable : function(value){
11416 if(value == this.editable){
11419 this.editable = value;
11421 this.inputEl().dom.setAttribute('readOnly', true);
11422 this.inputEl().on('mousedown', this.onTriggerClick, this);
11423 this.inputEl().addClass('x-combo-noedit');
11425 this.inputEl().dom.setAttribute('readOnly', false);
11426 this.inputEl().un('mousedown', this.onTriggerClick, this);
11427 this.inputEl().removeClass('x-combo-noedit');
11433 onBeforeLoad : function(combo,opts){
11434 if(!this.hasFocus){
11438 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11440 this.restrictHeight();
11441 this.selectedIndex = -1;
11445 onLoad : function(){
11447 this.hasQuery = false;
11449 if(!this.hasFocus){
11453 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11454 this.loading.hide();
11457 if(this.store.getCount() > 0){
11459 // this.restrictHeight();
11460 if(this.lastQuery == this.allQuery){
11461 if(this.editable && !this.tickable){
11462 this.inputEl().dom.select();
11466 !this.selectByValue(this.value, true) &&
11467 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11468 this.store.lastOptions.add != true)
11470 this.select(0, true);
11473 if(this.autoFocus){
11476 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11477 this.taTask.delay(this.typeAheadDelay);
11481 this.onEmptyResults();
11487 onLoadException : function()
11489 this.hasQuery = false;
11491 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11492 this.loading.hide();
11496 Roo.log(this.store.reader.jsonData);
11497 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11499 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11505 onTypeAhead : function(){
11506 if(this.store.getCount() > 0){
11507 var r = this.store.getAt(0);
11508 var newValue = r.data[this.displayField];
11509 var len = newValue.length;
11510 var selStart = this.getRawValue().length;
11512 if(selStart != len){
11513 this.setRawValue(newValue);
11514 this.selectText(selStart, newValue.length);
11520 onSelect : function(record, index){
11522 if(this.fireEvent('beforeselect', this, record, index) !== false){
11524 this.setFromData(index > -1 ? record.data : false);
11527 this.fireEvent('select', this, record, index);
11532 * Returns the currently selected field value or empty string if no value is set.
11533 * @return {String} value The selected value
11535 getValue : function(){
11538 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11541 if(this.valueField){
11542 return typeof this.value != 'undefined' ? this.value : '';
11544 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11549 * Clears any text/value currently set in the field
11551 clearValue : function(){
11552 if(this.hiddenField){
11553 this.hiddenField.dom.value = '';
11556 this.setRawValue('');
11557 this.lastSelectionText = '';
11558 this.lastData = false;
11563 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11564 * will be displayed in the field. If the value does not match the data value of an existing item,
11565 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11566 * Otherwise the field will be blank (although the value will still be set).
11567 * @param {String} value The value to match
11569 setValue : function(v){
11576 if(this.valueField){
11577 var r = this.findRecord(this.valueField, v);
11579 text = r.data[this.displayField];
11580 }else if(this.valueNotFoundText !== undefined){
11581 text = this.valueNotFoundText;
11584 this.lastSelectionText = text;
11585 if(this.hiddenField){
11586 this.hiddenField.dom.value = v;
11588 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11592 * @property {Object} the last set data for the element
11597 * Sets the value of the field based on a object which is related to the record format for the store.
11598 * @param {Object} value the value to set as. or false on reset?
11600 setFromData : function(o){
11607 var dv = ''; // display value
11608 var vv = ''; // value value..
11610 if (this.displayField) {
11611 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11613 // this is an error condition!!!
11614 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11617 if(this.valueField){
11618 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11621 if(this.hiddenField){
11622 this.hiddenField.dom.value = vv;
11624 this.lastSelectionText = dv;
11625 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11629 // no hidden field.. - we store the value in 'value', but still display
11630 // display field!!!!
11631 this.lastSelectionText = dv;
11632 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11638 reset : function(){
11639 // overridden so that last data is reset..
11640 this.setValue(this.originalValue);
11641 this.clearInvalid();
11642 this.lastData = false;
11644 this.view.clearSelections();
11648 findRecord : function(prop, value){
11650 if(this.store.getCount() > 0){
11651 this.store.each(function(r){
11652 if(r.data[prop] == value){
11662 getName: function()
11664 // returns hidden if it's set..
11665 if (!this.rendered) {return ''};
11666 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11670 onViewMove : function(e, t){
11671 this.inKeyMode = false;
11675 onViewOver : function(e, t){
11676 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11679 var item = this.view.findItemFromChild(t);
11682 var index = this.view.indexOf(item);
11683 this.select(index, false);
11688 onViewClick : function(view, doFocus, el, e)
11690 var index = this.view.getSelectedIndexes()[0];
11692 var r = this.store.getAt(index);
11696 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11703 Roo.each(this.tickItems, function(v,k){
11705 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11706 _this.tickItems.splice(k, 1);
11716 this.tickItems.push(r.data);
11721 this.onSelect(r, index);
11723 if(doFocus !== false && !this.blockFocus){
11724 this.inputEl().focus();
11729 restrictHeight : function(){
11730 //this.innerList.dom.style.height = '';
11731 //var inner = this.innerList.dom;
11732 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11733 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11734 //this.list.beginUpdate();
11735 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11736 this.list.alignTo(this.inputEl(), this.listAlign);
11737 this.list.alignTo(this.inputEl(), this.listAlign);
11738 //this.list.endUpdate();
11742 onEmptyResults : function(){
11747 * Returns true if the dropdown list is expanded, else false.
11749 isExpanded : function(){
11750 return this.list.isVisible();
11754 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11755 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11756 * @param {String} value The data value of the item to select
11757 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11758 * selected item if it is not currently in view (defaults to true)
11759 * @return {Boolean} True if the value matched an item in the list, else false
11761 selectByValue : function(v, scrollIntoView){
11762 if(v !== undefined && v !== null){
11763 var r = this.findRecord(this.valueField || this.displayField, v);
11765 this.select(this.store.indexOf(r), scrollIntoView);
11773 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11774 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11775 * @param {Number} index The zero-based index of the list item to select
11776 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11777 * selected item if it is not currently in view (defaults to true)
11779 select : function(index, scrollIntoView){
11780 this.selectedIndex = index;
11781 this.view.select(index);
11782 if(scrollIntoView !== false){
11783 var el = this.view.getNode(index);
11784 if(el && !this.multiple && !this.tickable){
11785 this.list.scrollChildIntoView(el, false);
11791 selectNext : function(){
11792 var ct = this.store.getCount();
11794 if(this.selectedIndex == -1){
11796 }else if(this.selectedIndex < ct-1){
11797 this.select(this.selectedIndex+1);
11803 selectPrev : function(){
11804 var ct = this.store.getCount();
11806 if(this.selectedIndex == -1){
11808 }else if(this.selectedIndex != 0){
11809 this.select(this.selectedIndex-1);
11815 onKeyUp : function(e){
11816 if(this.editable !== false && !e.isSpecialKey()){
11817 this.lastKey = e.getKey();
11818 this.dqTask.delay(this.queryDelay);
11823 validateBlur : function(){
11824 return !this.list || !this.list.isVisible();
11828 initQuery : function(){
11829 this.doQuery(this.getRawValue());
11833 doForce : function(){
11834 if(this.inputEl().dom.value.length > 0){
11835 this.inputEl().dom.value =
11836 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11842 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11843 * query allowing the query action to be canceled if needed.
11844 * @param {String} query The SQL query to execute
11845 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11846 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11847 * saved in the current store (defaults to false)
11849 doQuery : function(q, forceAll){
11851 if(q === undefined || q === null){
11856 forceAll: forceAll,
11860 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11865 forceAll = qe.forceAll;
11866 if(forceAll === true || (q.length >= this.minChars)){
11868 this.hasQuery = true;
11870 if(this.lastQuery != q || this.alwaysQuery){
11871 this.lastQuery = q;
11872 if(this.mode == 'local'){
11873 this.selectedIndex = -1;
11875 this.store.clearFilter();
11877 this.store.filter(this.displayField, q);
11881 this.store.baseParams[this.queryParam] = q;
11883 var options = {params : this.getParams(q)};
11886 options.add = true;
11887 options.params.start = this.page * this.pageSize;
11890 this.store.load(options);
11892 * this code will make the page width larger, at the beginning, the list not align correctly,
11893 * we should expand the list on onLoad
11894 * so command out it
11899 this.selectedIndex = -1;
11904 this.loadNext = false;
11908 getParams : function(q){
11910 //p[this.queryParam] = q;
11914 p.limit = this.pageSize;
11920 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11922 collapse : function(){
11923 if(!this.isExpanded()){
11930 this.hasFocus = false;
11932 this.cancelBtn.hide();
11933 this.trigger.show();
11936 Roo.get(document).un('mousedown', this.collapseIf, this);
11937 Roo.get(document).un('mousewheel', this.collapseIf, this);
11938 if (!this.editable) {
11939 Roo.get(document).un('keydown', this.listKeyPress, this);
11941 this.fireEvent('collapse', this);
11945 collapseIf : function(e){
11946 var in_combo = e.within(this.el);
11947 var in_list = e.within(this.list);
11948 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11950 if (in_combo || in_list || is_list) {
11951 //e.stopPropagation();
11956 this.onTickableFooterButtonClick(e, false, false);
11964 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11966 expand : function(){
11968 if(this.isExpanded() || !this.hasFocus){
11972 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11973 this.list.setWidth(lw);
11980 this.restrictHeight();
11984 this.tickItems = Roo.apply([], this.item);
11987 this.cancelBtn.show();
11988 this.trigger.hide();
11992 Roo.get(document).on('mousedown', this.collapseIf, this);
11993 Roo.get(document).on('mousewheel', this.collapseIf, this);
11994 if (!this.editable) {
11995 Roo.get(document).on('keydown', this.listKeyPress, this);
11998 this.fireEvent('expand', this);
12002 // Implements the default empty TriggerField.onTriggerClick function
12003 onTriggerClick : function(e)
12005 Roo.log('trigger click');
12007 if(this.disabled || !this.triggerList){
12012 this.loadNext = false;
12014 if(this.isExpanded()){
12016 if (!this.blockFocus) {
12017 this.inputEl().focus();
12021 this.hasFocus = true;
12022 if(this.triggerAction == 'all') {
12023 this.doQuery(this.allQuery, true);
12025 this.doQuery(this.getRawValue());
12027 if (!this.blockFocus) {
12028 this.inputEl().focus();
12033 onTickableTriggerClick : function(e)
12040 this.loadNext = false;
12041 this.hasFocus = true;
12043 if(this.triggerAction == 'all') {
12044 this.doQuery(this.allQuery, true);
12046 this.doQuery(this.getRawValue());
12050 onSearchFieldClick : function(e)
12052 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12053 this.onTickableFooterButtonClick(e, false, false);
12057 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12062 this.loadNext = false;
12063 this.hasFocus = true;
12065 if(this.triggerAction == 'all') {
12066 this.doQuery(this.allQuery, true);
12068 this.doQuery(this.getRawValue());
12072 listKeyPress : function(e)
12074 //Roo.log('listkeypress');
12075 // scroll to first matching element based on key pres..
12076 if (e.isSpecialKey()) {
12079 var k = String.fromCharCode(e.getKey()).toUpperCase();
12082 var csel = this.view.getSelectedNodes();
12083 var cselitem = false;
12085 var ix = this.view.indexOf(csel[0]);
12086 cselitem = this.store.getAt(ix);
12087 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12093 this.store.each(function(v) {
12095 // start at existing selection.
12096 if (cselitem.id == v.id) {
12102 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12103 match = this.store.indexOf(v);
12109 if (match === false) {
12110 return true; // no more action?
12113 this.view.select(match);
12114 var sn = Roo.get(this.view.getSelectedNodes()[0])
12115 sn.scrollIntoView(sn.dom.parentNode, false);
12118 onViewScroll : function(e, t){
12120 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){
12124 this.hasQuery = true;
12126 this.loading = this.list.select('.loading', true).first();
12128 if(this.loading === null){
12129 this.list.createChild({
12131 cls: 'loading select2-more-results select2-active',
12132 html: 'Loading more results...'
12135 this.loading = this.list.select('.loading', true).first();
12137 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12139 this.loading.hide();
12142 this.loading.show();
12147 this.loadNext = true;
12149 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12154 addItem : function(o)
12156 var dv = ''; // display value
12158 if (this.displayField) {
12159 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12161 // this is an error condition!!!
12162 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12169 var choice = this.choices.createChild({
12171 cls: 'select2-search-choice',
12180 cls: 'select2-search-choice-close',
12185 }, this.searchField);
12187 var close = choice.select('a.select2-search-choice-close', true).first()
12189 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12197 this.inputEl().dom.value = '';
12202 onRemoveItem : function(e, _self, o)
12204 e.preventDefault();
12206 this.lastItem = Roo.apply([], this.item);
12208 var index = this.item.indexOf(o.data) * 1;
12211 Roo.log('not this item?!');
12215 this.item.splice(index, 1);
12220 this.fireEvent('remove', this, e);
12226 syncValue : function()
12228 if(!this.item.length){
12235 Roo.each(this.item, function(i){
12236 if(_this.valueField){
12237 value.push(i[_this.valueField]);
12244 this.value = value.join(',');
12246 if(this.hiddenField){
12247 this.hiddenField.dom.value = this.value;
12251 clearItem : function()
12253 if(!this.multiple){
12259 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12268 inputEl: function ()
12271 return this.searchField;
12273 return this.el.select('input.form-control',true).first();
12277 onTickableFooterButtonClick : function(e, btn, el)
12279 e.preventDefault();
12281 this.lastItem = Roo.apply([], this.item);
12283 if(btn && btn.name == 'cancel'){
12284 this.tickItems = Roo.apply([], this.item);
12293 Roo.each(this.tickItems, function(o){
12301 validate : function()
12303 var v = this.getRawValue();
12306 v = this.getValue();
12309 if(this.disabled || this.allowBlank || v.length){
12314 this.markInvalid();
12321 * @cfg {Boolean} grow
12325 * @cfg {Number} growMin
12329 * @cfg {Number} growMax
12339 * Ext JS Library 1.1.1
12340 * Copyright(c) 2006-2007, Ext JS, LLC.
12342 * Originally Released Under LGPL - original licence link has changed is not relivant.
12345 * <script type="text/javascript">
12350 * @extends Roo.util.Observable
12351 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12352 * This class also supports single and multi selection modes. <br>
12353 * Create a data model bound view:
12355 var store = new Roo.data.Store(...);
12357 var view = new Roo.View({
12359 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12361 singleSelect: true,
12362 selectedClass: "ydataview-selected",
12366 // listen for node click?
12367 view.on("click", function(vw, index, node, e){
12368 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12372 dataModel.load("foobar.xml");
12374 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12376 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12377 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12379 * Note: old style constructor is still suported (container, template, config)
12382 * Create a new View
12383 * @param {Object} config The config object
12386 Roo.View = function(config, depreciated_tpl, depreciated_config){
12388 this.parent = false;
12390 if (typeof(depreciated_tpl) == 'undefined') {
12391 // new way.. - universal constructor.
12392 Roo.apply(this, config);
12393 this.el = Roo.get(this.el);
12396 this.el = Roo.get(config);
12397 this.tpl = depreciated_tpl;
12398 Roo.apply(this, depreciated_config);
12400 this.wrapEl = this.el.wrap().wrap();
12401 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12404 if(typeof(this.tpl) == "string"){
12405 this.tpl = new Roo.Template(this.tpl);
12407 // support xtype ctors..
12408 this.tpl = new Roo.factory(this.tpl, Roo);
12412 this.tpl.compile();
12417 * @event beforeclick
12418 * Fires before a click is processed. Returns false to cancel the default action.
12419 * @param {Roo.View} this
12420 * @param {Number} index The index of the target node
12421 * @param {HTMLElement} node The target node
12422 * @param {Roo.EventObject} e The raw event object
12424 "beforeclick" : true,
12427 * Fires when a template node is clicked.
12428 * @param {Roo.View} this
12429 * @param {Number} index The index of the target node
12430 * @param {HTMLElement} node The target node
12431 * @param {Roo.EventObject} e The raw event object
12436 * Fires when a template node is double clicked.
12437 * @param {Roo.View} this
12438 * @param {Number} index The index of the target node
12439 * @param {HTMLElement} node The target node
12440 * @param {Roo.EventObject} e The raw event object
12444 * @event contextmenu
12445 * Fires when a template node is right clicked.
12446 * @param {Roo.View} this
12447 * @param {Number} index The index of the target node
12448 * @param {HTMLElement} node The target node
12449 * @param {Roo.EventObject} e The raw event object
12451 "contextmenu" : true,
12453 * @event selectionchange
12454 * Fires when the selected nodes change.
12455 * @param {Roo.View} this
12456 * @param {Array} selections Array of the selected nodes
12458 "selectionchange" : true,
12461 * @event beforeselect
12462 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12463 * @param {Roo.View} this
12464 * @param {HTMLElement} node The node to be selected
12465 * @param {Array} selections Array of currently selected nodes
12467 "beforeselect" : true,
12469 * @event preparedata
12470 * Fires on every row to render, to allow you to change the data.
12471 * @param {Roo.View} this
12472 * @param {Object} data to be rendered (change this)
12474 "preparedata" : true
12482 "click": this.onClick,
12483 "dblclick": this.onDblClick,
12484 "contextmenu": this.onContextMenu,
12488 this.selections = [];
12490 this.cmp = new Roo.CompositeElementLite([]);
12492 this.store = Roo.factory(this.store, Roo.data);
12493 this.setStore(this.store, true);
12496 if ( this.footer && this.footer.xtype) {
12498 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12500 this.footer.dataSource = this.store
12501 this.footer.container = fctr;
12502 this.footer = Roo.factory(this.footer, Roo);
12503 fctr.insertFirst(this.el);
12505 // this is a bit insane - as the paging toolbar seems to detach the el..
12506 // dom.parentNode.parentNode.parentNode
12507 // they get detached?
12511 Roo.View.superclass.constructor.call(this);
12516 Roo.extend(Roo.View, Roo.util.Observable, {
12519 * @cfg {Roo.data.Store} store Data store to load data from.
12524 * @cfg {String|Roo.Element} el The container element.
12529 * @cfg {String|Roo.Template} tpl The template used by this View
12533 * @cfg {String} dataName the named area of the template to use as the data area
12534 * Works with domtemplates roo-name="name"
12538 * @cfg {String} selectedClass The css class to add to selected nodes
12540 selectedClass : "x-view-selected",
12542 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12547 * @cfg {String} text to display on mask (default Loading)
12551 * @cfg {Boolean} multiSelect Allow multiple selection
12553 multiSelect : false,
12555 * @cfg {Boolean} singleSelect Allow single selection
12557 singleSelect: false,
12560 * @cfg {Boolean} toggleSelect - selecting
12562 toggleSelect : false,
12565 * @cfg {Boolean} tickable - selecting
12570 * Returns the element this view is bound to.
12571 * @return {Roo.Element}
12573 getEl : function(){
12574 return this.wrapEl;
12580 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12582 refresh : function(){
12583 //Roo.log('refresh');
12586 // if we are using something like 'domtemplate', then
12587 // the what gets used is:
12588 // t.applySubtemplate(NAME, data, wrapping data..)
12589 // the outer template then get' applied with
12590 // the store 'extra data'
12591 // and the body get's added to the
12592 // roo-name="data" node?
12593 // <span class='roo-tpl-{name}'></span> ?????
12597 this.clearSelections();
12598 this.el.update("");
12600 var records = this.store.getRange();
12601 if(records.length < 1) {
12603 // is this valid?? = should it render a template??
12605 this.el.update(this.emptyText);
12609 if (this.dataName) {
12610 this.el.update(t.apply(this.store.meta)); //????
12611 el = this.el.child('.roo-tpl-' + this.dataName);
12614 for(var i = 0, len = records.length; i < len; i++){
12615 var data = this.prepareData(records[i].data, i, records[i]);
12616 this.fireEvent("preparedata", this, data, i, records[i]);
12618 var d = Roo.apply({}, data);
12621 Roo.apply(d, {'roo-id' : Roo.id()});
12625 Roo.each(this.parent.item, function(item){
12626 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12629 Roo.apply(d, {'roo-data-checked' : 'checked'});
12633 html[html.length] = Roo.util.Format.trim(
12635 t.applySubtemplate(this.dataName, d, this.store.meta) :
12642 el.update(html.join(""));
12643 this.nodes = el.dom.childNodes;
12644 this.updateIndexes(0);
12649 * Function to override to reformat the data that is sent to
12650 * the template for each node.
12651 * DEPRICATED - use the preparedata event handler.
12652 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12653 * a JSON object for an UpdateManager bound view).
12655 prepareData : function(data, index, record)
12657 this.fireEvent("preparedata", this, data, index, record);
12661 onUpdate : function(ds, record){
12662 // Roo.log('on update');
12663 this.clearSelections();
12664 var index = this.store.indexOf(record);
12665 var n = this.nodes[index];
12666 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12667 n.parentNode.removeChild(n);
12668 this.updateIndexes(index, index);
12674 onAdd : function(ds, records, index)
12676 //Roo.log(['on Add', ds, records, index] );
12677 this.clearSelections();
12678 if(this.nodes.length == 0){
12682 var n = this.nodes[index];
12683 for(var i = 0, len = records.length; i < len; i++){
12684 var d = this.prepareData(records[i].data, i, records[i]);
12686 this.tpl.insertBefore(n, d);
12689 this.tpl.append(this.el, d);
12692 this.updateIndexes(index);
12695 onRemove : function(ds, record, index){
12696 // Roo.log('onRemove');
12697 this.clearSelections();
12698 var el = this.dataName ?
12699 this.el.child('.roo-tpl-' + this.dataName) :
12702 el.dom.removeChild(this.nodes[index]);
12703 this.updateIndexes(index);
12707 * Refresh an individual node.
12708 * @param {Number} index
12710 refreshNode : function(index){
12711 this.onUpdate(this.store, this.store.getAt(index));
12714 updateIndexes : function(startIndex, endIndex){
12715 var ns = this.nodes;
12716 startIndex = startIndex || 0;
12717 endIndex = endIndex || ns.length - 1;
12718 for(var i = startIndex; i <= endIndex; i++){
12719 ns[i].nodeIndex = i;
12724 * Changes the data store this view uses and refresh the view.
12725 * @param {Store} store
12727 setStore : function(store, initial){
12728 if(!initial && this.store){
12729 this.store.un("datachanged", this.refresh);
12730 this.store.un("add", this.onAdd);
12731 this.store.un("remove", this.onRemove);
12732 this.store.un("update", this.onUpdate);
12733 this.store.un("clear", this.refresh);
12734 this.store.un("beforeload", this.onBeforeLoad);
12735 this.store.un("load", this.onLoad);
12736 this.store.un("loadexception", this.onLoad);
12740 store.on("datachanged", this.refresh, this);
12741 store.on("add", this.onAdd, this);
12742 store.on("remove", this.onRemove, this);
12743 store.on("update", this.onUpdate, this);
12744 store.on("clear", this.refresh, this);
12745 store.on("beforeload", this.onBeforeLoad, this);
12746 store.on("load", this.onLoad, this);
12747 store.on("loadexception", this.onLoad, this);
12755 * onbeforeLoad - masks the loading area.
12758 onBeforeLoad : function(store,opts)
12760 //Roo.log('onBeforeLoad');
12762 this.el.update("");
12764 this.el.mask(this.mask ? this.mask : "Loading" );
12766 onLoad : function ()
12773 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12774 * @param {HTMLElement} node
12775 * @return {HTMLElement} The template node
12777 findItemFromChild : function(node){
12778 var el = this.dataName ?
12779 this.el.child('.roo-tpl-' + this.dataName,true) :
12782 if(!node || node.parentNode == el){
12785 var p = node.parentNode;
12786 while(p && p != el){
12787 if(p.parentNode == el){
12796 onClick : function(e){
12797 var item = this.findItemFromChild(e.getTarget());
12799 var index = this.indexOf(item);
12800 if(this.onItemClick(item, index, e) !== false){
12801 this.fireEvent("click", this, index, item, e);
12804 this.clearSelections();
12809 onContextMenu : function(e){
12810 var item = this.findItemFromChild(e.getTarget());
12812 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12817 onDblClick : function(e){
12818 var item = this.findItemFromChild(e.getTarget());
12820 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12824 onItemClick : function(item, index, e)
12826 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12829 if (this.toggleSelect) {
12830 var m = this.isSelected(item) ? 'unselect' : 'select';
12833 _t[m](item, true, false);
12836 if(this.multiSelect || this.singleSelect){
12837 if(this.multiSelect && e.shiftKey && this.lastSelection){
12838 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12840 this.select(item, this.multiSelect && e.ctrlKey);
12841 this.lastSelection = item;
12844 if(!this.tickable){
12845 e.preventDefault();
12853 * Get the number of selected nodes.
12856 getSelectionCount : function(){
12857 return this.selections.length;
12861 * Get the currently selected nodes.
12862 * @return {Array} An array of HTMLElements
12864 getSelectedNodes : function(){
12865 return this.selections;
12869 * Get the indexes of the selected nodes.
12872 getSelectedIndexes : function(){
12873 var indexes = [], s = this.selections;
12874 for(var i = 0, len = s.length; i < len; i++){
12875 indexes.push(s[i].nodeIndex);
12881 * Clear all selections
12882 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12884 clearSelections : function(suppressEvent){
12885 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12886 this.cmp.elements = this.selections;
12887 this.cmp.removeClass(this.selectedClass);
12888 this.selections = [];
12889 if(!suppressEvent){
12890 this.fireEvent("selectionchange", this, this.selections);
12896 * Returns true if the passed node is selected
12897 * @param {HTMLElement/Number} node The node or node index
12898 * @return {Boolean}
12900 isSelected : function(node){
12901 var s = this.selections;
12905 node = this.getNode(node);
12906 return s.indexOf(node) !== -1;
12911 * @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
12912 * @param {Boolean} keepExisting (optional) true to keep existing selections
12913 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12915 select : function(nodeInfo, keepExisting, suppressEvent){
12916 if(nodeInfo instanceof Array){
12918 this.clearSelections(true);
12920 for(var i = 0, len = nodeInfo.length; i < len; i++){
12921 this.select(nodeInfo[i], true, true);
12925 var node = this.getNode(nodeInfo);
12926 if(!node || this.isSelected(node)){
12927 return; // already selected.
12930 this.clearSelections(true);
12933 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12934 Roo.fly(node).addClass(this.selectedClass);
12935 this.selections.push(node);
12936 if(!suppressEvent){
12937 this.fireEvent("selectionchange", this, this.selections);
12945 * @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
12946 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12947 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12949 unselect : function(nodeInfo, keepExisting, suppressEvent)
12951 if(nodeInfo instanceof Array){
12952 Roo.each(this.selections, function(s) {
12953 this.unselect(s, nodeInfo);
12957 var node = this.getNode(nodeInfo);
12958 if(!node || !this.isSelected(node)){
12959 //Roo.log("not selected");
12960 return; // not selected.
12964 Roo.each(this.selections, function(s) {
12966 Roo.fly(node).removeClass(this.selectedClass);
12973 this.selections= ns;
12974 this.fireEvent("selectionchange", this, this.selections);
12978 * Gets a template node.
12979 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12980 * @return {HTMLElement} The node or null if it wasn't found
12982 getNode : function(nodeInfo){
12983 if(typeof nodeInfo == "string"){
12984 return document.getElementById(nodeInfo);
12985 }else if(typeof nodeInfo == "number"){
12986 return this.nodes[nodeInfo];
12992 * Gets a range template nodes.
12993 * @param {Number} startIndex
12994 * @param {Number} endIndex
12995 * @return {Array} An array of nodes
12997 getNodes : function(start, end){
12998 var ns = this.nodes;
12999 start = start || 0;
13000 end = typeof end == "undefined" ? ns.length - 1 : end;
13003 for(var i = start; i <= end; i++){
13007 for(var i = start; i >= end; i--){
13015 * Finds the index of the passed node
13016 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13017 * @return {Number} The index of the node or -1
13019 indexOf : function(node){
13020 node = this.getNode(node);
13021 if(typeof node.nodeIndex == "number"){
13022 return node.nodeIndex;
13024 var ns = this.nodes;
13025 for(var i = 0, len = ns.length; i < len; i++){
13036 * based on jquery fullcalendar
13040 Roo.bootstrap = Roo.bootstrap || {};
13042 * @class Roo.bootstrap.Calendar
13043 * @extends Roo.bootstrap.Component
13044 * Bootstrap Calendar class
13045 * @cfg {Boolean} loadMask (true|false) default false
13046 * @cfg {Object} header generate the user specific header of the calendar, default false
13049 * Create a new Container
13050 * @param {Object} config The config object
13055 Roo.bootstrap.Calendar = function(config){
13056 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13060 * Fires when a date is selected
13061 * @param {DatePicker} this
13062 * @param {Date} date The selected date
13066 * @event monthchange
13067 * Fires when the displayed month changes
13068 * @param {DatePicker} this
13069 * @param {Date} date The selected month
13071 'monthchange': true,
13073 * @event evententer
13074 * Fires when mouse over an event
13075 * @param {Calendar} this
13076 * @param {event} Event
13078 'evententer': true,
13080 * @event eventleave
13081 * Fires when the mouse leaves an
13082 * @param {Calendar} this
13085 'eventleave': true,
13087 * @event eventclick
13088 * Fires when the mouse click an
13089 * @param {Calendar} this
13098 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13101 * @cfg {Number} startDay
13102 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13110 getAutoCreate : function(){
13113 var fc_button = function(name, corner, style, content ) {
13114 return Roo.apply({},{
13116 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13118 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13121 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13132 style : 'width:100%',
13139 cls : 'fc-header-left',
13141 fc_button('prev', 'left', 'arrow', '‹' ),
13142 fc_button('next', 'right', 'arrow', '›' ),
13143 { tag: 'span', cls: 'fc-header-space' },
13144 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13152 cls : 'fc-header-center',
13156 cls: 'fc-header-title',
13159 html : 'month / year'
13167 cls : 'fc-header-right',
13169 /* fc_button('month', 'left', '', 'month' ),
13170 fc_button('week', '', '', 'week' ),
13171 fc_button('day', 'right', '', 'day' )
13183 header = this.header;
13186 var cal_heads = function() {
13188 // fixme - handle this.
13190 for (var i =0; i < Date.dayNames.length; i++) {
13191 var d = Date.dayNames[i];
13194 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13195 html : d.substring(0,3)
13199 ret[0].cls += ' fc-first';
13200 ret[6].cls += ' fc-last';
13203 var cal_cell = function(n) {
13206 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13211 cls: 'fc-day-number',
13215 cls: 'fc-day-content',
13219 style: 'position: relative;' // height: 17px;
13231 var cal_rows = function() {
13234 for (var r = 0; r < 6; r++) {
13241 for (var i =0; i < Date.dayNames.length; i++) {
13242 var d = Date.dayNames[i];
13243 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13246 row.cn[0].cls+=' fc-first';
13247 row.cn[0].cn[0].style = 'min-height:90px';
13248 row.cn[6].cls+=' fc-last';
13252 ret[0].cls += ' fc-first';
13253 ret[4].cls += ' fc-prev-last';
13254 ret[5].cls += ' fc-last';
13261 cls: 'fc-border-separate',
13262 style : 'width:100%',
13270 cls : 'fc-first fc-last',
13288 cls : 'fc-content',
13289 style : "position: relative;",
13292 cls : 'fc-view fc-view-month fc-grid',
13293 style : 'position: relative',
13294 unselectable : 'on',
13297 cls : 'fc-event-container',
13298 style : 'position:absolute;z-index:8;top:0;left:0;'
13316 initEvents : function()
13319 throw "can not find store for calendar";
13325 style: "text-align:center",
13329 style: "background-color:white;width:50%;margin:250 auto",
13333 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13344 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13346 var size = this.el.select('.fc-content', true).first().getSize();
13347 this.maskEl.setSize(size.width, size.height);
13348 this.maskEl.enableDisplayMode("block");
13349 if(!this.loadMask){
13350 this.maskEl.hide();
13353 this.store = Roo.factory(this.store, Roo.data);
13354 this.store.on('load', this.onLoad, this);
13355 this.store.on('beforeload', this.onBeforeLoad, this);
13359 this.cells = this.el.select('.fc-day',true);
13360 //Roo.log(this.cells);
13361 this.textNodes = this.el.query('.fc-day-number');
13362 this.cells.addClassOnOver('fc-state-hover');
13364 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13365 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13366 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13367 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13369 this.on('monthchange', this.onMonthChange, this);
13371 this.update(new Date().clearTime());
13374 resize : function() {
13375 var sz = this.el.getSize();
13377 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13378 this.el.select('.fc-day-content div',true).setHeight(34);
13383 showPrevMonth : function(e){
13384 this.update(this.activeDate.add("mo", -1));
13386 showToday : function(e){
13387 this.update(new Date().clearTime());
13390 showNextMonth : function(e){
13391 this.update(this.activeDate.add("mo", 1));
13395 showPrevYear : function(){
13396 this.update(this.activeDate.add("y", -1));
13400 showNextYear : function(){
13401 this.update(this.activeDate.add("y", 1));
13406 update : function(date)
13408 var vd = this.activeDate;
13409 this.activeDate = date;
13410 // if(vd && this.el){
13411 // var t = date.getTime();
13412 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13413 // Roo.log('using add remove');
13415 // this.fireEvent('monthchange', this, date);
13417 // this.cells.removeClass("fc-state-highlight");
13418 // this.cells.each(function(c){
13419 // if(c.dateValue == t){
13420 // c.addClass("fc-state-highlight");
13421 // setTimeout(function(){
13422 // try{c.dom.firstChild.focus();}catch(e){}
13432 var days = date.getDaysInMonth();
13434 var firstOfMonth = date.getFirstDateOfMonth();
13435 var startingPos = firstOfMonth.getDay()-this.startDay;
13437 if(startingPos < this.startDay){
13441 var pm = date.add(Date.MONTH, -1);
13442 var prevStart = pm.getDaysInMonth()-startingPos;
13444 this.cells = this.el.select('.fc-day',true);
13445 this.textNodes = this.el.query('.fc-day-number');
13446 this.cells.addClassOnOver('fc-state-hover');
13448 var cells = this.cells.elements;
13449 var textEls = this.textNodes;
13451 Roo.each(cells, function(cell){
13452 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13455 days += startingPos;
13457 // convert everything to numbers so it's fast
13458 var day = 86400000;
13459 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13462 //Roo.log(prevStart);
13464 var today = new Date().clearTime().getTime();
13465 var sel = date.clearTime().getTime();
13466 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13467 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13468 var ddMatch = this.disabledDatesRE;
13469 var ddText = this.disabledDatesText;
13470 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13471 var ddaysText = this.disabledDaysText;
13472 var format = this.format;
13474 var setCellClass = function(cal, cell){
13478 //Roo.log('set Cell Class');
13480 var t = d.getTime();
13484 cell.dateValue = t;
13486 cell.className += " fc-today";
13487 cell.className += " fc-state-highlight";
13488 cell.title = cal.todayText;
13491 // disable highlight in other month..
13492 //cell.className += " fc-state-highlight";
13497 cell.className = " fc-state-disabled";
13498 cell.title = cal.minText;
13502 cell.className = " fc-state-disabled";
13503 cell.title = cal.maxText;
13507 if(ddays.indexOf(d.getDay()) != -1){
13508 cell.title = ddaysText;
13509 cell.className = " fc-state-disabled";
13512 if(ddMatch && format){
13513 var fvalue = d.dateFormat(format);
13514 if(ddMatch.test(fvalue)){
13515 cell.title = ddText.replace("%0", fvalue);
13516 cell.className = " fc-state-disabled";
13520 if (!cell.initialClassName) {
13521 cell.initialClassName = cell.dom.className;
13524 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13529 for(; i < startingPos; i++) {
13530 textEls[i].innerHTML = (++prevStart);
13531 d.setDate(d.getDate()+1);
13533 cells[i].className = "fc-past fc-other-month";
13534 setCellClass(this, cells[i]);
13539 for(; i < days; i++){
13540 intDay = i - startingPos + 1;
13541 textEls[i].innerHTML = (intDay);
13542 d.setDate(d.getDate()+1);
13544 cells[i].className = ''; // "x-date-active";
13545 setCellClass(this, cells[i]);
13549 for(; i < 42; i++) {
13550 textEls[i].innerHTML = (++extraDays);
13551 d.setDate(d.getDate()+1);
13553 cells[i].className = "fc-future fc-other-month";
13554 setCellClass(this, cells[i]);
13557 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13559 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13561 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13562 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13564 if(totalRows != 6){
13565 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13566 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13569 this.fireEvent('monthchange', this, date);
13573 if(!this.internalRender){
13574 var main = this.el.dom.firstChild;
13575 var w = main.offsetWidth;
13576 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13577 Roo.fly(main).setWidth(w);
13578 this.internalRender = true;
13579 // opera does not respect the auto grow header center column
13580 // then, after it gets a width opera refuses to recalculate
13581 // without a second pass
13582 if(Roo.isOpera && !this.secondPass){
13583 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13584 this.secondPass = true;
13585 this.update.defer(10, this, [date]);
13592 findCell : function(dt) {
13593 dt = dt.clearTime().getTime();
13595 this.cells.each(function(c){
13596 //Roo.log("check " +c.dateValue + '?=' + dt);
13597 if(c.dateValue == dt){
13607 findCells : function(ev) {
13608 var s = ev.start.clone().clearTime().getTime();
13610 var e= ev.end.clone().clearTime().getTime();
13613 this.cells.each(function(c){
13614 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13616 if(c.dateValue > e){
13619 if(c.dateValue < s){
13628 // findBestRow: function(cells)
13632 // for (var i =0 ; i < cells.length;i++) {
13633 // ret = Math.max(cells[i].rows || 0,ret);
13640 addItem : function(ev)
13642 // look for vertical location slot in
13643 var cells = this.findCells(ev);
13645 // ev.row = this.findBestRow(cells);
13647 // work out the location.
13651 for(var i =0; i < cells.length; i++) {
13653 cells[i].row = cells[0].row;
13656 cells[i].row = cells[i].row + 1;
13666 if (crow.start.getY() == cells[i].getY()) {
13668 crow.end = cells[i];
13685 cells[0].events.push(ev);
13687 this.calevents.push(ev);
13690 clearEvents: function() {
13692 if(!this.calevents){
13696 Roo.each(this.cells.elements, function(c){
13702 Roo.each(this.calevents, function(e) {
13703 Roo.each(e.els, function(el) {
13704 el.un('mouseenter' ,this.onEventEnter, this);
13705 el.un('mouseleave' ,this.onEventLeave, this);
13710 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13716 renderEvents: function()
13720 this.cells.each(function(c) {
13729 if(c.row != c.events.length){
13730 r = 4 - (4 - (c.row - c.events.length));
13733 c.events = ev.slice(0, r);
13734 c.more = ev.slice(r);
13736 if(c.more.length && c.more.length == 1){
13737 c.events.push(c.more.pop());
13740 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13744 this.cells.each(function(c) {
13746 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13749 for (var e = 0; e < c.events.length; e++){
13750 var ev = c.events[e];
13751 var rows = ev.rows;
13753 for(var i = 0; i < rows.length; i++) {
13755 // how many rows should it span..
13758 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13759 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13761 unselectable : "on",
13764 cls: 'fc-event-inner',
13768 // cls: 'fc-event-time',
13769 // html : cells.length > 1 ? '' : ev.time
13773 cls: 'fc-event-title',
13774 html : String.format('{0}', ev.title)
13781 cls: 'ui-resizable-handle ui-resizable-e',
13782 html : '  '
13789 cfg.cls += ' fc-event-start';
13791 if ((i+1) == rows.length) {
13792 cfg.cls += ' fc-event-end';
13795 var ctr = _this.el.select('.fc-event-container',true).first();
13796 var cg = ctr.createChild(cfg);
13798 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13799 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13801 var r = (c.more.length) ? 1 : 0;
13802 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13803 cg.setWidth(ebox.right - sbox.x -2);
13805 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13806 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13807 cg.on('click', _this.onEventClick, _this, ev);
13818 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13819 style : 'position: absolute',
13820 unselectable : "on",
13823 cls: 'fc-event-inner',
13827 cls: 'fc-event-title',
13835 cls: 'ui-resizable-handle ui-resizable-e',
13836 html : '  '
13842 var ctr = _this.el.select('.fc-event-container',true).first();
13843 var cg = ctr.createChild(cfg);
13845 var sbox = c.select('.fc-day-content',true).first().getBox();
13846 var ebox = c.select('.fc-day-content',true).first().getBox();
13848 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13849 cg.setWidth(ebox.right - sbox.x -2);
13851 cg.on('click', _this.onMoreEventClick, _this, c.more);
13861 onEventEnter: function (e, el,event,d) {
13862 this.fireEvent('evententer', this, el, event);
13865 onEventLeave: function (e, el,event,d) {
13866 this.fireEvent('eventleave', this, el, event);
13869 onEventClick: function (e, el,event,d) {
13870 this.fireEvent('eventclick', this, el, event);
13873 onMonthChange: function () {
13877 onMoreEventClick: function(e, el, more)
13881 this.calpopover.placement = 'right';
13882 this.calpopover.setTitle('More');
13884 this.calpopover.setContent('');
13886 var ctr = this.calpopover.el.select('.popover-content', true).first();
13888 Roo.each(more, function(m){
13890 cls : 'fc-event-hori fc-event-draggable',
13893 var cg = ctr.createChild(cfg);
13895 cg.on('click', _this.onEventClick, _this, m);
13898 this.calpopover.show(el);
13903 onLoad: function ()
13905 this.calevents = [];
13908 if(this.store.getCount() > 0){
13909 this.store.data.each(function(d){
13912 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13913 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13914 time : d.data.start_time,
13915 title : d.data.title,
13916 description : d.data.description,
13917 venue : d.data.venue
13922 this.renderEvents();
13924 if(this.calevents.length && this.loadMask){
13925 this.maskEl.hide();
13929 onBeforeLoad: function()
13931 this.clearEvents();
13933 this.maskEl.show();
13947 * @class Roo.bootstrap.Popover
13948 * @extends Roo.bootstrap.Component
13949 * Bootstrap Popover class
13950 * @cfg {String} html contents of the popover (or false to use children..)
13951 * @cfg {String} title of popover (or false to hide)
13952 * @cfg {String} placement how it is placed
13953 * @cfg {String} trigger click || hover (or false to trigger manually)
13954 * @cfg {String} over what (parent or false to trigger manually.)
13955 * @cfg {Number} delay - delay before showing
13958 * Create a new Popover
13959 * @param {Object} config The config object
13962 Roo.bootstrap.Popover = function(config){
13963 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13966 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13968 title: 'Fill in a title',
13971 placement : 'right',
13972 trigger : 'hover', // hover
13978 can_build_overlaid : false,
13980 getChildContainer : function()
13982 return this.el.select('.popover-content',true).first();
13985 getAutoCreate : function(){
13986 Roo.log('make popover?');
13988 cls : 'popover roo-dynamic',
13989 style: 'display:block',
13995 cls : 'popover-inner',
13999 cls: 'popover-title',
14003 cls : 'popover-content',
14014 setTitle: function(str)
14016 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14018 setContent: function(str)
14020 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14022 // as it get's added to the bottom of the page.
14023 onRender : function(ct, position)
14025 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14027 var cfg = Roo.apply({}, this.getAutoCreate());
14031 cfg.cls += ' ' + this.cls;
14034 cfg.style = this.style;
14036 Roo.log("adding to ")
14037 this.el = Roo.get(document.body).createChild(cfg, position);
14043 initEvents : function()
14045 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14046 this.el.enableDisplayMode('block');
14048 if (this.over === false) {
14051 if (this.triggers === false) {
14054 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14055 var triggers = this.trigger ? this.trigger.split(' ') : [];
14056 Roo.each(triggers, function(trigger) {
14058 if (trigger == 'click') {
14059 on_el.on('click', this.toggle, this);
14060 } else if (trigger != 'manual') {
14061 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14062 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14064 on_el.on(eventIn ,this.enter, this);
14065 on_el.on(eventOut, this.leave, this);
14076 toggle : function () {
14077 this.hoverState == 'in' ? this.leave() : this.enter();
14080 enter : function () {
14083 clearTimeout(this.timeout);
14085 this.hoverState = 'in';
14087 if (!this.delay || !this.delay.show) {
14092 this.timeout = setTimeout(function () {
14093 if (_t.hoverState == 'in') {
14096 }, this.delay.show)
14098 leave : function() {
14099 clearTimeout(this.timeout);
14101 this.hoverState = 'out';
14103 if (!this.delay || !this.delay.hide) {
14108 this.timeout = setTimeout(function () {
14109 if (_t.hoverState == 'out') {
14112 }, this.delay.hide)
14115 show : function (on_el)
14118 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14121 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14122 if (this.html !== false) {
14123 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14125 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14126 if (!this.title.length) {
14127 this.el.select('.popover-title',true).hide();
14130 var placement = typeof this.placement == 'function' ?
14131 this.placement.call(this, this.el, on_el) :
14134 var autoToken = /\s?auto?\s?/i;
14135 var autoPlace = autoToken.test(placement);
14137 placement = placement.replace(autoToken, '') || 'top';
14141 //this.el.setXY([0,0]);
14143 this.el.dom.style.display='block';
14144 this.el.addClass(placement);
14146 //this.el.appendTo(on_el);
14148 var p = this.getPosition();
14149 var box = this.el.getBox();
14154 var align = Roo.bootstrap.Popover.alignment[placement];
14155 this.el.alignTo(on_el, align[0],align[1]);
14156 //var arrow = this.el.select('.arrow',true).first();
14157 //arrow.set(align[2],
14159 this.el.addClass('in');
14160 this.hoverState = null;
14162 if (this.el.hasClass('fade')) {
14169 this.el.setXY([0,0]);
14170 this.el.removeClass('in');
14177 Roo.bootstrap.Popover.alignment = {
14178 'left' : ['r-l', [-10,0], 'right'],
14179 'right' : ['l-r', [10,0], 'left'],
14180 'bottom' : ['t-b', [0,10], 'top'],
14181 'top' : [ 'b-t', [0,-10], 'bottom']
14192 * @class Roo.bootstrap.Progress
14193 * @extends Roo.bootstrap.Component
14194 * Bootstrap Progress class
14195 * @cfg {Boolean} striped striped of the progress bar
14196 * @cfg {Boolean} active animated of the progress bar
14200 * Create a new Progress
14201 * @param {Object} config The config object
14204 Roo.bootstrap.Progress = function(config){
14205 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14208 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14213 getAutoCreate : function(){
14221 cfg.cls += ' progress-striped';
14225 cfg.cls += ' active';
14244 * @class Roo.bootstrap.ProgressBar
14245 * @extends Roo.bootstrap.Component
14246 * Bootstrap ProgressBar class
14247 * @cfg {Number} aria_valuenow aria-value now
14248 * @cfg {Number} aria_valuemin aria-value min
14249 * @cfg {Number} aria_valuemax aria-value max
14250 * @cfg {String} label label for the progress bar
14251 * @cfg {String} panel (success | info | warning | danger )
14252 * @cfg {String} role role of the progress bar
14253 * @cfg {String} sr_only text
14257 * Create a new ProgressBar
14258 * @param {Object} config The config object
14261 Roo.bootstrap.ProgressBar = function(config){
14262 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14265 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14269 aria_valuemax : 100,
14275 getAutoCreate : function()
14280 cls: 'progress-bar',
14281 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14293 cfg.role = this.role;
14296 if(this.aria_valuenow){
14297 cfg['aria-valuenow'] = this.aria_valuenow;
14300 if(this.aria_valuemin){
14301 cfg['aria-valuemin'] = this.aria_valuemin;
14304 if(this.aria_valuemax){
14305 cfg['aria-valuemax'] = this.aria_valuemax;
14308 if(this.label && !this.sr_only){
14309 cfg.html = this.label;
14313 cfg.cls += ' progress-bar-' + this.panel;
14319 update : function(aria_valuenow)
14321 this.aria_valuenow = aria_valuenow;
14323 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14338 * @class Roo.bootstrap.TabGroup
14339 * @extends Roo.bootstrap.Column
14340 * Bootstrap Column class
14341 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14342 * @cfg {Boolean} carousel true to make the group behave like a carousel
14345 * Create a new TabGroup
14346 * @param {Object} config The config object
14349 Roo.bootstrap.TabGroup = function(config){
14350 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14352 this.navId = Roo.id();
14355 Roo.bootstrap.TabGroup.register(this);
14359 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14362 transition : false,
14364 getAutoCreate : function()
14366 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14368 cfg.cls += ' tab-content';
14370 if (this.carousel) {
14371 cfg.cls += ' carousel slide';
14373 cls : 'carousel-inner'
14380 getChildContainer : function()
14382 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14386 * register a Navigation item
14387 * @param {Roo.bootstrap.NavItem} the navitem to add
14389 register : function(item)
14391 this.tabs.push( item);
14392 item.navId = this.navId; // not really needed..
14396 getActivePanel : function()
14399 Roo.each(this.tabs, function(t) {
14409 getPanelByName : function(n)
14412 Roo.each(this.tabs, function(t) {
14413 if (t.tabId == n) {
14421 indexOfPanel : function(p)
14424 Roo.each(this.tabs, function(t,i) {
14425 if (t.tabId == p.tabId) {
14434 * show a specific panel
14435 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14436 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14438 showPanel : function (pan)
14441 if (typeof(pan) == 'number') {
14442 pan = this.tabs[pan];
14444 if (typeof(pan) == 'string') {
14445 pan = this.getPanelByName(pan);
14447 if (pan.tabId == this.getActivePanel().tabId) {
14450 var cur = this.getActivePanel();
14452 if (false === cur.fireEvent('beforedeactivate')) {
14456 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14458 this.transition = true;
14459 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14460 var lr = dir == 'next' ? 'left' : 'right';
14461 pan.el.addClass(dir); // or prev
14462 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14463 cur.el.addClass(lr); // or right
14464 pan.el.addClass(lr);
14467 cur.el.on('transitionend', function() {
14468 Roo.log("trans end?");
14470 pan.el.removeClass([lr,dir]);
14471 pan.setActive(true);
14473 cur.el.removeClass([lr]);
14474 cur.setActive(false);
14476 _this.transition = false;
14478 }, this, { single: true } );
14482 cur.setActive(false);
14483 pan.setActive(true);
14487 showPanelNext : function()
14489 var i = this.indexOfPanel(this.getActivePanel());
14490 if (i > this.tabs.length) {
14493 this.showPanel(this.tabs[i+1]);
14495 showPanelPrev : function()
14497 var i = this.indexOfPanel(this.getActivePanel());
14501 this.showPanel(this.tabs[i-1]);
14512 Roo.apply(Roo.bootstrap.TabGroup, {
14516 * register a Navigation Group
14517 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14519 register : function(navgrp)
14521 this.groups[navgrp.navId] = navgrp;
14525 * fetch a Navigation Group based on the navigation ID
14526 * if one does not exist , it will get created.
14527 * @param {string} the navgroup to add
14528 * @returns {Roo.bootstrap.NavGroup} the navgroup
14530 get: function(navId) {
14531 if (typeof(this.groups[navId]) == 'undefined') {
14532 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14534 return this.groups[navId] ;
14549 * @class Roo.bootstrap.TabPanel
14550 * @extends Roo.bootstrap.Component
14551 * Bootstrap TabPanel class
14552 * @cfg {Boolean} active panel active
14553 * @cfg {String} html panel content
14554 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14555 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14559 * Create a new TabPanel
14560 * @param {Object} config The config object
14563 Roo.bootstrap.TabPanel = function(config){
14564 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14568 * Fires when the active status changes
14569 * @param {Roo.bootstrap.TabPanel} this
14570 * @param {Boolean} state the new state
14575 * @event beforedeactivate
14576 * Fires before a tab is de-activated - can be used to do validation on a form.
14577 * @param {Roo.bootstrap.TabPanel} this
14578 * @return {Boolean} false if there is an error
14581 'beforedeactivate': true
14584 this.tabId = this.tabId || Roo.id();
14588 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14595 getAutoCreate : function(){
14598 // item is needed for carousel - not sure if it has any effect otherwise
14599 cls: 'tab-pane item',
14600 html: this.html || ''
14604 cfg.cls += ' active';
14608 cfg.tabId = this.tabId;
14615 initEvents: function()
14617 Roo.log('-------- init events on tab panel ---------');
14619 var p = this.parent();
14620 this.navId = this.navId || p.navId;
14622 if (typeof(this.navId) != 'undefined') {
14623 // not really needed.. but just in case.. parent should be a NavGroup.
14624 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14625 Roo.log(['register', tg, this]);
14631 onRender : function(ct, position)
14633 // Roo.log("Call onRender: " + this.xtype);
14635 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14643 setActive: function(state)
14645 Roo.log("panel - set active " + this.tabId + "=" + state);
14647 this.active = state;
14649 this.el.removeClass('active');
14651 } else if (!this.el.hasClass('active')) {
14652 this.el.addClass('active');
14654 this.fireEvent('changed', this, state);
14671 * @class Roo.bootstrap.DateField
14672 * @extends Roo.bootstrap.Input
14673 * Bootstrap DateField class
14674 * @cfg {Number} weekStart default 0
14675 * @cfg {String} viewMode default empty, (months|years)
14676 * @cfg {String} minViewMode default empty, (months|years)
14677 * @cfg {Number} startDate default -Infinity
14678 * @cfg {Number} endDate default Infinity
14679 * @cfg {Boolean} todayHighlight default false
14680 * @cfg {Boolean} todayBtn default false
14681 * @cfg {Boolean} calendarWeeks default false
14682 * @cfg {Object} daysOfWeekDisabled default empty
14683 * @cfg {Boolean} singleMode default false (true | false)
14685 * @cfg {Boolean} keyboardNavigation default true
14686 * @cfg {String} language default en
14689 * Create a new DateField
14690 * @param {Object} config The config object
14693 Roo.bootstrap.DateField = function(config){
14694 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14698 * Fires when this field show.
14699 * @param {Roo.bootstrap.DateField} this
14700 * @param {Mixed} date The date value
14705 * Fires when this field hide.
14706 * @param {Roo.bootstrap.DateField} this
14707 * @param {Mixed} date The date value
14712 * Fires when select a date.
14713 * @param {Roo.bootstrap.DateField} this
14714 * @param {Mixed} date The date value
14720 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14723 * @cfg {String} format
14724 * The default date format string which can be overriden for localization support. The format must be
14725 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14729 * @cfg {String} altFormats
14730 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14731 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14733 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14741 todayHighlight : false,
14747 keyboardNavigation: true,
14749 calendarWeeks: false,
14751 startDate: -Infinity,
14755 daysOfWeekDisabled: [],
14759 singleMode : false,
14761 UTCDate: function()
14763 return new Date(Date.UTC.apply(Date, arguments));
14766 UTCToday: function()
14768 var today = new Date();
14769 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14772 getDate: function() {
14773 var d = this.getUTCDate();
14774 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14777 getUTCDate: function() {
14781 setDate: function(d) {
14782 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14785 setUTCDate: function(d) {
14787 this.setValue(this.formatDate(this.date));
14790 onRender: function(ct, position)
14793 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14795 this.language = this.language || 'en';
14796 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14797 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14799 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14800 this.format = this.format || 'm/d/y';
14801 this.isInline = false;
14802 this.isInput = true;
14803 this.component = this.el.select('.add-on', true).first() || false;
14804 this.component = (this.component && this.component.length === 0) ? false : this.component;
14805 this.hasInput = this.component && this.inputEL().length;
14807 if (typeof(this.minViewMode === 'string')) {
14808 switch (this.minViewMode) {
14810 this.minViewMode = 1;
14813 this.minViewMode = 2;
14816 this.minViewMode = 0;
14821 if (typeof(this.viewMode === 'string')) {
14822 switch (this.viewMode) {
14835 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14837 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14839 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14841 this.picker().on('mousedown', this.onMousedown, this);
14842 this.picker().on('click', this.onClick, this);
14844 this.picker().addClass('datepicker-dropdown');
14846 this.startViewMode = this.viewMode;
14848 if(this.singleMode){
14849 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14850 v.setVisibilityMode(Roo.Element.DISPLAY)
14854 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14855 v.setStyle('width', '189px');
14859 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14860 if(!this.calendarWeeks){
14865 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14866 v.attr('colspan', function(i, val){
14867 return parseInt(val) + 1;
14872 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14874 this.setStartDate(this.startDate);
14875 this.setEndDate(this.endDate);
14877 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14884 if(this.isInline) {
14889 picker : function()
14891 return this.pickerEl;
14892 // return this.el.select('.datepicker', true).first();
14895 fillDow: function()
14897 var dowCnt = this.weekStart;
14906 if(this.calendarWeeks){
14914 while (dowCnt < this.weekStart + 7) {
14918 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14922 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14925 fillMonths: function()
14928 var months = this.picker().select('>.datepicker-months td', true).first();
14930 months.dom.innerHTML = '';
14936 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14939 months.createChild(month);
14946 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;
14948 if (this.date < this.startDate) {
14949 this.viewDate = new Date(this.startDate);
14950 } else if (this.date > this.endDate) {
14951 this.viewDate = new Date(this.endDate);
14953 this.viewDate = new Date(this.date);
14961 var d = new Date(this.viewDate),
14962 year = d.getUTCFullYear(),
14963 month = d.getUTCMonth(),
14964 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14965 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14966 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14967 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14968 currentDate = this.date && this.date.valueOf(),
14969 today = this.UTCToday();
14971 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14973 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14975 // this.picker.select('>tfoot th.today').
14976 // .text(dates[this.language].today)
14977 // .toggle(this.todayBtn !== false);
14979 this.updateNavArrows();
14982 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14984 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14986 prevMonth.setUTCDate(day);
14988 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14990 var nextMonth = new Date(prevMonth);
14992 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14994 nextMonth = nextMonth.valueOf();
14996 var fillMonths = false;
14998 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15000 while(prevMonth.valueOf() < nextMonth) {
15003 if (prevMonth.getUTCDay() === this.weekStart) {
15005 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15013 if(this.calendarWeeks){
15014 // ISO 8601: First week contains first thursday.
15015 // ISO also states week starts on Monday, but we can be more abstract here.
15017 // Start of current week: based on weekstart/current date
15018 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15019 // Thursday of this week
15020 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15021 // First Thursday of year, year from thursday
15022 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15023 // Calendar week: ms between thursdays, div ms per day, div 7 days
15024 calWeek = (th - yth) / 864e5 / 7 + 1;
15026 fillMonths.cn.push({
15034 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15036 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15039 if (this.todayHighlight &&
15040 prevMonth.getUTCFullYear() == today.getFullYear() &&
15041 prevMonth.getUTCMonth() == today.getMonth() &&
15042 prevMonth.getUTCDate() == today.getDate()) {
15043 clsName += ' today';
15046 if (currentDate && prevMonth.valueOf() === currentDate) {
15047 clsName += ' active';
15050 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15051 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15052 clsName += ' disabled';
15055 fillMonths.cn.push({
15057 cls: 'day ' + clsName,
15058 html: prevMonth.getDate()
15061 prevMonth.setDate(prevMonth.getDate()+1);
15064 var currentYear = this.date && this.date.getUTCFullYear();
15065 var currentMonth = this.date && this.date.getUTCMonth();
15067 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15069 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15070 v.removeClass('active');
15072 if(currentYear === year && k === currentMonth){
15073 v.addClass('active');
15076 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15077 v.addClass('disabled');
15083 year = parseInt(year/10, 10) * 10;
15085 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15087 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15090 for (var i = -1; i < 11; i++) {
15091 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15093 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15101 showMode: function(dir)
15104 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15107 Roo.each(this.picker().select('>div',true).elements, function(v){
15108 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15111 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15116 if(this.isInline) return;
15118 this.picker().removeClass(['bottom', 'top']);
15120 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15122 * place to the top of element!
15126 this.picker().addClass('top');
15127 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15132 this.picker().addClass('bottom');
15134 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15137 parseDate : function(value)
15139 if(!value || value instanceof Date){
15142 var v = Date.parseDate(value, this.format);
15143 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15144 v = Date.parseDate(value, 'Y-m-d');
15146 if(!v && this.altFormats){
15147 if(!this.altFormatsArray){
15148 this.altFormatsArray = this.altFormats.split("|");
15150 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15151 v = Date.parseDate(value, this.altFormatsArray[i]);
15157 formatDate : function(date, fmt)
15159 return (!date || !(date instanceof Date)) ?
15160 date : date.dateFormat(fmt || this.format);
15163 onFocus : function()
15165 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15169 onBlur : function()
15171 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15173 var d = this.inputEl().getValue();
15182 this.picker().show();
15186 this.fireEvent('show', this, this.date);
15191 if(this.isInline) return;
15192 this.picker().hide();
15193 this.viewMode = this.startViewMode;
15196 this.fireEvent('hide', this, this.date);
15200 onMousedown: function(e)
15202 e.stopPropagation();
15203 e.preventDefault();
15208 Roo.bootstrap.DateField.superclass.keyup.call(this);
15212 setValue: function(v)
15215 // v can be a string or a date..
15218 var d = new Date(this.parseDate(v) ).clearTime();
15220 if(isNaN(d.getTime())){
15221 this.date = this.viewDate = '';
15222 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15226 v = this.formatDate(d);
15228 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15230 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15234 this.fireEvent('select', this, this.date);
15238 getValue: function()
15240 return this.formatDate(this.date);
15243 fireKey: function(e)
15245 if (!this.picker().isVisible()){
15246 if (e.keyCode == 27) // allow escape to hide and re-show picker
15251 var dateChanged = false,
15253 newDate, newViewDate;
15258 e.preventDefault();
15262 if (!this.keyboardNavigation) break;
15263 dir = e.keyCode == 37 ? -1 : 1;
15266 newDate = this.moveYear(this.date, dir);
15267 newViewDate = this.moveYear(this.viewDate, dir);
15268 } else if (e.shiftKey){
15269 newDate = this.moveMonth(this.date, dir);
15270 newViewDate = this.moveMonth(this.viewDate, dir);
15272 newDate = new Date(this.date);
15273 newDate.setUTCDate(this.date.getUTCDate() + dir);
15274 newViewDate = new Date(this.viewDate);
15275 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15277 if (this.dateWithinRange(newDate)){
15278 this.date = newDate;
15279 this.viewDate = newViewDate;
15280 this.setValue(this.formatDate(this.date));
15282 e.preventDefault();
15283 dateChanged = true;
15288 if (!this.keyboardNavigation) break;
15289 dir = e.keyCode == 38 ? -1 : 1;
15291 newDate = this.moveYear(this.date, dir);
15292 newViewDate = this.moveYear(this.viewDate, dir);
15293 } else if (e.shiftKey){
15294 newDate = this.moveMonth(this.date, dir);
15295 newViewDate = this.moveMonth(this.viewDate, dir);
15297 newDate = new Date(this.date);
15298 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15299 newViewDate = new Date(this.viewDate);
15300 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15302 if (this.dateWithinRange(newDate)){
15303 this.date = newDate;
15304 this.viewDate = newViewDate;
15305 this.setValue(this.formatDate(this.date));
15307 e.preventDefault();
15308 dateChanged = true;
15312 this.setValue(this.formatDate(this.date));
15314 e.preventDefault();
15317 this.setValue(this.formatDate(this.date));
15331 onClick: function(e)
15333 e.stopPropagation();
15334 e.preventDefault();
15336 var target = e.getTarget();
15338 if(target.nodeName.toLowerCase() === 'i'){
15339 target = Roo.get(target).dom.parentNode;
15342 var nodeName = target.nodeName;
15343 var className = target.className;
15344 var html = target.innerHTML;
15345 //Roo.log(nodeName);
15347 switch(nodeName.toLowerCase()) {
15349 switch(className) {
15355 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15356 switch(this.viewMode){
15358 this.viewDate = this.moveMonth(this.viewDate, dir);
15362 this.viewDate = this.moveYear(this.viewDate, dir);
15368 var date = new Date();
15369 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15371 this.setValue(this.formatDate(this.date));
15378 if (className.indexOf('disabled') < 0) {
15379 this.viewDate.setUTCDate(1);
15380 if (className.indexOf('month') > -1) {
15381 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15383 var year = parseInt(html, 10) || 0;
15384 this.viewDate.setUTCFullYear(year);
15388 if(this.singleMode){
15389 this.setValue(this.formatDate(this.viewDate));
15400 //Roo.log(className);
15401 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15402 var day = parseInt(html, 10) || 1;
15403 var year = this.viewDate.getUTCFullYear(),
15404 month = this.viewDate.getUTCMonth();
15406 if (className.indexOf('old') > -1) {
15413 } else if (className.indexOf('new') > -1) {
15421 //Roo.log([year,month,day]);
15422 this.date = this.UTCDate(year, month, day,0,0,0,0);
15423 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15425 //Roo.log(this.formatDate(this.date));
15426 this.setValue(this.formatDate(this.date));
15433 setStartDate: function(startDate)
15435 this.startDate = startDate || -Infinity;
15436 if (this.startDate !== -Infinity) {
15437 this.startDate = this.parseDate(this.startDate);
15440 this.updateNavArrows();
15443 setEndDate: function(endDate)
15445 this.endDate = endDate || Infinity;
15446 if (this.endDate !== Infinity) {
15447 this.endDate = this.parseDate(this.endDate);
15450 this.updateNavArrows();
15453 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15455 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15456 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15457 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15459 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15460 return parseInt(d, 10);
15463 this.updateNavArrows();
15466 updateNavArrows: function()
15468 if(this.singleMode){
15472 var d = new Date(this.viewDate),
15473 year = d.getUTCFullYear(),
15474 month = d.getUTCMonth();
15476 Roo.each(this.picker().select('.prev', true).elements, function(v){
15478 switch (this.viewMode) {
15481 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15487 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15494 Roo.each(this.picker().select('.next', true).elements, function(v){
15496 switch (this.viewMode) {
15499 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15505 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15513 moveMonth: function(date, dir)
15515 if (!dir) return date;
15516 var new_date = new Date(date.valueOf()),
15517 day = new_date.getUTCDate(),
15518 month = new_date.getUTCMonth(),
15519 mag = Math.abs(dir),
15521 dir = dir > 0 ? 1 : -1;
15524 // If going back one month, make sure month is not current month
15525 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15527 return new_date.getUTCMonth() == month;
15529 // If going forward one month, make sure month is as expected
15530 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15532 return new_date.getUTCMonth() != new_month;
15534 new_month = month + dir;
15535 new_date.setUTCMonth(new_month);
15536 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15537 if (new_month < 0 || new_month > 11)
15538 new_month = (new_month + 12) % 12;
15540 // For magnitudes >1, move one month at a time...
15541 for (var i=0; i<mag; i++)
15542 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15543 new_date = this.moveMonth(new_date, dir);
15544 // ...then reset the day, keeping it in the new month
15545 new_month = new_date.getUTCMonth();
15546 new_date.setUTCDate(day);
15548 return new_month != new_date.getUTCMonth();
15551 // Common date-resetting loop -- if date is beyond end of month, make it
15554 new_date.setUTCDate(--day);
15555 new_date.setUTCMonth(new_month);
15560 moveYear: function(date, dir)
15562 return this.moveMonth(date, dir*12);
15565 dateWithinRange: function(date)
15567 return date >= this.startDate && date <= this.endDate;
15573 this.picker().remove();
15578 Roo.apply(Roo.bootstrap.DateField, {
15589 html: '<i class="fa fa-arrow-left"/>'
15599 html: '<i class="fa fa-arrow-right"/>'
15641 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15642 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15643 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15644 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15645 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15658 navFnc: 'FullYear',
15663 navFnc: 'FullYear',
15668 Roo.apply(Roo.bootstrap.DateField, {
15672 cls: 'datepicker dropdown-menu roo-dynamic',
15676 cls: 'datepicker-days',
15680 cls: 'table-condensed',
15682 Roo.bootstrap.DateField.head,
15686 Roo.bootstrap.DateField.footer
15693 cls: 'datepicker-months',
15697 cls: 'table-condensed',
15699 Roo.bootstrap.DateField.head,
15700 Roo.bootstrap.DateField.content,
15701 Roo.bootstrap.DateField.footer
15708 cls: 'datepicker-years',
15712 cls: 'table-condensed',
15714 Roo.bootstrap.DateField.head,
15715 Roo.bootstrap.DateField.content,
15716 Roo.bootstrap.DateField.footer
15735 * @class Roo.bootstrap.TimeField
15736 * @extends Roo.bootstrap.Input
15737 * Bootstrap DateField class
15741 * Create a new TimeField
15742 * @param {Object} config The config object
15745 Roo.bootstrap.TimeField = function(config){
15746 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15750 * Fires when this field show.
15751 * @param {Roo.bootstrap.DateField} thisthis
15752 * @param {Mixed} date The date value
15757 * Fires when this field hide.
15758 * @param {Roo.bootstrap.DateField} this
15759 * @param {Mixed} date The date value
15764 * Fires when select a date.
15765 * @param {Roo.bootstrap.DateField} this
15766 * @param {Mixed} date The date value
15772 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15775 * @cfg {String} format
15776 * The default time format string which can be overriden for localization support. The format must be
15777 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15781 onRender: function(ct, position)
15784 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15786 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15788 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15790 this.pop = this.picker().select('>.datepicker-time',true).first();
15791 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15793 this.picker().on('mousedown', this.onMousedown, this);
15794 this.picker().on('click', this.onClick, this);
15796 this.picker().addClass('datepicker-dropdown');
15801 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15802 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15803 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15804 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15805 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15806 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15810 fireKey: function(e){
15811 if (!this.picker().isVisible()){
15812 if (e.keyCode == 27) { // allow escape to hide and re-show picker
15818 e.preventDefault();
15826 this.onTogglePeriod();
15829 this.onIncrementMinutes();
15832 this.onDecrementMinutes();
15841 onClick: function(e) {
15842 e.stopPropagation();
15843 e.preventDefault();
15846 picker : function()
15848 return this.el.select('.datepicker', true).first();
15851 fillTime: function()
15853 var time = this.pop.select('tbody', true).first();
15855 time.dom.innerHTML = '';
15870 cls: 'hours-up glyphicon glyphicon-chevron-up'
15890 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15911 cls: 'timepicker-hour',
15926 cls: 'timepicker-minute',
15941 cls: 'btn btn-primary period',
15963 cls: 'hours-down glyphicon glyphicon-chevron-down'
15983 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16001 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16008 var hours = this.time.getHours();
16009 var minutes = this.time.getMinutes();
16022 hours = hours - 12;
16026 hours = '0' + hours;
16030 minutes = '0' + minutes;
16033 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16034 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16035 this.pop.select('button', true).first().dom.innerHTML = period;
16041 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16043 var cls = ['bottom'];
16045 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16052 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16057 this.picker().addClass(cls.join('-'));
16061 Roo.each(cls, function(c){
16063 _this.picker().setTop(_this.inputEl().getHeight());
16067 _this.picker().setTop(0 - _this.picker().getHeight());
16072 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16076 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16083 onFocus : function()
16085 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16089 onBlur : function()
16091 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16097 this.picker().show();
16102 this.fireEvent('show', this, this.date);
16107 this.picker().hide();
16110 this.fireEvent('hide', this, this.date);
16113 setTime : function()
16116 this.setValue(this.time.format(this.format));
16118 this.fireEvent('select', this, this.date);
16123 onMousedown: function(e){
16124 e.stopPropagation();
16125 e.preventDefault();
16128 onIncrementHours: function()
16130 Roo.log('onIncrementHours');
16131 this.time = this.time.add(Date.HOUR, 1);
16136 onDecrementHours: function()
16138 Roo.log('onDecrementHours');
16139 this.time = this.time.add(Date.HOUR, -1);
16143 onIncrementMinutes: function()
16145 Roo.log('onIncrementMinutes');
16146 this.time = this.time.add(Date.MINUTE, 1);
16150 onDecrementMinutes: function()
16152 Roo.log('onDecrementMinutes');
16153 this.time = this.time.add(Date.MINUTE, -1);
16157 onTogglePeriod: function()
16159 Roo.log('onTogglePeriod');
16160 this.time = this.time.add(Date.HOUR, 12);
16167 Roo.apply(Roo.bootstrap.TimeField, {
16197 cls: 'btn btn-info ok',
16209 Roo.apply(Roo.bootstrap.TimeField, {
16213 cls: 'datepicker dropdown-menu',
16217 cls: 'datepicker-time',
16221 cls: 'table-condensed',
16223 Roo.bootstrap.TimeField.content,
16224 Roo.bootstrap.TimeField.footer
16243 * @class Roo.bootstrap.MonthField
16244 * @extends Roo.bootstrap.Input
16245 * Bootstrap MonthField class
16247 * @cfg {String} language default en
16250 * Create a new MonthField
16251 * @param {Object} config The config object
16254 Roo.bootstrap.MonthField = function(config){
16255 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16260 * Fires when this field show.
16261 * @param {Roo.bootstrap.MonthField} this
16262 * @param {Mixed} date The date value
16267 * Fires when this field hide.
16268 * @param {Roo.bootstrap.MonthField} this
16269 * @param {Mixed} date The date value
16274 * Fires when select a date.
16275 * @param {Roo.bootstrap.MonthField} this
16276 * @param {Mixed} date The date value
16282 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16284 onRender: function(ct, position)
16287 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16289 this.language = this.language || 'en';
16290 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16291 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16293 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16294 this.isInline = false;
16295 this.isInput = true;
16296 this.component = this.el.select('.add-on', true).first() || false;
16297 this.component = (this.component && this.component.length === 0) ? false : this.component;
16298 this.hasInput = this.component && this.inputEL().length;
16300 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16302 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16304 this.picker().on('mousedown', this.onMousedown, this);
16305 this.picker().on('click', this.onClick, this);
16307 this.picker().addClass('datepicker-dropdown');
16309 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16310 v.setStyle('width', '189px');
16317 if(this.isInline) {
16323 setValue: function(v)
16325 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16329 this.fireEvent('select', this, this.date);
16333 getValue: function()
16338 onClick: function(e)
16340 e.stopPropagation();
16341 e.preventDefault();
16343 var target = e.getTarget();
16345 if(target.nodeName.toLowerCase() === 'i'){
16346 target = Roo.get(target).dom.parentNode;
16349 var nodeName = target.nodeName;
16350 var className = target.className;
16351 var html = target.innerHTML;
16353 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16357 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16359 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16365 picker : function()
16367 return this.pickerEl;
16370 fillMonths: function()
16373 var months = this.picker().select('>.datepicker-months td', true).first();
16375 months.dom.innerHTML = '';
16381 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16384 months.createChild(month);
16393 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16394 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16397 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16398 e.removeClass('active');
16400 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16401 e.addClass('active');
16408 if(this.isInline) return;
16410 this.picker().removeClass(['bottom', 'top']);
16412 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16414 * place to the top of element!
16418 this.picker().addClass('top');
16419 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16424 this.picker().addClass('bottom');
16426 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16429 onFocus : function()
16431 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16435 onBlur : function()
16437 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16439 var d = this.inputEl().getValue();
16448 this.picker().show();
16449 this.picker().select('>.datepicker-months', true).first().show();
16453 this.fireEvent('show', this, this.date);
16458 if(this.isInline) return;
16459 this.picker().hide();
16460 this.fireEvent('hide', this, this.date);
16464 onMousedown: function(e)
16466 e.stopPropagation();
16467 e.preventDefault();
16472 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16476 fireKey: function(e)
16478 if (!this.picker().isVisible()){
16479 if (e.keyCode == 27) // allow escape to hide and re-show picker
16489 e.preventDefault();
16493 dir = e.keyCode == 37 ? -1 : 1;
16495 this.vIndex = this.vIndex + dir;
16497 if(this.vIndex < 0){
16501 if(this.vIndex > 11){
16505 if(isNaN(this.vIndex)){
16509 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16515 dir = e.keyCode == 38 ? -1 : 1;
16517 this.vIndex = this.vIndex + dir * 4;
16519 if(this.vIndex < 0){
16523 if(this.vIndex > 11){
16527 if(isNaN(this.vIndex)){
16531 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16536 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16537 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16541 e.preventDefault();
16544 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16545 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16561 this.picker().remove();
16566 Roo.apply(Roo.bootstrap.MonthField, {
16585 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16586 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16591 Roo.apply(Roo.bootstrap.MonthField, {
16595 cls: 'datepicker dropdown-menu roo-dynamic',
16599 cls: 'datepicker-months',
16603 cls: 'table-condensed',
16605 Roo.bootstrap.DateField.content
16625 * @class Roo.bootstrap.CheckBox
16626 * @extends Roo.bootstrap.Input
16627 * Bootstrap CheckBox class
16629 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16630 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16631 * @cfg {String} boxLabel The text that appears beside the checkbox
16632 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16633 * @cfg {Boolean} checked initnal the element
16634 * @cfg {Boolean} inline inline the element (default false)
16635 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16638 * Create a new CheckBox
16639 * @param {Object} config The config object
16642 Roo.bootstrap.CheckBox = function(config){
16643 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16648 * Fires when the element is checked or unchecked.
16649 * @param {Roo.bootstrap.CheckBox} this This input
16650 * @param {Boolean} checked The new checked value
16657 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16659 inputType: 'checkbox',
16667 getAutoCreate : function()
16669 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16675 cfg.cls = 'form-group ' + this.inputType; //input-group
16678 cfg.cls += ' ' + this.inputType + '-inline';
16684 type : this.inputType,
16685 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16686 cls : 'roo-' + this.inputType, //'form-box',
16687 placeholder : this.placeholder || ''
16691 if (this.weight) { // Validity check?
16692 cfg.cls += " " + this.inputType + "-" + this.weight;
16695 if (this.disabled) {
16696 input.disabled=true;
16700 input.checked = this.checked;
16704 input.name = this.name;
16708 input.cls += ' input-' + this.size;
16713 ['xs','sm','md','lg'].map(function(size){
16714 if (settings[size]) {
16715 cfg.cls += ' col-' + size + '-' + settings[size];
16719 var inputblock = input;
16721 if (this.before || this.after) {
16724 cls : 'input-group',
16729 inputblock.cn.push({
16731 cls : 'input-group-addon',
16736 inputblock.cn.push(input);
16739 inputblock.cn.push({
16741 cls : 'input-group-addon',
16748 if (align ==='left' && this.fieldLabel.length) {
16749 Roo.log("left and has label");
16755 cls : 'control-label col-md-' + this.labelWidth,
16756 html : this.fieldLabel
16760 cls : "col-md-" + (12 - this.labelWidth),
16767 } else if ( this.fieldLabel.length) {
16772 tag: this.boxLabel ? 'span' : 'label',
16774 cls: 'control-label box-input-label',
16775 //cls : 'input-group-addon',
16776 html : this.fieldLabel
16786 Roo.log(" no label && no align");
16787 cfg.cn = [ inputblock ] ;
16792 var boxLabelCfg = {
16794 //'for': id, // box label is handled by onclick - so no for...
16796 html: this.boxLabel
16800 boxLabelCfg.tooltip = this.tooltip;
16803 cfg.cn.push(boxLabelCfg);
16813 * return the real input element.
16815 inputEl: function ()
16817 return this.el.select('input.roo-' + this.inputType,true).first();
16820 labelEl: function()
16822 return this.el.select('label.control-label',true).first();
16824 /* depricated... */
16828 return this.labelEl();
16831 initEvents : function()
16833 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16835 this.inputEl().on('click', this.onClick, this);
16837 if (this.boxLabel) {
16838 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16841 this.startValue = this.getValue();
16844 Roo.bootstrap.CheckBox.register(this);
16848 onClick : function()
16850 this.setChecked(!this.checked);
16853 setChecked : function(state,suppressEvent)
16855 this.startValue = this.getValue();
16857 if(this.inputType == 'radio'){
16859 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16860 e.dom.checked = false;
16863 this.inputEl().dom.checked = true;
16865 this.inputEl().dom.value = this.inputValue;
16867 if(suppressEvent !== true){
16868 this.fireEvent('check', this, true);
16876 this.checked = state;
16878 this.inputEl().dom.checked = state;
16880 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16882 if(suppressEvent !== true){
16883 this.fireEvent('check', this, state);
16889 getValue : function()
16891 if(this.inputType == 'radio'){
16892 return this.getGroupValue();
16895 return this.inputEl().getValue();
16899 getGroupValue : function()
16901 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16905 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16908 setValue : function(v,suppressEvent)
16910 if(this.inputType == 'radio'){
16911 this.setGroupValue(v, suppressEvent);
16915 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16920 setGroupValue : function(v, suppressEvent)
16922 this.startValue = this.getValue();
16924 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16925 e.dom.checked = false;
16927 if(e.dom.value == v){
16928 e.dom.checked = true;
16932 if(suppressEvent !== true){
16933 this.fireEvent('check', this, true);
16941 validate : function()
16945 (this.inputType == 'radio' && this.getValue().length) ||
16946 (this.inputType == 'checkbox' && this.validateGroup())
16952 this.markInvalid();
16956 validateGroup : function()
16959 return (this.getValue() == this.inputValue) ? true : false;
16962 var group = Roo.bootstrap.CheckBox.get(this.groupId);
16970 for(var i in group){
16975 r = (group[i].getValue() == group[i].inputValue) ? true : false;
16982 * Mark this field as valid
16984 markValid : function()
16988 this.fireEvent('valid', this);
16990 if(this.inputType == 'radio'){
16991 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16992 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
16993 e.findParent('.form-group', false, true).addClass(_this.validClass);
17000 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17001 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17005 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17011 for(var i in group){
17012 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17013 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17018 * Mark this field as invalid
17019 * @param {String} msg The validation message
17021 markInvalid : function(msg)
17025 this.fireEvent('invalid', this, msg);
17027 if(this.inputType == 'radio'){
17028 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17029 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17030 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17037 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17038 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17042 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17048 for(var i in group){
17049 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17050 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17057 Roo.apply(Roo.bootstrap.CheckBox, {
17062 * register a CheckBox Group
17063 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17065 register : function(checkbox)
17067 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17068 this.groups[checkbox.groupId] = {};
17071 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17075 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17079 * fetch a CheckBox Group based on the group ID
17080 * @param {string} the group ID
17081 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17083 get: function(groupId) {
17084 if (typeof(this.groups[groupId]) == 'undefined') {
17088 return this.groups[groupId] ;
17100 *<div class="radio">
17102 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17103 Option one is this and that—be sure to include why it's great
17110 *<label class="radio-inline">fieldLabel</label>
17111 *<label class="radio-inline">
17112 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17120 * @class Roo.bootstrap.Radio
17121 * @extends Roo.bootstrap.CheckBox
17122 * Bootstrap Radio class
17125 * Create a new Radio
17126 * @param {Object} config The config object
17129 Roo.bootstrap.Radio = function(config){
17130 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17134 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17136 inputType: 'radio',
17140 getAutoCreate : function()
17142 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17143 align = align || 'left'; // default...
17150 tag : this.inline ? 'span' : 'div',
17155 var inline = this.inline ? ' radio-inline' : '';
17159 // does not need for, as we wrap the input with it..
17161 cls : 'control-label box-label' + inline,
17164 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17168 //cls : 'control-label' + inline,
17169 html : this.fieldLabel,
17170 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17179 type : this.inputType,
17180 //value : (!this.checked) ? this.valueOff : this.inputValue,
17181 value : this.inputValue,
17183 placeholder : this.placeholder || '' // ?? needed????
17186 if (this.weight) { // Validity check?
17187 input.cls += " radio-" + this.weight;
17189 if (this.disabled) {
17190 input.disabled=true;
17194 input.checked = this.checked;
17198 input.name = this.name;
17202 input.cls += ' input-' + this.size;
17205 //?? can span's inline have a width??
17208 ['xs','sm','md','lg'].map(function(size){
17209 if (settings[size]) {
17210 cfg.cls += ' col-' + size + '-' + settings[size];
17214 var inputblock = input;
17216 if (this.before || this.after) {
17219 cls : 'input-group',
17224 inputblock.cn.push({
17226 cls : 'input-group-addon',
17230 inputblock.cn.push(input);
17232 inputblock.cn.push({
17234 cls : 'input-group-addon',
17242 if (this.fieldLabel && this.fieldLabel.length) {
17243 cfg.cn.push(fieldLabel);
17246 // normal bootstrap puts the input inside the label.
17247 // however with our styled version - it has to go after the input.
17249 //lbl.cn.push(inputblock);
17253 cls: 'radio' + inline,
17260 cfg.cn.push( lblwrap);
17265 html: this.boxLabel
17274 initEvents : function()
17276 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17278 this.inputEl().on('click', this.onClick, this);
17279 if (this.boxLabel) {
17280 Roo.log('find label')
17281 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17286 inputEl: function ()
17288 return this.el.select('input.roo-radio',true).first();
17290 onClick : function()
17293 this.setChecked(true);
17296 setChecked : function(state,suppressEvent)
17299 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17300 v.dom.checked = false;
17303 Roo.log(this.inputEl().dom);
17304 this.checked = state;
17305 this.inputEl().dom.checked = state;
17307 if(suppressEvent !== true){
17308 this.fireEvent('check', this, state);
17311 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17315 getGroupValue : function()
17318 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17319 if(v.dom.checked == true){
17320 value = v.dom.value;
17328 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17329 * @return {Mixed} value The field value
17331 getValue : function(){
17332 return this.getGroupValue();
17338 //<script type="text/javascript">
17341 * Based Ext JS Library 1.1.1
17342 * Copyright(c) 2006-2007, Ext JS, LLC.
17348 * @class Roo.HtmlEditorCore
17349 * @extends Roo.Component
17350 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17352 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17355 Roo.HtmlEditorCore = function(config){
17358 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17363 * @event initialize
17364 * Fires when the editor is fully initialized (including the iframe)
17365 * @param {Roo.HtmlEditorCore} this
17370 * Fires when the editor is first receives the focus. Any insertion must wait
17371 * until after this event.
17372 * @param {Roo.HtmlEditorCore} this
17376 * @event beforesync
17377 * Fires before the textarea is updated with content from the editor iframe. Return false
17378 * to cancel the sync.
17379 * @param {Roo.HtmlEditorCore} this
17380 * @param {String} html
17384 * @event beforepush
17385 * Fires before the iframe editor is updated with content from the textarea. Return false
17386 * to cancel the push.
17387 * @param {Roo.HtmlEditorCore} this
17388 * @param {String} html
17393 * Fires when the textarea is updated with content from the editor iframe.
17394 * @param {Roo.HtmlEditorCore} this
17395 * @param {String} html
17400 * Fires when the iframe editor is updated with content from the textarea.
17401 * @param {Roo.HtmlEditorCore} this
17402 * @param {String} html
17407 * @event editorevent
17408 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17409 * @param {Roo.HtmlEditorCore} this
17415 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17417 // defaults : white / black...
17418 this.applyBlacklists();
17425 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17429 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17435 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17440 * @cfg {Number} height (in pixels)
17444 * @cfg {Number} width (in pixels)
17449 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17452 stylesheets: false,
17457 // private properties
17458 validationEvent : false,
17460 initialized : false,
17462 sourceEditMode : false,
17463 onFocus : Roo.emptyFn,
17465 hideMode:'offsets',
17469 // blacklist + whitelisted elements..
17476 * Protected method that will not generally be called directly. It
17477 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17478 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17480 getDocMarkup : function(){
17484 // inherit styels from page...??
17485 if (this.stylesheets === false) {
17487 Roo.get(document.head).select('style').each(function(node) {
17488 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17491 Roo.get(document.head).select('link').each(function(node) {
17492 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17495 } else if (!this.stylesheets.length) {
17497 st = '<style type="text/css">' +
17498 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17504 st += '<style type="text/css">' +
17505 'IMG { cursor: pointer } ' +
17509 return '<html><head>' + st +
17510 //<style type="text/css">' +
17511 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17513 ' </head><body class="roo-htmleditor-body"></body></html>';
17517 onRender : function(ct, position)
17520 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17521 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17524 this.el.dom.style.border = '0 none';
17525 this.el.dom.setAttribute('tabIndex', -1);
17526 this.el.addClass('x-hidden hide');
17530 if(Roo.isIE){ // fix IE 1px bogus margin
17531 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17535 this.frameId = Roo.id();
17539 var iframe = this.owner.wrap.createChild({
17541 cls: 'form-control', // bootstrap..
17543 name: this.frameId,
17544 frameBorder : 'no',
17545 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17550 this.iframe = iframe.dom;
17552 this.assignDocWin();
17554 this.doc.designMode = 'on';
17557 this.doc.write(this.getDocMarkup());
17561 var task = { // must defer to wait for browser to be ready
17563 //console.log("run task?" + this.doc.readyState);
17564 this.assignDocWin();
17565 if(this.doc.body || this.doc.readyState == 'complete'){
17567 this.doc.designMode="on";
17571 Roo.TaskMgr.stop(task);
17572 this.initEditor.defer(10, this);
17579 Roo.TaskMgr.start(task);
17584 onResize : function(w, h)
17586 Roo.log('resize: ' +w + ',' + h );
17587 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17591 if(typeof w == 'number'){
17593 this.iframe.style.width = w + 'px';
17595 if(typeof h == 'number'){
17597 this.iframe.style.height = h + 'px';
17599 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17606 * Toggles the editor between standard and source edit mode.
17607 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17609 toggleSourceEdit : function(sourceEditMode){
17611 this.sourceEditMode = sourceEditMode === true;
17613 if(this.sourceEditMode){
17615 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17618 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17619 //this.iframe.className = '';
17622 //this.setSize(this.owner.wrap.getSize());
17623 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17630 * Protected method that will not generally be called directly. If you need/want
17631 * custom HTML cleanup, this is the method you should override.
17632 * @param {String} html The HTML to be cleaned
17633 * return {String} The cleaned HTML
17635 cleanHtml : function(html){
17636 html = String(html);
17637 if(html.length > 5){
17638 if(Roo.isSafari){ // strip safari nonsense
17639 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17642 if(html == ' '){
17649 * HTML Editor -> Textarea
17650 * Protected method that will not generally be called directly. Syncs the contents
17651 * of the editor iframe with the textarea.
17653 syncValue : function(){
17654 if(this.initialized){
17655 var bd = (this.doc.body || this.doc.documentElement);
17656 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17657 var html = bd.innerHTML;
17659 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17660 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17662 html = '<div style="'+m[0]+'">' + html + '</div>';
17665 html = this.cleanHtml(html);
17666 // fix up the special chars.. normaly like back quotes in word...
17667 // however we do not want to do this with chinese..
17668 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17669 var cc = b.charCodeAt();
17671 (cc >= 0x4E00 && cc < 0xA000 ) ||
17672 (cc >= 0x3400 && cc < 0x4E00 ) ||
17673 (cc >= 0xf900 && cc < 0xfb00 )
17679 if(this.owner.fireEvent('beforesync', this, html) !== false){
17680 this.el.dom.value = html;
17681 this.owner.fireEvent('sync', this, html);
17687 * Protected method that will not generally be called directly. Pushes the value of the textarea
17688 * into the iframe editor.
17690 pushValue : function(){
17691 if(this.initialized){
17692 var v = this.el.dom.value.trim();
17694 // if(v.length < 1){
17698 if(this.owner.fireEvent('beforepush', this, v) !== false){
17699 var d = (this.doc.body || this.doc.documentElement);
17701 this.cleanUpPaste();
17702 this.el.dom.value = d.innerHTML;
17703 this.owner.fireEvent('push', this, v);
17709 deferFocus : function(){
17710 this.focus.defer(10, this);
17714 focus : function(){
17715 if(this.win && !this.sourceEditMode){
17722 assignDocWin: function()
17724 var iframe = this.iframe;
17727 this.doc = iframe.contentWindow.document;
17728 this.win = iframe.contentWindow;
17730 // if (!Roo.get(this.frameId)) {
17733 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17734 // this.win = Roo.get(this.frameId).dom.contentWindow;
17736 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17740 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17741 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17746 initEditor : function(){
17747 //console.log("INIT EDITOR");
17748 this.assignDocWin();
17752 this.doc.designMode="on";
17754 this.doc.write(this.getDocMarkup());
17757 var dbody = (this.doc.body || this.doc.documentElement);
17758 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17759 // this copies styles from the containing element into thsi one..
17760 // not sure why we need all of this..
17761 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17763 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17764 //ss['background-attachment'] = 'fixed'; // w3c
17765 dbody.bgProperties = 'fixed'; // ie
17766 //Roo.DomHelper.applyStyles(dbody, ss);
17767 Roo.EventManager.on(this.doc, {
17768 //'mousedown': this.onEditorEvent,
17769 'mouseup': this.onEditorEvent,
17770 'dblclick': this.onEditorEvent,
17771 'click': this.onEditorEvent,
17772 'keyup': this.onEditorEvent,
17777 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17779 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17780 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17782 this.initialized = true;
17784 this.owner.fireEvent('initialize', this);
17789 onDestroy : function(){
17795 //for (var i =0; i < this.toolbars.length;i++) {
17796 // // fixme - ask toolbars for heights?
17797 // this.toolbars[i].onDestroy();
17800 //this.wrap.dom.innerHTML = '';
17801 //this.wrap.remove();
17806 onFirstFocus : function(){
17808 this.assignDocWin();
17811 this.activated = true;
17814 if(Roo.isGecko){ // prevent silly gecko errors
17816 var s = this.win.getSelection();
17817 if(!s.focusNode || s.focusNode.nodeType != 3){
17818 var r = s.getRangeAt(0);
17819 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17824 this.execCmd('useCSS', true);
17825 this.execCmd('styleWithCSS', false);
17828 this.owner.fireEvent('activate', this);
17832 adjustFont: function(btn){
17833 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17834 //if(Roo.isSafari){ // safari
17837 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17838 if(Roo.isSafari){ // safari
17839 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17840 v = (v < 10) ? 10 : v;
17841 v = (v > 48) ? 48 : v;
17842 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17847 v = Math.max(1, v+adjust);
17849 this.execCmd('FontSize', v );
17852 onEditorEvent : function(e){
17853 this.owner.fireEvent('editorevent', this, e);
17854 // this.updateToolbar();
17855 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17858 insertTag : function(tg)
17860 // could be a bit smarter... -> wrap the current selected tRoo..
17861 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17863 range = this.createRange(this.getSelection());
17864 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17865 wrappingNode.appendChild(range.extractContents());
17866 range.insertNode(wrappingNode);
17873 this.execCmd("formatblock", tg);
17877 insertText : function(txt)
17881 var range = this.createRange();
17882 range.deleteContents();
17883 //alert(Sender.getAttribute('label'));
17885 range.insertNode(this.doc.createTextNode(txt));
17891 * Executes a Midas editor command on the editor document and performs necessary focus and
17892 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17893 * @param {String} cmd The Midas command
17894 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17896 relayCmd : function(cmd, value){
17898 this.execCmd(cmd, value);
17899 this.owner.fireEvent('editorevent', this);
17900 //this.updateToolbar();
17901 this.owner.deferFocus();
17905 * Executes a Midas editor command directly on the editor document.
17906 * For visual commands, you should use {@link #relayCmd} instead.
17907 * <b>This should only be called after the editor is initialized.</b>
17908 * @param {String} cmd The Midas command
17909 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17911 execCmd : function(cmd, value){
17912 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17919 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17921 * @param {String} text | dom node..
17923 insertAtCursor : function(text)
17928 if(!this.activated){
17934 var r = this.doc.selection.createRange();
17945 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17949 // from jquery ui (MIT licenced)
17951 var win = this.win;
17953 if (win.getSelection && win.getSelection().getRangeAt) {
17954 range = win.getSelection().getRangeAt(0);
17955 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17956 range.insertNode(node);
17957 } else if (win.document.selection && win.document.selection.createRange) {
17958 // no firefox support
17959 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17960 win.document.selection.createRange().pasteHTML(txt);
17962 // no firefox support
17963 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17964 this.execCmd('InsertHTML', txt);
17973 mozKeyPress : function(e){
17975 var c = e.getCharCode(), cmd;
17978 c = String.fromCharCode(c).toLowerCase();
17992 this.cleanUpPaste.defer(100, this);
18000 e.preventDefault();
18008 fixKeys : function(){ // load time branching for fastest keydown performance
18010 return function(e){
18011 var k = e.getKey(), r;
18014 r = this.doc.selection.createRange();
18017 r.pasteHTML('    ');
18024 r = this.doc.selection.createRange();
18026 var target = r.parentElement();
18027 if(!target || target.tagName.toLowerCase() != 'li'){
18029 r.pasteHTML('<br />');
18035 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18036 this.cleanUpPaste.defer(100, this);
18042 }else if(Roo.isOpera){
18043 return function(e){
18044 var k = e.getKey();
18048 this.execCmd('InsertHTML','    ');
18051 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18052 this.cleanUpPaste.defer(100, this);
18057 }else if(Roo.isSafari){
18058 return function(e){
18059 var k = e.getKey();
18063 this.execCmd('InsertText','\t');
18067 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18068 this.cleanUpPaste.defer(100, this);
18076 getAllAncestors: function()
18078 var p = this.getSelectedNode();
18081 a.push(p); // push blank onto stack..
18082 p = this.getParentElement();
18086 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18090 a.push(this.doc.body);
18094 lastSelNode : false,
18097 getSelection : function()
18099 this.assignDocWin();
18100 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18103 getSelectedNode: function()
18105 // this may only work on Gecko!!!
18107 // should we cache this!!!!
18112 var range = this.createRange(this.getSelection()).cloneRange();
18115 var parent = range.parentElement();
18117 var testRange = range.duplicate();
18118 testRange.moveToElementText(parent);
18119 if (testRange.inRange(range)) {
18122 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18125 parent = parent.parentElement;
18130 // is ancestor a text element.
18131 var ac = range.commonAncestorContainer;
18132 if (ac.nodeType == 3) {
18133 ac = ac.parentNode;
18136 var ar = ac.childNodes;
18139 var other_nodes = [];
18140 var has_other_nodes = false;
18141 for (var i=0;i<ar.length;i++) {
18142 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18145 // fullly contained node.
18147 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18152 // probably selected..
18153 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18154 other_nodes.push(ar[i]);
18158 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18163 has_other_nodes = true;
18165 if (!nodes.length && other_nodes.length) {
18166 nodes= other_nodes;
18168 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18174 createRange: function(sel)
18176 // this has strange effects when using with
18177 // top toolbar - not sure if it's a great idea.
18178 //this.editor.contentWindow.focus();
18179 if (typeof sel != "undefined") {
18181 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18183 return this.doc.createRange();
18186 return this.doc.createRange();
18189 getParentElement: function()
18192 this.assignDocWin();
18193 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18195 var range = this.createRange(sel);
18198 var p = range.commonAncestorContainer;
18199 while (p.nodeType == 3) { // text node
18210 * Range intersection.. the hard stuff...
18214 * [ -- selected range --- ]
18218 * if end is before start or hits it. fail.
18219 * if start is after end or hits it fail.
18221 * if either hits (but other is outside. - then it's not
18227 // @see http://www.thismuchiknow.co.uk/?p=64.
18228 rangeIntersectsNode : function(range, node)
18230 var nodeRange = node.ownerDocument.createRange();
18232 nodeRange.selectNode(node);
18234 nodeRange.selectNodeContents(node);
18237 var rangeStartRange = range.cloneRange();
18238 rangeStartRange.collapse(true);
18240 var rangeEndRange = range.cloneRange();
18241 rangeEndRange.collapse(false);
18243 var nodeStartRange = nodeRange.cloneRange();
18244 nodeStartRange.collapse(true);
18246 var nodeEndRange = nodeRange.cloneRange();
18247 nodeEndRange.collapse(false);
18249 return rangeStartRange.compareBoundaryPoints(
18250 Range.START_TO_START, nodeEndRange) == -1 &&
18251 rangeEndRange.compareBoundaryPoints(
18252 Range.START_TO_START, nodeStartRange) == 1;
18256 rangeCompareNode : function(range, node)
18258 var nodeRange = node.ownerDocument.createRange();
18260 nodeRange.selectNode(node);
18262 nodeRange.selectNodeContents(node);
18266 range.collapse(true);
18268 nodeRange.collapse(true);
18270 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18271 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18273 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18275 var nodeIsBefore = ss == 1;
18276 var nodeIsAfter = ee == -1;
18278 if (nodeIsBefore && nodeIsAfter)
18280 if (!nodeIsBefore && nodeIsAfter)
18281 return 1; //right trailed.
18283 if (nodeIsBefore && !nodeIsAfter)
18284 return 2; // left trailed.
18289 // private? - in a new class?
18290 cleanUpPaste : function()
18292 // cleans up the whole document..
18293 Roo.log('cleanuppaste');
18295 this.cleanUpChildren(this.doc.body);
18296 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18297 if (clean != this.doc.body.innerHTML) {
18298 this.doc.body.innerHTML = clean;
18303 cleanWordChars : function(input) {// change the chars to hex code
18304 var he = Roo.HtmlEditorCore;
18306 var output = input;
18307 Roo.each(he.swapCodes, function(sw) {
18308 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18310 output = output.replace(swapper, sw[1]);
18317 cleanUpChildren : function (n)
18319 if (!n.childNodes.length) {
18322 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18323 this.cleanUpChild(n.childNodes[i]);
18330 cleanUpChild : function (node)
18333 //console.log(node);
18334 if (node.nodeName == "#text") {
18335 // clean up silly Windows -- stuff?
18338 if (node.nodeName == "#comment") {
18339 node.parentNode.removeChild(node);
18340 // clean up silly Windows -- stuff?
18343 var lcname = node.tagName.toLowerCase();
18344 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18345 // whitelist of tags..
18347 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18349 node.parentNode.removeChild(node);
18354 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18356 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18357 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18359 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18360 // remove_keep_children = true;
18363 if (remove_keep_children) {
18364 this.cleanUpChildren(node);
18365 // inserts everything just before this node...
18366 while (node.childNodes.length) {
18367 var cn = node.childNodes[0];
18368 node.removeChild(cn);
18369 node.parentNode.insertBefore(cn, node);
18371 node.parentNode.removeChild(node);
18375 if (!node.attributes || !node.attributes.length) {
18376 this.cleanUpChildren(node);
18380 function cleanAttr(n,v)
18383 if (v.match(/^\./) || v.match(/^\//)) {
18386 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18389 if (v.match(/^#/)) {
18392 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18393 node.removeAttribute(n);
18397 var cwhite = this.cwhite;
18398 var cblack = this.cblack;
18400 function cleanStyle(n,v)
18402 if (v.match(/expression/)) { //XSS?? should we even bother..
18403 node.removeAttribute(n);
18407 var parts = v.split(/;/);
18410 Roo.each(parts, function(p) {
18411 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18415 var l = p.split(':').shift().replace(/\s+/g,'');
18416 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18418 if ( cwhite.length && cblack.indexOf(l) > -1) {
18419 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18420 //node.removeAttribute(n);
18424 // only allow 'c whitelisted system attributes'
18425 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18426 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18427 //node.removeAttribute(n);
18437 if (clean.length) {
18438 node.setAttribute(n, clean.join(';'));
18440 node.removeAttribute(n);
18446 for (var i = node.attributes.length-1; i > -1 ; i--) {
18447 var a = node.attributes[i];
18450 if (a.name.toLowerCase().substr(0,2)=='on') {
18451 node.removeAttribute(a.name);
18454 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18455 node.removeAttribute(a.name);
18458 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18459 cleanAttr(a.name,a.value); // fixme..
18462 if (a.name == 'style') {
18463 cleanStyle(a.name,a.value);
18466 /// clean up MS crap..
18467 // tecnically this should be a list of valid class'es..
18470 if (a.name == 'class') {
18471 if (a.value.match(/^Mso/)) {
18472 node.className = '';
18475 if (a.value.match(/body/)) {
18476 node.className = '';
18487 this.cleanUpChildren(node);
18492 * Clean up MS wordisms...
18494 cleanWord : function(node)
18497 var cleanWordChildren = function()
18499 if (!node.childNodes.length) {
18502 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18503 _t.cleanWord(node.childNodes[i]);
18509 this.cleanWord(this.doc.body);
18512 if (node.nodeName == "#text") {
18513 // clean up silly Windows -- stuff?
18516 if (node.nodeName == "#comment") {
18517 node.parentNode.removeChild(node);
18518 // clean up silly Windows -- stuff?
18522 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18523 node.parentNode.removeChild(node);
18527 // remove - but keep children..
18528 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18529 while (node.childNodes.length) {
18530 var cn = node.childNodes[0];
18531 node.removeChild(cn);
18532 node.parentNode.insertBefore(cn, node);
18534 node.parentNode.removeChild(node);
18535 cleanWordChildren();
18539 if (node.className.length) {
18541 var cn = node.className.split(/\W+/);
18543 Roo.each(cn, function(cls) {
18544 if (cls.match(/Mso[a-zA-Z]+/)) {
18549 node.className = cna.length ? cna.join(' ') : '';
18551 node.removeAttribute("class");
18555 if (node.hasAttribute("lang")) {
18556 node.removeAttribute("lang");
18559 if (node.hasAttribute("style")) {
18561 var styles = node.getAttribute("style").split(";");
18563 Roo.each(styles, function(s) {
18564 if (!s.match(/:/)) {
18567 var kv = s.split(":");
18568 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18571 // what ever is left... we allow.
18574 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18575 if (!nstyle.length) {
18576 node.removeAttribute('style');
18580 cleanWordChildren();
18584 domToHTML : function(currentElement, depth, nopadtext) {
18586 depth = depth || 0;
18587 nopadtext = nopadtext || false;
18589 if (!currentElement) {
18590 return this.domToHTML(this.doc.body);
18593 //Roo.log(currentElement);
18595 var allText = false;
18596 var nodeName = currentElement.nodeName;
18597 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18599 if (nodeName == '#text') {
18601 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18606 if (nodeName != 'BODY') {
18609 // Prints the node tagName, such as <A>, <IMG>, etc
18612 for(i = 0; i < currentElement.attributes.length;i++) {
18614 var aname = currentElement.attributes.item(i).name;
18615 if (!currentElement.attributes.item(i).value.length) {
18618 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18621 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18630 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18633 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18638 // Traverse the tree
18640 var currentElementChild = currentElement.childNodes.item(i);
18641 var allText = true;
18642 var innerHTML = '';
18644 while (currentElementChild) {
18645 // Formatting code (indent the tree so it looks nice on the screen)
18646 var nopad = nopadtext;
18647 if (lastnode == 'SPAN') {
18651 if (currentElementChild.nodeName == '#text') {
18652 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18653 toadd = nopadtext ? toadd : toadd.trim();
18654 if (!nopad && toadd.length > 80) {
18655 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18657 innerHTML += toadd;
18660 currentElementChild = currentElement.childNodes.item(i);
18666 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18668 // Recursively traverse the tree structure of the child node
18669 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18670 lastnode = currentElementChild.nodeName;
18672 currentElementChild=currentElement.childNodes.item(i);
18678 // The remaining code is mostly for formatting the tree
18679 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18684 ret+= "</"+tagName+">";
18690 applyBlacklists : function()
18692 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18693 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18697 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18698 if (b.indexOf(tag) > -1) {
18701 this.white.push(tag);
18705 Roo.each(w, function(tag) {
18706 if (b.indexOf(tag) > -1) {
18709 if (this.white.indexOf(tag) > -1) {
18712 this.white.push(tag);
18717 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18718 if (w.indexOf(tag) > -1) {
18721 this.black.push(tag);
18725 Roo.each(b, function(tag) {
18726 if (w.indexOf(tag) > -1) {
18729 if (this.black.indexOf(tag) > -1) {
18732 this.black.push(tag);
18737 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18738 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18742 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18743 if (b.indexOf(tag) > -1) {
18746 this.cwhite.push(tag);
18750 Roo.each(w, function(tag) {
18751 if (b.indexOf(tag) > -1) {
18754 if (this.cwhite.indexOf(tag) > -1) {
18757 this.cwhite.push(tag);
18762 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18763 if (w.indexOf(tag) > -1) {
18766 this.cblack.push(tag);
18770 Roo.each(b, function(tag) {
18771 if (w.indexOf(tag) > -1) {
18774 if (this.cblack.indexOf(tag) > -1) {
18777 this.cblack.push(tag);
18782 setStylesheets : function(stylesheets)
18784 if(typeof(stylesheets) == 'string'){
18785 Roo.get(this.iframe.contentDocument.head).createChild({
18787 rel : 'stylesheet',
18796 Roo.each(stylesheets, function(s) {
18801 Roo.get(_this.iframe.contentDocument.head).createChild({
18803 rel : 'stylesheet',
18812 removeStylesheets : function()
18816 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18821 // hide stuff that is not compatible
18835 * @event specialkey
18839 * @cfg {String} fieldClass @hide
18842 * @cfg {String} focusClass @hide
18845 * @cfg {String} autoCreate @hide
18848 * @cfg {String} inputType @hide
18851 * @cfg {String} invalidClass @hide
18854 * @cfg {String} invalidText @hide
18857 * @cfg {String} msgFx @hide
18860 * @cfg {String} validateOnBlur @hide
18864 Roo.HtmlEditorCore.white = [
18865 'area', 'br', 'img', 'input', 'hr', 'wbr',
18867 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18868 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18869 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18870 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18871 'table', 'ul', 'xmp',
18873 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18876 'dir', 'menu', 'ol', 'ul', 'dl',
18882 Roo.HtmlEditorCore.black = [
18883 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18885 'base', 'basefont', 'bgsound', 'blink', 'body',
18886 'frame', 'frameset', 'head', 'html', 'ilayer',
18887 'iframe', 'layer', 'link', 'meta', 'object',
18888 'script', 'style' ,'title', 'xml' // clean later..
18890 Roo.HtmlEditorCore.clean = [
18891 'script', 'style', 'title', 'xml'
18893 Roo.HtmlEditorCore.remove = [
18898 Roo.HtmlEditorCore.ablack = [
18902 Roo.HtmlEditorCore.aclean = [
18903 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18907 Roo.HtmlEditorCore.pwhite= [
18908 'http', 'https', 'mailto'
18911 // white listed style attributes.
18912 Roo.HtmlEditorCore.cwhite= [
18913 // 'text-align', /// default is to allow most things..
18919 // black listed style attributes.
18920 Roo.HtmlEditorCore.cblack= [
18921 // 'font-size' -- this can be set by the project
18925 Roo.HtmlEditorCore.swapCodes =[
18944 * @class Roo.bootstrap.HtmlEditor
18945 * @extends Roo.bootstrap.TextArea
18946 * Bootstrap HtmlEditor class
18949 * Create a new HtmlEditor
18950 * @param {Object} config The config object
18953 Roo.bootstrap.HtmlEditor = function(config){
18954 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18955 if (!this.toolbars) {
18956 this.toolbars = [];
18958 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18961 * @event initialize
18962 * Fires when the editor is fully initialized (including the iframe)
18963 * @param {HtmlEditor} this
18968 * Fires when the editor is first receives the focus. Any insertion must wait
18969 * until after this event.
18970 * @param {HtmlEditor} this
18974 * @event beforesync
18975 * Fires before the textarea is updated with content from the editor iframe. Return false
18976 * to cancel the sync.
18977 * @param {HtmlEditor} this
18978 * @param {String} html
18982 * @event beforepush
18983 * Fires before the iframe editor is updated with content from the textarea. Return false
18984 * to cancel the push.
18985 * @param {HtmlEditor} this
18986 * @param {String} html
18991 * Fires when the textarea is updated with content from the editor iframe.
18992 * @param {HtmlEditor} this
18993 * @param {String} html
18998 * Fires when the iframe editor is updated with content from the textarea.
18999 * @param {HtmlEditor} this
19000 * @param {String} html
19004 * @event editmodechange
19005 * Fires when the editor switches edit modes
19006 * @param {HtmlEditor} this
19007 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19009 editmodechange: true,
19011 * @event editorevent
19012 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19013 * @param {HtmlEditor} this
19017 * @event firstfocus
19018 * Fires when on first focus - needed by toolbars..
19019 * @param {HtmlEditor} this
19024 * Auto save the htmlEditor value as a file into Events
19025 * @param {HtmlEditor} this
19029 * @event savedpreview
19030 * preview the saved version of htmlEditor
19031 * @param {HtmlEditor} this
19038 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19042 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19047 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19052 * @cfg {Number} height (in pixels)
19056 * @cfg {Number} width (in pixels)
19061 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19064 stylesheets: false,
19069 // private properties
19070 validationEvent : false,
19072 initialized : false,
19075 onFocus : Roo.emptyFn,
19077 hideMode:'offsets',
19080 tbContainer : false,
19082 toolbarContainer :function() {
19083 return this.wrap.select('.x-html-editor-tb',true).first();
19087 * Protected method that will not generally be called directly. It
19088 * is called when the editor creates its toolbar. Override this method if you need to
19089 * add custom toolbar buttons.
19090 * @param {HtmlEditor} editor
19092 createToolbar : function(){
19094 Roo.log("create toolbars");
19096 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19097 this.toolbars[0].render(this.toolbarContainer());
19101 // if (!editor.toolbars || !editor.toolbars.length) {
19102 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19105 // for (var i =0 ; i < editor.toolbars.length;i++) {
19106 // editor.toolbars[i] = Roo.factory(
19107 // typeof(editor.toolbars[i]) == 'string' ?
19108 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19109 // Roo.bootstrap.HtmlEditor);
19110 // editor.toolbars[i].init(editor);
19116 onRender : function(ct, position)
19118 // Roo.log("Call onRender: " + this.xtype);
19120 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19122 this.wrap = this.inputEl().wrap({
19123 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19126 this.editorcore.onRender(ct, position);
19128 if (this.resizable) {
19129 this.resizeEl = new Roo.Resizable(this.wrap, {
19133 minHeight : this.height,
19134 height: this.height,
19135 handles : this.resizable,
19138 resize : function(r, w, h) {
19139 _t.onResize(w,h); // -something
19145 this.createToolbar(this);
19148 if(!this.width && this.resizable){
19149 this.setSize(this.wrap.getSize());
19151 if (this.resizeEl) {
19152 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19153 // should trigger onReize..
19159 onResize : function(w, h)
19161 Roo.log('resize: ' +w + ',' + h );
19162 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19166 if(this.inputEl() ){
19167 if(typeof w == 'number'){
19168 var aw = w - this.wrap.getFrameWidth('lr');
19169 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19172 if(typeof h == 'number'){
19173 var tbh = -11; // fixme it needs to tool bar size!
19174 for (var i =0; i < this.toolbars.length;i++) {
19175 // fixme - ask toolbars for heights?
19176 tbh += this.toolbars[i].el.getHeight();
19177 //if (this.toolbars[i].footer) {
19178 // tbh += this.toolbars[i].footer.el.getHeight();
19186 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19187 ah -= 5; // knock a few pixes off for look..
19188 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19192 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19193 this.editorcore.onResize(ew,eh);
19198 * Toggles the editor between standard and source edit mode.
19199 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19201 toggleSourceEdit : function(sourceEditMode)
19203 this.editorcore.toggleSourceEdit(sourceEditMode);
19205 if(this.editorcore.sourceEditMode){
19206 Roo.log('editor - showing textarea');
19209 // Roo.log(this.syncValue());
19211 this.inputEl().removeClass(['hide', 'x-hidden']);
19212 this.inputEl().dom.removeAttribute('tabIndex');
19213 this.inputEl().focus();
19215 Roo.log('editor - hiding textarea');
19217 // Roo.log(this.pushValue());
19220 this.inputEl().addClass(['hide', 'x-hidden']);
19221 this.inputEl().dom.setAttribute('tabIndex', -1);
19222 //this.deferFocus();
19225 if(this.resizable){
19226 this.setSize(this.wrap.getSize());
19229 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19232 // private (for BoxComponent)
19233 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19235 // private (for BoxComponent)
19236 getResizeEl : function(){
19240 // private (for BoxComponent)
19241 getPositionEl : function(){
19246 initEvents : function(){
19247 this.originalValue = this.getValue();
19251 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19254 // markInvalid : Roo.emptyFn,
19256 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19259 // clearInvalid : Roo.emptyFn,
19261 setValue : function(v){
19262 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19263 this.editorcore.pushValue();
19268 deferFocus : function(){
19269 this.focus.defer(10, this);
19273 focus : function(){
19274 this.editorcore.focus();
19280 onDestroy : function(){
19286 for (var i =0; i < this.toolbars.length;i++) {
19287 // fixme - ask toolbars for heights?
19288 this.toolbars[i].onDestroy();
19291 this.wrap.dom.innerHTML = '';
19292 this.wrap.remove();
19297 onFirstFocus : function(){
19298 //Roo.log("onFirstFocus");
19299 this.editorcore.onFirstFocus();
19300 for (var i =0; i < this.toolbars.length;i++) {
19301 this.toolbars[i].onFirstFocus();
19307 syncValue : function()
19309 this.editorcore.syncValue();
19312 pushValue : function()
19314 this.editorcore.pushValue();
19318 // hide stuff that is not compatible
19332 * @event specialkey
19336 * @cfg {String} fieldClass @hide
19339 * @cfg {String} focusClass @hide
19342 * @cfg {String} autoCreate @hide
19345 * @cfg {String} inputType @hide
19348 * @cfg {String} invalidClass @hide
19351 * @cfg {String} invalidText @hide
19354 * @cfg {String} msgFx @hide
19357 * @cfg {String} validateOnBlur @hide
19366 Roo.namespace('Roo.bootstrap.htmleditor');
19368 * @class Roo.bootstrap.HtmlEditorToolbar1
19373 new Roo.bootstrap.HtmlEditor({
19376 new Roo.bootstrap.HtmlEditorToolbar1({
19377 disable : { fonts: 1 , format: 1, ..., ... , ...],
19383 * @cfg {Object} disable List of elements to disable..
19384 * @cfg {Array} btns List of additional buttons.
19388 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19391 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19394 Roo.apply(this, config);
19396 // default disabled, based on 'good practice'..
19397 this.disable = this.disable || {};
19398 Roo.applyIf(this.disable, {
19401 specialElements : true
19403 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19405 this.editor = config.editor;
19406 this.editorcore = config.editor.editorcore;
19408 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19410 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19411 // dont call parent... till later.
19413 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19418 editorcore : false,
19423 "h1","h2","h3","h4","h5","h6",
19425 "abbr", "acronym", "address", "cite", "samp", "var",
19429 onRender : function(ct, position)
19431 // Roo.log("Call onRender: " + this.xtype);
19433 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19435 this.el.dom.style.marginBottom = '0';
19437 var editorcore = this.editorcore;
19438 var editor= this.editor;
19441 var btn = function(id,cmd , toggle, handler){
19443 var event = toggle ? 'toggle' : 'click';
19448 xns: Roo.bootstrap,
19451 enableToggle:toggle !== false,
19453 pressed : toggle ? false : null,
19456 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19457 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19466 xns: Roo.bootstrap,
19467 glyphicon : 'font',
19471 xns: Roo.bootstrap,
19475 Roo.each(this.formats, function(f) {
19476 style.menu.items.push({
19478 xns: Roo.bootstrap,
19479 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19484 editorcore.insertTag(this.tagname);
19491 children.push(style);
19494 btn('bold',false,true);
19495 btn('italic',false,true);
19496 btn('align-left', 'justifyleft',true);
19497 btn('align-center', 'justifycenter',true);
19498 btn('align-right' , 'justifyright',true);
19499 btn('link', false, false, function(btn) {
19500 //Roo.log("create link?");
19501 var url = prompt(this.createLinkText, this.defaultLinkValue);
19502 if(url && url != 'http:/'+'/'){
19503 this.editorcore.relayCmd('createlink', url);
19506 btn('list','insertunorderedlist',true);
19507 btn('pencil', false,true, function(btn){
19510 this.toggleSourceEdit(btn.pressed);
19516 xns: Roo.bootstrap,
19521 xns: Roo.bootstrap,
19526 cog.menu.items.push({
19528 xns: Roo.bootstrap,
19529 html : Clean styles,
19534 editorcore.insertTag(this.tagname);
19543 this.xtype = 'NavSimplebar';
19545 for(var i=0;i< children.length;i++) {
19547 this.buttons.add(this.addxtypeChild(children[i]));
19551 editor.on('editorevent', this.updateToolbar, this);
19553 onBtnClick : function(id)
19555 this.editorcore.relayCmd(id);
19556 this.editorcore.focus();
19560 * Protected method that will not generally be called directly. It triggers
19561 * a toolbar update by reading the markup state of the current selection in the editor.
19563 updateToolbar: function(){
19565 if(!this.editorcore.activated){
19566 this.editor.onFirstFocus(); // is this neeed?
19570 var btns = this.buttons;
19571 var doc = this.editorcore.doc;
19572 btns.get('bold').setActive(doc.queryCommandState('bold'));
19573 btns.get('italic').setActive(doc.queryCommandState('italic'));
19574 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19576 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19577 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19578 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19580 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19581 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19584 var ans = this.editorcore.getAllAncestors();
19585 if (this.formatCombo) {
19588 var store = this.formatCombo.store;
19589 this.formatCombo.setValue("");
19590 for (var i =0; i < ans.length;i++) {
19591 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19593 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19601 // hides menus... - so this cant be on a menu...
19602 Roo.bootstrap.MenuMgr.hideAll();
19604 Roo.bootstrap.MenuMgr.hideAll();
19605 //this.editorsyncValue();
19607 onFirstFocus: function() {
19608 this.buttons.each(function(item){
19612 toggleSourceEdit : function(sourceEditMode){
19615 if(sourceEditMode){
19616 Roo.log("disabling buttons");
19617 this.buttons.each( function(item){
19618 if(item.cmd != 'pencil'){
19624 Roo.log("enabling buttons");
19625 if(this.editorcore.initialized){
19626 this.buttons.each( function(item){
19632 Roo.log("calling toggole on editor");
19633 // tell the editor that it's been pressed..
19634 this.editor.toggleSourceEdit(sourceEditMode);
19644 * @class Roo.bootstrap.Table.AbstractSelectionModel
19645 * @extends Roo.util.Observable
19646 * Abstract base class for grid SelectionModels. It provides the interface that should be
19647 * implemented by descendant classes. This class should not be directly instantiated.
19650 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19651 this.locked = false;
19652 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19656 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19657 /** @ignore Called by the grid automatically. Do not call directly. */
19658 init : function(grid){
19664 * Locks the selections.
19667 this.locked = true;
19671 * Unlocks the selections.
19673 unlock : function(){
19674 this.locked = false;
19678 * Returns true if the selections are locked.
19679 * @return {Boolean}
19681 isLocked : function(){
19682 return this.locked;
19686 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19687 * @class Roo.bootstrap.Table.RowSelectionModel
19688 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19689 * It supports multiple selections and keyboard selection/navigation.
19691 * @param {Object} config
19694 Roo.bootstrap.Table.RowSelectionModel = function(config){
19695 Roo.apply(this, config);
19696 this.selections = new Roo.util.MixedCollection(false, function(o){
19701 this.lastActive = false;
19705 * @event selectionchange
19706 * Fires when the selection changes
19707 * @param {SelectionModel} this
19709 "selectionchange" : true,
19711 * @event afterselectionchange
19712 * Fires after the selection changes (eg. by key press or clicking)
19713 * @param {SelectionModel} this
19715 "afterselectionchange" : true,
19717 * @event beforerowselect
19718 * Fires when a row is selected being selected, return false to cancel.
19719 * @param {SelectionModel} this
19720 * @param {Number} rowIndex The selected index
19721 * @param {Boolean} keepExisting False if other selections will be cleared
19723 "beforerowselect" : true,
19726 * Fires when a row is selected.
19727 * @param {SelectionModel} this
19728 * @param {Number} rowIndex The selected index
19729 * @param {Roo.data.Record} r The record
19731 "rowselect" : true,
19733 * @event rowdeselect
19734 * Fires when a row is deselected.
19735 * @param {SelectionModel} this
19736 * @param {Number} rowIndex The selected index
19738 "rowdeselect" : true
19740 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19741 this.locked = false;
19744 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19746 * @cfg {Boolean} singleSelect
19747 * True to allow selection of only one row at a time (defaults to false)
19749 singleSelect : false,
19752 initEvents : function(){
19754 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19755 this.grid.on("mousedown", this.handleMouseDown, this);
19756 }else{ // allow click to work like normal
19757 this.grid.on("rowclick", this.handleDragableRowClick, this);
19760 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19761 "up" : function(e){
19763 this.selectPrevious(e.shiftKey);
19764 }else if(this.last !== false && this.lastActive !== false){
19765 var last = this.last;
19766 this.selectRange(this.last, this.lastActive-1);
19767 this.grid.getView().focusRow(this.lastActive);
19768 if(last !== false){
19772 this.selectFirstRow();
19774 this.fireEvent("afterselectionchange", this);
19776 "down" : function(e){
19778 this.selectNext(e.shiftKey);
19779 }else if(this.last !== false && this.lastActive !== false){
19780 var last = this.last;
19781 this.selectRange(this.last, this.lastActive+1);
19782 this.grid.getView().focusRow(this.lastActive);
19783 if(last !== false){
19787 this.selectFirstRow();
19789 this.fireEvent("afterselectionchange", this);
19794 var view = this.grid.view;
19795 view.on("refresh", this.onRefresh, this);
19796 view.on("rowupdated", this.onRowUpdated, this);
19797 view.on("rowremoved", this.onRemove, this);
19801 onRefresh : function(){
19802 var ds = this.grid.dataSource, i, v = this.grid.view;
19803 var s = this.selections;
19804 s.each(function(r){
19805 if((i = ds.indexOfId(r.id)) != -1){
19814 onRemove : function(v, index, r){
19815 this.selections.remove(r);
19819 onRowUpdated : function(v, index, r){
19820 if(this.isSelected(r)){
19821 v.onRowSelect(index);
19827 * @param {Array} records The records to select
19828 * @param {Boolean} keepExisting (optional) True to keep existing selections
19830 selectRecords : function(records, keepExisting){
19832 this.clearSelections();
19834 var ds = this.grid.dataSource;
19835 for(var i = 0, len = records.length; i < len; i++){
19836 this.selectRow(ds.indexOf(records[i]), true);
19841 * Gets the number of selected rows.
19844 getCount : function(){
19845 return this.selections.length;
19849 * Selects the first row in the grid.
19851 selectFirstRow : function(){
19856 * Select the last row.
19857 * @param {Boolean} keepExisting (optional) True to keep existing selections
19859 selectLastRow : function(keepExisting){
19860 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19864 * Selects the row immediately following the last selected row.
19865 * @param {Boolean} keepExisting (optional) True to keep existing selections
19867 selectNext : function(keepExisting){
19868 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19869 this.selectRow(this.last+1, keepExisting);
19870 this.grid.getView().focusRow(this.last);
19875 * Selects the row that precedes the last selected row.
19876 * @param {Boolean} keepExisting (optional) True to keep existing selections
19878 selectPrevious : function(keepExisting){
19880 this.selectRow(this.last-1, keepExisting);
19881 this.grid.getView().focusRow(this.last);
19886 * Returns the selected records
19887 * @return {Array} Array of selected records
19889 getSelections : function(){
19890 return [].concat(this.selections.items);
19894 * Returns the first selected record.
19897 getSelected : function(){
19898 return this.selections.itemAt(0);
19903 * Clears all selections.
19905 clearSelections : function(fast){
19906 if(this.locked) return;
19908 var ds = this.grid.dataSource;
19909 var s = this.selections;
19910 s.each(function(r){
19911 this.deselectRow(ds.indexOfId(r.id));
19915 this.selections.clear();
19922 * Selects all rows.
19924 selectAll : function(){
19925 if(this.locked) return;
19926 this.selections.clear();
19927 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19928 this.selectRow(i, true);
19933 * Returns True if there is a selection.
19934 * @return {Boolean}
19936 hasSelection : function(){
19937 return this.selections.length > 0;
19941 * Returns True if the specified row is selected.
19942 * @param {Number/Record} record The record or index of the record to check
19943 * @return {Boolean}
19945 isSelected : function(index){
19946 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19947 return (r && this.selections.key(r.id) ? true : false);
19951 * Returns True if the specified record id is selected.
19952 * @param {String} id The id of record to check
19953 * @return {Boolean}
19955 isIdSelected : function(id){
19956 return (this.selections.key(id) ? true : false);
19960 handleMouseDown : function(e, t){
19961 var view = this.grid.getView(), rowIndex;
19962 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19965 if(e.shiftKey && this.last !== false){
19966 var last = this.last;
19967 this.selectRange(last, rowIndex, e.ctrlKey);
19968 this.last = last; // reset the last
19969 view.focusRow(rowIndex);
19971 var isSelected = this.isSelected(rowIndex);
19972 if(e.button !== 0 && isSelected){
19973 view.focusRow(rowIndex);
19974 }else if(e.ctrlKey && isSelected){
19975 this.deselectRow(rowIndex);
19976 }else if(!isSelected){
19977 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19978 view.focusRow(rowIndex);
19981 this.fireEvent("afterselectionchange", this);
19984 handleDragableRowClick : function(grid, rowIndex, e)
19986 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19987 this.selectRow(rowIndex, false);
19988 grid.view.focusRow(rowIndex);
19989 this.fireEvent("afterselectionchange", this);
19994 * Selects multiple rows.
19995 * @param {Array} rows Array of the indexes of the row to select
19996 * @param {Boolean} keepExisting (optional) True to keep existing selections
19998 selectRows : function(rows, keepExisting){
20000 this.clearSelections();
20002 for(var i = 0, len = rows.length; i < len; i++){
20003 this.selectRow(rows[i], true);
20008 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20009 * @param {Number} startRow The index of the first row in the range
20010 * @param {Number} endRow The index of the last row in the range
20011 * @param {Boolean} keepExisting (optional) True to retain existing selections
20013 selectRange : function(startRow, endRow, keepExisting){
20014 if(this.locked) return;
20016 this.clearSelections();
20018 if(startRow <= endRow){
20019 for(var i = startRow; i <= endRow; i++){
20020 this.selectRow(i, true);
20023 for(var i = startRow; i >= endRow; i--){
20024 this.selectRow(i, true);
20030 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20031 * @param {Number} startRow The index of the first row in the range
20032 * @param {Number} endRow The index of the last row in the range
20034 deselectRange : function(startRow, endRow, preventViewNotify){
20035 if(this.locked) return;
20036 for(var i = startRow; i <= endRow; i++){
20037 this.deselectRow(i, preventViewNotify);
20043 * @param {Number} row The index of the row to select
20044 * @param {Boolean} keepExisting (optional) True to keep existing selections
20046 selectRow : function(index, keepExisting, preventViewNotify){
20047 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20048 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20049 if(!keepExisting || this.singleSelect){
20050 this.clearSelections();
20052 var r = this.grid.dataSource.getAt(index);
20053 this.selections.add(r);
20054 this.last = this.lastActive = index;
20055 if(!preventViewNotify){
20056 this.grid.getView().onRowSelect(index);
20058 this.fireEvent("rowselect", this, index, r);
20059 this.fireEvent("selectionchange", this);
20065 * @param {Number} row The index of the row to deselect
20067 deselectRow : function(index, preventViewNotify){
20068 if(this.locked) return;
20069 if(this.last == index){
20072 if(this.lastActive == index){
20073 this.lastActive = false;
20075 var r = this.grid.dataSource.getAt(index);
20076 this.selections.remove(r);
20077 if(!preventViewNotify){
20078 this.grid.getView().onRowDeselect(index);
20080 this.fireEvent("rowdeselect", this, index);
20081 this.fireEvent("selectionchange", this);
20085 restoreLast : function(){
20087 this.last = this._last;
20092 acceptsNav : function(row, col, cm){
20093 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20097 onEditorKey : function(field, e){
20098 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20103 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20105 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20107 }else if(k == e.ENTER && !e.ctrlKey){
20111 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20113 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20115 }else if(k == e.ESC){
20119 g.startEditing(newCell[0], newCell[1]);
20124 * Ext JS Library 1.1.1
20125 * Copyright(c) 2006-2007, Ext JS, LLC.
20127 * Originally Released Under LGPL - original licence link has changed is not relivant.
20130 * <script type="text/javascript">
20134 * @class Roo.bootstrap.PagingToolbar
20136 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20138 * Create a new PagingToolbar
20139 * @param {Object} config The config object
20141 Roo.bootstrap.PagingToolbar = function(config)
20143 // old args format still supported... - xtype is prefered..
20144 // created from xtype...
20145 var ds = config.dataSource;
20146 this.toolbarItems = [];
20147 if (config.items) {
20148 this.toolbarItems = config.items;
20149 // config.items = [];
20152 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20159 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20163 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20165 * @cfg {Roo.data.Store} dataSource
20166 * The underlying data store providing the paged data
20169 * @cfg {String/HTMLElement/Element} container
20170 * container The id or element that will contain the toolbar
20173 * @cfg {Boolean} displayInfo
20174 * True to display the displayMsg (defaults to false)
20177 * @cfg {Number} pageSize
20178 * The number of records to display per page (defaults to 20)
20182 * @cfg {String} displayMsg
20183 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20185 displayMsg : 'Displaying {0} - {1} of {2}',
20187 * @cfg {String} emptyMsg
20188 * The message to display when no records are found (defaults to "No data to display")
20190 emptyMsg : 'No data to display',
20192 * Customizable piece of the default paging text (defaults to "Page")
20195 beforePageText : "Page",
20197 * Customizable piece of the default paging text (defaults to "of %0")
20200 afterPageText : "of {0}",
20202 * Customizable piece of the default paging text (defaults to "First Page")
20205 firstText : "First Page",
20207 * Customizable piece of the default paging text (defaults to "Previous Page")
20210 prevText : "Previous Page",
20212 * Customizable piece of the default paging text (defaults to "Next Page")
20215 nextText : "Next Page",
20217 * Customizable piece of the default paging text (defaults to "Last Page")
20220 lastText : "Last Page",
20222 * Customizable piece of the default paging text (defaults to "Refresh")
20225 refreshText : "Refresh",
20229 onRender : function(ct, position)
20231 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20232 this.navgroup.parentId = this.id;
20233 this.navgroup.onRender(this.el, null);
20234 // add the buttons to the navgroup
20236 if(this.displayInfo){
20237 Roo.log(this.el.select('ul.navbar-nav',true).first());
20238 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20239 this.displayEl = this.el.select('.x-paging-info', true).first();
20240 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20241 // this.displayEl = navel.el.select('span',true).first();
20247 Roo.each(_this.buttons, function(e){
20248 Roo.factory(e).onRender(_this.el, null);
20252 Roo.each(_this.toolbarItems, function(e) {
20253 _this.navgroup.addItem(e);
20257 this.first = this.navgroup.addItem({
20258 tooltip: this.firstText,
20260 icon : 'fa fa-backward',
20262 preventDefault: true,
20263 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20266 this.prev = this.navgroup.addItem({
20267 tooltip: this.prevText,
20269 icon : 'fa fa-step-backward',
20271 preventDefault: true,
20272 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20274 //this.addSeparator();
20277 var field = this.navgroup.addItem( {
20279 cls : 'x-paging-position',
20281 html : this.beforePageText +
20282 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20283 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20286 this.field = field.el.select('input', true).first();
20287 this.field.on("keydown", this.onPagingKeydown, this);
20288 this.field.on("focus", function(){this.dom.select();});
20291 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20292 //this.field.setHeight(18);
20293 //this.addSeparator();
20294 this.next = this.navgroup.addItem({
20295 tooltip: this.nextText,
20297 html : ' <i class="fa fa-step-forward">',
20299 preventDefault: true,
20300 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20302 this.last = this.navgroup.addItem({
20303 tooltip: this.lastText,
20304 icon : 'fa fa-forward',
20307 preventDefault: true,
20308 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20310 //this.addSeparator();
20311 this.loading = this.navgroup.addItem({
20312 tooltip: this.refreshText,
20313 icon: 'fa fa-refresh',
20314 preventDefault: true,
20315 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20321 updateInfo : function(){
20322 if(this.displayEl){
20323 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20324 var msg = count == 0 ?
20328 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20330 this.displayEl.update(msg);
20335 onLoad : function(ds, r, o){
20336 this.cursor = o.params ? o.params.start : 0;
20337 var d = this.getPageData(),
20341 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20342 this.field.dom.value = ap;
20343 this.first.setDisabled(ap == 1);
20344 this.prev.setDisabled(ap == 1);
20345 this.next.setDisabled(ap == ps);
20346 this.last.setDisabled(ap == ps);
20347 this.loading.enable();
20352 getPageData : function(){
20353 var total = this.ds.getTotalCount();
20356 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20357 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20362 onLoadError : function(){
20363 this.loading.enable();
20367 onPagingKeydown : function(e){
20368 var k = e.getKey();
20369 var d = this.getPageData();
20371 var v = this.field.dom.value, pageNum;
20372 if(!v || isNaN(pageNum = parseInt(v, 10))){
20373 this.field.dom.value = d.activePage;
20376 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20377 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20380 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))
20382 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20383 this.field.dom.value = pageNum;
20384 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20387 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20389 var v = this.field.dom.value, pageNum;
20390 var increment = (e.shiftKey) ? 10 : 1;
20391 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20393 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20394 this.field.dom.value = d.activePage;
20397 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20399 this.field.dom.value = parseInt(v, 10) + increment;
20400 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20401 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20408 beforeLoad : function(){
20410 this.loading.disable();
20415 onClick : function(which){
20424 ds.load({params:{start: 0, limit: this.pageSize}});
20427 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20430 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20433 var total = ds.getTotalCount();
20434 var extra = total % this.pageSize;
20435 var lastStart = extra ? (total - extra) : total-this.pageSize;
20436 ds.load({params:{start: lastStart, limit: this.pageSize}});
20439 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20445 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20446 * @param {Roo.data.Store} store The data store to unbind
20448 unbind : function(ds){
20449 ds.un("beforeload", this.beforeLoad, this);
20450 ds.un("load", this.onLoad, this);
20451 ds.un("loadexception", this.onLoadError, this);
20452 ds.un("remove", this.updateInfo, this);
20453 ds.un("add", this.updateInfo, this);
20454 this.ds = undefined;
20458 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20459 * @param {Roo.data.Store} store The data store to bind
20461 bind : function(ds){
20462 ds.on("beforeload", this.beforeLoad, this);
20463 ds.on("load", this.onLoad, this);
20464 ds.on("loadexception", this.onLoadError, this);
20465 ds.on("remove", this.updateInfo, this);
20466 ds.on("add", this.updateInfo, this);
20477 * @class Roo.bootstrap.MessageBar
20478 * @extends Roo.bootstrap.Component
20479 * Bootstrap MessageBar class
20480 * @cfg {String} html contents of the MessageBar
20481 * @cfg {String} weight (info | success | warning | danger) default info
20482 * @cfg {String} beforeClass insert the bar before the given class
20483 * @cfg {Boolean} closable (true | false) default false
20484 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20487 * Create a new Element
20488 * @param {Object} config The config object
20491 Roo.bootstrap.MessageBar = function(config){
20492 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20495 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20501 beforeClass: 'bootstrap-sticky-wrap',
20503 getAutoCreate : function(){
20507 cls: 'alert alert-dismissable alert-' + this.weight,
20512 html: this.html || ''
20518 cfg.cls += ' alert-messages-fixed';
20532 onRender : function(ct, position)
20534 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20537 var cfg = Roo.apply({}, this.getAutoCreate());
20541 cfg.cls += ' ' + this.cls;
20544 cfg.style = this.style;
20546 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20548 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20551 this.el.select('>button.close').on('click', this.hide, this);
20557 if (!this.rendered) {
20563 this.fireEvent('show', this);
20569 if (!this.rendered) {
20575 this.fireEvent('hide', this);
20578 update : function()
20580 // var e = this.el.dom.firstChild;
20582 // if(this.closable){
20583 // e = e.nextSibling;
20586 // e.data = this.html || '';
20588 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20604 * @class Roo.bootstrap.Graph
20605 * @extends Roo.bootstrap.Component
20606 * Bootstrap Graph class
20610 @cfg {String} graphtype bar | vbar | pie
20611 @cfg {number} g_x coodinator | centre x (pie)
20612 @cfg {number} g_y coodinator | centre y (pie)
20613 @cfg {number} g_r radius (pie)
20614 @cfg {number} g_height height of the chart (respected by all elements in the set)
20615 @cfg {number} g_width width of the chart (respected by all elements in the set)
20616 @cfg {Object} title The title of the chart
20619 -opts (object) options for the chart
20621 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20622 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20624 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.
20625 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20627 o stretch (boolean)
20629 -opts (object) options for the pie
20632 o startAngle (number)
20633 o endAngle (number)
20637 * Create a new Input
20638 * @param {Object} config The config object
20641 Roo.bootstrap.Graph = function(config){
20642 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20648 * The img click event for the img.
20649 * @param {Roo.EventObject} e
20655 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20666 //g_colors: this.colors,
20673 getAutoCreate : function(){
20684 onRender : function(ct,position){
20685 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20686 this.raphael = Raphael(this.el.dom);
20688 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20689 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20690 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20691 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20693 r.text(160, 10, "Single Series Chart").attr(txtattr);
20694 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20695 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20696 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20698 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20699 r.barchart(330, 10, 300, 220, data1);
20700 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20701 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20704 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20705 // r.barchart(30, 30, 560, 250, xdata, {
20706 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20707 // axis : "0 0 1 1",
20708 // axisxlabels : xdata
20709 // //yvalues : cols,
20712 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20714 // this.load(null,xdata,{
20715 // axis : "0 0 1 1",
20716 // axisxlabels : xdata
20721 load : function(graphtype,xdata,opts){
20722 this.raphael.clear();
20724 graphtype = this.graphtype;
20729 var r = this.raphael,
20730 fin = function () {
20731 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20733 fout = function () {
20734 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20736 pfin = function() {
20737 this.sector.stop();
20738 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20741 this.label[0].stop();
20742 this.label[0].attr({ r: 7.5 });
20743 this.label[1].attr({ "font-weight": 800 });
20746 pfout = function() {
20747 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20750 this.label[0].animate({ r: 5 }, 500, "bounce");
20751 this.label[1].attr({ "font-weight": 400 });
20757 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20760 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20763 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20764 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20766 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20773 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20778 setTitle: function(o)
20783 initEvents: function() {
20786 this.el.on('click', this.onClick, this);
20790 onClick : function(e)
20792 Roo.log('img onclick');
20793 this.fireEvent('click', this, e);
20805 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20808 * @class Roo.bootstrap.dash.NumberBox
20809 * @extends Roo.bootstrap.Component
20810 * Bootstrap NumberBox class
20811 * @cfg {String} headline Box headline
20812 * @cfg {String} content Box content
20813 * @cfg {String} icon Box icon
20814 * @cfg {String} footer Footer text
20815 * @cfg {String} fhref Footer href
20818 * Create a new NumberBox
20819 * @param {Object} config The config object
20823 Roo.bootstrap.dash.NumberBox = function(config){
20824 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20828 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20837 getAutoCreate : function(){
20841 cls : 'small-box ',
20849 cls : 'roo-headline',
20850 html : this.headline
20854 cls : 'roo-content',
20855 html : this.content
20869 cls : 'ion ' + this.icon
20878 cls : 'small-box-footer',
20879 href : this.fhref || '#',
20883 cfg.cn.push(footer);
20890 onRender : function(ct,position){
20891 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20898 setHeadline: function (value)
20900 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20903 setFooter: function (value, href)
20905 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20908 this.el.select('a.small-box-footer',true).first().attr('href', href);
20913 setContent: function (value)
20915 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20918 initEvents: function()
20932 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20935 * @class Roo.bootstrap.dash.TabBox
20936 * @extends Roo.bootstrap.Component
20937 * Bootstrap TabBox class
20938 * @cfg {String} title Title of the TabBox
20939 * @cfg {String} icon Icon of the TabBox
20940 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20941 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20944 * Create a new TabBox
20945 * @param {Object} config The config object
20949 Roo.bootstrap.dash.TabBox = function(config){
20950 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20955 * When a pane is added
20956 * @param {Roo.bootstrap.dash.TabPane} pane
20960 * @event activatepane
20961 * When a pane is activated
20962 * @param {Roo.bootstrap.dash.TabPane} pane
20964 "activatepane" : true
20972 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20977 tabScrollable : false,
20979 getChildContainer : function()
20981 return this.el.select('.tab-content', true).first();
20984 getAutoCreate : function(){
20988 cls: 'pull-left header',
20996 cls: 'fa ' + this.icon
21002 cls: 'nav nav-tabs pull-right',
21008 if(this.tabScrollable){
21015 cls: 'nav nav-tabs pull-right',
21026 cls: 'nav-tabs-custom',
21031 cls: 'tab-content no-padding',
21039 initEvents : function()
21041 //Roo.log('add add pane handler');
21042 this.on('addpane', this.onAddPane, this);
21045 * Updates the box title
21046 * @param {String} html to set the title to.
21048 setTitle : function(value)
21050 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21052 onAddPane : function(pane)
21054 this.panes.push(pane);
21055 //Roo.log('addpane');
21057 // tabs are rendere left to right..
21058 if(!this.showtabs){
21062 var ctr = this.el.select('.nav-tabs', true).first();
21065 var existing = ctr.select('.nav-tab',true);
21066 var qty = existing.getCount();;
21069 var tab = ctr.createChild({
21071 cls : 'nav-tab' + (qty ? '' : ' active'),
21079 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21082 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21084 pane.el.addClass('active');
21089 onTabClick : function(ev,un,ob,pane)
21091 //Roo.log('tab - prev default');
21092 ev.preventDefault();
21095 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21096 pane.tab.addClass('active');
21097 //Roo.log(pane.title);
21098 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21099 // technically we should have a deactivate event.. but maybe add later.
21100 // and it should not de-activate the selected tab...
21101 this.fireEvent('activatepane', pane);
21102 pane.el.addClass('active');
21103 pane.fireEvent('activate');
21108 getActivePane : function()
21111 Roo.each(this.panes, function(p) {
21112 if(p.el.hasClass('active')){
21133 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21135 * @class Roo.bootstrap.TabPane
21136 * @extends Roo.bootstrap.Component
21137 * Bootstrap TabPane class
21138 * @cfg {Boolean} active (false | true) Default false
21139 * @cfg {String} title title of panel
21143 * Create a new TabPane
21144 * @param {Object} config The config object
21147 Roo.bootstrap.dash.TabPane = function(config){
21148 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21154 * When a pane is activated
21155 * @param {Roo.bootstrap.dash.TabPane} pane
21162 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21167 // the tabBox that this is attached to.
21170 getAutoCreate : function()
21178 cfg.cls += ' active';
21183 initEvents : function()
21185 //Roo.log('trigger add pane handler');
21186 this.parent().fireEvent('addpane', this)
21190 * Updates the tab title
21191 * @param {String} html to set the title to.
21193 setTitle: function(str)
21199 this.tab.select('a', true).first().dom.innerHTML = str;
21216 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21219 * @class Roo.bootstrap.menu.Menu
21220 * @extends Roo.bootstrap.Component
21221 * Bootstrap Menu class - container for Menu
21222 * @cfg {String} html Text of the menu
21223 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21224 * @cfg {String} icon Font awesome icon
21225 * @cfg {String} pos Menu align to (top | bottom) default bottom
21229 * Create a new Menu
21230 * @param {Object} config The config object
21234 Roo.bootstrap.menu.Menu = function(config){
21235 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21239 * @event beforeshow
21240 * Fires before this menu is displayed
21241 * @param {Roo.bootstrap.menu.Menu} this
21245 * @event beforehide
21246 * Fires before this menu is hidden
21247 * @param {Roo.bootstrap.menu.Menu} this
21252 * Fires after this menu is displayed
21253 * @param {Roo.bootstrap.menu.Menu} this
21258 * Fires after this menu is hidden
21259 * @param {Roo.bootstrap.menu.Menu} this
21264 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21265 * @param {Roo.bootstrap.menu.Menu} this
21266 * @param {Roo.EventObject} e
21273 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21277 weight : 'default',
21282 getChildContainer : function() {
21283 if(this.isSubMenu){
21287 return this.el.select('ul.dropdown-menu', true).first();
21290 getAutoCreate : function()
21295 cls : 'roo-menu-text',
21303 cls : 'fa ' + this.icon
21314 cls : 'dropdown-button btn btn-' + this.weight,
21319 cls : 'dropdown-toggle btn btn-' + this.weight,
21329 cls : 'dropdown-menu'
21335 if(this.pos == 'top'){
21336 cfg.cls += ' dropup';
21339 if(this.isSubMenu){
21342 cls : 'dropdown-menu'
21349 onRender : function(ct, position)
21351 this.isSubMenu = ct.hasClass('dropdown-submenu');
21353 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21356 initEvents : function()
21358 if(this.isSubMenu){
21362 this.hidden = true;
21364 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21365 this.triggerEl.on('click', this.onTriggerPress, this);
21367 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21368 this.buttonEl.on('click', this.onClick, this);
21374 if(this.isSubMenu){
21378 return this.el.select('ul.dropdown-menu', true).first();
21381 onClick : function(e)
21383 this.fireEvent("click", this, e);
21386 onTriggerPress : function(e)
21388 if (this.isVisible()) {
21395 isVisible : function(){
21396 return !this.hidden;
21401 this.fireEvent("beforeshow", this);
21403 this.hidden = false;
21404 this.el.addClass('open');
21406 Roo.get(document).on("mouseup", this.onMouseUp, this);
21408 this.fireEvent("show", this);
21415 this.fireEvent("beforehide", this);
21417 this.hidden = true;
21418 this.el.removeClass('open');
21420 Roo.get(document).un("mouseup", this.onMouseUp);
21422 this.fireEvent("hide", this);
21425 onMouseUp : function()
21439 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21442 * @class Roo.bootstrap.menu.Item
21443 * @extends Roo.bootstrap.Component
21444 * Bootstrap MenuItem class
21445 * @cfg {Boolean} submenu (true | false) default false
21446 * @cfg {String} html text of the item
21447 * @cfg {String} href the link
21448 * @cfg {Boolean} disable (true | false) default false
21449 * @cfg {Boolean} preventDefault (true | false) default true
21450 * @cfg {String} icon Font awesome icon
21451 * @cfg {String} pos Submenu align to (left | right) default right
21455 * Create a new Item
21456 * @param {Object} config The config object
21460 Roo.bootstrap.menu.Item = function(config){
21461 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21465 * Fires when the mouse is hovering over this menu
21466 * @param {Roo.bootstrap.menu.Item} this
21467 * @param {Roo.EventObject} e
21472 * Fires when the mouse exits this menu
21473 * @param {Roo.bootstrap.menu.Item} this
21474 * @param {Roo.EventObject} e
21480 * The raw click event for the entire grid.
21481 * @param {Roo.EventObject} e
21487 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21492 preventDefault: true,
21497 getAutoCreate : function()
21502 cls : 'roo-menu-item-text',
21510 cls : 'fa ' + this.icon
21519 href : this.href || '#',
21526 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21530 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21532 if(this.pos == 'left'){
21533 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21540 initEvents : function()
21542 this.el.on('mouseover', this.onMouseOver, this);
21543 this.el.on('mouseout', this.onMouseOut, this);
21545 this.el.select('a', true).first().on('click', this.onClick, this);
21549 onClick : function(e)
21551 if(this.preventDefault){
21552 e.preventDefault();
21555 this.fireEvent("click", this, e);
21558 onMouseOver : function(e)
21560 if(this.submenu && this.pos == 'left'){
21561 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21564 this.fireEvent("mouseover", this, e);
21567 onMouseOut : function(e)
21569 this.fireEvent("mouseout", this, e);
21581 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21584 * @class Roo.bootstrap.menu.Separator
21585 * @extends Roo.bootstrap.Component
21586 * Bootstrap Separator class
21589 * Create a new Separator
21590 * @param {Object} config The config object
21594 Roo.bootstrap.menu.Separator = function(config){
21595 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21598 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21600 getAutoCreate : function(){
21621 * @class Roo.bootstrap.Tooltip
21622 * Bootstrap Tooltip class
21623 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21624 * to determine which dom element triggers the tooltip.
21626 * It needs to add support for additional attributes like tooltip-position
21629 * Create a new Toolti
21630 * @param {Object} config The config object
21633 Roo.bootstrap.Tooltip = function(config){
21634 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21637 Roo.apply(Roo.bootstrap.Tooltip, {
21639 * @function init initialize tooltip monitoring.
21643 currentTip : false,
21644 currentRegion : false,
21650 Roo.get(document).on('mouseover', this.enter ,this);
21651 Roo.get(document).on('mouseout', this.leave, this);
21654 this.currentTip = new Roo.bootstrap.Tooltip();
21657 enter : function(ev)
21659 var dom = ev.getTarget();
21660 //Roo.log(['enter',dom]);
21661 var el = Roo.fly(dom);
21662 if (this.currentEl) {
21664 //Roo.log(this.currentEl);
21665 //Roo.log(this.currentEl.contains(dom));
21666 if (this.currentEl == el) {
21669 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21677 if (this.currentTip.el) {
21678 this.currentTip.el.hide(); // force hiding...
21681 if (!el.attr('tooltip')) { // parents who have tip?
21684 this.currentEl = el;
21685 this.currentTip.bind(el);
21686 this.currentRegion = Roo.lib.Region.getRegion(dom);
21687 this.currentTip.enter();
21690 leave : function(ev)
21692 var dom = ev.getTarget();
21693 //Roo.log(['leave',dom]);
21694 if (!this.currentEl) {
21699 if (dom != this.currentEl.dom) {
21702 var xy = ev.getXY();
21703 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21706 // only activate leave if mouse cursor is outside... bounding box..
21711 if (this.currentTip) {
21712 this.currentTip.leave();
21714 //Roo.log('clear currentEl');
21715 this.currentEl = false;
21720 'left' : ['r-l', [-2,0], 'right'],
21721 'right' : ['l-r', [2,0], 'left'],
21722 'bottom' : ['t-b', [0,2], 'top'],
21723 'top' : [ 'b-t', [0,-2], 'bottom']
21729 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21734 delay : null, // can be { show : 300 , hide: 500}
21738 hoverState : null, //???
21740 placement : 'bottom',
21742 getAutoCreate : function(){
21749 cls : 'tooltip-arrow'
21752 cls : 'tooltip-inner'
21759 bind : function(el)
21765 enter : function () {
21767 if (this.timeout != null) {
21768 clearTimeout(this.timeout);
21771 this.hoverState = 'in';
21772 //Roo.log("enter - show");
21773 if (!this.delay || !this.delay.show) {
21778 this.timeout = setTimeout(function () {
21779 if (_t.hoverState == 'in') {
21782 }, this.delay.show);
21786 clearTimeout(this.timeout);
21788 this.hoverState = 'out';
21789 if (!this.delay || !this.delay.hide) {
21795 this.timeout = setTimeout(function () {
21796 //Roo.log("leave - timeout");
21798 if (_t.hoverState == 'out') {
21800 Roo.bootstrap.Tooltip.currentEl = false;
21808 this.render(document.body);
21811 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21812 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21814 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21816 var placement = typeof this.placement == 'function' ?
21817 this.placement.call(this, this.el, on_el) :
21820 var autoToken = /\s?auto?\s?/i;
21821 var autoPlace = autoToken.test(placement);
21823 placement = placement.replace(autoToken, '') || 'top';
21827 //this.el.setXY([0,0]);
21829 //this.el.dom.style.display='block';
21830 this.el.addClass(placement);
21832 //this.el.appendTo(on_el);
21834 var p = this.getPosition();
21835 var box = this.el.getBox();
21840 var align = Roo.bootstrap.Tooltip.alignment[placement];
21841 this.el.alignTo(this.bindEl, align[0],align[1]);
21842 //var arrow = this.el.select('.arrow',true).first();
21843 //arrow.set(align[2],
21845 this.el.addClass('in fade');
21846 this.hoverState = null;
21848 if (this.el.hasClass('fade')) {
21859 //this.el.setXY([0,0]);
21860 this.el.removeClass('in');
21876 * @class Roo.bootstrap.LocationPicker
21877 * @extends Roo.bootstrap.Component
21878 * Bootstrap LocationPicker class
21879 * @cfg {Number} latitude Position when init default 0
21880 * @cfg {Number} longitude Position when init default 0
21881 * @cfg {Number} zoom default 15
21882 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21883 * @cfg {Boolean} mapTypeControl default false
21884 * @cfg {Boolean} disableDoubleClickZoom default false
21885 * @cfg {Boolean} scrollwheel default true
21886 * @cfg {Boolean} streetViewControl default false
21887 * @cfg {Number} radius default 0
21888 * @cfg {String} locationName
21889 * @cfg {Boolean} draggable default true
21890 * @cfg {Boolean} enableAutocomplete default false
21891 * @cfg {Boolean} enableReverseGeocode default true
21892 * @cfg {String} markerTitle
21895 * Create a new LocationPicker
21896 * @param {Object} config The config object
21900 Roo.bootstrap.LocationPicker = function(config){
21902 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21907 * Fires when the picker initialized.
21908 * @param {Roo.bootstrap.LocationPicker} this
21909 * @param {Google Location} location
21913 * @event positionchanged
21914 * Fires when the picker position changed.
21915 * @param {Roo.bootstrap.LocationPicker} this
21916 * @param {Google Location} location
21918 positionchanged : true,
21921 * Fires when the map resize.
21922 * @param {Roo.bootstrap.LocationPicker} this
21927 * Fires when the map show.
21928 * @param {Roo.bootstrap.LocationPicker} this
21933 * Fires when the map hide.
21934 * @param {Roo.bootstrap.LocationPicker} this
21939 * Fires when click the map.
21940 * @param {Roo.bootstrap.LocationPicker} this
21941 * @param {Map event} e
21945 * @event mapRightClick
21946 * Fires when right click the map.
21947 * @param {Roo.bootstrap.LocationPicker} this
21948 * @param {Map event} e
21950 mapRightClick : true,
21952 * @event markerClick
21953 * Fires when click the marker.
21954 * @param {Roo.bootstrap.LocationPicker} this
21955 * @param {Map event} e
21957 markerClick : true,
21959 * @event markerRightClick
21960 * Fires when right click the marker.
21961 * @param {Roo.bootstrap.LocationPicker} this
21962 * @param {Map event} e
21964 markerRightClick : true,
21966 * @event OverlayViewDraw
21967 * Fires when OverlayView Draw
21968 * @param {Roo.bootstrap.LocationPicker} this
21970 OverlayViewDraw : true,
21972 * @event OverlayViewOnAdd
21973 * Fires when OverlayView Draw
21974 * @param {Roo.bootstrap.LocationPicker} this
21976 OverlayViewOnAdd : true,
21978 * @event OverlayViewOnRemove
21979 * Fires when OverlayView Draw
21980 * @param {Roo.bootstrap.LocationPicker} this
21982 OverlayViewOnRemove : true,
21984 * @event OverlayViewShow
21985 * Fires when OverlayView Draw
21986 * @param {Roo.bootstrap.LocationPicker} this
21987 * @param {Pixel} cpx
21989 OverlayViewShow : true,
21991 * @event OverlayViewHide
21992 * Fires when OverlayView Draw
21993 * @param {Roo.bootstrap.LocationPicker} this
21995 OverlayViewHide : true
22000 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22002 gMapContext: false,
22008 mapTypeControl: false,
22009 disableDoubleClickZoom: false,
22011 streetViewControl: false,
22015 enableAutocomplete: false,
22016 enableReverseGeocode: true,
22019 getAutoCreate: function()
22024 cls: 'roo-location-picker'
22030 initEvents: function(ct, position)
22032 if(!this.el.getWidth() || this.isApplied()){
22036 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22041 initial: function()
22043 if(!this.mapTypeId){
22044 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22047 this.gMapContext = this.GMapContext();
22049 this.initOverlayView();
22051 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22055 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22056 _this.setPosition(_this.gMapContext.marker.position);
22059 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22060 _this.fireEvent('mapClick', this, event);
22064 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22065 _this.fireEvent('mapRightClick', this, event);
22069 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22070 _this.fireEvent('markerClick', this, event);
22074 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22075 _this.fireEvent('markerRightClick', this, event);
22079 this.setPosition(this.gMapContext.location);
22081 this.fireEvent('initial', this, this.gMapContext.location);
22084 initOverlayView: function()
22088 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22092 _this.fireEvent('OverlayViewDraw', _this);
22097 _this.fireEvent('OverlayViewOnAdd', _this);
22100 onRemove: function()
22102 _this.fireEvent('OverlayViewOnRemove', _this);
22105 show: function(cpx)
22107 _this.fireEvent('OverlayViewShow', _this, cpx);
22112 _this.fireEvent('OverlayViewHide', _this);
22118 fromLatLngToContainerPixel: function(event)
22120 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22123 isApplied: function()
22125 return this.getGmapContext() == false ? false : true;
22128 getGmapContext: function()
22130 return this.gMapContext
22133 GMapContext: function()
22135 var _map = new google.maps.Map(this.el.dom, this);
22136 var _marker = new google.maps.Marker({
22137 position: new google.maps.LatLng(this.latitude, this.longitude),
22139 title: this.markerTitle,
22140 draggable: this.draggable
22147 location: _marker.position,
22148 radius: this.radius,
22149 locationName: this.locationName,
22150 addressComponents: {
22151 formatted_address: null,
22152 addressLine1: null,
22153 addressLine2: null,
22155 streetNumber: null,
22159 stateOrProvince: null
22162 domContainer: this.el.dom,
22163 geodecoder: new google.maps.Geocoder()
22167 drawCircle: function(center, radius, options)
22169 if (this.gMapContext.circle != null) {
22170 this.gMapContext.circle.setMap(null);
22174 options = Roo.apply({}, options, {
22175 strokeColor: "#0000FF",
22176 strokeOpacity: .35,
22178 fillColor: "#0000FF",
22182 options.map = this.gMapContext.map;
22183 options.radius = radius;
22184 options.center = center;
22185 this.gMapContext.circle = new google.maps.Circle(options);
22186 return this.gMapContext.circle;
22192 setPosition: function(location)
22194 this.gMapContext.location = location;
22195 this.gMapContext.marker.setPosition(location);
22196 this.gMapContext.map.panTo(location);
22197 this.drawCircle(location, this.gMapContext.radius, {});
22201 if (this.gMapContext.settings.enableReverseGeocode) {
22202 this.gMapContext.geodecoder.geocode({
22203 latLng: this.gMapContext.location
22204 }, function(results, status) {
22206 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22207 _this.gMapContext.locationName = results[0].formatted_address;
22208 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22210 _this.fireEvent('positionchanged', this, location);
22217 this.fireEvent('positionchanged', this, location);
22222 google.maps.event.trigger(this.gMapContext.map, "resize");
22224 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22226 this.fireEvent('resize', this);
22229 setPositionByLatLng: function(latitude, longitude)
22231 this.setPosition(new google.maps.LatLng(latitude, longitude));
22234 getCurrentPosition: function()
22237 latitude: this.gMapContext.location.lat(),
22238 longitude: this.gMapContext.location.lng()
22242 getAddressName: function()
22244 return this.gMapContext.locationName;
22247 getAddressComponents: function()
22249 return this.gMapContext.addressComponents;
22252 address_component_from_google_geocode: function(address_components)
22256 for (var i = 0; i < address_components.length; i++) {
22257 var component = address_components[i];
22258 if (component.types.indexOf("postal_code") >= 0) {
22259 result.postalCode = component.short_name;
22260 } else if (component.types.indexOf("street_number") >= 0) {
22261 result.streetNumber = component.short_name;
22262 } else if (component.types.indexOf("route") >= 0) {
22263 result.streetName = component.short_name;
22264 } else if (component.types.indexOf("neighborhood") >= 0) {
22265 result.city = component.short_name;
22266 } else if (component.types.indexOf("locality") >= 0) {
22267 result.city = component.short_name;
22268 } else if (component.types.indexOf("sublocality") >= 0) {
22269 result.district = component.short_name;
22270 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22271 result.stateOrProvince = component.short_name;
22272 } else if (component.types.indexOf("country") >= 0) {
22273 result.country = component.short_name;
22277 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22278 result.addressLine2 = "";
22282 setZoomLevel: function(zoom)
22284 this.gMapContext.map.setZoom(zoom);
22297 this.fireEvent('show', this);
22308 this.fireEvent('hide', this);
22313 Roo.apply(Roo.bootstrap.LocationPicker, {
22315 OverlayView : function(map, options)
22317 options = options || {};
22331 * @class Roo.bootstrap.Alert
22332 * @extends Roo.bootstrap.Component
22333 * Bootstrap Alert class
22334 * @cfg {String} title The title of alert
22335 * @cfg {String} html The content of alert
22336 * @cfg {String} weight ( success | info | warning | danger )
22337 * @cfg {String} faicon font-awesomeicon
22340 * Create a new alert
22341 * @param {Object} config The config object
22345 Roo.bootstrap.Alert = function(config){
22346 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22350 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22357 getAutoCreate : function()
22366 cls : 'roo-alert-icon'
22371 cls : 'roo-alert-title',
22376 cls : 'roo-alert-text',
22383 cfg.cn[0].cls += ' fa ' + this.faicon;
22387 cfg.cls += ' alert-' + this.weight;
22393 initEvents: function()
22395 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22398 setTitle : function(str)
22400 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22403 setText : function(str)
22405 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22408 setWeight : function(weight)
22411 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22414 this.weight = weight;
22416 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22419 setIcon : function(icon)
22422 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22427 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);