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' && !this.allowBlank){
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' && !this.allowBlank){
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 if(this.disabled || this.allowBlank){
7749 this.el.addClass(this.validClass);
7751 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7753 var feedback = this.el.select('.form-control-feedback', true).first();
7756 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7757 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7762 this.fireEvent('valid', this);
7766 * Mark this field as invalid
7767 * @param {String} msg The validation message
7769 markInvalid : function(msg){
7770 if(!this.el || this.preventMark){ // not rendered
7774 this.el.removeClass([this.invalidClass, this.validClass]);
7776 if(this.disabled || this.allowBlank){
7780 this.el.addClass(this.invalidClass);
7782 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7784 var feedback = this.el.select('.form-control-feedback', true).first();
7787 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7789 if(this.getValue().length){
7790 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7797 this.fireEvent('invalid', this, msg);
7800 SafariOnKeyDown : function(event)
7802 // this is a workaround for a password hang bug on chrome/ webkit.
7804 var isSelectAll = false;
7806 if(this.inputEl().dom.selectionEnd > 0){
7807 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7809 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7810 event.preventDefault();
7815 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7817 event.preventDefault();
7818 // this is very hacky as keydown always get's upper case.
7820 var cc = String.fromCharCode(event.getCharCode());
7821 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7825 adjustWidth : function(tag, w){
7826 tag = tag.toLowerCase();
7827 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7828 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7832 if(tag == 'textarea'){
7835 }else if(Roo.isOpera){
7839 if(tag == 'textarea'){
7858 * @class Roo.bootstrap.TextArea
7859 * @extends Roo.bootstrap.Input
7860 * Bootstrap TextArea class
7861 * @cfg {Number} cols Specifies the visible width of a text area
7862 * @cfg {Number} rows Specifies the visible number of lines in a text area
7863 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7864 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7865 * @cfg {string} html text
7868 * Create a new TextArea
7869 * @param {Object} config The config object
7872 Roo.bootstrap.TextArea = function(config){
7873 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7877 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7887 getAutoCreate : function(){
7889 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7900 value : this.value || '',
7901 html: this.html || '',
7902 cls : 'form-control',
7903 placeholder : this.placeholder || ''
7907 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7908 input.maxLength = this.maxLength;
7912 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7916 input.cols = this.cols;
7919 if (this.readOnly) {
7920 input.readonly = true;
7924 input.name = this.name;
7928 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7932 ['xs','sm','md','lg'].map(function(size){
7933 if (settings[size]) {
7934 cfg.cls += ' col-' + size + '-' + settings[size];
7938 var inputblock = input;
7940 if(this.hasFeedback && !this.allowBlank){
7944 cls: 'glyphicon form-control-feedback'
7948 cls : 'has-feedback',
7957 if (this.before || this.after) {
7960 cls : 'input-group',
7964 inputblock.cn.push({
7966 cls : 'input-group-addon',
7971 inputblock.cn.push(input);
7973 if(this.hasFeedback && !this.allowBlank){
7974 inputblock.cls += ' has-feedback';
7975 inputblock.cn.push(feedback);
7979 inputblock.cn.push({
7981 cls : 'input-group-addon',
7988 if (align ==='left' && this.fieldLabel.length) {
7989 Roo.log("left and has label");
7995 cls : 'control-label col-sm-' + this.labelWidth,
7996 html : this.fieldLabel
8000 cls : "col-sm-" + (12 - this.labelWidth),
8007 } else if ( this.fieldLabel.length) {
8013 //cls : 'input-group-addon',
8014 html : this.fieldLabel
8024 Roo.log(" no label && no align");
8034 if (this.disabled) {
8035 input.disabled=true;
8042 * return the real textarea element.
8044 inputEl: function ()
8046 return this.el.select('textarea.form-control',true).first();
8054 * trigger field - base class for combo..
8059 * @class Roo.bootstrap.TriggerField
8060 * @extends Roo.bootstrap.Input
8061 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8062 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8063 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8064 * for which you can provide a custom implementation. For example:
8066 var trigger = new Roo.bootstrap.TriggerField();
8067 trigger.onTriggerClick = myTriggerFn;
8068 trigger.applyTo('my-field');
8071 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8072 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8073 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8074 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8075 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8078 * Create a new TriggerField.
8079 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8080 * to the base TextField)
8082 Roo.bootstrap.TriggerField = function(config){
8083 this.mimicing = false;
8084 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8087 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8089 * @cfg {String} triggerClass A CSS class to apply to the trigger
8092 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8096 /** @cfg {Boolean} grow @hide */
8097 /** @cfg {Number} growMin @hide */
8098 /** @cfg {Number} growMax @hide */
8104 autoSize: Roo.emptyFn,
8111 actionMode : 'wrap',
8116 getAutoCreate : function(){
8118 var align = this.labelAlign || this.parentLabelAlign();
8123 cls: 'form-group' //input-group
8130 type : this.inputType,
8131 cls : 'form-control',
8132 autocomplete: 'new-password',
8133 placeholder : this.placeholder || ''
8137 input.name = this.name;
8140 input.cls += ' input-' + this.size;
8143 if (this.disabled) {
8144 input.disabled=true;
8147 var inputblock = input;
8149 if(this.hasFeedback && !this.allowBlank){
8153 cls: 'glyphicon form-control-feedback'
8157 cls : 'has-feedback',
8165 if (this.before || this.after) {
8168 cls : 'input-group',
8172 inputblock.cn.push({
8174 cls : 'input-group-addon',
8179 inputblock.cn.push(input);
8181 if(this.hasFeedback && !this.allowBlank){
8182 inputblock.cls += ' has-feedback';
8183 inputblock.cn.push(feedback);
8187 inputblock.cn.push({
8189 cls : 'input-group-addon',
8202 cls: 'form-hidden-field'
8210 Roo.log('multiple');
8218 cls: 'form-hidden-field'
8222 cls: 'select2-choices',
8226 cls: 'select2-search-field',
8239 cls: 'select2-container input-group',
8244 // cls: 'typeahead typeahead-long dropdown-menu',
8245 // style: 'display:none'
8250 if(!this.multiple && this.showToggleBtn){
8256 if (this.caret != false) {
8259 cls: 'fa fa-' + this.caret
8266 cls : 'input-group-addon btn dropdown-toggle',
8271 cls: 'combobox-clear',
8285 combobox.cls += ' select2-container-multi';
8288 if (align ==='left' && this.fieldLabel.length) {
8290 Roo.log("left and has label");
8296 cls : 'control-label col-sm-' + this.labelWidth,
8297 html : this.fieldLabel
8301 cls : "col-sm-" + (12 - this.labelWidth),
8308 } else if ( this.fieldLabel.length) {
8314 //cls : 'input-group-addon',
8315 html : this.fieldLabel
8325 Roo.log(" no label && no align");
8332 ['xs','sm','md','lg'].map(function(size){
8333 if (settings[size]) {
8334 cfg.cls += ' col-' + size + '-' + settings[size];
8345 onResize : function(w, h){
8346 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8347 // if(typeof w == 'number'){
8348 // var x = w - this.trigger.getWidth();
8349 // this.inputEl().setWidth(this.adjustWidth('input', x));
8350 // this.trigger.setStyle('left', x+'px');
8355 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8358 getResizeEl : function(){
8359 return this.inputEl();
8363 getPositionEl : function(){
8364 return this.inputEl();
8368 alignErrorIcon : function(){
8369 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8373 initEvents : function(){
8377 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8378 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8379 if(!this.multiple && this.showToggleBtn){
8380 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8381 if(this.hideTrigger){
8382 this.trigger.setDisplayed(false);
8384 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8388 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8391 //this.trigger.addClassOnOver('x-form-trigger-over');
8392 //this.trigger.addClassOnClick('x-form-trigger-click');
8395 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8399 createList : function()
8401 this.list = Roo.get(document.body).createChild({
8403 cls: 'typeahead typeahead-long dropdown-menu',
8404 style: 'display:none'
8407 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8412 initTrigger : function(){
8417 onDestroy : function(){
8419 this.trigger.removeAllListeners();
8420 // this.trigger.remove();
8423 // this.wrap.remove();
8425 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8429 onFocus : function(){
8430 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8433 this.wrap.addClass('x-trigger-wrap-focus');
8434 this.mimicing = true;
8435 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8436 if(this.monitorTab){
8437 this.el.on("keydown", this.checkTab, this);
8444 checkTab : function(e){
8445 if(e.getKey() == e.TAB){
8451 onBlur : function(){
8456 mimicBlur : function(e, t){
8458 if(!this.wrap.contains(t) && this.validateBlur()){
8465 triggerBlur : function(){
8466 this.mimicing = false;
8467 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8468 if(this.monitorTab){
8469 this.el.un("keydown", this.checkTab, this);
8471 //this.wrap.removeClass('x-trigger-wrap-focus');
8472 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8476 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8477 validateBlur : function(e, t){
8482 onDisable : function(){
8483 this.inputEl().dom.disabled = true;
8484 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8486 // this.wrap.addClass('x-item-disabled');
8491 onEnable : function(){
8492 this.inputEl().dom.disabled = false;
8493 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8495 // this.el.removeClass('x-item-disabled');
8500 onShow : function(){
8501 var ae = this.getActionEl();
8504 ae.dom.style.display = '';
8505 ae.dom.style.visibility = 'visible';
8511 onHide : function(){
8512 var ae = this.getActionEl();
8513 ae.dom.style.display = 'none';
8517 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8518 * by an implementing function.
8520 * @param {EventObject} e
8522 onTriggerClick : Roo.emptyFn
8526 * Ext JS Library 1.1.1
8527 * Copyright(c) 2006-2007, Ext JS, LLC.
8529 * Originally Released Under LGPL - original licence link has changed is not relivant.
8532 * <script type="text/javascript">
8537 * @class Roo.data.SortTypes
8539 * Defines the default sorting (casting?) comparison functions used when sorting data.
8541 Roo.data.SortTypes = {
8543 * Default sort that does nothing
8544 * @param {Mixed} s The value being converted
8545 * @return {Mixed} The comparison value
8552 * The regular expression used to strip tags
8556 stripTagsRE : /<\/?[^>]+>/gi,
8559 * Strips all HTML tags to sort on text only
8560 * @param {Mixed} s The value being converted
8561 * @return {String} The comparison value
8563 asText : function(s){
8564 return String(s).replace(this.stripTagsRE, "");
8568 * Strips all HTML tags to sort on text only - Case insensitive
8569 * @param {Mixed} s The value being converted
8570 * @return {String} The comparison value
8572 asUCText : function(s){
8573 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8577 * Case insensitive string
8578 * @param {Mixed} s The value being converted
8579 * @return {String} The comparison value
8581 asUCString : function(s) {
8582 return String(s).toUpperCase();
8587 * @param {Mixed} s The value being converted
8588 * @return {Number} The comparison value
8590 asDate : function(s) {
8594 if(s instanceof Date){
8597 return Date.parse(String(s));
8602 * @param {Mixed} s The value being converted
8603 * @return {Float} The comparison value
8605 asFloat : function(s) {
8606 var val = parseFloat(String(s).replace(/,/g, ""));
8607 if(isNaN(val)) val = 0;
8613 * @param {Mixed} s The value being converted
8614 * @return {Number} The comparison value
8616 asInt : function(s) {
8617 var val = parseInt(String(s).replace(/,/g, ""));
8618 if(isNaN(val)) val = 0;
8623 * Ext JS Library 1.1.1
8624 * Copyright(c) 2006-2007, Ext JS, LLC.
8626 * Originally Released Under LGPL - original licence link has changed is not relivant.
8629 * <script type="text/javascript">
8633 * @class Roo.data.Record
8634 * Instances of this class encapsulate both record <em>definition</em> information, and record
8635 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8636 * to access Records cached in an {@link Roo.data.Store} object.<br>
8638 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8639 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8642 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8644 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8645 * {@link #create}. The parameters are the same.
8646 * @param {Array} data An associative Array of data values keyed by the field name.
8647 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8648 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8649 * not specified an integer id is generated.
8651 Roo.data.Record = function(data, id){
8652 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8657 * Generate a constructor for a specific record layout.
8658 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8659 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8660 * Each field definition object may contain the following properties: <ul>
8661 * <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,
8662 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8663 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8664 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8665 * is being used, then this is a string containing the javascript expression to reference the data relative to
8666 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8667 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8668 * this may be omitted.</p></li>
8669 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8670 * <ul><li>auto (Default, implies no conversion)</li>
8675 * <li>date</li></ul></p></li>
8676 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8677 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8678 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8679 * by the Reader into an object that will be stored in the Record. It is passed the
8680 * following parameters:<ul>
8681 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8683 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8685 * <br>usage:<br><pre><code>
8686 var TopicRecord = Roo.data.Record.create(
8687 {name: 'title', mapping: 'topic_title'},
8688 {name: 'author', mapping: 'username'},
8689 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8690 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8691 {name: 'lastPoster', mapping: 'user2'},
8692 {name: 'excerpt', mapping: 'post_text'}
8695 var myNewRecord = new TopicRecord({
8696 title: 'Do my job please',
8699 lastPost: new Date(),
8700 lastPoster: 'Animal',
8701 excerpt: 'No way dude!'
8703 myStore.add(myNewRecord);
8708 Roo.data.Record.create = function(o){
8710 f.superclass.constructor.apply(this, arguments);
8712 Roo.extend(f, Roo.data.Record);
8713 var p = f.prototype;
8714 p.fields = new Roo.util.MixedCollection(false, function(field){
8717 for(var i = 0, len = o.length; i < len; i++){
8718 p.fields.add(new Roo.data.Field(o[i]));
8720 f.getField = function(name){
8721 return p.fields.get(name);
8726 Roo.data.Record.AUTO_ID = 1000;
8727 Roo.data.Record.EDIT = 'edit';
8728 Roo.data.Record.REJECT = 'reject';
8729 Roo.data.Record.COMMIT = 'commit';
8731 Roo.data.Record.prototype = {
8733 * Readonly flag - true if this record has been modified.
8742 join : function(store){
8747 * Set the named field to the specified value.
8748 * @param {String} name The name of the field to set.
8749 * @param {Object} value The value to set the field to.
8751 set : function(name, value){
8752 if(this.data[name] == value){
8759 if(typeof this.modified[name] == 'undefined'){
8760 this.modified[name] = this.data[name];
8762 this.data[name] = value;
8763 if(!this.editing && this.store){
8764 this.store.afterEdit(this);
8769 * Get the value of the named field.
8770 * @param {String} name The name of the field to get the value of.
8771 * @return {Object} The value of the field.
8773 get : function(name){
8774 return this.data[name];
8778 beginEdit : function(){
8779 this.editing = true;
8784 cancelEdit : function(){
8785 this.editing = false;
8786 delete this.modified;
8790 endEdit : function(){
8791 this.editing = false;
8792 if(this.dirty && this.store){
8793 this.store.afterEdit(this);
8798 * Usually called by the {@link Roo.data.Store} which owns the Record.
8799 * Rejects all changes made to the Record since either creation, or the last commit operation.
8800 * Modified fields are reverted to their original values.
8802 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8803 * of reject operations.
8805 reject : function(){
8806 var m = this.modified;
8808 if(typeof m[n] != "function"){
8809 this.data[n] = m[n];
8813 delete this.modified;
8814 this.editing = false;
8816 this.store.afterReject(this);
8821 * Usually called by the {@link Roo.data.Store} which owns the Record.
8822 * Commits all changes made to the Record since either creation, or the last commit operation.
8824 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8825 * of commit operations.
8827 commit : function(){
8829 delete this.modified;
8830 this.editing = false;
8832 this.store.afterCommit(this);
8837 hasError : function(){
8838 return this.error != null;
8842 clearError : function(){
8847 * Creates a copy of this record.
8848 * @param {String} id (optional) A new record id if you don't want to use this record's id
8851 copy : function(newId) {
8852 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8856 * Ext JS Library 1.1.1
8857 * Copyright(c) 2006-2007, Ext JS, LLC.
8859 * Originally Released Under LGPL - original licence link has changed is not relivant.
8862 * <script type="text/javascript">
8868 * @class Roo.data.Store
8869 * @extends Roo.util.Observable
8870 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8871 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8873 * 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
8874 * has no knowledge of the format of the data returned by the Proxy.<br>
8876 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8877 * instances from the data object. These records are cached and made available through accessor functions.
8879 * Creates a new Store.
8880 * @param {Object} config A config object containing the objects needed for the Store to access data,
8881 * and read the data into Records.
8883 Roo.data.Store = function(config){
8884 this.data = new Roo.util.MixedCollection(false);
8885 this.data.getKey = function(o){
8888 this.baseParams = {};
8895 "multisort" : "_multisort"
8898 if(config && config.data){
8899 this.inlineData = config.data;
8903 Roo.apply(this, config);
8905 if(this.reader){ // reader passed
8906 this.reader = Roo.factory(this.reader, Roo.data);
8907 this.reader.xmodule = this.xmodule || false;
8908 if(!this.recordType){
8909 this.recordType = this.reader.recordType;
8911 if(this.reader.onMetaChange){
8912 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8916 if(this.recordType){
8917 this.fields = this.recordType.prototype.fields;
8923 * @event datachanged
8924 * Fires when the data cache has changed, and a widget which is using this Store
8925 * as a Record cache should refresh its view.
8926 * @param {Store} this
8931 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8932 * @param {Store} this
8933 * @param {Object} meta The JSON metadata
8938 * Fires when Records have been added to the Store
8939 * @param {Store} this
8940 * @param {Roo.data.Record[]} records The array of Records added
8941 * @param {Number} index The index at which the record(s) were added
8946 * Fires when a Record has been removed from the Store
8947 * @param {Store} this
8948 * @param {Roo.data.Record} record The Record that was removed
8949 * @param {Number} index The index at which the record was removed
8954 * Fires when a Record has been updated
8955 * @param {Store} this
8956 * @param {Roo.data.Record} record The Record that was updated
8957 * @param {String} operation The update operation being performed. Value may be one of:
8959 Roo.data.Record.EDIT
8960 Roo.data.Record.REJECT
8961 Roo.data.Record.COMMIT
8967 * Fires when the data cache has been cleared.
8968 * @param {Store} this
8973 * Fires before a request is made for a new data object. If the beforeload handler returns false
8974 * the load action will be canceled.
8975 * @param {Store} this
8976 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8980 * @event beforeloadadd
8981 * Fires after a new set of Records has been loaded.
8982 * @param {Store} this
8983 * @param {Roo.data.Record[]} records The Records that were loaded
8984 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8986 beforeloadadd : true,
8989 * Fires after a new set of Records has been loaded, before they are added to the store.
8990 * @param {Store} this
8991 * @param {Roo.data.Record[]} records The Records that were loaded
8992 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8993 * @params {Object} return from reader
8997 * @event loadexception
8998 * Fires if an exception occurs in the Proxy during loading.
8999 * Called with the signature of the Proxy's "loadexception" event.
9000 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9003 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9004 * @param {Object} load options
9005 * @param {Object} jsonData from your request (normally this contains the Exception)
9007 loadexception : true
9011 this.proxy = Roo.factory(this.proxy, Roo.data);
9012 this.proxy.xmodule = this.xmodule || false;
9013 this.relayEvents(this.proxy, ["loadexception"]);
9015 this.sortToggle = {};
9016 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9018 Roo.data.Store.superclass.constructor.call(this);
9020 if(this.inlineData){
9021 this.loadData(this.inlineData);
9022 delete this.inlineData;
9026 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9028 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9029 * without a remote query - used by combo/forms at present.
9033 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9036 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9039 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9040 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9043 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9044 * on any HTTP request
9047 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9050 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9054 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9055 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9060 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9061 * loaded or when a record is removed. (defaults to false).
9063 pruneModifiedRecords : false,
9069 * Add Records to the Store and fires the add event.
9070 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9072 add : function(records){
9073 records = [].concat(records);
9074 for(var i = 0, len = records.length; i < len; i++){
9075 records[i].join(this);
9077 var index = this.data.length;
9078 this.data.addAll(records);
9079 this.fireEvent("add", this, records, index);
9083 * Remove a Record from the Store and fires the remove event.
9084 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9086 remove : function(record){
9087 var index = this.data.indexOf(record);
9088 this.data.removeAt(index);
9089 if(this.pruneModifiedRecords){
9090 this.modified.remove(record);
9092 this.fireEvent("remove", this, record, index);
9096 * Remove all Records from the Store and fires the clear event.
9098 removeAll : function(){
9100 if(this.pruneModifiedRecords){
9103 this.fireEvent("clear", this);
9107 * Inserts Records to the Store at the given index and fires the add event.
9108 * @param {Number} index The start index at which to insert the passed Records.
9109 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9111 insert : function(index, records){
9112 records = [].concat(records);
9113 for(var i = 0, len = records.length; i < len; i++){
9114 this.data.insert(index, records[i]);
9115 records[i].join(this);
9117 this.fireEvent("add", this, records, index);
9121 * Get the index within the cache of the passed Record.
9122 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9123 * @return {Number} The index of the passed Record. Returns -1 if not found.
9125 indexOf : function(record){
9126 return this.data.indexOf(record);
9130 * Get the index within the cache of the Record with the passed id.
9131 * @param {String} id The id of the Record to find.
9132 * @return {Number} The index of the Record. Returns -1 if not found.
9134 indexOfId : function(id){
9135 return this.data.indexOfKey(id);
9139 * Get the Record with the specified id.
9140 * @param {String} id The id of the Record to find.
9141 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9143 getById : function(id){
9144 return this.data.key(id);
9148 * Get the Record at the specified index.
9149 * @param {Number} index The index of the Record to find.
9150 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9152 getAt : function(index){
9153 return this.data.itemAt(index);
9157 * Returns a range of Records between specified indices.
9158 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9159 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9160 * @return {Roo.data.Record[]} An array of Records
9162 getRange : function(start, end){
9163 return this.data.getRange(start, end);
9167 storeOptions : function(o){
9168 o = Roo.apply({}, o);
9171 this.lastOptions = o;
9175 * Loads the Record cache from the configured Proxy using the configured Reader.
9177 * If using remote paging, then the first load call must specify the <em>start</em>
9178 * and <em>limit</em> properties in the options.params property to establish the initial
9179 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9181 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9182 * and this call will return before the new data has been loaded. Perform any post-processing
9183 * in a callback function, or in a "load" event handler.</strong>
9185 * @param {Object} options An object containing properties which control loading options:<ul>
9186 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9187 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9188 * passed the following arguments:<ul>
9189 * <li>r : Roo.data.Record[]</li>
9190 * <li>options: Options object from the load call</li>
9191 * <li>success: Boolean success indicator</li></ul></li>
9192 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9193 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9196 load : function(options){
9197 options = options || {};
9198 if(this.fireEvent("beforeload", this, options) !== false){
9199 this.storeOptions(options);
9200 var p = Roo.apply(options.params || {}, this.baseParams);
9201 // if meta was not loaded from remote source.. try requesting it.
9202 if (!this.reader.metaFromRemote) {
9205 if(this.sortInfo && this.remoteSort){
9206 var pn = this.paramNames;
9207 p[pn["sort"]] = this.sortInfo.field;
9208 p[pn["dir"]] = this.sortInfo.direction;
9210 if (this.multiSort) {
9211 var pn = this.paramNames;
9212 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9215 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9220 * Reloads the Record cache from the configured Proxy using the configured Reader and
9221 * the options from the last load operation performed.
9222 * @param {Object} options (optional) An object containing properties which may override the options
9223 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9224 * the most recently used options are reused).
9226 reload : function(options){
9227 this.load(Roo.applyIf(options||{}, this.lastOptions));
9231 // Called as a callback by the Reader during a load operation.
9232 loadRecords : function(o, options, success){
9233 if(!o || success === false){
9234 if(success !== false){
9235 this.fireEvent("load", this, [], options, o);
9237 if(options.callback){
9238 options.callback.call(options.scope || this, [], options, false);
9242 // if data returned failure - throw an exception.
9243 if (o.success === false) {
9244 // show a message if no listener is registered.
9245 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9246 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9248 // loadmask wil be hooked into this..
9249 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9252 var r = o.records, t = o.totalRecords || r.length;
9254 this.fireEvent("beforeloadadd", this, r, options, o);
9256 if(!options || options.add !== true){
9257 if(this.pruneModifiedRecords){
9260 for(var i = 0, len = r.length; i < len; i++){
9264 this.data = this.snapshot;
9265 delete this.snapshot;
9268 this.data.addAll(r);
9269 this.totalLength = t;
9271 this.fireEvent("datachanged", this);
9273 this.totalLength = Math.max(t, this.data.length+r.length);
9276 this.fireEvent("load", this, r, options, o);
9277 if(options.callback){
9278 options.callback.call(options.scope || this, r, options, true);
9284 * Loads data from a passed data block. A Reader which understands the format of the data
9285 * must have been configured in the constructor.
9286 * @param {Object} data The data block from which to read the Records. The format of the data expected
9287 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9288 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9290 loadData : function(o, append){
9291 var r = this.reader.readRecords(o);
9292 this.loadRecords(r, {add: append}, true);
9296 * Gets the number of cached records.
9298 * <em>If using paging, this may not be the total size of the dataset. If the data object
9299 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9300 * the data set size</em>
9302 getCount : function(){
9303 return this.data.length || 0;
9307 * Gets the total number of records in the dataset as returned by the server.
9309 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9310 * the dataset size</em>
9312 getTotalCount : function(){
9313 return this.totalLength || 0;
9317 * Returns the sort state of the Store as an object with two properties:
9319 field {String} The name of the field by which the Records are sorted
9320 direction {String} The sort order, "ASC" or "DESC"
9323 getSortState : function(){
9324 return this.sortInfo;
9328 applySort : function(){
9329 if(this.sortInfo && !this.remoteSort){
9330 var s = this.sortInfo, f = s.field;
9331 var st = this.fields.get(f).sortType;
9332 var fn = function(r1, r2){
9333 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9334 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9336 this.data.sort(s.direction, fn);
9337 if(this.snapshot && this.snapshot != this.data){
9338 this.snapshot.sort(s.direction, fn);
9344 * Sets the default sort column and order to be used by the next load operation.
9345 * @param {String} fieldName The name of the field to sort by.
9346 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9348 setDefaultSort : function(field, dir){
9349 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9354 * If remote sorting is used, the sort is performed on the server, and the cache is
9355 * reloaded. If local sorting is used, the cache is sorted internally.
9356 * @param {String} fieldName The name of the field to sort by.
9357 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9359 sort : function(fieldName, dir){
9360 var f = this.fields.get(fieldName);
9362 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9364 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9365 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9370 this.sortToggle[f.name] = dir;
9371 this.sortInfo = {field: f.name, direction: dir};
9372 if(!this.remoteSort){
9374 this.fireEvent("datachanged", this);
9376 this.load(this.lastOptions);
9381 * Calls the specified function for each of the Records in the cache.
9382 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9383 * Returning <em>false</em> aborts and exits the iteration.
9384 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9386 each : function(fn, scope){
9387 this.data.each(fn, scope);
9391 * Gets all records modified since the last commit. Modified records are persisted across load operations
9392 * (e.g., during paging).
9393 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9395 getModifiedRecords : function(){
9396 return this.modified;
9400 createFilterFn : function(property, value, anyMatch){
9401 if(!value.exec){ // not a regex
9402 value = String(value);
9403 if(value.length == 0){
9406 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9409 return value.test(r.data[property]);
9414 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9415 * @param {String} property A field on your records
9416 * @param {Number} start The record index to start at (defaults to 0)
9417 * @param {Number} end The last record index to include (defaults to length - 1)
9418 * @return {Number} The sum
9420 sum : function(property, start, end){
9421 var rs = this.data.items, v = 0;
9423 end = (end || end === 0) ? end : rs.length-1;
9425 for(var i = start; i <= end; i++){
9426 v += (rs[i].data[property] || 0);
9432 * Filter the records by a specified property.
9433 * @param {String} field A field on your records
9434 * @param {String/RegExp} value Either a string that the field
9435 * should start with or a RegExp to test against the field
9436 * @param {Boolean} anyMatch True to match any part not just the beginning
9438 filter : function(property, value, anyMatch){
9439 var fn = this.createFilterFn(property, value, anyMatch);
9440 return fn ? this.filterBy(fn) : this.clearFilter();
9444 * Filter by a function. The specified function will be called with each
9445 * record in this data source. If the function returns true the record is included,
9446 * otherwise it is filtered.
9447 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9448 * @param {Object} scope (optional) The scope of the function (defaults to this)
9450 filterBy : function(fn, scope){
9451 this.snapshot = this.snapshot || this.data;
9452 this.data = this.queryBy(fn, scope||this);
9453 this.fireEvent("datachanged", this);
9457 * Query the records by a specified property.
9458 * @param {String} field A field on your records
9459 * @param {String/RegExp} value Either a string that the field
9460 * should start with or a RegExp to test against the field
9461 * @param {Boolean} anyMatch True to match any part not just the beginning
9462 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9464 query : function(property, value, anyMatch){
9465 var fn = this.createFilterFn(property, value, anyMatch);
9466 return fn ? this.queryBy(fn) : this.data.clone();
9470 * Query by a function. The specified function will be called with each
9471 * record in this data source. If the function returns true the record is included
9473 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9474 * @param {Object} scope (optional) The scope of the function (defaults to this)
9475 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9477 queryBy : function(fn, scope){
9478 var data = this.snapshot || this.data;
9479 return data.filterBy(fn, scope||this);
9483 * Collects unique values for a particular dataIndex from this store.
9484 * @param {String} dataIndex The property to collect
9485 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9486 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9487 * @return {Array} An array of the unique values
9489 collect : function(dataIndex, allowNull, bypassFilter){
9490 var d = (bypassFilter === true && this.snapshot) ?
9491 this.snapshot.items : this.data.items;
9492 var v, sv, r = [], l = {};
9493 for(var i = 0, len = d.length; i < len; i++){
9494 v = d[i].data[dataIndex];
9496 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9505 * Revert to a view of the Record cache with no filtering applied.
9506 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9508 clearFilter : function(suppressEvent){
9509 if(this.snapshot && this.snapshot != this.data){
9510 this.data = this.snapshot;
9511 delete this.snapshot;
9512 if(suppressEvent !== true){
9513 this.fireEvent("datachanged", this);
9519 afterEdit : function(record){
9520 if(this.modified.indexOf(record) == -1){
9521 this.modified.push(record);
9523 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9527 afterReject : function(record){
9528 this.modified.remove(record);
9529 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9533 afterCommit : function(record){
9534 this.modified.remove(record);
9535 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9539 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9540 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9542 commitChanges : function(){
9543 var m = this.modified.slice(0);
9545 for(var i = 0, len = m.length; i < len; i++){
9551 * Cancel outstanding changes on all changed records.
9553 rejectChanges : function(){
9554 var m = this.modified.slice(0);
9556 for(var i = 0, len = m.length; i < len; i++){
9561 onMetaChange : function(meta, rtype, o){
9562 this.recordType = rtype;
9563 this.fields = rtype.prototype.fields;
9564 delete this.snapshot;
9565 this.sortInfo = meta.sortInfo || this.sortInfo;
9567 this.fireEvent('metachange', this, this.reader.meta);
9570 moveIndex : function(data, type)
9572 var index = this.indexOf(data);
9574 var newIndex = index + type;
9578 this.insert(newIndex, data);
9583 * Ext JS Library 1.1.1
9584 * Copyright(c) 2006-2007, Ext JS, LLC.
9586 * Originally Released Under LGPL - original licence link has changed is not relivant.
9589 * <script type="text/javascript">
9593 * @class Roo.data.SimpleStore
9594 * @extends Roo.data.Store
9595 * Small helper class to make creating Stores from Array data easier.
9596 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9597 * @cfg {Array} fields An array of field definition objects, or field name strings.
9598 * @cfg {Array} data The multi-dimensional array of data
9600 * @param {Object} config
9602 Roo.data.SimpleStore = function(config){
9603 Roo.data.SimpleStore.superclass.constructor.call(this, {
9605 reader: new Roo.data.ArrayReader({
9608 Roo.data.Record.create(config.fields)
9610 proxy : new Roo.data.MemoryProxy(config.data)
9614 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9616 * Ext JS Library 1.1.1
9617 * Copyright(c) 2006-2007, Ext JS, LLC.
9619 * Originally Released Under LGPL - original licence link has changed is not relivant.
9622 * <script type="text/javascript">
9627 * @extends Roo.data.Store
9628 * @class Roo.data.JsonStore
9629 * Small helper class to make creating Stores for JSON data easier. <br/>
9631 var store = new Roo.data.JsonStore({
9632 url: 'get-images.php',
9634 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9637 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9638 * JsonReader and HttpProxy (unless inline data is provided).</b>
9639 * @cfg {Array} fields An array of field definition objects, or field name strings.
9641 * @param {Object} config
9643 Roo.data.JsonStore = function(c){
9644 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9645 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9646 reader: new Roo.data.JsonReader(c, c.fields)
9649 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9651 * Ext JS Library 1.1.1
9652 * Copyright(c) 2006-2007, Ext JS, LLC.
9654 * Originally Released Under LGPL - original licence link has changed is not relivant.
9657 * <script type="text/javascript">
9661 Roo.data.Field = function(config){
9662 if(typeof config == "string"){
9663 config = {name: config};
9665 Roo.apply(this, config);
9671 var st = Roo.data.SortTypes;
9672 // named sortTypes are supported, here we look them up
9673 if(typeof this.sortType == "string"){
9674 this.sortType = st[this.sortType];
9677 // set default sortType for strings and dates
9681 this.sortType = st.asUCString;
9684 this.sortType = st.asDate;
9687 this.sortType = st.none;
9692 var stripRe = /[\$,%]/g;
9694 // prebuilt conversion function for this field, instead of
9695 // switching every time we're reading a value
9697 var cv, dateFormat = this.dateFormat;
9702 cv = function(v){ return v; };
9705 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9709 return v !== undefined && v !== null && v !== '' ?
9710 parseInt(String(v).replace(stripRe, ""), 10) : '';
9715 return v !== undefined && v !== null && v !== '' ?
9716 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9721 cv = function(v){ return v === true || v === "true" || v == 1; };
9728 if(v instanceof Date){
9732 if(dateFormat == "timestamp"){
9733 return new Date(v*1000);
9735 return Date.parseDate(v, dateFormat);
9737 var parsed = Date.parse(v);
9738 return parsed ? new Date(parsed) : null;
9747 Roo.data.Field.prototype = {
9755 * Ext JS Library 1.1.1
9756 * Copyright(c) 2006-2007, Ext JS, LLC.
9758 * Originally Released Under LGPL - original licence link has changed is not relivant.
9761 * <script type="text/javascript">
9764 // Base class for reading structured data from a data source. This class is intended to be
9765 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9768 * @class Roo.data.DataReader
9769 * Base class for reading structured data from a data source. This class is intended to be
9770 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9773 Roo.data.DataReader = function(meta, recordType){
9777 this.recordType = recordType instanceof Array ?
9778 Roo.data.Record.create(recordType) : recordType;
9781 Roo.data.DataReader.prototype = {
9783 * Create an empty record
9784 * @param {Object} data (optional) - overlay some values
9785 * @return {Roo.data.Record} record created.
9787 newRow : function(d) {
9789 this.recordType.prototype.fields.each(function(c) {
9791 case 'int' : da[c.name] = 0; break;
9792 case 'date' : da[c.name] = new Date(); break;
9793 case 'float' : da[c.name] = 0.0; break;
9794 case 'boolean' : da[c.name] = false; break;
9795 default : da[c.name] = ""; break;
9799 return new this.recordType(Roo.apply(da, d));
9804 * Ext JS Library 1.1.1
9805 * Copyright(c) 2006-2007, Ext JS, LLC.
9807 * Originally Released Under LGPL - original licence link has changed is not relivant.
9810 * <script type="text/javascript">
9814 * @class Roo.data.DataProxy
9815 * @extends Roo.data.Observable
9816 * This class is an abstract base class for implementations which provide retrieval of
9817 * unformatted data objects.<br>
9819 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9820 * (of the appropriate type which knows how to parse the data object) to provide a block of
9821 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9823 * Custom implementations must implement the load method as described in
9824 * {@link Roo.data.HttpProxy#load}.
9826 Roo.data.DataProxy = function(){
9830 * Fires before a network request is made to retrieve a data object.
9831 * @param {Object} This DataProxy object.
9832 * @param {Object} params The params parameter to the load function.
9837 * Fires before the load method's callback is called.
9838 * @param {Object} This DataProxy object.
9839 * @param {Object} o The data object.
9840 * @param {Object} arg The callback argument object passed to the load function.
9844 * @event loadexception
9845 * Fires if an Exception occurs during data retrieval.
9846 * @param {Object} This DataProxy object.
9847 * @param {Object} o The data object.
9848 * @param {Object} arg The callback argument object passed to the load function.
9849 * @param {Object} e The Exception.
9851 loadexception : true
9853 Roo.data.DataProxy.superclass.constructor.call(this);
9856 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9859 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9863 * Ext JS Library 1.1.1
9864 * Copyright(c) 2006-2007, Ext JS, LLC.
9866 * Originally Released Under LGPL - original licence link has changed is not relivant.
9869 * <script type="text/javascript">
9872 * @class Roo.data.MemoryProxy
9873 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9874 * to the Reader when its load method is called.
9876 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9878 Roo.data.MemoryProxy = function(data){
9882 Roo.data.MemoryProxy.superclass.constructor.call(this);
9886 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9888 * Load data from the requested source (in this case an in-memory
9889 * data object passed to the constructor), read the data object into
9890 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9891 * process that block using the passed callback.
9892 * @param {Object} params This parameter is not used by the MemoryProxy class.
9893 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9894 * object into a block of Roo.data.Records.
9895 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9896 * The function must be passed <ul>
9897 * <li>The Record block object</li>
9898 * <li>The "arg" argument from the load function</li>
9899 * <li>A boolean success indicator</li>
9901 * @param {Object} scope The scope in which to call the callback
9902 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9904 load : function(params, reader, callback, scope, arg){
9905 params = params || {};
9908 result = reader.readRecords(this.data);
9910 this.fireEvent("loadexception", this, arg, null, e);
9911 callback.call(scope, null, arg, false);
9914 callback.call(scope, result, arg, true);
9918 update : function(params, records){
9923 * Ext JS Library 1.1.1
9924 * Copyright(c) 2006-2007, Ext JS, LLC.
9926 * Originally Released Under LGPL - original licence link has changed is not relivant.
9929 * <script type="text/javascript">
9932 * @class Roo.data.HttpProxy
9933 * @extends Roo.data.DataProxy
9934 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9935 * configured to reference a certain URL.<br><br>
9937 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9938 * from which the running page was served.<br><br>
9940 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9942 * Be aware that to enable the browser to parse an XML document, the server must set
9943 * the Content-Type header in the HTTP response to "text/xml".
9945 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9946 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9947 * will be used to make the request.
9949 Roo.data.HttpProxy = function(conn){
9950 Roo.data.HttpProxy.superclass.constructor.call(this);
9951 // is conn a conn config or a real conn?
9953 this.useAjax = !conn || !conn.events;
9957 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9958 // thse are take from connection...
9961 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9964 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9965 * extra parameters to each request made by this object. (defaults to undefined)
9968 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9969 * to each request made by this object. (defaults to undefined)
9972 * @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)
9975 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9978 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9984 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9988 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9989 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9990 * a finer-grained basis than the DataProxy events.
9992 getConnection : function(){
9993 return this.useAjax ? Roo.Ajax : this.conn;
9997 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9998 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9999 * process that block using the passed callback.
10000 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10001 * for the request to the remote server.
10002 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10003 * object into a block of Roo.data.Records.
10004 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10005 * The function must be passed <ul>
10006 * <li>The Record block object</li>
10007 * <li>The "arg" argument from the load function</li>
10008 * <li>A boolean success indicator</li>
10010 * @param {Object} scope The scope in which to call the callback
10011 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10013 load : function(params, reader, callback, scope, arg){
10014 if(this.fireEvent("beforeload", this, params) !== false){
10016 params : params || {},
10018 callback : callback,
10023 callback : this.loadResponse,
10027 Roo.applyIf(o, this.conn);
10028 if(this.activeRequest){
10029 Roo.Ajax.abort(this.activeRequest);
10031 this.activeRequest = Roo.Ajax.request(o);
10033 this.conn.request(o);
10036 callback.call(scope||this, null, arg, false);
10041 loadResponse : function(o, success, response){
10042 delete this.activeRequest;
10044 this.fireEvent("loadexception", this, o, response);
10045 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10050 result = o.reader.read(response);
10052 this.fireEvent("loadexception", this, o, response, e);
10053 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10057 this.fireEvent("load", this, o, o.request.arg);
10058 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10062 update : function(dataSet){
10067 updateResponse : function(dataSet){
10072 * Ext JS Library 1.1.1
10073 * Copyright(c) 2006-2007, Ext JS, LLC.
10075 * Originally Released Under LGPL - original licence link has changed is not relivant.
10078 * <script type="text/javascript">
10082 * @class Roo.data.ScriptTagProxy
10083 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10084 * other than the originating domain of the running page.<br><br>
10086 * <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
10087 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10089 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10090 * source code that is used as the source inside a <script> tag.<br><br>
10092 * In order for the browser to process the returned data, the server must wrap the data object
10093 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10094 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10095 * depending on whether the callback name was passed:
10098 boolean scriptTag = false;
10099 String cb = request.getParameter("callback");
10102 response.setContentType("text/javascript");
10104 response.setContentType("application/x-json");
10106 Writer out = response.getWriter();
10108 out.write(cb + "(");
10110 out.print(dataBlock.toJsonString());
10117 * @param {Object} config A configuration object.
10119 Roo.data.ScriptTagProxy = function(config){
10120 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10121 Roo.apply(this, config);
10122 this.head = document.getElementsByTagName("head")[0];
10125 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10127 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10129 * @cfg {String} url The URL from which to request the data object.
10132 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10136 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10137 * the server the name of the callback function set up by the load call to process the returned data object.
10138 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10139 * javascript output which calls this named function passing the data object as its only parameter.
10141 callbackParam : "callback",
10143 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10144 * name to the request.
10149 * Load data from the configured URL, read the data object into
10150 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10151 * process that block using the passed callback.
10152 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10153 * for the request to the remote server.
10154 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10155 * object into a block of Roo.data.Records.
10156 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10157 * The function must be passed <ul>
10158 * <li>The Record block object</li>
10159 * <li>The "arg" argument from the load function</li>
10160 * <li>A boolean success indicator</li>
10162 * @param {Object} scope The scope in which to call the callback
10163 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10165 load : function(params, reader, callback, scope, arg){
10166 if(this.fireEvent("beforeload", this, params) !== false){
10168 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10170 var url = this.url;
10171 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10173 url += "&_dc=" + (new Date().getTime());
10175 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10178 cb : "stcCallback"+transId,
10179 scriptId : "stcScript"+transId,
10183 callback : callback,
10189 window[trans.cb] = function(o){
10190 conn.handleResponse(o, trans);
10193 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10195 if(this.autoAbort !== false){
10199 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10201 var script = document.createElement("script");
10202 script.setAttribute("src", url);
10203 script.setAttribute("type", "text/javascript");
10204 script.setAttribute("id", trans.scriptId);
10205 this.head.appendChild(script);
10207 this.trans = trans;
10209 callback.call(scope||this, null, arg, false);
10214 isLoading : function(){
10215 return this.trans ? true : false;
10219 * Abort the current server request.
10221 abort : function(){
10222 if(this.isLoading()){
10223 this.destroyTrans(this.trans);
10228 destroyTrans : function(trans, isLoaded){
10229 this.head.removeChild(document.getElementById(trans.scriptId));
10230 clearTimeout(trans.timeoutId);
10232 window[trans.cb] = undefined;
10234 delete window[trans.cb];
10237 // if hasn't been loaded, wait for load to remove it to prevent script error
10238 window[trans.cb] = function(){
10239 window[trans.cb] = undefined;
10241 delete window[trans.cb];
10248 handleResponse : function(o, trans){
10249 this.trans = false;
10250 this.destroyTrans(trans, true);
10253 result = trans.reader.readRecords(o);
10255 this.fireEvent("loadexception", this, o, trans.arg, e);
10256 trans.callback.call(trans.scope||window, null, trans.arg, false);
10259 this.fireEvent("load", this, o, trans.arg);
10260 trans.callback.call(trans.scope||window, result, trans.arg, true);
10264 handleFailure : function(trans){
10265 this.trans = false;
10266 this.destroyTrans(trans, false);
10267 this.fireEvent("loadexception", this, null, trans.arg);
10268 trans.callback.call(trans.scope||window, null, trans.arg, false);
10272 * Ext JS Library 1.1.1
10273 * Copyright(c) 2006-2007, Ext JS, LLC.
10275 * Originally Released Under LGPL - original licence link has changed is not relivant.
10278 * <script type="text/javascript">
10282 * @class Roo.data.JsonReader
10283 * @extends Roo.data.DataReader
10284 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10285 * based on mappings in a provided Roo.data.Record constructor.
10287 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10288 * in the reply previously.
10293 var RecordDef = Roo.data.Record.create([
10294 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10295 {name: 'occupation'} // This field will use "occupation" as the mapping.
10297 var myReader = new Roo.data.JsonReader({
10298 totalProperty: "results", // The property which contains the total dataset size (optional)
10299 root: "rows", // The property which contains an Array of row objects
10300 id: "id" // The property within each row object that provides an ID for the record (optional)
10304 * This would consume a JSON file like this:
10306 { 'results': 2, 'rows': [
10307 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10308 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10311 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10312 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10313 * paged from the remote server.
10314 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10315 * @cfg {String} root name of the property which contains the Array of row objects.
10316 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10318 * Create a new JsonReader
10319 * @param {Object} meta Metadata configuration options
10320 * @param {Object} recordType Either an Array of field definition objects,
10321 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10323 Roo.data.JsonReader = function(meta, recordType){
10326 // set some defaults:
10327 Roo.applyIf(meta, {
10328 totalProperty: 'total',
10329 successProperty : 'success',
10334 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10336 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10339 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10340 * Used by Store query builder to append _requestMeta to params.
10343 metaFromRemote : false,
10345 * This method is only used by a DataProxy which has retrieved data from a remote server.
10346 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10347 * @return {Object} data A data block which is used by an Roo.data.Store object as
10348 * a cache of Roo.data.Records.
10350 read : function(response){
10351 var json = response.responseText;
10353 var o = /* eval:var:o */ eval("("+json+")");
10355 throw {message: "JsonReader.read: Json object not found"};
10361 this.metaFromRemote = true;
10362 this.meta = o.metaData;
10363 this.recordType = Roo.data.Record.create(o.metaData.fields);
10364 this.onMetaChange(this.meta, this.recordType, o);
10366 return this.readRecords(o);
10369 // private function a store will implement
10370 onMetaChange : function(meta, recordType, o){
10377 simpleAccess: function(obj, subsc) {
10384 getJsonAccessor: function(){
10386 return function(expr) {
10388 return(re.test(expr))
10389 ? new Function("obj", "return obj." + expr)
10394 return Roo.emptyFn;
10399 * Create a data block containing Roo.data.Records from an XML document.
10400 * @param {Object} o An object which contains an Array of row objects in the property specified
10401 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10402 * which contains the total size of the dataset.
10403 * @return {Object} data A data block which is used by an Roo.data.Store object as
10404 * a cache of Roo.data.Records.
10406 readRecords : function(o){
10408 * After any data loads, the raw JSON data is available for further custom processing.
10412 var s = this.meta, Record = this.recordType,
10413 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10415 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10417 if(s.totalProperty) {
10418 this.getTotal = this.getJsonAccessor(s.totalProperty);
10420 if(s.successProperty) {
10421 this.getSuccess = this.getJsonAccessor(s.successProperty);
10423 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10425 var g = this.getJsonAccessor(s.id);
10426 this.getId = function(rec) {
10428 return (r === undefined || r === "") ? null : r;
10431 this.getId = function(){return null;};
10434 for(var jj = 0; jj < fl; jj++){
10436 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10437 this.ef[jj] = this.getJsonAccessor(map);
10441 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10442 if(s.totalProperty){
10443 var vt = parseInt(this.getTotal(o), 10);
10448 if(s.successProperty){
10449 var vs = this.getSuccess(o);
10450 if(vs === false || vs === 'false'){
10455 for(var i = 0; i < c; i++){
10458 var id = this.getId(n);
10459 for(var j = 0; j < fl; j++){
10461 var v = this.ef[j](n);
10463 Roo.log('missing convert for ' + f.name);
10467 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10469 var record = new Record(values, id);
10471 records[i] = record;
10477 totalRecords : totalRecords
10482 * Ext JS Library 1.1.1
10483 * Copyright(c) 2006-2007, Ext JS, LLC.
10485 * Originally Released Under LGPL - original licence link has changed is not relivant.
10488 * <script type="text/javascript">
10492 * @class Roo.data.ArrayReader
10493 * @extends Roo.data.DataReader
10494 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10495 * Each element of that Array represents a row of data fields. The
10496 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10497 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10501 var RecordDef = Roo.data.Record.create([
10502 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10503 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10505 var myReader = new Roo.data.ArrayReader({
10506 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10510 * This would consume an Array like this:
10512 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10514 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10516 * Create a new JsonReader
10517 * @param {Object} meta Metadata configuration options.
10518 * @param {Object} recordType Either an Array of field definition objects
10519 * as specified to {@link Roo.data.Record#create},
10520 * or an {@link Roo.data.Record} object
10521 * created using {@link Roo.data.Record#create}.
10523 Roo.data.ArrayReader = function(meta, recordType){
10524 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10527 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10529 * Create a data block containing Roo.data.Records from an XML document.
10530 * @param {Object} o An Array of row objects which represents the dataset.
10531 * @return {Object} data A data block which is used by an Roo.data.Store object as
10532 * a cache of Roo.data.Records.
10534 readRecords : function(o){
10535 var sid = this.meta ? this.meta.id : null;
10536 var recordType = this.recordType, fields = recordType.prototype.fields;
10539 for(var i = 0; i < root.length; i++){
10542 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10543 for(var j = 0, jlen = fields.length; j < jlen; j++){
10544 var f = fields.items[j];
10545 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10546 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10548 values[f.name] = v;
10550 var record = new recordType(values, id);
10552 records[records.length] = record;
10556 totalRecords : records.length
10565 * @class Roo.bootstrap.ComboBox
10566 * @extends Roo.bootstrap.TriggerField
10567 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10568 * @cfg {Boolean} append (true|false) default false
10569 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10570 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10571 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10572 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10573 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10575 * Create a new ComboBox.
10576 * @param {Object} config Configuration options
10578 Roo.bootstrap.ComboBox = function(config){
10579 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10583 * Fires when the dropdown list is expanded
10584 * @param {Roo.bootstrap.ComboBox} combo This combo box
10589 * Fires when the dropdown list is collapsed
10590 * @param {Roo.bootstrap.ComboBox} combo This combo box
10594 * @event beforeselect
10595 * Fires before a list item is selected. Return false to cancel the selection.
10596 * @param {Roo.bootstrap.ComboBox} combo This combo box
10597 * @param {Roo.data.Record} record The data record returned from the underlying store
10598 * @param {Number} index The index of the selected item in the dropdown list
10600 'beforeselect' : true,
10603 * Fires when a list item is selected
10604 * @param {Roo.bootstrap.ComboBox} combo This combo box
10605 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10606 * @param {Number} index The index of the selected item in the dropdown list
10610 * @event beforequery
10611 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10612 * The event object passed has these properties:
10613 * @param {Roo.bootstrap.ComboBox} combo This combo box
10614 * @param {String} query The query
10615 * @param {Boolean} forceAll true to force "all" query
10616 * @param {Boolean} cancel true to cancel the query
10617 * @param {Object} e The query event object
10619 'beforequery': true,
10622 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10623 * @param {Roo.bootstrap.ComboBox} combo This combo box
10628 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10629 * @param {Roo.bootstrap.ComboBox} combo This combo box
10630 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10635 * Fires when the remove value from the combobox array
10636 * @param {Roo.bootstrap.ComboBox} combo This combo box
10643 this.tickItems = [];
10645 this.selectedIndex = -1;
10646 if(this.mode == 'local'){
10647 if(config.queryDelay === undefined){
10648 this.queryDelay = 10;
10650 if(config.minChars === undefined){
10656 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10659 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10660 * rendering into an Roo.Editor, defaults to false)
10663 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10664 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10667 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10670 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10671 * the dropdown list (defaults to undefined, with no header element)
10675 * @cfg {String/Roo.Template} tpl The template to use to render the output
10679 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10681 listWidth: undefined,
10683 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10684 * mode = 'remote' or 'text' if mode = 'local')
10686 displayField: undefined,
10688 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10689 * mode = 'remote' or 'value' if mode = 'local').
10690 * Note: use of a valueField requires the user make a selection
10691 * in order for a value to be mapped.
10693 valueField: undefined,
10697 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10698 * field's data value (defaults to the underlying DOM element's name)
10700 hiddenName: undefined,
10702 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10706 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10708 selectedClass: 'active',
10711 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10715 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10716 * anchor positions (defaults to 'tl-bl')
10718 listAlign: 'tl-bl?',
10720 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10724 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10725 * query specified by the allQuery config option (defaults to 'query')
10727 triggerAction: 'query',
10729 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10730 * (defaults to 4, does not apply if editable = false)
10734 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10735 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10739 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10740 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10744 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10745 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10749 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10750 * when editable = true (defaults to false)
10752 selectOnFocus:false,
10754 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10756 queryParam: 'query',
10758 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10759 * when mode = 'remote' (defaults to 'Loading...')
10761 loadingText: 'Loading...',
10763 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10767 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10771 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10772 * traditional select (defaults to true)
10776 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10780 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10784 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10785 * listWidth has a higher value)
10789 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10790 * allow the user to set arbitrary text into the field (defaults to false)
10792 forceSelection:false,
10794 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10795 * if typeAhead = true (defaults to 250)
10797 typeAheadDelay : 250,
10799 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10800 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10802 valueNotFoundText : undefined,
10804 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10806 blockFocus : false,
10809 * @cfg {Boolean} disableClear Disable showing of clear button.
10811 disableClear : false,
10813 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10815 alwaysQuery : false,
10818 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10823 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10825 invalidClass : "has-warning",
10828 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10830 validClass : "has-success",
10842 btnPosition : 'right',
10843 triggerList : true,
10844 showToggleBtn : true,
10845 // element that contains real text value.. (when hidden is used..)
10847 getAutoCreate : function()
10854 if(!this.tickable){
10855 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10860 * ComboBox with tickable selections
10863 var align = this.labelAlign || this.parentLabelAlign();
10866 cls : 'form-group roo-combobox-tickable' //input-group
10872 cls : 'tickable-buttons',
10877 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10884 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10891 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10898 Roo.each(buttons.cn, function(c){
10900 c.cls += ' btn-' + _this.size;
10903 if (_this.disabled) {
10914 cls: 'form-hidden-field'
10918 cls: 'select2-choices',
10922 cls: 'select2-search-field',
10934 cls: 'select2-container input-group select2-container-multi',
10939 // cls: 'typeahead typeahead-long dropdown-menu',
10940 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10945 if(this.hasFeedback && !this.allowBlank){
10949 cls: 'glyphicon form-control-feedback'
10952 combobox.cn.push(feedback);
10955 if (align ==='left' && this.fieldLabel.length) {
10957 Roo.log("left and has label");
10963 cls : 'control-label col-sm-' + this.labelWidth,
10964 html : this.fieldLabel
10968 cls : "col-sm-" + (12 - this.labelWidth),
10975 } else if ( this.fieldLabel.length) {
10981 //cls : 'input-group-addon',
10982 html : this.fieldLabel
10992 Roo.log(" no label && no align");
10999 ['xs','sm','md','lg'].map(function(size){
11000 if (settings[size]) {
11001 cfg.cls += ' col-' + size + '-' + settings[size];
11010 initEvents: function()
11014 throw "can not find store for combo";
11016 this.store = Roo.factory(this.store, Roo.data);
11019 this.initTickableEvents();
11023 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11025 if(this.hiddenName){
11027 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11029 this.hiddenField.dom.value =
11030 this.hiddenValue !== undefined ? this.hiddenValue :
11031 this.value !== undefined ? this.value : '';
11033 // prevent input submission
11034 this.el.dom.removeAttribute('name');
11035 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11040 // this.el.dom.setAttribute('autocomplete', 'off');
11043 var cls = 'x-combo-list';
11045 //this.list = new Roo.Layer({
11046 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11052 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11053 _this.list.setWidth(lw);
11056 this.list.on('mouseover', this.onViewOver, this);
11057 this.list.on('mousemove', this.onViewMove, this);
11059 this.list.on('scroll', this.onViewScroll, this);
11062 this.list.swallowEvent('mousewheel');
11063 this.assetHeight = 0;
11066 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11067 this.assetHeight += this.header.getHeight();
11070 this.innerList = this.list.createChild({cls:cls+'-inner'});
11071 this.innerList.on('mouseover', this.onViewOver, this);
11072 this.innerList.on('mousemove', this.onViewMove, this);
11073 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11075 if(this.allowBlank && !this.pageSize && !this.disableClear){
11076 this.footer = this.list.createChild({cls:cls+'-ft'});
11077 this.pageTb = new Roo.Toolbar(this.footer);
11081 this.footer = this.list.createChild({cls:cls+'-ft'});
11082 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11083 {pageSize: this.pageSize});
11087 if (this.pageTb && this.allowBlank && !this.disableClear) {
11089 this.pageTb.add(new Roo.Toolbar.Fill(), {
11090 cls: 'x-btn-icon x-btn-clear',
11092 handler: function()
11095 _this.clearValue();
11096 _this.onSelect(false, -1);
11101 this.assetHeight += this.footer.getHeight();
11106 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11109 this.view = new Roo.View(this.list, this.tpl, {
11110 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11112 //this.view.wrapEl.setDisplayed(false);
11113 this.view.on('click', this.onViewClick, this);
11117 this.store.on('beforeload', this.onBeforeLoad, this);
11118 this.store.on('load', this.onLoad, this);
11119 this.store.on('loadexception', this.onLoadException, this);
11121 if(this.resizable){
11122 this.resizer = new Roo.Resizable(this.list, {
11123 pinned:true, handles:'se'
11125 this.resizer.on('resize', function(r, w, h){
11126 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11127 this.listWidth = w;
11128 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11129 this.restrictHeight();
11131 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11134 if(!this.editable){
11135 this.editable = true;
11136 this.setEditable(false);
11141 if (typeof(this.events.add.listeners) != 'undefined') {
11143 this.addicon = this.wrap.createChild(
11144 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11146 this.addicon.on('click', function(e) {
11147 this.fireEvent('add', this);
11150 if (typeof(this.events.edit.listeners) != 'undefined') {
11152 this.editicon = this.wrap.createChild(
11153 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11154 if (this.addicon) {
11155 this.editicon.setStyle('margin-left', '40px');
11157 this.editicon.on('click', function(e) {
11159 // we fire even if inothing is selected..
11160 this.fireEvent('edit', this, this.lastData );
11166 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11167 "up" : function(e){
11168 this.inKeyMode = true;
11172 "down" : function(e){
11173 if(!this.isExpanded()){
11174 this.onTriggerClick();
11176 this.inKeyMode = true;
11181 "enter" : function(e){
11182 // this.onViewClick();
11186 if(this.fireEvent("specialkey", this, e)){
11187 this.onViewClick(false);
11193 "esc" : function(e){
11197 "tab" : function(e){
11200 if(this.fireEvent("specialkey", this, e)){
11201 this.onViewClick(false);
11209 doRelay : function(foo, bar, hname){
11210 if(hname == 'down' || this.scope.isExpanded()){
11211 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11220 this.queryDelay = Math.max(this.queryDelay || 10,
11221 this.mode == 'local' ? 10 : 250);
11224 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11226 if(this.typeAhead){
11227 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11229 if(this.editable !== false){
11230 this.inputEl().on("keyup", this.onKeyUp, this);
11232 if(this.forceSelection){
11233 this.inputEl().on('blur', this.doForce, this);
11237 this.choices = this.el.select('ul.select2-choices', true).first();
11238 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11242 initTickableEvents: function()
11246 if(this.hiddenName){
11248 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11250 this.hiddenField.dom.value =
11251 this.hiddenValue !== undefined ? this.hiddenValue :
11252 this.value !== undefined ? this.value : '';
11254 // prevent input submission
11255 this.el.dom.removeAttribute('name');
11256 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11261 // this.list = this.el.select('ul.dropdown-menu',true).first();
11263 this.choices = this.el.select('ul.select2-choices', true).first();
11264 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11265 if(this.triggerList){
11266 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11269 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11270 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11272 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11273 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11275 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11276 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11278 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11279 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11280 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11283 this.cancelBtn.hide();
11288 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11289 _this.list.setWidth(lw);
11292 this.list.on('mouseover', this.onViewOver, this);
11293 this.list.on('mousemove', this.onViewMove, this);
11295 this.list.on('scroll', this.onViewScroll, this);
11298 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>';
11301 this.view = new Roo.View(this.list, this.tpl, {
11302 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11305 //this.view.wrapEl.setDisplayed(false);
11306 this.view.on('click', this.onViewClick, this);
11310 this.store.on('beforeload', this.onBeforeLoad, this);
11311 this.store.on('load', this.onLoad, this);
11312 this.store.on('loadexception', this.onLoadException, this);
11314 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11315 // "up" : function(e){
11316 // this.inKeyMode = true;
11317 // this.selectPrev();
11320 // "down" : function(e){
11321 // if(!this.isExpanded()){
11322 // this.onTriggerClick();
11324 // this.inKeyMode = true;
11325 // this.selectNext();
11329 // "enter" : function(e){
11330 //// this.onViewClick();
11332 // this.collapse();
11334 // if(this.fireEvent("specialkey", this, e)){
11335 // this.onViewClick(false);
11341 // "esc" : function(e){
11342 // this.collapse();
11345 // "tab" : function(e){
11346 // this.collapse();
11348 // if(this.fireEvent("specialkey", this, e)){
11349 // this.onViewClick(false);
11357 // doRelay : function(foo, bar, hname){
11358 // if(hname == 'down' || this.scope.isExpanded()){
11359 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11364 // forceKeyDown: true
11368 this.queryDelay = Math.max(this.queryDelay || 10,
11369 this.mode == 'local' ? 10 : 250);
11372 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11374 if(this.typeAhead){
11375 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11380 onDestroy : function(){
11382 this.view.setStore(null);
11383 this.view.el.removeAllListeners();
11384 this.view.el.remove();
11385 this.view.purgeListeners();
11388 this.list.dom.innerHTML = '';
11392 this.store.un('beforeload', this.onBeforeLoad, this);
11393 this.store.un('load', this.onLoad, this);
11394 this.store.un('loadexception', this.onLoadException, this);
11396 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11400 fireKey : function(e){
11401 if(e.isNavKeyPress() && !this.list.isVisible()){
11402 this.fireEvent("specialkey", this, e);
11407 onResize: function(w, h){
11408 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11410 // if(typeof w != 'number'){
11411 // // we do not handle it!?!?
11414 // var tw = this.trigger.getWidth();
11415 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11416 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11418 // this.inputEl().setWidth( this.adjustWidth('input', x));
11420 // //this.trigger.setStyle('left', x+'px');
11422 // if(this.list && this.listWidth === undefined){
11423 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11424 // this.list.setWidth(lw);
11425 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11433 * Allow or prevent the user from directly editing the field text. If false is passed,
11434 * the user will only be able to select from the items defined in the dropdown list. This method
11435 * is the runtime equivalent of setting the 'editable' config option at config time.
11436 * @param {Boolean} value True to allow the user to directly edit the field text
11438 setEditable : function(value){
11439 if(value == this.editable){
11442 this.editable = value;
11444 this.inputEl().dom.setAttribute('readOnly', true);
11445 this.inputEl().on('mousedown', this.onTriggerClick, this);
11446 this.inputEl().addClass('x-combo-noedit');
11448 this.inputEl().dom.setAttribute('readOnly', false);
11449 this.inputEl().un('mousedown', this.onTriggerClick, this);
11450 this.inputEl().removeClass('x-combo-noedit');
11456 onBeforeLoad : function(combo,opts){
11457 if(!this.hasFocus){
11461 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11463 this.restrictHeight();
11464 this.selectedIndex = -1;
11468 onLoad : function(){
11470 this.hasQuery = false;
11472 if(!this.hasFocus){
11476 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11477 this.loading.hide();
11480 if(this.store.getCount() > 0){
11482 // this.restrictHeight();
11483 if(this.lastQuery == this.allQuery){
11484 if(this.editable && !this.tickable){
11485 this.inputEl().dom.select();
11489 !this.selectByValue(this.value, true) &&
11490 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11491 this.store.lastOptions.add != true)
11493 this.select(0, true);
11496 if(this.autoFocus){
11499 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11500 this.taTask.delay(this.typeAheadDelay);
11504 this.onEmptyResults();
11510 onLoadException : function()
11512 this.hasQuery = false;
11514 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11515 this.loading.hide();
11519 Roo.log(this.store.reader.jsonData);
11520 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11522 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11528 onTypeAhead : function(){
11529 if(this.store.getCount() > 0){
11530 var r = this.store.getAt(0);
11531 var newValue = r.data[this.displayField];
11532 var len = newValue.length;
11533 var selStart = this.getRawValue().length;
11535 if(selStart != len){
11536 this.setRawValue(newValue);
11537 this.selectText(selStart, newValue.length);
11543 onSelect : function(record, index){
11545 if(this.fireEvent('beforeselect', this, record, index) !== false){
11547 this.setFromData(index > -1 ? record.data : false);
11550 this.fireEvent('select', this, record, index);
11555 * Returns the currently selected field value or empty string if no value is set.
11556 * @return {String} value The selected value
11558 getValue : function(){
11561 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11564 if(this.valueField){
11565 return typeof this.value != 'undefined' ? this.value : '';
11567 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11572 * Clears any text/value currently set in the field
11574 clearValue : function(){
11575 if(this.hiddenField){
11576 this.hiddenField.dom.value = '';
11579 this.setRawValue('');
11580 this.lastSelectionText = '';
11581 this.lastData = false;
11586 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11587 * will be displayed in the field. If the value does not match the data value of an existing item,
11588 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11589 * Otherwise the field will be blank (although the value will still be set).
11590 * @param {String} value The value to match
11592 setValue : function(v){
11599 if(this.valueField){
11600 var r = this.findRecord(this.valueField, v);
11602 text = r.data[this.displayField];
11603 }else if(this.valueNotFoundText !== undefined){
11604 text = this.valueNotFoundText;
11607 this.lastSelectionText = text;
11608 if(this.hiddenField){
11609 this.hiddenField.dom.value = v;
11611 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11615 * @property {Object} the last set data for the element
11620 * Sets the value of the field based on a object which is related to the record format for the store.
11621 * @param {Object} value the value to set as. or false on reset?
11623 setFromData : function(o){
11630 var dv = ''; // display value
11631 var vv = ''; // value value..
11633 if (this.displayField) {
11634 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11636 // this is an error condition!!!
11637 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11640 if(this.valueField){
11641 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11644 if(this.hiddenField){
11645 this.hiddenField.dom.value = vv;
11647 this.lastSelectionText = dv;
11648 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11652 // no hidden field.. - we store the value in 'value', but still display
11653 // display field!!!!
11654 this.lastSelectionText = dv;
11655 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11661 reset : function(){
11662 // overridden so that last data is reset..
11663 this.setValue(this.originalValue);
11664 this.clearInvalid();
11665 this.lastData = false;
11667 this.view.clearSelections();
11671 findRecord : function(prop, value){
11673 if(this.store.getCount() > 0){
11674 this.store.each(function(r){
11675 if(r.data[prop] == value){
11685 getName: function()
11687 // returns hidden if it's set..
11688 if (!this.rendered) {return ''};
11689 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11693 onViewMove : function(e, t){
11694 this.inKeyMode = false;
11698 onViewOver : function(e, t){
11699 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11702 var item = this.view.findItemFromChild(t);
11705 var index = this.view.indexOf(item);
11706 this.select(index, false);
11711 onViewClick : function(view, doFocus, el, e)
11713 var index = this.view.getSelectedIndexes()[0];
11715 var r = this.store.getAt(index);
11719 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11726 Roo.each(this.tickItems, function(v,k){
11728 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11729 _this.tickItems.splice(k, 1);
11739 this.tickItems.push(r.data);
11744 this.onSelect(r, index);
11746 if(doFocus !== false && !this.blockFocus){
11747 this.inputEl().focus();
11752 restrictHeight : function(){
11753 //this.innerList.dom.style.height = '';
11754 //var inner = this.innerList.dom;
11755 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11756 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11757 //this.list.beginUpdate();
11758 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11759 this.list.alignTo(this.inputEl(), this.listAlign);
11760 this.list.alignTo(this.inputEl(), this.listAlign);
11761 //this.list.endUpdate();
11765 onEmptyResults : function(){
11770 * Returns true if the dropdown list is expanded, else false.
11772 isExpanded : function(){
11773 return this.list.isVisible();
11777 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11778 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11779 * @param {String} value The data value of the item to select
11780 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11781 * selected item if it is not currently in view (defaults to true)
11782 * @return {Boolean} True if the value matched an item in the list, else false
11784 selectByValue : function(v, scrollIntoView){
11785 if(v !== undefined && v !== null){
11786 var r = this.findRecord(this.valueField || this.displayField, v);
11788 this.select(this.store.indexOf(r), scrollIntoView);
11796 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11797 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11798 * @param {Number} index The zero-based index of the list item to select
11799 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11800 * selected item if it is not currently in view (defaults to true)
11802 select : function(index, scrollIntoView){
11803 this.selectedIndex = index;
11804 this.view.select(index);
11805 if(scrollIntoView !== false){
11806 var el = this.view.getNode(index);
11807 if(el && !this.multiple && !this.tickable){
11808 this.list.scrollChildIntoView(el, false);
11814 selectNext : function(){
11815 var ct = this.store.getCount();
11817 if(this.selectedIndex == -1){
11819 }else if(this.selectedIndex < ct-1){
11820 this.select(this.selectedIndex+1);
11826 selectPrev : function(){
11827 var ct = this.store.getCount();
11829 if(this.selectedIndex == -1){
11831 }else if(this.selectedIndex != 0){
11832 this.select(this.selectedIndex-1);
11838 onKeyUp : function(e){
11839 if(this.editable !== false && !e.isSpecialKey()){
11840 this.lastKey = e.getKey();
11841 this.dqTask.delay(this.queryDelay);
11846 validateBlur : function(){
11847 return !this.list || !this.list.isVisible();
11851 initQuery : function(){
11852 this.doQuery(this.getRawValue());
11856 doForce : function(){
11857 if(this.inputEl().dom.value.length > 0){
11858 this.inputEl().dom.value =
11859 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11865 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11866 * query allowing the query action to be canceled if needed.
11867 * @param {String} query The SQL query to execute
11868 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11869 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11870 * saved in the current store (defaults to false)
11872 doQuery : function(q, forceAll){
11874 if(q === undefined || q === null){
11879 forceAll: forceAll,
11883 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11888 forceAll = qe.forceAll;
11889 if(forceAll === true || (q.length >= this.minChars)){
11891 this.hasQuery = true;
11893 if(this.lastQuery != q || this.alwaysQuery){
11894 this.lastQuery = q;
11895 if(this.mode == 'local'){
11896 this.selectedIndex = -1;
11898 this.store.clearFilter();
11900 this.store.filter(this.displayField, q);
11904 this.store.baseParams[this.queryParam] = q;
11906 var options = {params : this.getParams(q)};
11909 options.add = true;
11910 options.params.start = this.page * this.pageSize;
11913 this.store.load(options);
11915 * this code will make the page width larger, at the beginning, the list not align correctly,
11916 * we should expand the list on onLoad
11917 * so command out it
11922 this.selectedIndex = -1;
11927 this.loadNext = false;
11931 getParams : function(q){
11933 //p[this.queryParam] = q;
11937 p.limit = this.pageSize;
11943 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11945 collapse : function(){
11946 if(!this.isExpanded()){
11953 this.hasFocus = false;
11955 this.cancelBtn.hide();
11956 this.trigger.show();
11959 Roo.get(document).un('mousedown', this.collapseIf, this);
11960 Roo.get(document).un('mousewheel', this.collapseIf, this);
11961 if (!this.editable) {
11962 Roo.get(document).un('keydown', this.listKeyPress, this);
11964 this.fireEvent('collapse', this);
11968 collapseIf : function(e){
11969 var in_combo = e.within(this.el);
11970 var in_list = e.within(this.list);
11971 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11973 if (in_combo || in_list || is_list) {
11974 //e.stopPropagation();
11979 this.onTickableFooterButtonClick(e, false, false);
11987 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11989 expand : function(){
11991 if(this.isExpanded() || !this.hasFocus){
11995 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11996 this.list.setWidth(lw);
12003 this.restrictHeight();
12007 this.tickItems = Roo.apply([], this.item);
12010 this.cancelBtn.show();
12011 this.trigger.hide();
12015 Roo.get(document).on('mousedown', this.collapseIf, this);
12016 Roo.get(document).on('mousewheel', this.collapseIf, this);
12017 if (!this.editable) {
12018 Roo.get(document).on('keydown', this.listKeyPress, this);
12021 this.fireEvent('expand', this);
12025 // Implements the default empty TriggerField.onTriggerClick function
12026 onTriggerClick : function(e)
12028 Roo.log('trigger click');
12030 if(this.disabled || !this.triggerList){
12035 this.loadNext = false;
12037 if(this.isExpanded()){
12039 if (!this.blockFocus) {
12040 this.inputEl().focus();
12044 this.hasFocus = true;
12045 if(this.triggerAction == 'all') {
12046 this.doQuery(this.allQuery, true);
12048 this.doQuery(this.getRawValue());
12050 if (!this.blockFocus) {
12051 this.inputEl().focus();
12056 onTickableTriggerClick : function(e)
12063 this.loadNext = false;
12064 this.hasFocus = true;
12066 if(this.triggerAction == 'all') {
12067 this.doQuery(this.allQuery, true);
12069 this.doQuery(this.getRawValue());
12073 onSearchFieldClick : function(e)
12075 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12076 this.onTickableFooterButtonClick(e, false, false);
12080 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12085 this.loadNext = false;
12086 this.hasFocus = true;
12088 if(this.triggerAction == 'all') {
12089 this.doQuery(this.allQuery, true);
12091 this.doQuery(this.getRawValue());
12095 listKeyPress : function(e)
12097 //Roo.log('listkeypress');
12098 // scroll to first matching element based on key pres..
12099 if (e.isSpecialKey()) {
12102 var k = String.fromCharCode(e.getKey()).toUpperCase();
12105 var csel = this.view.getSelectedNodes();
12106 var cselitem = false;
12108 var ix = this.view.indexOf(csel[0]);
12109 cselitem = this.store.getAt(ix);
12110 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12116 this.store.each(function(v) {
12118 // start at existing selection.
12119 if (cselitem.id == v.id) {
12125 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12126 match = this.store.indexOf(v);
12132 if (match === false) {
12133 return true; // no more action?
12136 this.view.select(match);
12137 var sn = Roo.get(this.view.getSelectedNodes()[0])
12138 sn.scrollIntoView(sn.dom.parentNode, false);
12141 onViewScroll : function(e, t){
12143 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){
12147 this.hasQuery = true;
12149 this.loading = this.list.select('.loading', true).first();
12151 if(this.loading === null){
12152 this.list.createChild({
12154 cls: 'loading select2-more-results select2-active',
12155 html: 'Loading more results...'
12158 this.loading = this.list.select('.loading', true).first();
12160 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12162 this.loading.hide();
12165 this.loading.show();
12170 this.loadNext = true;
12172 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12177 addItem : function(o)
12179 var dv = ''; // display value
12181 if (this.displayField) {
12182 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12184 // this is an error condition!!!
12185 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12192 var choice = this.choices.createChild({
12194 cls: 'select2-search-choice',
12203 cls: 'select2-search-choice-close',
12208 }, this.searchField);
12210 var close = choice.select('a.select2-search-choice-close', true).first()
12212 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12220 this.inputEl().dom.value = '';
12225 onRemoveItem : function(e, _self, o)
12227 e.preventDefault();
12229 this.lastItem = Roo.apply([], this.item);
12231 var index = this.item.indexOf(o.data) * 1;
12234 Roo.log('not this item?!');
12238 this.item.splice(index, 1);
12243 this.fireEvent('remove', this, e);
12249 syncValue : function()
12251 if(!this.item.length){
12258 Roo.each(this.item, function(i){
12259 if(_this.valueField){
12260 value.push(i[_this.valueField]);
12267 this.value = value.join(',');
12269 if(this.hiddenField){
12270 this.hiddenField.dom.value = this.value;
12274 clearItem : function()
12276 if(!this.multiple){
12282 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12291 inputEl: function ()
12294 return this.searchField;
12296 return this.el.select('input.form-control',true).first();
12300 onTickableFooterButtonClick : function(e, btn, el)
12302 e.preventDefault();
12304 this.lastItem = Roo.apply([], this.item);
12306 if(btn && btn.name == 'cancel'){
12307 this.tickItems = Roo.apply([], this.item);
12316 Roo.each(this.tickItems, function(o){
12324 validate : function()
12326 var v = this.getRawValue();
12329 v = this.getValue();
12332 if(this.disabled || this.allowBlank || v.length){
12337 this.markInvalid();
12344 * @cfg {Boolean} grow
12348 * @cfg {Number} growMin
12352 * @cfg {Number} growMax
12362 * Ext JS Library 1.1.1
12363 * Copyright(c) 2006-2007, Ext JS, LLC.
12365 * Originally Released Under LGPL - original licence link has changed is not relivant.
12368 * <script type="text/javascript">
12373 * @extends Roo.util.Observable
12374 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12375 * This class also supports single and multi selection modes. <br>
12376 * Create a data model bound view:
12378 var store = new Roo.data.Store(...);
12380 var view = new Roo.View({
12382 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12384 singleSelect: true,
12385 selectedClass: "ydataview-selected",
12389 // listen for node click?
12390 view.on("click", function(vw, index, node, e){
12391 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12395 dataModel.load("foobar.xml");
12397 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12399 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12400 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12402 * Note: old style constructor is still suported (container, template, config)
12405 * Create a new View
12406 * @param {Object} config The config object
12409 Roo.View = function(config, depreciated_tpl, depreciated_config){
12411 this.parent = false;
12413 if (typeof(depreciated_tpl) == 'undefined') {
12414 // new way.. - universal constructor.
12415 Roo.apply(this, config);
12416 this.el = Roo.get(this.el);
12419 this.el = Roo.get(config);
12420 this.tpl = depreciated_tpl;
12421 Roo.apply(this, depreciated_config);
12423 this.wrapEl = this.el.wrap().wrap();
12424 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12427 if(typeof(this.tpl) == "string"){
12428 this.tpl = new Roo.Template(this.tpl);
12430 // support xtype ctors..
12431 this.tpl = new Roo.factory(this.tpl, Roo);
12435 this.tpl.compile();
12440 * @event beforeclick
12441 * Fires before a click is processed. Returns false to cancel the default action.
12442 * @param {Roo.View} this
12443 * @param {Number} index The index of the target node
12444 * @param {HTMLElement} node The target node
12445 * @param {Roo.EventObject} e The raw event object
12447 "beforeclick" : true,
12450 * Fires when a template node is clicked.
12451 * @param {Roo.View} this
12452 * @param {Number} index The index of the target node
12453 * @param {HTMLElement} node The target node
12454 * @param {Roo.EventObject} e The raw event object
12459 * Fires when a template node is double clicked.
12460 * @param {Roo.View} this
12461 * @param {Number} index The index of the target node
12462 * @param {HTMLElement} node The target node
12463 * @param {Roo.EventObject} e The raw event object
12467 * @event contextmenu
12468 * Fires when a template node is right clicked.
12469 * @param {Roo.View} this
12470 * @param {Number} index The index of the target node
12471 * @param {HTMLElement} node The target node
12472 * @param {Roo.EventObject} e The raw event object
12474 "contextmenu" : true,
12476 * @event selectionchange
12477 * Fires when the selected nodes change.
12478 * @param {Roo.View} this
12479 * @param {Array} selections Array of the selected nodes
12481 "selectionchange" : true,
12484 * @event beforeselect
12485 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12486 * @param {Roo.View} this
12487 * @param {HTMLElement} node The node to be selected
12488 * @param {Array} selections Array of currently selected nodes
12490 "beforeselect" : true,
12492 * @event preparedata
12493 * Fires on every row to render, to allow you to change the data.
12494 * @param {Roo.View} this
12495 * @param {Object} data to be rendered (change this)
12497 "preparedata" : true
12505 "click": this.onClick,
12506 "dblclick": this.onDblClick,
12507 "contextmenu": this.onContextMenu,
12511 this.selections = [];
12513 this.cmp = new Roo.CompositeElementLite([]);
12515 this.store = Roo.factory(this.store, Roo.data);
12516 this.setStore(this.store, true);
12519 if ( this.footer && this.footer.xtype) {
12521 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12523 this.footer.dataSource = this.store
12524 this.footer.container = fctr;
12525 this.footer = Roo.factory(this.footer, Roo);
12526 fctr.insertFirst(this.el);
12528 // this is a bit insane - as the paging toolbar seems to detach the el..
12529 // dom.parentNode.parentNode.parentNode
12530 // they get detached?
12534 Roo.View.superclass.constructor.call(this);
12539 Roo.extend(Roo.View, Roo.util.Observable, {
12542 * @cfg {Roo.data.Store} store Data store to load data from.
12547 * @cfg {String|Roo.Element} el The container element.
12552 * @cfg {String|Roo.Template} tpl The template used by this View
12556 * @cfg {String} dataName the named area of the template to use as the data area
12557 * Works with domtemplates roo-name="name"
12561 * @cfg {String} selectedClass The css class to add to selected nodes
12563 selectedClass : "x-view-selected",
12565 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12570 * @cfg {String} text to display on mask (default Loading)
12574 * @cfg {Boolean} multiSelect Allow multiple selection
12576 multiSelect : false,
12578 * @cfg {Boolean} singleSelect Allow single selection
12580 singleSelect: false,
12583 * @cfg {Boolean} toggleSelect - selecting
12585 toggleSelect : false,
12588 * @cfg {Boolean} tickable - selecting
12593 * Returns the element this view is bound to.
12594 * @return {Roo.Element}
12596 getEl : function(){
12597 return this.wrapEl;
12603 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12605 refresh : function(){
12606 //Roo.log('refresh');
12609 // if we are using something like 'domtemplate', then
12610 // the what gets used is:
12611 // t.applySubtemplate(NAME, data, wrapping data..)
12612 // the outer template then get' applied with
12613 // the store 'extra data'
12614 // and the body get's added to the
12615 // roo-name="data" node?
12616 // <span class='roo-tpl-{name}'></span> ?????
12620 this.clearSelections();
12621 this.el.update("");
12623 var records = this.store.getRange();
12624 if(records.length < 1) {
12626 // is this valid?? = should it render a template??
12628 this.el.update(this.emptyText);
12632 if (this.dataName) {
12633 this.el.update(t.apply(this.store.meta)); //????
12634 el = this.el.child('.roo-tpl-' + this.dataName);
12637 for(var i = 0, len = records.length; i < len; i++){
12638 var data = this.prepareData(records[i].data, i, records[i]);
12639 this.fireEvent("preparedata", this, data, i, records[i]);
12641 var d = Roo.apply({}, data);
12644 Roo.apply(d, {'roo-id' : Roo.id()});
12648 Roo.each(this.parent.item, function(item){
12649 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12652 Roo.apply(d, {'roo-data-checked' : 'checked'});
12656 html[html.length] = Roo.util.Format.trim(
12658 t.applySubtemplate(this.dataName, d, this.store.meta) :
12665 el.update(html.join(""));
12666 this.nodes = el.dom.childNodes;
12667 this.updateIndexes(0);
12672 * Function to override to reformat the data that is sent to
12673 * the template for each node.
12674 * DEPRICATED - use the preparedata event handler.
12675 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12676 * a JSON object for an UpdateManager bound view).
12678 prepareData : function(data, index, record)
12680 this.fireEvent("preparedata", this, data, index, record);
12684 onUpdate : function(ds, record){
12685 // Roo.log('on update');
12686 this.clearSelections();
12687 var index = this.store.indexOf(record);
12688 var n = this.nodes[index];
12689 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12690 n.parentNode.removeChild(n);
12691 this.updateIndexes(index, index);
12697 onAdd : function(ds, records, index)
12699 //Roo.log(['on Add', ds, records, index] );
12700 this.clearSelections();
12701 if(this.nodes.length == 0){
12705 var n = this.nodes[index];
12706 for(var i = 0, len = records.length; i < len; i++){
12707 var d = this.prepareData(records[i].data, i, records[i]);
12709 this.tpl.insertBefore(n, d);
12712 this.tpl.append(this.el, d);
12715 this.updateIndexes(index);
12718 onRemove : function(ds, record, index){
12719 // Roo.log('onRemove');
12720 this.clearSelections();
12721 var el = this.dataName ?
12722 this.el.child('.roo-tpl-' + this.dataName) :
12725 el.dom.removeChild(this.nodes[index]);
12726 this.updateIndexes(index);
12730 * Refresh an individual node.
12731 * @param {Number} index
12733 refreshNode : function(index){
12734 this.onUpdate(this.store, this.store.getAt(index));
12737 updateIndexes : function(startIndex, endIndex){
12738 var ns = this.nodes;
12739 startIndex = startIndex || 0;
12740 endIndex = endIndex || ns.length - 1;
12741 for(var i = startIndex; i <= endIndex; i++){
12742 ns[i].nodeIndex = i;
12747 * Changes the data store this view uses and refresh the view.
12748 * @param {Store} store
12750 setStore : function(store, initial){
12751 if(!initial && this.store){
12752 this.store.un("datachanged", this.refresh);
12753 this.store.un("add", this.onAdd);
12754 this.store.un("remove", this.onRemove);
12755 this.store.un("update", this.onUpdate);
12756 this.store.un("clear", this.refresh);
12757 this.store.un("beforeload", this.onBeforeLoad);
12758 this.store.un("load", this.onLoad);
12759 this.store.un("loadexception", this.onLoad);
12763 store.on("datachanged", this.refresh, this);
12764 store.on("add", this.onAdd, this);
12765 store.on("remove", this.onRemove, this);
12766 store.on("update", this.onUpdate, this);
12767 store.on("clear", this.refresh, this);
12768 store.on("beforeload", this.onBeforeLoad, this);
12769 store.on("load", this.onLoad, this);
12770 store.on("loadexception", this.onLoad, this);
12778 * onbeforeLoad - masks the loading area.
12781 onBeforeLoad : function(store,opts)
12783 //Roo.log('onBeforeLoad');
12785 this.el.update("");
12787 this.el.mask(this.mask ? this.mask : "Loading" );
12789 onLoad : function ()
12796 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12797 * @param {HTMLElement} node
12798 * @return {HTMLElement} The template node
12800 findItemFromChild : function(node){
12801 var el = this.dataName ?
12802 this.el.child('.roo-tpl-' + this.dataName,true) :
12805 if(!node || node.parentNode == el){
12808 var p = node.parentNode;
12809 while(p && p != el){
12810 if(p.parentNode == el){
12819 onClick : function(e){
12820 var item = this.findItemFromChild(e.getTarget());
12822 var index = this.indexOf(item);
12823 if(this.onItemClick(item, index, e) !== false){
12824 this.fireEvent("click", this, index, item, e);
12827 this.clearSelections();
12832 onContextMenu : function(e){
12833 var item = this.findItemFromChild(e.getTarget());
12835 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12840 onDblClick : function(e){
12841 var item = this.findItemFromChild(e.getTarget());
12843 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12847 onItemClick : function(item, index, e)
12849 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12852 if (this.toggleSelect) {
12853 var m = this.isSelected(item) ? 'unselect' : 'select';
12856 _t[m](item, true, false);
12859 if(this.multiSelect || this.singleSelect){
12860 if(this.multiSelect && e.shiftKey && this.lastSelection){
12861 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12863 this.select(item, this.multiSelect && e.ctrlKey);
12864 this.lastSelection = item;
12867 if(!this.tickable){
12868 e.preventDefault();
12876 * Get the number of selected nodes.
12879 getSelectionCount : function(){
12880 return this.selections.length;
12884 * Get the currently selected nodes.
12885 * @return {Array} An array of HTMLElements
12887 getSelectedNodes : function(){
12888 return this.selections;
12892 * Get the indexes of the selected nodes.
12895 getSelectedIndexes : function(){
12896 var indexes = [], s = this.selections;
12897 for(var i = 0, len = s.length; i < len; i++){
12898 indexes.push(s[i].nodeIndex);
12904 * Clear all selections
12905 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12907 clearSelections : function(suppressEvent){
12908 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12909 this.cmp.elements = this.selections;
12910 this.cmp.removeClass(this.selectedClass);
12911 this.selections = [];
12912 if(!suppressEvent){
12913 this.fireEvent("selectionchange", this, this.selections);
12919 * Returns true if the passed node is selected
12920 * @param {HTMLElement/Number} node The node or node index
12921 * @return {Boolean}
12923 isSelected : function(node){
12924 var s = this.selections;
12928 node = this.getNode(node);
12929 return s.indexOf(node) !== -1;
12934 * @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
12935 * @param {Boolean} keepExisting (optional) true to keep existing selections
12936 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12938 select : function(nodeInfo, keepExisting, suppressEvent){
12939 if(nodeInfo instanceof Array){
12941 this.clearSelections(true);
12943 for(var i = 0, len = nodeInfo.length; i < len; i++){
12944 this.select(nodeInfo[i], true, true);
12948 var node = this.getNode(nodeInfo);
12949 if(!node || this.isSelected(node)){
12950 return; // already selected.
12953 this.clearSelections(true);
12956 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12957 Roo.fly(node).addClass(this.selectedClass);
12958 this.selections.push(node);
12959 if(!suppressEvent){
12960 this.fireEvent("selectionchange", this, this.selections);
12968 * @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
12969 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12970 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12972 unselect : function(nodeInfo, keepExisting, suppressEvent)
12974 if(nodeInfo instanceof Array){
12975 Roo.each(this.selections, function(s) {
12976 this.unselect(s, nodeInfo);
12980 var node = this.getNode(nodeInfo);
12981 if(!node || !this.isSelected(node)){
12982 //Roo.log("not selected");
12983 return; // not selected.
12987 Roo.each(this.selections, function(s) {
12989 Roo.fly(node).removeClass(this.selectedClass);
12996 this.selections= ns;
12997 this.fireEvent("selectionchange", this, this.selections);
13001 * Gets a template node.
13002 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13003 * @return {HTMLElement} The node or null if it wasn't found
13005 getNode : function(nodeInfo){
13006 if(typeof nodeInfo == "string"){
13007 return document.getElementById(nodeInfo);
13008 }else if(typeof nodeInfo == "number"){
13009 return this.nodes[nodeInfo];
13015 * Gets a range template nodes.
13016 * @param {Number} startIndex
13017 * @param {Number} endIndex
13018 * @return {Array} An array of nodes
13020 getNodes : function(start, end){
13021 var ns = this.nodes;
13022 start = start || 0;
13023 end = typeof end == "undefined" ? ns.length - 1 : end;
13026 for(var i = start; i <= end; i++){
13030 for(var i = start; i >= end; i--){
13038 * Finds the index of the passed node
13039 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13040 * @return {Number} The index of the node or -1
13042 indexOf : function(node){
13043 node = this.getNode(node);
13044 if(typeof node.nodeIndex == "number"){
13045 return node.nodeIndex;
13047 var ns = this.nodes;
13048 for(var i = 0, len = ns.length; i < len; i++){
13059 * based on jquery fullcalendar
13063 Roo.bootstrap = Roo.bootstrap || {};
13065 * @class Roo.bootstrap.Calendar
13066 * @extends Roo.bootstrap.Component
13067 * Bootstrap Calendar class
13068 * @cfg {Boolean} loadMask (true|false) default false
13069 * @cfg {Object} header generate the user specific header of the calendar, default false
13072 * Create a new Container
13073 * @param {Object} config The config object
13078 Roo.bootstrap.Calendar = function(config){
13079 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13083 * Fires when a date is selected
13084 * @param {DatePicker} this
13085 * @param {Date} date The selected date
13089 * @event monthchange
13090 * Fires when the displayed month changes
13091 * @param {DatePicker} this
13092 * @param {Date} date The selected month
13094 'monthchange': true,
13096 * @event evententer
13097 * Fires when mouse over an event
13098 * @param {Calendar} this
13099 * @param {event} Event
13101 'evententer': true,
13103 * @event eventleave
13104 * Fires when the mouse leaves an
13105 * @param {Calendar} this
13108 'eventleave': true,
13110 * @event eventclick
13111 * Fires when the mouse click an
13112 * @param {Calendar} this
13121 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13124 * @cfg {Number} startDay
13125 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13133 getAutoCreate : function(){
13136 var fc_button = function(name, corner, style, content ) {
13137 return Roo.apply({},{
13139 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13141 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13144 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13155 style : 'width:100%',
13162 cls : 'fc-header-left',
13164 fc_button('prev', 'left', 'arrow', '‹' ),
13165 fc_button('next', 'right', 'arrow', '›' ),
13166 { tag: 'span', cls: 'fc-header-space' },
13167 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13175 cls : 'fc-header-center',
13179 cls: 'fc-header-title',
13182 html : 'month / year'
13190 cls : 'fc-header-right',
13192 /* fc_button('month', 'left', '', 'month' ),
13193 fc_button('week', '', '', 'week' ),
13194 fc_button('day', 'right', '', 'day' )
13206 header = this.header;
13209 var cal_heads = function() {
13211 // fixme - handle this.
13213 for (var i =0; i < Date.dayNames.length; i++) {
13214 var d = Date.dayNames[i];
13217 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13218 html : d.substring(0,3)
13222 ret[0].cls += ' fc-first';
13223 ret[6].cls += ' fc-last';
13226 var cal_cell = function(n) {
13229 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13234 cls: 'fc-day-number',
13238 cls: 'fc-day-content',
13242 style: 'position: relative;' // height: 17px;
13254 var cal_rows = function() {
13257 for (var r = 0; r < 6; r++) {
13264 for (var i =0; i < Date.dayNames.length; i++) {
13265 var d = Date.dayNames[i];
13266 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13269 row.cn[0].cls+=' fc-first';
13270 row.cn[0].cn[0].style = 'min-height:90px';
13271 row.cn[6].cls+=' fc-last';
13275 ret[0].cls += ' fc-first';
13276 ret[4].cls += ' fc-prev-last';
13277 ret[5].cls += ' fc-last';
13284 cls: 'fc-border-separate',
13285 style : 'width:100%',
13293 cls : 'fc-first fc-last',
13311 cls : 'fc-content',
13312 style : "position: relative;",
13315 cls : 'fc-view fc-view-month fc-grid',
13316 style : 'position: relative',
13317 unselectable : 'on',
13320 cls : 'fc-event-container',
13321 style : 'position:absolute;z-index:8;top:0;left:0;'
13339 initEvents : function()
13342 throw "can not find store for calendar";
13348 style: "text-align:center",
13352 style: "background-color:white;width:50%;margin:250 auto",
13356 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13367 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13369 var size = this.el.select('.fc-content', true).first().getSize();
13370 this.maskEl.setSize(size.width, size.height);
13371 this.maskEl.enableDisplayMode("block");
13372 if(!this.loadMask){
13373 this.maskEl.hide();
13376 this.store = Roo.factory(this.store, Roo.data);
13377 this.store.on('load', this.onLoad, this);
13378 this.store.on('beforeload', this.onBeforeLoad, this);
13382 this.cells = this.el.select('.fc-day',true);
13383 //Roo.log(this.cells);
13384 this.textNodes = this.el.query('.fc-day-number');
13385 this.cells.addClassOnOver('fc-state-hover');
13387 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13388 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13389 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13390 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13392 this.on('monthchange', this.onMonthChange, this);
13394 this.update(new Date().clearTime());
13397 resize : function() {
13398 var sz = this.el.getSize();
13400 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13401 this.el.select('.fc-day-content div',true).setHeight(34);
13406 showPrevMonth : function(e){
13407 this.update(this.activeDate.add("mo", -1));
13409 showToday : function(e){
13410 this.update(new Date().clearTime());
13413 showNextMonth : function(e){
13414 this.update(this.activeDate.add("mo", 1));
13418 showPrevYear : function(){
13419 this.update(this.activeDate.add("y", -1));
13423 showNextYear : function(){
13424 this.update(this.activeDate.add("y", 1));
13429 update : function(date)
13431 var vd = this.activeDate;
13432 this.activeDate = date;
13433 // if(vd && this.el){
13434 // var t = date.getTime();
13435 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13436 // Roo.log('using add remove');
13438 // this.fireEvent('monthchange', this, date);
13440 // this.cells.removeClass("fc-state-highlight");
13441 // this.cells.each(function(c){
13442 // if(c.dateValue == t){
13443 // c.addClass("fc-state-highlight");
13444 // setTimeout(function(){
13445 // try{c.dom.firstChild.focus();}catch(e){}
13455 var days = date.getDaysInMonth();
13457 var firstOfMonth = date.getFirstDateOfMonth();
13458 var startingPos = firstOfMonth.getDay()-this.startDay;
13460 if(startingPos < this.startDay){
13464 var pm = date.add(Date.MONTH, -1);
13465 var prevStart = pm.getDaysInMonth()-startingPos;
13467 this.cells = this.el.select('.fc-day',true);
13468 this.textNodes = this.el.query('.fc-day-number');
13469 this.cells.addClassOnOver('fc-state-hover');
13471 var cells = this.cells.elements;
13472 var textEls = this.textNodes;
13474 Roo.each(cells, function(cell){
13475 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13478 days += startingPos;
13480 // convert everything to numbers so it's fast
13481 var day = 86400000;
13482 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13485 //Roo.log(prevStart);
13487 var today = new Date().clearTime().getTime();
13488 var sel = date.clearTime().getTime();
13489 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13490 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13491 var ddMatch = this.disabledDatesRE;
13492 var ddText = this.disabledDatesText;
13493 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13494 var ddaysText = this.disabledDaysText;
13495 var format = this.format;
13497 var setCellClass = function(cal, cell){
13501 //Roo.log('set Cell Class');
13503 var t = d.getTime();
13507 cell.dateValue = t;
13509 cell.className += " fc-today";
13510 cell.className += " fc-state-highlight";
13511 cell.title = cal.todayText;
13514 // disable highlight in other month..
13515 //cell.className += " fc-state-highlight";
13520 cell.className = " fc-state-disabled";
13521 cell.title = cal.minText;
13525 cell.className = " fc-state-disabled";
13526 cell.title = cal.maxText;
13530 if(ddays.indexOf(d.getDay()) != -1){
13531 cell.title = ddaysText;
13532 cell.className = " fc-state-disabled";
13535 if(ddMatch && format){
13536 var fvalue = d.dateFormat(format);
13537 if(ddMatch.test(fvalue)){
13538 cell.title = ddText.replace("%0", fvalue);
13539 cell.className = " fc-state-disabled";
13543 if (!cell.initialClassName) {
13544 cell.initialClassName = cell.dom.className;
13547 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13552 for(; i < startingPos; i++) {
13553 textEls[i].innerHTML = (++prevStart);
13554 d.setDate(d.getDate()+1);
13556 cells[i].className = "fc-past fc-other-month";
13557 setCellClass(this, cells[i]);
13562 for(; i < days; i++){
13563 intDay = i - startingPos + 1;
13564 textEls[i].innerHTML = (intDay);
13565 d.setDate(d.getDate()+1);
13567 cells[i].className = ''; // "x-date-active";
13568 setCellClass(this, cells[i]);
13572 for(; i < 42; i++) {
13573 textEls[i].innerHTML = (++extraDays);
13574 d.setDate(d.getDate()+1);
13576 cells[i].className = "fc-future fc-other-month";
13577 setCellClass(this, cells[i]);
13580 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13582 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13584 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13585 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13587 if(totalRows != 6){
13588 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13589 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13592 this.fireEvent('monthchange', this, date);
13596 if(!this.internalRender){
13597 var main = this.el.dom.firstChild;
13598 var w = main.offsetWidth;
13599 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13600 Roo.fly(main).setWidth(w);
13601 this.internalRender = true;
13602 // opera does not respect the auto grow header center column
13603 // then, after it gets a width opera refuses to recalculate
13604 // without a second pass
13605 if(Roo.isOpera && !this.secondPass){
13606 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13607 this.secondPass = true;
13608 this.update.defer(10, this, [date]);
13615 findCell : function(dt) {
13616 dt = dt.clearTime().getTime();
13618 this.cells.each(function(c){
13619 //Roo.log("check " +c.dateValue + '?=' + dt);
13620 if(c.dateValue == dt){
13630 findCells : function(ev) {
13631 var s = ev.start.clone().clearTime().getTime();
13633 var e= ev.end.clone().clearTime().getTime();
13636 this.cells.each(function(c){
13637 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13639 if(c.dateValue > e){
13642 if(c.dateValue < s){
13651 // findBestRow: function(cells)
13655 // for (var i =0 ; i < cells.length;i++) {
13656 // ret = Math.max(cells[i].rows || 0,ret);
13663 addItem : function(ev)
13665 // look for vertical location slot in
13666 var cells = this.findCells(ev);
13668 // ev.row = this.findBestRow(cells);
13670 // work out the location.
13674 for(var i =0; i < cells.length; i++) {
13676 cells[i].row = cells[0].row;
13679 cells[i].row = cells[i].row + 1;
13689 if (crow.start.getY() == cells[i].getY()) {
13691 crow.end = cells[i];
13708 cells[0].events.push(ev);
13710 this.calevents.push(ev);
13713 clearEvents: function() {
13715 if(!this.calevents){
13719 Roo.each(this.cells.elements, function(c){
13725 Roo.each(this.calevents, function(e) {
13726 Roo.each(e.els, function(el) {
13727 el.un('mouseenter' ,this.onEventEnter, this);
13728 el.un('mouseleave' ,this.onEventLeave, this);
13733 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13739 renderEvents: function()
13743 this.cells.each(function(c) {
13752 if(c.row != c.events.length){
13753 r = 4 - (4 - (c.row - c.events.length));
13756 c.events = ev.slice(0, r);
13757 c.more = ev.slice(r);
13759 if(c.more.length && c.more.length == 1){
13760 c.events.push(c.more.pop());
13763 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13767 this.cells.each(function(c) {
13769 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13772 for (var e = 0; e < c.events.length; e++){
13773 var ev = c.events[e];
13774 var rows = ev.rows;
13776 for(var i = 0; i < rows.length; i++) {
13778 // how many rows should it span..
13781 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13782 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13784 unselectable : "on",
13787 cls: 'fc-event-inner',
13791 // cls: 'fc-event-time',
13792 // html : cells.length > 1 ? '' : ev.time
13796 cls: 'fc-event-title',
13797 html : String.format('{0}', ev.title)
13804 cls: 'ui-resizable-handle ui-resizable-e',
13805 html : '  '
13812 cfg.cls += ' fc-event-start';
13814 if ((i+1) == rows.length) {
13815 cfg.cls += ' fc-event-end';
13818 var ctr = _this.el.select('.fc-event-container',true).first();
13819 var cg = ctr.createChild(cfg);
13821 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13822 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13824 var r = (c.more.length) ? 1 : 0;
13825 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13826 cg.setWidth(ebox.right - sbox.x -2);
13828 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13829 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13830 cg.on('click', _this.onEventClick, _this, ev);
13841 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13842 style : 'position: absolute',
13843 unselectable : "on",
13846 cls: 'fc-event-inner',
13850 cls: 'fc-event-title',
13858 cls: 'ui-resizable-handle ui-resizable-e',
13859 html : '  '
13865 var ctr = _this.el.select('.fc-event-container',true).first();
13866 var cg = ctr.createChild(cfg);
13868 var sbox = c.select('.fc-day-content',true).first().getBox();
13869 var ebox = c.select('.fc-day-content',true).first().getBox();
13871 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13872 cg.setWidth(ebox.right - sbox.x -2);
13874 cg.on('click', _this.onMoreEventClick, _this, c.more);
13884 onEventEnter: function (e, el,event,d) {
13885 this.fireEvent('evententer', this, el, event);
13888 onEventLeave: function (e, el,event,d) {
13889 this.fireEvent('eventleave', this, el, event);
13892 onEventClick: function (e, el,event,d) {
13893 this.fireEvent('eventclick', this, el, event);
13896 onMonthChange: function () {
13900 onMoreEventClick: function(e, el, more)
13904 this.calpopover.placement = 'right';
13905 this.calpopover.setTitle('More');
13907 this.calpopover.setContent('');
13909 var ctr = this.calpopover.el.select('.popover-content', true).first();
13911 Roo.each(more, function(m){
13913 cls : 'fc-event-hori fc-event-draggable',
13916 var cg = ctr.createChild(cfg);
13918 cg.on('click', _this.onEventClick, _this, m);
13921 this.calpopover.show(el);
13926 onLoad: function ()
13928 this.calevents = [];
13931 if(this.store.getCount() > 0){
13932 this.store.data.each(function(d){
13935 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13936 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13937 time : d.data.start_time,
13938 title : d.data.title,
13939 description : d.data.description,
13940 venue : d.data.venue
13945 this.renderEvents();
13947 if(this.calevents.length && this.loadMask){
13948 this.maskEl.hide();
13952 onBeforeLoad: function()
13954 this.clearEvents();
13956 this.maskEl.show();
13970 * @class Roo.bootstrap.Popover
13971 * @extends Roo.bootstrap.Component
13972 * Bootstrap Popover class
13973 * @cfg {String} html contents of the popover (or false to use children..)
13974 * @cfg {String} title of popover (or false to hide)
13975 * @cfg {String} placement how it is placed
13976 * @cfg {String} trigger click || hover (or false to trigger manually)
13977 * @cfg {String} over what (parent or false to trigger manually.)
13978 * @cfg {Number} delay - delay before showing
13981 * Create a new Popover
13982 * @param {Object} config The config object
13985 Roo.bootstrap.Popover = function(config){
13986 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13989 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13991 title: 'Fill in a title',
13994 placement : 'right',
13995 trigger : 'hover', // hover
14001 can_build_overlaid : false,
14003 getChildContainer : function()
14005 return this.el.select('.popover-content',true).first();
14008 getAutoCreate : function(){
14009 Roo.log('make popover?');
14011 cls : 'popover roo-dynamic',
14012 style: 'display:block',
14018 cls : 'popover-inner',
14022 cls: 'popover-title',
14026 cls : 'popover-content',
14037 setTitle: function(str)
14039 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14041 setContent: function(str)
14043 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14045 // as it get's added to the bottom of the page.
14046 onRender : function(ct, position)
14048 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14050 var cfg = Roo.apply({}, this.getAutoCreate());
14054 cfg.cls += ' ' + this.cls;
14057 cfg.style = this.style;
14059 Roo.log("adding to ")
14060 this.el = Roo.get(document.body).createChild(cfg, position);
14066 initEvents : function()
14068 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14069 this.el.enableDisplayMode('block');
14071 if (this.over === false) {
14074 if (this.triggers === false) {
14077 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14078 var triggers = this.trigger ? this.trigger.split(' ') : [];
14079 Roo.each(triggers, function(trigger) {
14081 if (trigger == 'click') {
14082 on_el.on('click', this.toggle, this);
14083 } else if (trigger != 'manual') {
14084 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14085 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14087 on_el.on(eventIn ,this.enter, this);
14088 on_el.on(eventOut, this.leave, this);
14099 toggle : function () {
14100 this.hoverState == 'in' ? this.leave() : this.enter();
14103 enter : function () {
14106 clearTimeout(this.timeout);
14108 this.hoverState = 'in';
14110 if (!this.delay || !this.delay.show) {
14115 this.timeout = setTimeout(function () {
14116 if (_t.hoverState == 'in') {
14119 }, this.delay.show)
14121 leave : function() {
14122 clearTimeout(this.timeout);
14124 this.hoverState = 'out';
14126 if (!this.delay || !this.delay.hide) {
14131 this.timeout = setTimeout(function () {
14132 if (_t.hoverState == 'out') {
14135 }, this.delay.hide)
14138 show : function (on_el)
14141 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14144 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14145 if (this.html !== false) {
14146 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14148 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14149 if (!this.title.length) {
14150 this.el.select('.popover-title',true).hide();
14153 var placement = typeof this.placement == 'function' ?
14154 this.placement.call(this, this.el, on_el) :
14157 var autoToken = /\s?auto?\s?/i;
14158 var autoPlace = autoToken.test(placement);
14160 placement = placement.replace(autoToken, '') || 'top';
14164 //this.el.setXY([0,0]);
14166 this.el.dom.style.display='block';
14167 this.el.addClass(placement);
14169 //this.el.appendTo(on_el);
14171 var p = this.getPosition();
14172 var box = this.el.getBox();
14177 var align = Roo.bootstrap.Popover.alignment[placement];
14178 this.el.alignTo(on_el, align[0],align[1]);
14179 //var arrow = this.el.select('.arrow',true).first();
14180 //arrow.set(align[2],
14182 this.el.addClass('in');
14183 this.hoverState = null;
14185 if (this.el.hasClass('fade')) {
14192 this.el.setXY([0,0]);
14193 this.el.removeClass('in');
14200 Roo.bootstrap.Popover.alignment = {
14201 'left' : ['r-l', [-10,0], 'right'],
14202 'right' : ['l-r', [10,0], 'left'],
14203 'bottom' : ['t-b', [0,10], 'top'],
14204 'top' : [ 'b-t', [0,-10], 'bottom']
14215 * @class Roo.bootstrap.Progress
14216 * @extends Roo.bootstrap.Component
14217 * Bootstrap Progress class
14218 * @cfg {Boolean} striped striped of the progress bar
14219 * @cfg {Boolean} active animated of the progress bar
14223 * Create a new Progress
14224 * @param {Object} config The config object
14227 Roo.bootstrap.Progress = function(config){
14228 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14231 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14236 getAutoCreate : function(){
14244 cfg.cls += ' progress-striped';
14248 cfg.cls += ' active';
14267 * @class Roo.bootstrap.ProgressBar
14268 * @extends Roo.bootstrap.Component
14269 * Bootstrap ProgressBar class
14270 * @cfg {Number} aria_valuenow aria-value now
14271 * @cfg {Number} aria_valuemin aria-value min
14272 * @cfg {Number} aria_valuemax aria-value max
14273 * @cfg {String} label label for the progress bar
14274 * @cfg {String} panel (success | info | warning | danger )
14275 * @cfg {String} role role of the progress bar
14276 * @cfg {String} sr_only text
14280 * Create a new ProgressBar
14281 * @param {Object} config The config object
14284 Roo.bootstrap.ProgressBar = function(config){
14285 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14288 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14292 aria_valuemax : 100,
14298 getAutoCreate : function()
14303 cls: 'progress-bar',
14304 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14316 cfg.role = this.role;
14319 if(this.aria_valuenow){
14320 cfg['aria-valuenow'] = this.aria_valuenow;
14323 if(this.aria_valuemin){
14324 cfg['aria-valuemin'] = this.aria_valuemin;
14327 if(this.aria_valuemax){
14328 cfg['aria-valuemax'] = this.aria_valuemax;
14331 if(this.label && !this.sr_only){
14332 cfg.html = this.label;
14336 cfg.cls += ' progress-bar-' + this.panel;
14342 update : function(aria_valuenow)
14344 this.aria_valuenow = aria_valuenow;
14346 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14361 * @class Roo.bootstrap.TabGroup
14362 * @extends Roo.bootstrap.Column
14363 * Bootstrap Column class
14364 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14365 * @cfg {Boolean} carousel true to make the group behave like a carousel
14368 * Create a new TabGroup
14369 * @param {Object} config The config object
14372 Roo.bootstrap.TabGroup = function(config){
14373 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14375 this.navId = Roo.id();
14378 Roo.bootstrap.TabGroup.register(this);
14382 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14385 transition : false,
14387 getAutoCreate : function()
14389 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14391 cfg.cls += ' tab-content';
14393 if (this.carousel) {
14394 cfg.cls += ' carousel slide';
14396 cls : 'carousel-inner'
14403 getChildContainer : function()
14405 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14409 * register a Navigation item
14410 * @param {Roo.bootstrap.NavItem} the navitem to add
14412 register : function(item)
14414 this.tabs.push( item);
14415 item.navId = this.navId; // not really needed..
14419 getActivePanel : function()
14422 Roo.each(this.tabs, function(t) {
14432 getPanelByName : function(n)
14435 Roo.each(this.tabs, function(t) {
14436 if (t.tabId == n) {
14444 indexOfPanel : function(p)
14447 Roo.each(this.tabs, function(t,i) {
14448 if (t.tabId == p.tabId) {
14457 * show a specific panel
14458 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14459 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14461 showPanel : function (pan)
14464 if (typeof(pan) == 'number') {
14465 pan = this.tabs[pan];
14467 if (typeof(pan) == 'string') {
14468 pan = this.getPanelByName(pan);
14470 if (pan.tabId == this.getActivePanel().tabId) {
14473 var cur = this.getActivePanel();
14475 if (false === cur.fireEvent('beforedeactivate')) {
14479 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14481 this.transition = true;
14482 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14483 var lr = dir == 'next' ? 'left' : 'right';
14484 pan.el.addClass(dir); // or prev
14485 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14486 cur.el.addClass(lr); // or right
14487 pan.el.addClass(lr);
14490 cur.el.on('transitionend', function() {
14491 Roo.log("trans end?");
14493 pan.el.removeClass([lr,dir]);
14494 pan.setActive(true);
14496 cur.el.removeClass([lr]);
14497 cur.setActive(false);
14499 _this.transition = false;
14501 }, this, { single: true } );
14505 cur.setActive(false);
14506 pan.setActive(true);
14510 showPanelNext : function()
14512 var i = this.indexOfPanel(this.getActivePanel());
14513 if (i > this.tabs.length) {
14516 this.showPanel(this.tabs[i+1]);
14518 showPanelPrev : function()
14520 var i = this.indexOfPanel(this.getActivePanel());
14524 this.showPanel(this.tabs[i-1]);
14535 Roo.apply(Roo.bootstrap.TabGroup, {
14539 * register a Navigation Group
14540 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14542 register : function(navgrp)
14544 this.groups[navgrp.navId] = navgrp;
14548 * fetch a Navigation Group based on the navigation ID
14549 * if one does not exist , it will get created.
14550 * @param {string} the navgroup to add
14551 * @returns {Roo.bootstrap.NavGroup} the navgroup
14553 get: function(navId) {
14554 if (typeof(this.groups[navId]) == 'undefined') {
14555 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14557 return this.groups[navId] ;
14572 * @class Roo.bootstrap.TabPanel
14573 * @extends Roo.bootstrap.Component
14574 * Bootstrap TabPanel class
14575 * @cfg {Boolean} active panel active
14576 * @cfg {String} html panel content
14577 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14578 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14582 * Create a new TabPanel
14583 * @param {Object} config The config object
14586 Roo.bootstrap.TabPanel = function(config){
14587 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14591 * Fires when the active status changes
14592 * @param {Roo.bootstrap.TabPanel} this
14593 * @param {Boolean} state the new state
14598 * @event beforedeactivate
14599 * Fires before a tab is de-activated - can be used to do validation on a form.
14600 * @param {Roo.bootstrap.TabPanel} this
14601 * @return {Boolean} false if there is an error
14604 'beforedeactivate': true
14607 this.tabId = this.tabId || Roo.id();
14611 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14618 getAutoCreate : function(){
14621 // item is needed for carousel - not sure if it has any effect otherwise
14622 cls: 'tab-pane item',
14623 html: this.html || ''
14627 cfg.cls += ' active';
14631 cfg.tabId = this.tabId;
14638 initEvents: function()
14640 Roo.log('-------- init events on tab panel ---------');
14642 var p = this.parent();
14643 this.navId = this.navId || p.navId;
14645 if (typeof(this.navId) != 'undefined') {
14646 // not really needed.. but just in case.. parent should be a NavGroup.
14647 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14648 Roo.log(['register', tg, this]);
14654 onRender : function(ct, position)
14656 // Roo.log("Call onRender: " + this.xtype);
14658 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14666 setActive: function(state)
14668 Roo.log("panel - set active " + this.tabId + "=" + state);
14670 this.active = state;
14672 this.el.removeClass('active');
14674 } else if (!this.el.hasClass('active')) {
14675 this.el.addClass('active');
14677 this.fireEvent('changed', this, state);
14694 * @class Roo.bootstrap.DateField
14695 * @extends Roo.bootstrap.Input
14696 * Bootstrap DateField class
14697 * @cfg {Number} weekStart default 0
14698 * @cfg {String} viewMode default empty, (months|years)
14699 * @cfg {String} minViewMode default empty, (months|years)
14700 * @cfg {Number} startDate default -Infinity
14701 * @cfg {Number} endDate default Infinity
14702 * @cfg {Boolean} todayHighlight default false
14703 * @cfg {Boolean} todayBtn default false
14704 * @cfg {Boolean} calendarWeeks default false
14705 * @cfg {Object} daysOfWeekDisabled default empty
14706 * @cfg {Boolean} singleMode default false (true | false)
14708 * @cfg {Boolean} keyboardNavigation default true
14709 * @cfg {String} language default en
14712 * Create a new DateField
14713 * @param {Object} config The config object
14716 Roo.bootstrap.DateField = function(config){
14717 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14721 * Fires when this field show.
14722 * @param {Roo.bootstrap.DateField} this
14723 * @param {Mixed} date The date value
14728 * Fires when this field hide.
14729 * @param {Roo.bootstrap.DateField} this
14730 * @param {Mixed} date The date value
14735 * Fires when select a date.
14736 * @param {Roo.bootstrap.DateField} this
14737 * @param {Mixed} date The date value
14743 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14746 * @cfg {String} format
14747 * The default date format string which can be overriden for localization support. The format must be
14748 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14752 * @cfg {String} altFormats
14753 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14754 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14756 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14764 todayHighlight : false,
14770 keyboardNavigation: true,
14772 calendarWeeks: false,
14774 startDate: -Infinity,
14778 daysOfWeekDisabled: [],
14782 singleMode : false,
14784 UTCDate: function()
14786 return new Date(Date.UTC.apply(Date, arguments));
14789 UTCToday: function()
14791 var today = new Date();
14792 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14795 getDate: function() {
14796 var d = this.getUTCDate();
14797 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14800 getUTCDate: function() {
14804 setDate: function(d) {
14805 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14808 setUTCDate: function(d) {
14810 this.setValue(this.formatDate(this.date));
14813 onRender: function(ct, position)
14816 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14818 this.language = this.language || 'en';
14819 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14820 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14822 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14823 this.format = this.format || 'm/d/y';
14824 this.isInline = false;
14825 this.isInput = true;
14826 this.component = this.el.select('.add-on', true).first() || false;
14827 this.component = (this.component && this.component.length === 0) ? false : this.component;
14828 this.hasInput = this.component && this.inputEL().length;
14830 if (typeof(this.minViewMode === 'string')) {
14831 switch (this.minViewMode) {
14833 this.minViewMode = 1;
14836 this.minViewMode = 2;
14839 this.minViewMode = 0;
14844 if (typeof(this.viewMode === 'string')) {
14845 switch (this.viewMode) {
14858 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14860 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14862 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14864 this.picker().on('mousedown', this.onMousedown, this);
14865 this.picker().on('click', this.onClick, this);
14867 this.picker().addClass('datepicker-dropdown');
14869 this.startViewMode = this.viewMode;
14871 if(this.singleMode){
14872 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14873 v.setVisibilityMode(Roo.Element.DISPLAY)
14877 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14878 v.setStyle('width', '189px');
14882 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14883 if(!this.calendarWeeks){
14888 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14889 v.attr('colspan', function(i, val){
14890 return parseInt(val) + 1;
14895 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14897 this.setStartDate(this.startDate);
14898 this.setEndDate(this.endDate);
14900 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14907 if(this.isInline) {
14912 picker : function()
14914 return this.pickerEl;
14915 // return this.el.select('.datepicker', true).first();
14918 fillDow: function()
14920 var dowCnt = this.weekStart;
14929 if(this.calendarWeeks){
14937 while (dowCnt < this.weekStart + 7) {
14941 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14945 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14948 fillMonths: function()
14951 var months = this.picker().select('>.datepicker-months td', true).first();
14953 months.dom.innerHTML = '';
14959 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14962 months.createChild(month);
14969 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;
14971 if (this.date < this.startDate) {
14972 this.viewDate = new Date(this.startDate);
14973 } else if (this.date > this.endDate) {
14974 this.viewDate = new Date(this.endDate);
14976 this.viewDate = new Date(this.date);
14984 var d = new Date(this.viewDate),
14985 year = d.getUTCFullYear(),
14986 month = d.getUTCMonth(),
14987 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14988 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14989 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14990 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14991 currentDate = this.date && this.date.valueOf(),
14992 today = this.UTCToday();
14994 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14996 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14998 // this.picker.select('>tfoot th.today').
14999 // .text(dates[this.language].today)
15000 // .toggle(this.todayBtn !== false);
15002 this.updateNavArrows();
15005 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15007 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15009 prevMonth.setUTCDate(day);
15011 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15013 var nextMonth = new Date(prevMonth);
15015 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15017 nextMonth = nextMonth.valueOf();
15019 var fillMonths = false;
15021 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15023 while(prevMonth.valueOf() < nextMonth) {
15026 if (prevMonth.getUTCDay() === this.weekStart) {
15028 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15036 if(this.calendarWeeks){
15037 // ISO 8601: First week contains first thursday.
15038 // ISO also states week starts on Monday, but we can be more abstract here.
15040 // Start of current week: based on weekstart/current date
15041 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15042 // Thursday of this week
15043 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15044 // First Thursday of year, year from thursday
15045 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15046 // Calendar week: ms between thursdays, div ms per day, div 7 days
15047 calWeek = (th - yth) / 864e5 / 7 + 1;
15049 fillMonths.cn.push({
15057 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15059 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15062 if (this.todayHighlight &&
15063 prevMonth.getUTCFullYear() == today.getFullYear() &&
15064 prevMonth.getUTCMonth() == today.getMonth() &&
15065 prevMonth.getUTCDate() == today.getDate()) {
15066 clsName += ' today';
15069 if (currentDate && prevMonth.valueOf() === currentDate) {
15070 clsName += ' active';
15073 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15074 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15075 clsName += ' disabled';
15078 fillMonths.cn.push({
15080 cls: 'day ' + clsName,
15081 html: prevMonth.getDate()
15084 prevMonth.setDate(prevMonth.getDate()+1);
15087 var currentYear = this.date && this.date.getUTCFullYear();
15088 var currentMonth = this.date && this.date.getUTCMonth();
15090 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15092 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15093 v.removeClass('active');
15095 if(currentYear === year && k === currentMonth){
15096 v.addClass('active');
15099 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15100 v.addClass('disabled');
15106 year = parseInt(year/10, 10) * 10;
15108 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15110 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15113 for (var i = -1; i < 11; i++) {
15114 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15116 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15124 showMode: function(dir)
15127 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15130 Roo.each(this.picker().select('>div',true).elements, function(v){
15131 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15134 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15139 if(this.isInline) return;
15141 this.picker().removeClass(['bottom', 'top']);
15143 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15145 * place to the top of element!
15149 this.picker().addClass('top');
15150 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15155 this.picker().addClass('bottom');
15157 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15160 parseDate : function(value)
15162 if(!value || value instanceof Date){
15165 var v = Date.parseDate(value, this.format);
15166 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15167 v = Date.parseDate(value, 'Y-m-d');
15169 if(!v && this.altFormats){
15170 if(!this.altFormatsArray){
15171 this.altFormatsArray = this.altFormats.split("|");
15173 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15174 v = Date.parseDate(value, this.altFormatsArray[i]);
15180 formatDate : function(date, fmt)
15182 return (!date || !(date instanceof Date)) ?
15183 date : date.dateFormat(fmt || this.format);
15186 onFocus : function()
15188 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15192 onBlur : function()
15194 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15196 var d = this.inputEl().getValue();
15205 this.picker().show();
15209 this.fireEvent('show', this, this.date);
15214 if(this.isInline) return;
15215 this.picker().hide();
15216 this.viewMode = this.startViewMode;
15219 this.fireEvent('hide', this, this.date);
15223 onMousedown: function(e)
15225 e.stopPropagation();
15226 e.preventDefault();
15231 Roo.bootstrap.DateField.superclass.keyup.call(this);
15235 setValue: function(v)
15238 // v can be a string or a date..
15241 var d = new Date(this.parseDate(v) ).clearTime();
15243 if(isNaN(d.getTime())){
15244 this.date = this.viewDate = '';
15245 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15249 v = this.formatDate(d);
15251 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15253 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15257 this.fireEvent('select', this, this.date);
15261 getValue: function()
15263 return this.formatDate(this.date);
15266 fireKey: function(e)
15268 if (!this.picker().isVisible()){
15269 if (e.keyCode == 27) // allow escape to hide and re-show picker
15274 var dateChanged = false,
15276 newDate, newViewDate;
15281 e.preventDefault();
15285 if (!this.keyboardNavigation) break;
15286 dir = e.keyCode == 37 ? -1 : 1;
15289 newDate = this.moveYear(this.date, dir);
15290 newViewDate = this.moveYear(this.viewDate, dir);
15291 } else if (e.shiftKey){
15292 newDate = this.moveMonth(this.date, dir);
15293 newViewDate = this.moveMonth(this.viewDate, dir);
15295 newDate = new Date(this.date);
15296 newDate.setUTCDate(this.date.getUTCDate() + dir);
15297 newViewDate = new Date(this.viewDate);
15298 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15300 if (this.dateWithinRange(newDate)){
15301 this.date = newDate;
15302 this.viewDate = newViewDate;
15303 this.setValue(this.formatDate(this.date));
15305 e.preventDefault();
15306 dateChanged = true;
15311 if (!this.keyboardNavigation) break;
15312 dir = e.keyCode == 38 ? -1 : 1;
15314 newDate = this.moveYear(this.date, dir);
15315 newViewDate = this.moveYear(this.viewDate, dir);
15316 } else if (e.shiftKey){
15317 newDate = this.moveMonth(this.date, dir);
15318 newViewDate = this.moveMonth(this.viewDate, dir);
15320 newDate = new Date(this.date);
15321 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15322 newViewDate = new Date(this.viewDate);
15323 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15325 if (this.dateWithinRange(newDate)){
15326 this.date = newDate;
15327 this.viewDate = newViewDate;
15328 this.setValue(this.formatDate(this.date));
15330 e.preventDefault();
15331 dateChanged = true;
15335 this.setValue(this.formatDate(this.date));
15337 e.preventDefault();
15340 this.setValue(this.formatDate(this.date));
15354 onClick: function(e)
15356 e.stopPropagation();
15357 e.preventDefault();
15359 var target = e.getTarget();
15361 if(target.nodeName.toLowerCase() === 'i'){
15362 target = Roo.get(target).dom.parentNode;
15365 var nodeName = target.nodeName;
15366 var className = target.className;
15367 var html = target.innerHTML;
15368 //Roo.log(nodeName);
15370 switch(nodeName.toLowerCase()) {
15372 switch(className) {
15378 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15379 switch(this.viewMode){
15381 this.viewDate = this.moveMonth(this.viewDate, dir);
15385 this.viewDate = this.moveYear(this.viewDate, dir);
15391 var date = new Date();
15392 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15394 this.setValue(this.formatDate(this.date));
15401 if (className.indexOf('disabled') < 0) {
15402 this.viewDate.setUTCDate(1);
15403 if (className.indexOf('month') > -1) {
15404 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15406 var year = parseInt(html, 10) || 0;
15407 this.viewDate.setUTCFullYear(year);
15411 if(this.singleMode){
15412 this.setValue(this.formatDate(this.viewDate));
15423 //Roo.log(className);
15424 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15425 var day = parseInt(html, 10) || 1;
15426 var year = this.viewDate.getUTCFullYear(),
15427 month = this.viewDate.getUTCMonth();
15429 if (className.indexOf('old') > -1) {
15436 } else if (className.indexOf('new') > -1) {
15444 //Roo.log([year,month,day]);
15445 this.date = this.UTCDate(year, month, day,0,0,0,0);
15446 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15448 //Roo.log(this.formatDate(this.date));
15449 this.setValue(this.formatDate(this.date));
15456 setStartDate: function(startDate)
15458 this.startDate = startDate || -Infinity;
15459 if (this.startDate !== -Infinity) {
15460 this.startDate = this.parseDate(this.startDate);
15463 this.updateNavArrows();
15466 setEndDate: function(endDate)
15468 this.endDate = endDate || Infinity;
15469 if (this.endDate !== Infinity) {
15470 this.endDate = this.parseDate(this.endDate);
15473 this.updateNavArrows();
15476 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15478 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15479 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15480 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15482 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15483 return parseInt(d, 10);
15486 this.updateNavArrows();
15489 updateNavArrows: function()
15491 if(this.singleMode){
15495 var d = new Date(this.viewDate),
15496 year = d.getUTCFullYear(),
15497 month = d.getUTCMonth();
15499 Roo.each(this.picker().select('.prev', true).elements, function(v){
15501 switch (this.viewMode) {
15504 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15510 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15517 Roo.each(this.picker().select('.next', true).elements, function(v){
15519 switch (this.viewMode) {
15522 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15528 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15536 moveMonth: function(date, dir)
15538 if (!dir) return date;
15539 var new_date = new Date(date.valueOf()),
15540 day = new_date.getUTCDate(),
15541 month = new_date.getUTCMonth(),
15542 mag = Math.abs(dir),
15544 dir = dir > 0 ? 1 : -1;
15547 // If going back one month, make sure month is not current month
15548 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15550 return new_date.getUTCMonth() == month;
15552 // If going forward one month, make sure month is as expected
15553 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15555 return new_date.getUTCMonth() != new_month;
15557 new_month = month + dir;
15558 new_date.setUTCMonth(new_month);
15559 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15560 if (new_month < 0 || new_month > 11)
15561 new_month = (new_month + 12) % 12;
15563 // For magnitudes >1, move one month at a time...
15564 for (var i=0; i<mag; i++)
15565 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15566 new_date = this.moveMonth(new_date, dir);
15567 // ...then reset the day, keeping it in the new month
15568 new_month = new_date.getUTCMonth();
15569 new_date.setUTCDate(day);
15571 return new_month != new_date.getUTCMonth();
15574 // Common date-resetting loop -- if date is beyond end of month, make it
15577 new_date.setUTCDate(--day);
15578 new_date.setUTCMonth(new_month);
15583 moveYear: function(date, dir)
15585 return this.moveMonth(date, dir*12);
15588 dateWithinRange: function(date)
15590 return date >= this.startDate && date <= this.endDate;
15596 this.picker().remove();
15601 Roo.apply(Roo.bootstrap.DateField, {
15612 html: '<i class="fa fa-arrow-left"/>'
15622 html: '<i class="fa fa-arrow-right"/>'
15664 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15665 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15666 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15667 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15668 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15681 navFnc: 'FullYear',
15686 navFnc: 'FullYear',
15691 Roo.apply(Roo.bootstrap.DateField, {
15695 cls: 'datepicker dropdown-menu roo-dynamic',
15699 cls: 'datepicker-days',
15703 cls: 'table-condensed',
15705 Roo.bootstrap.DateField.head,
15709 Roo.bootstrap.DateField.footer
15716 cls: 'datepicker-months',
15720 cls: 'table-condensed',
15722 Roo.bootstrap.DateField.head,
15723 Roo.bootstrap.DateField.content,
15724 Roo.bootstrap.DateField.footer
15731 cls: 'datepicker-years',
15735 cls: 'table-condensed',
15737 Roo.bootstrap.DateField.head,
15738 Roo.bootstrap.DateField.content,
15739 Roo.bootstrap.DateField.footer
15758 * @class Roo.bootstrap.TimeField
15759 * @extends Roo.bootstrap.Input
15760 * Bootstrap DateField class
15764 * Create a new TimeField
15765 * @param {Object} config The config object
15768 Roo.bootstrap.TimeField = function(config){
15769 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15773 * Fires when this field show.
15774 * @param {Roo.bootstrap.DateField} thisthis
15775 * @param {Mixed} date The date value
15780 * Fires when this field hide.
15781 * @param {Roo.bootstrap.DateField} this
15782 * @param {Mixed} date The date value
15787 * Fires when select a date.
15788 * @param {Roo.bootstrap.DateField} this
15789 * @param {Mixed} date The date value
15795 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15798 * @cfg {String} format
15799 * The default time format string which can be overriden for localization support. The format must be
15800 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15804 onRender: function(ct, position)
15807 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15809 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15811 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15813 this.pop = this.picker().select('>.datepicker-time',true).first();
15814 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15816 this.picker().on('mousedown', this.onMousedown, this);
15817 this.picker().on('click', this.onClick, this);
15819 this.picker().addClass('datepicker-dropdown');
15824 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15825 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15826 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15827 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15828 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15829 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15833 fireKey: function(e){
15834 if (!this.picker().isVisible()){
15835 if (e.keyCode == 27) { // allow escape to hide and re-show picker
15841 e.preventDefault();
15849 this.onTogglePeriod();
15852 this.onIncrementMinutes();
15855 this.onDecrementMinutes();
15864 onClick: function(e) {
15865 e.stopPropagation();
15866 e.preventDefault();
15869 picker : function()
15871 return this.el.select('.datepicker', true).first();
15874 fillTime: function()
15876 var time = this.pop.select('tbody', true).first();
15878 time.dom.innerHTML = '';
15893 cls: 'hours-up glyphicon glyphicon-chevron-up'
15913 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15934 cls: 'timepicker-hour',
15949 cls: 'timepicker-minute',
15964 cls: 'btn btn-primary period',
15986 cls: 'hours-down glyphicon glyphicon-chevron-down'
16006 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16024 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16031 var hours = this.time.getHours();
16032 var minutes = this.time.getMinutes();
16045 hours = hours - 12;
16049 hours = '0' + hours;
16053 minutes = '0' + minutes;
16056 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16057 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16058 this.pop.select('button', true).first().dom.innerHTML = period;
16064 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16066 var cls = ['bottom'];
16068 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16075 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16080 this.picker().addClass(cls.join('-'));
16084 Roo.each(cls, function(c){
16086 _this.picker().setTop(_this.inputEl().getHeight());
16090 _this.picker().setTop(0 - _this.picker().getHeight());
16095 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16099 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16106 onFocus : function()
16108 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16112 onBlur : function()
16114 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16120 this.picker().show();
16125 this.fireEvent('show', this, this.date);
16130 this.picker().hide();
16133 this.fireEvent('hide', this, this.date);
16136 setTime : function()
16139 this.setValue(this.time.format(this.format));
16141 this.fireEvent('select', this, this.date);
16146 onMousedown: function(e){
16147 e.stopPropagation();
16148 e.preventDefault();
16151 onIncrementHours: function()
16153 Roo.log('onIncrementHours');
16154 this.time = this.time.add(Date.HOUR, 1);
16159 onDecrementHours: function()
16161 Roo.log('onDecrementHours');
16162 this.time = this.time.add(Date.HOUR, -1);
16166 onIncrementMinutes: function()
16168 Roo.log('onIncrementMinutes');
16169 this.time = this.time.add(Date.MINUTE, 1);
16173 onDecrementMinutes: function()
16175 Roo.log('onDecrementMinutes');
16176 this.time = this.time.add(Date.MINUTE, -1);
16180 onTogglePeriod: function()
16182 Roo.log('onTogglePeriod');
16183 this.time = this.time.add(Date.HOUR, 12);
16190 Roo.apply(Roo.bootstrap.TimeField, {
16220 cls: 'btn btn-info ok',
16232 Roo.apply(Roo.bootstrap.TimeField, {
16236 cls: 'datepicker dropdown-menu',
16240 cls: 'datepicker-time',
16244 cls: 'table-condensed',
16246 Roo.bootstrap.TimeField.content,
16247 Roo.bootstrap.TimeField.footer
16266 * @class Roo.bootstrap.MonthField
16267 * @extends Roo.bootstrap.Input
16268 * Bootstrap MonthField class
16270 * @cfg {String} language default en
16273 * Create a new MonthField
16274 * @param {Object} config The config object
16277 Roo.bootstrap.MonthField = function(config){
16278 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16283 * Fires when this field show.
16284 * @param {Roo.bootstrap.MonthField} this
16285 * @param {Mixed} date The date value
16290 * Fires when this field hide.
16291 * @param {Roo.bootstrap.MonthField} this
16292 * @param {Mixed} date The date value
16297 * Fires when select a date.
16298 * @param {Roo.bootstrap.MonthField} this
16299 * @param {String} oldvalue The old value
16300 * @param {String} newvalue The new value
16306 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16308 onRender: function(ct, position)
16311 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16313 this.language = this.language || 'en';
16314 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16315 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16317 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16318 this.isInline = false;
16319 this.isInput = true;
16320 this.component = this.el.select('.add-on', true).first() || false;
16321 this.component = (this.component && this.component.length === 0) ? false : this.component;
16322 this.hasInput = this.component && this.inputEL().length;
16324 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16326 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16328 this.picker().on('mousedown', this.onMousedown, this);
16329 this.picker().on('click', this.onClick, this);
16331 this.picker().addClass('datepicker-dropdown');
16333 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16334 v.setStyle('width', '189px');
16341 if(this.isInline) {
16347 setValue: function(v, suppressEvent)
16349 var o = this.getValue();
16351 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16355 if(suppressEvent !== true){
16356 this.fireEvent('select', this, o, v);
16361 getValue: function()
16366 onClick: function(e)
16368 e.stopPropagation();
16369 e.preventDefault();
16371 var target = e.getTarget();
16373 if(target.nodeName.toLowerCase() === 'i'){
16374 target = Roo.get(target).dom.parentNode;
16377 var nodeName = target.nodeName;
16378 var className = target.className;
16379 var html = target.innerHTML;
16381 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16385 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16387 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16393 picker : function()
16395 return this.pickerEl;
16398 fillMonths: function()
16401 var months = this.picker().select('>.datepicker-months td', true).first();
16403 months.dom.innerHTML = '';
16409 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16412 months.createChild(month);
16421 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16422 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16425 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16426 e.removeClass('active');
16428 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16429 e.addClass('active');
16436 if(this.isInline) return;
16438 this.picker().removeClass(['bottom', 'top']);
16440 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16442 * place to the top of element!
16446 this.picker().addClass('top');
16447 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16452 this.picker().addClass('bottom');
16454 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16457 onFocus : function()
16459 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16463 onBlur : function()
16465 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16467 var d = this.inputEl().getValue();
16476 this.picker().show();
16477 this.picker().select('>.datepicker-months', true).first().show();
16481 this.fireEvent('show', this, this.date);
16486 if(this.isInline) return;
16487 this.picker().hide();
16488 this.fireEvent('hide', this, this.date);
16492 onMousedown: function(e)
16494 e.stopPropagation();
16495 e.preventDefault();
16500 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16504 fireKey: function(e)
16506 if (!this.picker().isVisible()){
16507 if (e.keyCode == 27) // allow escape to hide and re-show picker
16517 e.preventDefault();
16521 dir = e.keyCode == 37 ? -1 : 1;
16523 this.vIndex = this.vIndex + dir;
16525 if(this.vIndex < 0){
16529 if(this.vIndex > 11){
16533 if(isNaN(this.vIndex)){
16537 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16543 dir = e.keyCode == 38 ? -1 : 1;
16545 this.vIndex = this.vIndex + dir * 4;
16547 if(this.vIndex < 0){
16551 if(this.vIndex > 11){
16555 if(isNaN(this.vIndex)){
16559 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16564 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16565 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16569 e.preventDefault();
16572 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16573 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16589 this.picker().remove();
16594 Roo.apply(Roo.bootstrap.MonthField, {
16613 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16614 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16619 Roo.apply(Roo.bootstrap.MonthField, {
16623 cls: 'datepicker dropdown-menu roo-dynamic',
16627 cls: 'datepicker-months',
16631 cls: 'table-condensed',
16633 Roo.bootstrap.DateField.content
16653 * @class Roo.bootstrap.CheckBox
16654 * @extends Roo.bootstrap.Input
16655 * Bootstrap CheckBox class
16657 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16658 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16659 * @cfg {String} boxLabel The text that appears beside the checkbox
16660 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16661 * @cfg {Boolean} checked initnal the element
16662 * @cfg {Boolean} inline inline the element (default false)
16663 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16666 * Create a new CheckBox
16667 * @param {Object} config The config object
16670 Roo.bootstrap.CheckBox = function(config){
16671 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16676 * Fires when the element is checked or unchecked.
16677 * @param {Roo.bootstrap.CheckBox} this This input
16678 * @param {Boolean} checked The new checked value
16685 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16687 inputType: 'checkbox',
16695 getAutoCreate : function()
16697 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16703 cfg.cls = 'form-group ' + this.inputType; //input-group
16706 cfg.cls += ' ' + this.inputType + '-inline';
16712 type : this.inputType,
16713 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16714 cls : 'roo-' + this.inputType, //'form-box',
16715 placeholder : this.placeholder || ''
16719 if (this.weight) { // Validity check?
16720 cfg.cls += " " + this.inputType + "-" + this.weight;
16723 if (this.disabled) {
16724 input.disabled=true;
16728 input.checked = this.checked;
16732 input.name = this.name;
16736 input.cls += ' input-' + this.size;
16741 ['xs','sm','md','lg'].map(function(size){
16742 if (settings[size]) {
16743 cfg.cls += ' col-' + size + '-' + settings[size];
16747 var inputblock = input;
16749 if (this.before || this.after) {
16752 cls : 'input-group',
16757 inputblock.cn.push({
16759 cls : 'input-group-addon',
16764 inputblock.cn.push(input);
16767 inputblock.cn.push({
16769 cls : 'input-group-addon',
16776 if (align ==='left' && this.fieldLabel.length) {
16777 Roo.log("left and has label");
16783 cls : 'control-label col-md-' + this.labelWidth,
16784 html : this.fieldLabel
16788 cls : "col-md-" + (12 - this.labelWidth),
16795 } else if ( this.fieldLabel.length) {
16800 tag: this.boxLabel ? 'span' : 'label',
16802 cls: 'control-label box-input-label',
16803 //cls : 'input-group-addon',
16804 html : this.fieldLabel
16814 Roo.log(" no label && no align");
16815 cfg.cn = [ inputblock ] ;
16820 var boxLabelCfg = {
16822 //'for': id, // box label is handled by onclick - so no for...
16824 html: this.boxLabel
16828 boxLabelCfg.tooltip = this.tooltip;
16831 cfg.cn.push(boxLabelCfg);
16841 * return the real input element.
16843 inputEl: function ()
16845 return this.el.select('input.roo-' + this.inputType,true).first();
16848 labelEl: function()
16850 return this.el.select('label.control-label',true).first();
16852 /* depricated... */
16856 return this.labelEl();
16859 initEvents : function()
16861 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16863 this.inputEl().on('click', this.onClick, this);
16865 if (this.boxLabel) {
16866 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16869 this.startValue = this.getValue();
16872 Roo.bootstrap.CheckBox.register(this);
16876 onClick : function()
16878 this.setChecked(!this.checked);
16881 setChecked : function(state,suppressEvent)
16883 this.startValue = this.getValue();
16885 if(this.inputType == 'radio'){
16887 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16888 e.dom.checked = false;
16891 this.inputEl().dom.checked = true;
16893 this.inputEl().dom.value = this.inputValue;
16895 if(suppressEvent !== true){
16896 this.fireEvent('check', this, true);
16904 this.checked = state;
16906 this.inputEl().dom.checked = state;
16908 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16910 if(suppressEvent !== true){
16911 this.fireEvent('check', this, state);
16917 getValue : function()
16919 if(this.inputType == 'radio'){
16920 return this.getGroupValue();
16923 return this.inputEl().getValue();
16927 getGroupValue : function()
16929 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16933 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16936 setValue : function(v,suppressEvent)
16938 if(this.inputType == 'radio'){
16939 this.setGroupValue(v, suppressEvent);
16943 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16948 setGroupValue : function(v, suppressEvent)
16950 this.startValue = this.getValue();
16952 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16953 e.dom.checked = false;
16955 if(e.dom.value == v){
16956 e.dom.checked = true;
16960 if(suppressEvent !== true){
16961 this.fireEvent('check', this, true);
16969 validate : function()
16973 (this.inputType == 'radio' && this.getValue().length) ||
16974 (this.inputType == 'checkbox' && this.validateGroup())
16980 this.markInvalid();
16984 validateGroup : function()
16987 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
16990 var group = Roo.bootstrap.CheckBox.get(this.groupId);
16998 for(var i in group){
17003 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17010 * Mark this field as valid
17012 markValid : function()
17016 this.fireEvent('valid', this);
17018 if(this.inputType == 'radio'){
17019 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17020 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17021 e.findParent('.form-group', false, true).addClass(_this.validClass);
17028 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17029 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17033 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17039 for(var i in group){
17040 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17041 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17046 * Mark this field as invalid
17047 * @param {String} msg The validation message
17049 markInvalid : function(msg)
17053 this.fireEvent('invalid', this, msg);
17055 if(this.inputType == 'radio'){
17056 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17057 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17058 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17065 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17066 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17070 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17076 for(var i in group){
17077 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17078 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17085 Roo.apply(Roo.bootstrap.CheckBox, {
17090 * register a CheckBox Group
17091 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17093 register : function(checkbox)
17095 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17096 this.groups[checkbox.groupId] = {};
17099 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17103 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17107 * fetch a CheckBox Group based on the group ID
17108 * @param {string} the group ID
17109 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17111 get: function(groupId) {
17112 if (typeof(this.groups[groupId]) == 'undefined') {
17116 return this.groups[groupId] ;
17128 *<div class="radio">
17130 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17131 Option one is this and that—be sure to include why it's great
17138 *<label class="radio-inline">fieldLabel</label>
17139 *<label class="radio-inline">
17140 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17148 * @class Roo.bootstrap.Radio
17149 * @extends Roo.bootstrap.CheckBox
17150 * Bootstrap Radio class
17153 * Create a new Radio
17154 * @param {Object} config The config object
17157 Roo.bootstrap.Radio = function(config){
17158 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17162 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17164 inputType: 'radio',
17168 getAutoCreate : function()
17170 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17171 align = align || 'left'; // default...
17178 tag : this.inline ? 'span' : 'div',
17183 var inline = this.inline ? ' radio-inline' : '';
17187 // does not need for, as we wrap the input with it..
17189 cls : 'control-label box-label' + inline,
17192 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17196 //cls : 'control-label' + inline,
17197 html : this.fieldLabel,
17198 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17207 type : this.inputType,
17208 //value : (!this.checked) ? this.valueOff : this.inputValue,
17209 value : this.inputValue,
17211 placeholder : this.placeholder || '' // ?? needed????
17214 if (this.weight) { // Validity check?
17215 input.cls += " radio-" + this.weight;
17217 if (this.disabled) {
17218 input.disabled=true;
17222 input.checked = this.checked;
17226 input.name = this.name;
17230 input.cls += ' input-' + this.size;
17233 //?? can span's inline have a width??
17236 ['xs','sm','md','lg'].map(function(size){
17237 if (settings[size]) {
17238 cfg.cls += ' col-' + size + '-' + settings[size];
17242 var inputblock = input;
17244 if (this.before || this.after) {
17247 cls : 'input-group',
17252 inputblock.cn.push({
17254 cls : 'input-group-addon',
17258 inputblock.cn.push(input);
17260 inputblock.cn.push({
17262 cls : 'input-group-addon',
17270 if (this.fieldLabel && this.fieldLabel.length) {
17271 cfg.cn.push(fieldLabel);
17274 // normal bootstrap puts the input inside the label.
17275 // however with our styled version - it has to go after the input.
17277 //lbl.cn.push(inputblock);
17281 cls: 'radio' + inline,
17288 cfg.cn.push( lblwrap);
17293 html: this.boxLabel
17302 initEvents : function()
17304 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17306 this.inputEl().on('click', this.onClick, this);
17307 if (this.boxLabel) {
17308 Roo.log('find label')
17309 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17314 inputEl: function ()
17316 return this.el.select('input.roo-radio',true).first();
17318 onClick : function()
17321 this.setChecked(true);
17324 setChecked : function(state,suppressEvent)
17327 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17328 v.dom.checked = false;
17331 Roo.log(this.inputEl().dom);
17332 this.checked = state;
17333 this.inputEl().dom.checked = state;
17335 if(suppressEvent !== true){
17336 this.fireEvent('check', this, state);
17339 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17343 getGroupValue : function()
17346 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17347 if(v.dom.checked == true){
17348 value = v.dom.value;
17356 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17357 * @return {Mixed} value The field value
17359 getValue : function(){
17360 return this.getGroupValue();
17366 //<script type="text/javascript">
17369 * Based Ext JS Library 1.1.1
17370 * Copyright(c) 2006-2007, Ext JS, LLC.
17376 * @class Roo.HtmlEditorCore
17377 * @extends Roo.Component
17378 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17380 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17383 Roo.HtmlEditorCore = function(config){
17386 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17391 * @event initialize
17392 * Fires when the editor is fully initialized (including the iframe)
17393 * @param {Roo.HtmlEditorCore} this
17398 * Fires when the editor is first receives the focus. Any insertion must wait
17399 * until after this event.
17400 * @param {Roo.HtmlEditorCore} this
17404 * @event beforesync
17405 * Fires before the textarea is updated with content from the editor iframe. Return false
17406 * to cancel the sync.
17407 * @param {Roo.HtmlEditorCore} this
17408 * @param {String} html
17412 * @event beforepush
17413 * Fires before the iframe editor is updated with content from the textarea. Return false
17414 * to cancel the push.
17415 * @param {Roo.HtmlEditorCore} this
17416 * @param {String} html
17421 * Fires when the textarea is updated with content from the editor iframe.
17422 * @param {Roo.HtmlEditorCore} this
17423 * @param {String} html
17428 * Fires when the iframe editor is updated with content from the textarea.
17429 * @param {Roo.HtmlEditorCore} this
17430 * @param {String} html
17435 * @event editorevent
17436 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17437 * @param {Roo.HtmlEditorCore} this
17443 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17445 // defaults : white / black...
17446 this.applyBlacklists();
17453 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17457 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17463 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17468 * @cfg {Number} height (in pixels)
17472 * @cfg {Number} width (in pixels)
17477 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17480 stylesheets: false,
17485 // private properties
17486 validationEvent : false,
17488 initialized : false,
17490 sourceEditMode : false,
17491 onFocus : Roo.emptyFn,
17493 hideMode:'offsets',
17497 // blacklist + whitelisted elements..
17504 * Protected method that will not generally be called directly. It
17505 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17506 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17508 getDocMarkup : function(){
17512 // inherit styels from page...??
17513 if (this.stylesheets === false) {
17515 Roo.get(document.head).select('style').each(function(node) {
17516 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17519 Roo.get(document.head).select('link').each(function(node) {
17520 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17523 } else if (!this.stylesheets.length) {
17525 st = '<style type="text/css">' +
17526 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17532 st += '<style type="text/css">' +
17533 'IMG { cursor: pointer } ' +
17537 return '<html><head>' + st +
17538 //<style type="text/css">' +
17539 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17541 ' </head><body class="roo-htmleditor-body"></body></html>';
17545 onRender : function(ct, position)
17548 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17549 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17552 this.el.dom.style.border = '0 none';
17553 this.el.dom.setAttribute('tabIndex', -1);
17554 this.el.addClass('x-hidden hide');
17558 if(Roo.isIE){ // fix IE 1px bogus margin
17559 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17563 this.frameId = Roo.id();
17567 var iframe = this.owner.wrap.createChild({
17569 cls: 'form-control', // bootstrap..
17571 name: this.frameId,
17572 frameBorder : 'no',
17573 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17578 this.iframe = iframe.dom;
17580 this.assignDocWin();
17582 this.doc.designMode = 'on';
17585 this.doc.write(this.getDocMarkup());
17589 var task = { // must defer to wait for browser to be ready
17591 //console.log("run task?" + this.doc.readyState);
17592 this.assignDocWin();
17593 if(this.doc.body || this.doc.readyState == 'complete'){
17595 this.doc.designMode="on";
17599 Roo.TaskMgr.stop(task);
17600 this.initEditor.defer(10, this);
17607 Roo.TaskMgr.start(task);
17612 onResize : function(w, h)
17614 Roo.log('resize: ' +w + ',' + h );
17615 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17619 if(typeof w == 'number'){
17621 this.iframe.style.width = w + 'px';
17623 if(typeof h == 'number'){
17625 this.iframe.style.height = h + 'px';
17627 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17634 * Toggles the editor between standard and source edit mode.
17635 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17637 toggleSourceEdit : function(sourceEditMode){
17639 this.sourceEditMode = sourceEditMode === true;
17641 if(this.sourceEditMode){
17643 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17646 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17647 //this.iframe.className = '';
17650 //this.setSize(this.owner.wrap.getSize());
17651 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17658 * Protected method that will not generally be called directly. If you need/want
17659 * custom HTML cleanup, this is the method you should override.
17660 * @param {String} html The HTML to be cleaned
17661 * return {String} The cleaned HTML
17663 cleanHtml : function(html){
17664 html = String(html);
17665 if(html.length > 5){
17666 if(Roo.isSafari){ // strip safari nonsense
17667 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17670 if(html == ' '){
17677 * HTML Editor -> Textarea
17678 * Protected method that will not generally be called directly. Syncs the contents
17679 * of the editor iframe with the textarea.
17681 syncValue : function(){
17682 if(this.initialized){
17683 var bd = (this.doc.body || this.doc.documentElement);
17684 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17685 var html = bd.innerHTML;
17687 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17688 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17690 html = '<div style="'+m[0]+'">' + html + '</div>';
17693 html = this.cleanHtml(html);
17694 // fix up the special chars.. normaly like back quotes in word...
17695 // however we do not want to do this with chinese..
17696 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17697 var cc = b.charCodeAt();
17699 (cc >= 0x4E00 && cc < 0xA000 ) ||
17700 (cc >= 0x3400 && cc < 0x4E00 ) ||
17701 (cc >= 0xf900 && cc < 0xfb00 )
17707 if(this.owner.fireEvent('beforesync', this, html) !== false){
17708 this.el.dom.value = html;
17709 this.owner.fireEvent('sync', this, html);
17715 * Protected method that will not generally be called directly. Pushes the value of the textarea
17716 * into the iframe editor.
17718 pushValue : function(){
17719 if(this.initialized){
17720 var v = this.el.dom.value.trim();
17722 // if(v.length < 1){
17726 if(this.owner.fireEvent('beforepush', this, v) !== false){
17727 var d = (this.doc.body || this.doc.documentElement);
17729 this.cleanUpPaste();
17730 this.el.dom.value = d.innerHTML;
17731 this.owner.fireEvent('push', this, v);
17737 deferFocus : function(){
17738 this.focus.defer(10, this);
17742 focus : function(){
17743 if(this.win && !this.sourceEditMode){
17750 assignDocWin: function()
17752 var iframe = this.iframe;
17755 this.doc = iframe.contentWindow.document;
17756 this.win = iframe.contentWindow;
17758 // if (!Roo.get(this.frameId)) {
17761 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17762 // this.win = Roo.get(this.frameId).dom.contentWindow;
17764 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17768 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17769 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17774 initEditor : function(){
17775 //console.log("INIT EDITOR");
17776 this.assignDocWin();
17780 this.doc.designMode="on";
17782 this.doc.write(this.getDocMarkup());
17785 var dbody = (this.doc.body || this.doc.documentElement);
17786 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17787 // this copies styles from the containing element into thsi one..
17788 // not sure why we need all of this..
17789 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17791 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17792 //ss['background-attachment'] = 'fixed'; // w3c
17793 dbody.bgProperties = 'fixed'; // ie
17794 //Roo.DomHelper.applyStyles(dbody, ss);
17795 Roo.EventManager.on(this.doc, {
17796 //'mousedown': this.onEditorEvent,
17797 'mouseup': this.onEditorEvent,
17798 'dblclick': this.onEditorEvent,
17799 'click': this.onEditorEvent,
17800 'keyup': this.onEditorEvent,
17805 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17807 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17808 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17810 this.initialized = true;
17812 this.owner.fireEvent('initialize', this);
17817 onDestroy : function(){
17823 //for (var i =0; i < this.toolbars.length;i++) {
17824 // // fixme - ask toolbars for heights?
17825 // this.toolbars[i].onDestroy();
17828 //this.wrap.dom.innerHTML = '';
17829 //this.wrap.remove();
17834 onFirstFocus : function(){
17836 this.assignDocWin();
17839 this.activated = true;
17842 if(Roo.isGecko){ // prevent silly gecko errors
17844 var s = this.win.getSelection();
17845 if(!s.focusNode || s.focusNode.nodeType != 3){
17846 var r = s.getRangeAt(0);
17847 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17852 this.execCmd('useCSS', true);
17853 this.execCmd('styleWithCSS', false);
17856 this.owner.fireEvent('activate', this);
17860 adjustFont: function(btn){
17861 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17862 //if(Roo.isSafari){ // safari
17865 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17866 if(Roo.isSafari){ // safari
17867 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17868 v = (v < 10) ? 10 : v;
17869 v = (v > 48) ? 48 : v;
17870 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17875 v = Math.max(1, v+adjust);
17877 this.execCmd('FontSize', v );
17880 onEditorEvent : function(e){
17881 this.owner.fireEvent('editorevent', this, e);
17882 // this.updateToolbar();
17883 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17886 insertTag : function(tg)
17888 // could be a bit smarter... -> wrap the current selected tRoo..
17889 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17891 range = this.createRange(this.getSelection());
17892 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17893 wrappingNode.appendChild(range.extractContents());
17894 range.insertNode(wrappingNode);
17901 this.execCmd("formatblock", tg);
17905 insertText : function(txt)
17909 var range = this.createRange();
17910 range.deleteContents();
17911 //alert(Sender.getAttribute('label'));
17913 range.insertNode(this.doc.createTextNode(txt));
17919 * Executes a Midas editor command on the editor document and performs necessary focus and
17920 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17921 * @param {String} cmd The Midas command
17922 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17924 relayCmd : function(cmd, value){
17926 this.execCmd(cmd, value);
17927 this.owner.fireEvent('editorevent', this);
17928 //this.updateToolbar();
17929 this.owner.deferFocus();
17933 * Executes a Midas editor command directly on the editor document.
17934 * For visual commands, you should use {@link #relayCmd} instead.
17935 * <b>This should only be called after the editor is initialized.</b>
17936 * @param {String} cmd The Midas command
17937 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17939 execCmd : function(cmd, value){
17940 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17947 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17949 * @param {String} text | dom node..
17951 insertAtCursor : function(text)
17956 if(!this.activated){
17962 var r = this.doc.selection.createRange();
17973 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17977 // from jquery ui (MIT licenced)
17979 var win = this.win;
17981 if (win.getSelection && win.getSelection().getRangeAt) {
17982 range = win.getSelection().getRangeAt(0);
17983 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17984 range.insertNode(node);
17985 } else if (win.document.selection && win.document.selection.createRange) {
17986 // no firefox support
17987 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17988 win.document.selection.createRange().pasteHTML(txt);
17990 // no firefox support
17991 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17992 this.execCmd('InsertHTML', txt);
18001 mozKeyPress : function(e){
18003 var c = e.getCharCode(), cmd;
18006 c = String.fromCharCode(c).toLowerCase();
18020 this.cleanUpPaste.defer(100, this);
18028 e.preventDefault();
18036 fixKeys : function(){ // load time branching for fastest keydown performance
18038 return function(e){
18039 var k = e.getKey(), r;
18042 r = this.doc.selection.createRange();
18045 r.pasteHTML('    ');
18052 r = this.doc.selection.createRange();
18054 var target = r.parentElement();
18055 if(!target || target.tagName.toLowerCase() != 'li'){
18057 r.pasteHTML('<br />');
18063 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18064 this.cleanUpPaste.defer(100, this);
18070 }else if(Roo.isOpera){
18071 return function(e){
18072 var k = e.getKey();
18076 this.execCmd('InsertHTML','    ');
18079 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18080 this.cleanUpPaste.defer(100, this);
18085 }else if(Roo.isSafari){
18086 return function(e){
18087 var k = e.getKey();
18091 this.execCmd('InsertText','\t');
18095 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18096 this.cleanUpPaste.defer(100, this);
18104 getAllAncestors: function()
18106 var p = this.getSelectedNode();
18109 a.push(p); // push blank onto stack..
18110 p = this.getParentElement();
18114 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18118 a.push(this.doc.body);
18122 lastSelNode : false,
18125 getSelection : function()
18127 this.assignDocWin();
18128 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18131 getSelectedNode: function()
18133 // this may only work on Gecko!!!
18135 // should we cache this!!!!
18140 var range = this.createRange(this.getSelection()).cloneRange();
18143 var parent = range.parentElement();
18145 var testRange = range.duplicate();
18146 testRange.moveToElementText(parent);
18147 if (testRange.inRange(range)) {
18150 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18153 parent = parent.parentElement;
18158 // is ancestor a text element.
18159 var ac = range.commonAncestorContainer;
18160 if (ac.nodeType == 3) {
18161 ac = ac.parentNode;
18164 var ar = ac.childNodes;
18167 var other_nodes = [];
18168 var has_other_nodes = false;
18169 for (var i=0;i<ar.length;i++) {
18170 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18173 // fullly contained node.
18175 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18180 // probably selected..
18181 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18182 other_nodes.push(ar[i]);
18186 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18191 has_other_nodes = true;
18193 if (!nodes.length && other_nodes.length) {
18194 nodes= other_nodes;
18196 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18202 createRange: function(sel)
18204 // this has strange effects when using with
18205 // top toolbar - not sure if it's a great idea.
18206 //this.editor.contentWindow.focus();
18207 if (typeof sel != "undefined") {
18209 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18211 return this.doc.createRange();
18214 return this.doc.createRange();
18217 getParentElement: function()
18220 this.assignDocWin();
18221 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18223 var range = this.createRange(sel);
18226 var p = range.commonAncestorContainer;
18227 while (p.nodeType == 3) { // text node
18238 * Range intersection.. the hard stuff...
18242 * [ -- selected range --- ]
18246 * if end is before start or hits it. fail.
18247 * if start is after end or hits it fail.
18249 * if either hits (but other is outside. - then it's not
18255 // @see http://www.thismuchiknow.co.uk/?p=64.
18256 rangeIntersectsNode : function(range, node)
18258 var nodeRange = node.ownerDocument.createRange();
18260 nodeRange.selectNode(node);
18262 nodeRange.selectNodeContents(node);
18265 var rangeStartRange = range.cloneRange();
18266 rangeStartRange.collapse(true);
18268 var rangeEndRange = range.cloneRange();
18269 rangeEndRange.collapse(false);
18271 var nodeStartRange = nodeRange.cloneRange();
18272 nodeStartRange.collapse(true);
18274 var nodeEndRange = nodeRange.cloneRange();
18275 nodeEndRange.collapse(false);
18277 return rangeStartRange.compareBoundaryPoints(
18278 Range.START_TO_START, nodeEndRange) == -1 &&
18279 rangeEndRange.compareBoundaryPoints(
18280 Range.START_TO_START, nodeStartRange) == 1;
18284 rangeCompareNode : function(range, node)
18286 var nodeRange = node.ownerDocument.createRange();
18288 nodeRange.selectNode(node);
18290 nodeRange.selectNodeContents(node);
18294 range.collapse(true);
18296 nodeRange.collapse(true);
18298 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18299 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18301 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18303 var nodeIsBefore = ss == 1;
18304 var nodeIsAfter = ee == -1;
18306 if (nodeIsBefore && nodeIsAfter)
18308 if (!nodeIsBefore && nodeIsAfter)
18309 return 1; //right trailed.
18311 if (nodeIsBefore && !nodeIsAfter)
18312 return 2; // left trailed.
18317 // private? - in a new class?
18318 cleanUpPaste : function()
18320 // cleans up the whole document..
18321 Roo.log('cleanuppaste');
18323 this.cleanUpChildren(this.doc.body);
18324 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18325 if (clean != this.doc.body.innerHTML) {
18326 this.doc.body.innerHTML = clean;
18331 cleanWordChars : function(input) {// change the chars to hex code
18332 var he = Roo.HtmlEditorCore;
18334 var output = input;
18335 Roo.each(he.swapCodes, function(sw) {
18336 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18338 output = output.replace(swapper, sw[1]);
18345 cleanUpChildren : function (n)
18347 if (!n.childNodes.length) {
18350 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18351 this.cleanUpChild(n.childNodes[i]);
18358 cleanUpChild : function (node)
18361 //console.log(node);
18362 if (node.nodeName == "#text") {
18363 // clean up silly Windows -- stuff?
18366 if (node.nodeName == "#comment") {
18367 node.parentNode.removeChild(node);
18368 // clean up silly Windows -- stuff?
18371 var lcname = node.tagName.toLowerCase();
18372 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18373 // whitelist of tags..
18375 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18377 node.parentNode.removeChild(node);
18382 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18384 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18385 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18387 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18388 // remove_keep_children = true;
18391 if (remove_keep_children) {
18392 this.cleanUpChildren(node);
18393 // inserts everything just before this node...
18394 while (node.childNodes.length) {
18395 var cn = node.childNodes[0];
18396 node.removeChild(cn);
18397 node.parentNode.insertBefore(cn, node);
18399 node.parentNode.removeChild(node);
18403 if (!node.attributes || !node.attributes.length) {
18404 this.cleanUpChildren(node);
18408 function cleanAttr(n,v)
18411 if (v.match(/^\./) || v.match(/^\//)) {
18414 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18417 if (v.match(/^#/)) {
18420 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18421 node.removeAttribute(n);
18425 var cwhite = this.cwhite;
18426 var cblack = this.cblack;
18428 function cleanStyle(n,v)
18430 if (v.match(/expression/)) { //XSS?? should we even bother..
18431 node.removeAttribute(n);
18435 var parts = v.split(/;/);
18438 Roo.each(parts, function(p) {
18439 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18443 var l = p.split(':').shift().replace(/\s+/g,'');
18444 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18446 if ( cwhite.length && cblack.indexOf(l) > -1) {
18447 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18448 //node.removeAttribute(n);
18452 // only allow 'c whitelisted system attributes'
18453 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18454 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18455 //node.removeAttribute(n);
18465 if (clean.length) {
18466 node.setAttribute(n, clean.join(';'));
18468 node.removeAttribute(n);
18474 for (var i = node.attributes.length-1; i > -1 ; i--) {
18475 var a = node.attributes[i];
18478 if (a.name.toLowerCase().substr(0,2)=='on') {
18479 node.removeAttribute(a.name);
18482 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18483 node.removeAttribute(a.name);
18486 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18487 cleanAttr(a.name,a.value); // fixme..
18490 if (a.name == 'style') {
18491 cleanStyle(a.name,a.value);
18494 /// clean up MS crap..
18495 // tecnically this should be a list of valid class'es..
18498 if (a.name == 'class') {
18499 if (a.value.match(/^Mso/)) {
18500 node.className = '';
18503 if (a.value.match(/body/)) {
18504 node.className = '';
18515 this.cleanUpChildren(node);
18520 * Clean up MS wordisms...
18522 cleanWord : function(node)
18525 var cleanWordChildren = function()
18527 if (!node.childNodes.length) {
18530 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18531 _t.cleanWord(node.childNodes[i]);
18537 this.cleanWord(this.doc.body);
18540 if (node.nodeName == "#text") {
18541 // clean up silly Windows -- stuff?
18544 if (node.nodeName == "#comment") {
18545 node.parentNode.removeChild(node);
18546 // clean up silly Windows -- stuff?
18550 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18551 node.parentNode.removeChild(node);
18555 // remove - but keep children..
18556 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18557 while (node.childNodes.length) {
18558 var cn = node.childNodes[0];
18559 node.removeChild(cn);
18560 node.parentNode.insertBefore(cn, node);
18562 node.parentNode.removeChild(node);
18563 cleanWordChildren();
18567 if (node.className.length) {
18569 var cn = node.className.split(/\W+/);
18571 Roo.each(cn, function(cls) {
18572 if (cls.match(/Mso[a-zA-Z]+/)) {
18577 node.className = cna.length ? cna.join(' ') : '';
18579 node.removeAttribute("class");
18583 if (node.hasAttribute("lang")) {
18584 node.removeAttribute("lang");
18587 if (node.hasAttribute("style")) {
18589 var styles = node.getAttribute("style").split(";");
18591 Roo.each(styles, function(s) {
18592 if (!s.match(/:/)) {
18595 var kv = s.split(":");
18596 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18599 // what ever is left... we allow.
18602 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18603 if (!nstyle.length) {
18604 node.removeAttribute('style');
18608 cleanWordChildren();
18612 domToHTML : function(currentElement, depth, nopadtext) {
18614 depth = depth || 0;
18615 nopadtext = nopadtext || false;
18617 if (!currentElement) {
18618 return this.domToHTML(this.doc.body);
18621 //Roo.log(currentElement);
18623 var allText = false;
18624 var nodeName = currentElement.nodeName;
18625 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18627 if (nodeName == '#text') {
18629 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18634 if (nodeName != 'BODY') {
18637 // Prints the node tagName, such as <A>, <IMG>, etc
18640 for(i = 0; i < currentElement.attributes.length;i++) {
18642 var aname = currentElement.attributes.item(i).name;
18643 if (!currentElement.attributes.item(i).value.length) {
18646 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18649 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18658 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18661 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18666 // Traverse the tree
18668 var currentElementChild = currentElement.childNodes.item(i);
18669 var allText = true;
18670 var innerHTML = '';
18672 while (currentElementChild) {
18673 // Formatting code (indent the tree so it looks nice on the screen)
18674 var nopad = nopadtext;
18675 if (lastnode == 'SPAN') {
18679 if (currentElementChild.nodeName == '#text') {
18680 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18681 toadd = nopadtext ? toadd : toadd.trim();
18682 if (!nopad && toadd.length > 80) {
18683 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18685 innerHTML += toadd;
18688 currentElementChild = currentElement.childNodes.item(i);
18694 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18696 // Recursively traverse the tree structure of the child node
18697 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18698 lastnode = currentElementChild.nodeName;
18700 currentElementChild=currentElement.childNodes.item(i);
18706 // The remaining code is mostly for formatting the tree
18707 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18712 ret+= "</"+tagName+">";
18718 applyBlacklists : function()
18720 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18721 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18725 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18726 if (b.indexOf(tag) > -1) {
18729 this.white.push(tag);
18733 Roo.each(w, function(tag) {
18734 if (b.indexOf(tag) > -1) {
18737 if (this.white.indexOf(tag) > -1) {
18740 this.white.push(tag);
18745 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18746 if (w.indexOf(tag) > -1) {
18749 this.black.push(tag);
18753 Roo.each(b, function(tag) {
18754 if (w.indexOf(tag) > -1) {
18757 if (this.black.indexOf(tag) > -1) {
18760 this.black.push(tag);
18765 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18766 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18770 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18771 if (b.indexOf(tag) > -1) {
18774 this.cwhite.push(tag);
18778 Roo.each(w, function(tag) {
18779 if (b.indexOf(tag) > -1) {
18782 if (this.cwhite.indexOf(tag) > -1) {
18785 this.cwhite.push(tag);
18790 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18791 if (w.indexOf(tag) > -1) {
18794 this.cblack.push(tag);
18798 Roo.each(b, function(tag) {
18799 if (w.indexOf(tag) > -1) {
18802 if (this.cblack.indexOf(tag) > -1) {
18805 this.cblack.push(tag);
18810 setStylesheets : function(stylesheets)
18812 if(typeof(stylesheets) == 'string'){
18813 Roo.get(this.iframe.contentDocument.head).createChild({
18815 rel : 'stylesheet',
18824 Roo.each(stylesheets, function(s) {
18829 Roo.get(_this.iframe.contentDocument.head).createChild({
18831 rel : 'stylesheet',
18840 removeStylesheets : function()
18844 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18849 // hide stuff that is not compatible
18863 * @event specialkey
18867 * @cfg {String} fieldClass @hide
18870 * @cfg {String} focusClass @hide
18873 * @cfg {String} autoCreate @hide
18876 * @cfg {String} inputType @hide
18879 * @cfg {String} invalidClass @hide
18882 * @cfg {String} invalidText @hide
18885 * @cfg {String} msgFx @hide
18888 * @cfg {String} validateOnBlur @hide
18892 Roo.HtmlEditorCore.white = [
18893 'area', 'br', 'img', 'input', 'hr', 'wbr',
18895 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18896 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18897 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18898 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18899 'table', 'ul', 'xmp',
18901 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18904 'dir', 'menu', 'ol', 'ul', 'dl',
18910 Roo.HtmlEditorCore.black = [
18911 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18913 'base', 'basefont', 'bgsound', 'blink', 'body',
18914 'frame', 'frameset', 'head', 'html', 'ilayer',
18915 'iframe', 'layer', 'link', 'meta', 'object',
18916 'script', 'style' ,'title', 'xml' // clean later..
18918 Roo.HtmlEditorCore.clean = [
18919 'script', 'style', 'title', 'xml'
18921 Roo.HtmlEditorCore.remove = [
18926 Roo.HtmlEditorCore.ablack = [
18930 Roo.HtmlEditorCore.aclean = [
18931 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18935 Roo.HtmlEditorCore.pwhite= [
18936 'http', 'https', 'mailto'
18939 // white listed style attributes.
18940 Roo.HtmlEditorCore.cwhite= [
18941 // 'text-align', /// default is to allow most things..
18947 // black listed style attributes.
18948 Roo.HtmlEditorCore.cblack= [
18949 // 'font-size' -- this can be set by the project
18953 Roo.HtmlEditorCore.swapCodes =[
18972 * @class Roo.bootstrap.HtmlEditor
18973 * @extends Roo.bootstrap.TextArea
18974 * Bootstrap HtmlEditor class
18977 * Create a new HtmlEditor
18978 * @param {Object} config The config object
18981 Roo.bootstrap.HtmlEditor = function(config){
18982 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18983 if (!this.toolbars) {
18984 this.toolbars = [];
18986 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18989 * @event initialize
18990 * Fires when the editor is fully initialized (including the iframe)
18991 * @param {HtmlEditor} this
18996 * Fires when the editor is first receives the focus. Any insertion must wait
18997 * until after this event.
18998 * @param {HtmlEditor} this
19002 * @event beforesync
19003 * Fires before the textarea is updated with content from the editor iframe. Return false
19004 * to cancel the sync.
19005 * @param {HtmlEditor} this
19006 * @param {String} html
19010 * @event beforepush
19011 * Fires before the iframe editor is updated with content from the textarea. Return false
19012 * to cancel the push.
19013 * @param {HtmlEditor} this
19014 * @param {String} html
19019 * Fires when the textarea is updated with content from the editor iframe.
19020 * @param {HtmlEditor} this
19021 * @param {String} html
19026 * Fires when the iframe editor is updated with content from the textarea.
19027 * @param {HtmlEditor} this
19028 * @param {String} html
19032 * @event editmodechange
19033 * Fires when the editor switches edit modes
19034 * @param {HtmlEditor} this
19035 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19037 editmodechange: true,
19039 * @event editorevent
19040 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19041 * @param {HtmlEditor} this
19045 * @event firstfocus
19046 * Fires when on first focus - needed by toolbars..
19047 * @param {HtmlEditor} this
19052 * Auto save the htmlEditor value as a file into Events
19053 * @param {HtmlEditor} this
19057 * @event savedpreview
19058 * preview the saved version of htmlEditor
19059 * @param {HtmlEditor} this
19066 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19070 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19075 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19080 * @cfg {Number} height (in pixels)
19084 * @cfg {Number} width (in pixels)
19089 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19092 stylesheets: false,
19097 // private properties
19098 validationEvent : false,
19100 initialized : false,
19103 onFocus : Roo.emptyFn,
19105 hideMode:'offsets',
19108 tbContainer : false,
19110 toolbarContainer :function() {
19111 return this.wrap.select('.x-html-editor-tb',true).first();
19115 * Protected method that will not generally be called directly. It
19116 * is called when the editor creates its toolbar. Override this method if you need to
19117 * add custom toolbar buttons.
19118 * @param {HtmlEditor} editor
19120 createToolbar : function(){
19122 Roo.log("create toolbars");
19124 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19125 this.toolbars[0].render(this.toolbarContainer());
19129 // if (!editor.toolbars || !editor.toolbars.length) {
19130 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19133 // for (var i =0 ; i < editor.toolbars.length;i++) {
19134 // editor.toolbars[i] = Roo.factory(
19135 // typeof(editor.toolbars[i]) == 'string' ?
19136 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19137 // Roo.bootstrap.HtmlEditor);
19138 // editor.toolbars[i].init(editor);
19144 onRender : function(ct, position)
19146 // Roo.log("Call onRender: " + this.xtype);
19148 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19150 this.wrap = this.inputEl().wrap({
19151 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19154 this.editorcore.onRender(ct, position);
19156 if (this.resizable) {
19157 this.resizeEl = new Roo.Resizable(this.wrap, {
19161 minHeight : this.height,
19162 height: this.height,
19163 handles : this.resizable,
19166 resize : function(r, w, h) {
19167 _t.onResize(w,h); // -something
19173 this.createToolbar(this);
19176 if(!this.width && this.resizable){
19177 this.setSize(this.wrap.getSize());
19179 if (this.resizeEl) {
19180 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19181 // should trigger onReize..
19187 onResize : function(w, h)
19189 Roo.log('resize: ' +w + ',' + h );
19190 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19194 if(this.inputEl() ){
19195 if(typeof w == 'number'){
19196 var aw = w - this.wrap.getFrameWidth('lr');
19197 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19200 if(typeof h == 'number'){
19201 var tbh = -11; // fixme it needs to tool bar size!
19202 for (var i =0; i < this.toolbars.length;i++) {
19203 // fixme - ask toolbars for heights?
19204 tbh += this.toolbars[i].el.getHeight();
19205 //if (this.toolbars[i].footer) {
19206 // tbh += this.toolbars[i].footer.el.getHeight();
19214 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19215 ah -= 5; // knock a few pixes off for look..
19216 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19220 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19221 this.editorcore.onResize(ew,eh);
19226 * Toggles the editor between standard and source edit mode.
19227 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19229 toggleSourceEdit : function(sourceEditMode)
19231 this.editorcore.toggleSourceEdit(sourceEditMode);
19233 if(this.editorcore.sourceEditMode){
19234 Roo.log('editor - showing textarea');
19237 // Roo.log(this.syncValue());
19239 this.inputEl().removeClass(['hide', 'x-hidden']);
19240 this.inputEl().dom.removeAttribute('tabIndex');
19241 this.inputEl().focus();
19243 Roo.log('editor - hiding textarea');
19245 // Roo.log(this.pushValue());
19248 this.inputEl().addClass(['hide', 'x-hidden']);
19249 this.inputEl().dom.setAttribute('tabIndex', -1);
19250 //this.deferFocus();
19253 if(this.resizable){
19254 this.setSize(this.wrap.getSize());
19257 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19260 // private (for BoxComponent)
19261 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19263 // private (for BoxComponent)
19264 getResizeEl : function(){
19268 // private (for BoxComponent)
19269 getPositionEl : function(){
19274 initEvents : function(){
19275 this.originalValue = this.getValue();
19279 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19282 // markInvalid : Roo.emptyFn,
19284 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19287 // clearInvalid : Roo.emptyFn,
19289 setValue : function(v){
19290 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19291 this.editorcore.pushValue();
19296 deferFocus : function(){
19297 this.focus.defer(10, this);
19301 focus : function(){
19302 this.editorcore.focus();
19308 onDestroy : function(){
19314 for (var i =0; i < this.toolbars.length;i++) {
19315 // fixme - ask toolbars for heights?
19316 this.toolbars[i].onDestroy();
19319 this.wrap.dom.innerHTML = '';
19320 this.wrap.remove();
19325 onFirstFocus : function(){
19326 //Roo.log("onFirstFocus");
19327 this.editorcore.onFirstFocus();
19328 for (var i =0; i < this.toolbars.length;i++) {
19329 this.toolbars[i].onFirstFocus();
19335 syncValue : function()
19337 this.editorcore.syncValue();
19340 pushValue : function()
19342 this.editorcore.pushValue();
19346 // hide stuff that is not compatible
19360 * @event specialkey
19364 * @cfg {String} fieldClass @hide
19367 * @cfg {String} focusClass @hide
19370 * @cfg {String} autoCreate @hide
19373 * @cfg {String} inputType @hide
19376 * @cfg {String} invalidClass @hide
19379 * @cfg {String} invalidText @hide
19382 * @cfg {String} msgFx @hide
19385 * @cfg {String} validateOnBlur @hide
19394 Roo.namespace('Roo.bootstrap.htmleditor');
19396 * @class Roo.bootstrap.HtmlEditorToolbar1
19401 new Roo.bootstrap.HtmlEditor({
19404 new Roo.bootstrap.HtmlEditorToolbar1({
19405 disable : { fonts: 1 , format: 1, ..., ... , ...],
19411 * @cfg {Object} disable List of elements to disable..
19412 * @cfg {Array} btns List of additional buttons.
19416 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19419 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19422 Roo.apply(this, config);
19424 // default disabled, based on 'good practice'..
19425 this.disable = this.disable || {};
19426 Roo.applyIf(this.disable, {
19429 specialElements : true
19431 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19433 this.editor = config.editor;
19434 this.editorcore = config.editor.editorcore;
19436 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19438 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19439 // dont call parent... till later.
19441 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19446 editorcore : false,
19451 "h1","h2","h3","h4","h5","h6",
19453 "abbr", "acronym", "address", "cite", "samp", "var",
19457 onRender : function(ct, position)
19459 // Roo.log("Call onRender: " + this.xtype);
19461 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19463 this.el.dom.style.marginBottom = '0';
19465 var editorcore = this.editorcore;
19466 var editor= this.editor;
19469 var btn = function(id,cmd , toggle, handler){
19471 var event = toggle ? 'toggle' : 'click';
19476 xns: Roo.bootstrap,
19479 enableToggle:toggle !== false,
19481 pressed : toggle ? false : null,
19484 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19485 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19494 xns: Roo.bootstrap,
19495 glyphicon : 'font',
19499 xns: Roo.bootstrap,
19503 Roo.each(this.formats, function(f) {
19504 style.menu.items.push({
19506 xns: Roo.bootstrap,
19507 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19512 editorcore.insertTag(this.tagname);
19519 children.push(style);
19522 btn('bold',false,true);
19523 btn('italic',false,true);
19524 btn('align-left', 'justifyleft',true);
19525 btn('align-center', 'justifycenter',true);
19526 btn('align-right' , 'justifyright',true);
19527 btn('link', false, false, function(btn) {
19528 //Roo.log("create link?");
19529 var url = prompt(this.createLinkText, this.defaultLinkValue);
19530 if(url && url != 'http:/'+'/'){
19531 this.editorcore.relayCmd('createlink', url);
19534 btn('list','insertunorderedlist',true);
19535 btn('pencil', false,true, function(btn){
19538 this.toggleSourceEdit(btn.pressed);
19544 xns: Roo.bootstrap,
19549 xns: Roo.bootstrap,
19554 cog.menu.items.push({
19556 xns: Roo.bootstrap,
19557 html : Clean styles,
19562 editorcore.insertTag(this.tagname);
19571 this.xtype = 'NavSimplebar';
19573 for(var i=0;i< children.length;i++) {
19575 this.buttons.add(this.addxtypeChild(children[i]));
19579 editor.on('editorevent', this.updateToolbar, this);
19581 onBtnClick : function(id)
19583 this.editorcore.relayCmd(id);
19584 this.editorcore.focus();
19588 * Protected method that will not generally be called directly. It triggers
19589 * a toolbar update by reading the markup state of the current selection in the editor.
19591 updateToolbar: function(){
19593 if(!this.editorcore.activated){
19594 this.editor.onFirstFocus(); // is this neeed?
19598 var btns = this.buttons;
19599 var doc = this.editorcore.doc;
19600 btns.get('bold').setActive(doc.queryCommandState('bold'));
19601 btns.get('italic').setActive(doc.queryCommandState('italic'));
19602 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19604 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19605 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19606 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19608 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19609 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19612 var ans = this.editorcore.getAllAncestors();
19613 if (this.formatCombo) {
19616 var store = this.formatCombo.store;
19617 this.formatCombo.setValue("");
19618 for (var i =0; i < ans.length;i++) {
19619 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19621 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19629 // hides menus... - so this cant be on a menu...
19630 Roo.bootstrap.MenuMgr.hideAll();
19632 Roo.bootstrap.MenuMgr.hideAll();
19633 //this.editorsyncValue();
19635 onFirstFocus: function() {
19636 this.buttons.each(function(item){
19640 toggleSourceEdit : function(sourceEditMode){
19643 if(sourceEditMode){
19644 Roo.log("disabling buttons");
19645 this.buttons.each( function(item){
19646 if(item.cmd != 'pencil'){
19652 Roo.log("enabling buttons");
19653 if(this.editorcore.initialized){
19654 this.buttons.each( function(item){
19660 Roo.log("calling toggole on editor");
19661 // tell the editor that it's been pressed..
19662 this.editor.toggleSourceEdit(sourceEditMode);
19672 * @class Roo.bootstrap.Table.AbstractSelectionModel
19673 * @extends Roo.util.Observable
19674 * Abstract base class for grid SelectionModels. It provides the interface that should be
19675 * implemented by descendant classes. This class should not be directly instantiated.
19678 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19679 this.locked = false;
19680 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19684 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19685 /** @ignore Called by the grid automatically. Do not call directly. */
19686 init : function(grid){
19692 * Locks the selections.
19695 this.locked = true;
19699 * Unlocks the selections.
19701 unlock : function(){
19702 this.locked = false;
19706 * Returns true if the selections are locked.
19707 * @return {Boolean}
19709 isLocked : function(){
19710 return this.locked;
19714 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19715 * @class Roo.bootstrap.Table.RowSelectionModel
19716 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19717 * It supports multiple selections and keyboard selection/navigation.
19719 * @param {Object} config
19722 Roo.bootstrap.Table.RowSelectionModel = function(config){
19723 Roo.apply(this, config);
19724 this.selections = new Roo.util.MixedCollection(false, function(o){
19729 this.lastActive = false;
19733 * @event selectionchange
19734 * Fires when the selection changes
19735 * @param {SelectionModel} this
19737 "selectionchange" : true,
19739 * @event afterselectionchange
19740 * Fires after the selection changes (eg. by key press or clicking)
19741 * @param {SelectionModel} this
19743 "afterselectionchange" : true,
19745 * @event beforerowselect
19746 * Fires when a row is selected being selected, return false to cancel.
19747 * @param {SelectionModel} this
19748 * @param {Number} rowIndex The selected index
19749 * @param {Boolean} keepExisting False if other selections will be cleared
19751 "beforerowselect" : true,
19754 * Fires when a row is selected.
19755 * @param {SelectionModel} this
19756 * @param {Number} rowIndex The selected index
19757 * @param {Roo.data.Record} r The record
19759 "rowselect" : true,
19761 * @event rowdeselect
19762 * Fires when a row is deselected.
19763 * @param {SelectionModel} this
19764 * @param {Number} rowIndex The selected index
19766 "rowdeselect" : true
19768 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19769 this.locked = false;
19772 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19774 * @cfg {Boolean} singleSelect
19775 * True to allow selection of only one row at a time (defaults to false)
19777 singleSelect : false,
19780 initEvents : function(){
19782 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19783 this.grid.on("mousedown", this.handleMouseDown, this);
19784 }else{ // allow click to work like normal
19785 this.grid.on("rowclick", this.handleDragableRowClick, this);
19788 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19789 "up" : function(e){
19791 this.selectPrevious(e.shiftKey);
19792 }else if(this.last !== false && this.lastActive !== false){
19793 var last = this.last;
19794 this.selectRange(this.last, this.lastActive-1);
19795 this.grid.getView().focusRow(this.lastActive);
19796 if(last !== false){
19800 this.selectFirstRow();
19802 this.fireEvent("afterselectionchange", this);
19804 "down" : function(e){
19806 this.selectNext(e.shiftKey);
19807 }else if(this.last !== false && this.lastActive !== false){
19808 var last = this.last;
19809 this.selectRange(this.last, this.lastActive+1);
19810 this.grid.getView().focusRow(this.lastActive);
19811 if(last !== false){
19815 this.selectFirstRow();
19817 this.fireEvent("afterselectionchange", this);
19822 var view = this.grid.view;
19823 view.on("refresh", this.onRefresh, this);
19824 view.on("rowupdated", this.onRowUpdated, this);
19825 view.on("rowremoved", this.onRemove, this);
19829 onRefresh : function(){
19830 var ds = this.grid.dataSource, i, v = this.grid.view;
19831 var s = this.selections;
19832 s.each(function(r){
19833 if((i = ds.indexOfId(r.id)) != -1){
19842 onRemove : function(v, index, r){
19843 this.selections.remove(r);
19847 onRowUpdated : function(v, index, r){
19848 if(this.isSelected(r)){
19849 v.onRowSelect(index);
19855 * @param {Array} records The records to select
19856 * @param {Boolean} keepExisting (optional) True to keep existing selections
19858 selectRecords : function(records, keepExisting){
19860 this.clearSelections();
19862 var ds = this.grid.dataSource;
19863 for(var i = 0, len = records.length; i < len; i++){
19864 this.selectRow(ds.indexOf(records[i]), true);
19869 * Gets the number of selected rows.
19872 getCount : function(){
19873 return this.selections.length;
19877 * Selects the first row in the grid.
19879 selectFirstRow : function(){
19884 * Select the last row.
19885 * @param {Boolean} keepExisting (optional) True to keep existing selections
19887 selectLastRow : function(keepExisting){
19888 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19892 * Selects the row immediately following the last selected row.
19893 * @param {Boolean} keepExisting (optional) True to keep existing selections
19895 selectNext : function(keepExisting){
19896 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19897 this.selectRow(this.last+1, keepExisting);
19898 this.grid.getView().focusRow(this.last);
19903 * Selects the row that precedes the last selected row.
19904 * @param {Boolean} keepExisting (optional) True to keep existing selections
19906 selectPrevious : function(keepExisting){
19908 this.selectRow(this.last-1, keepExisting);
19909 this.grid.getView().focusRow(this.last);
19914 * Returns the selected records
19915 * @return {Array} Array of selected records
19917 getSelections : function(){
19918 return [].concat(this.selections.items);
19922 * Returns the first selected record.
19925 getSelected : function(){
19926 return this.selections.itemAt(0);
19931 * Clears all selections.
19933 clearSelections : function(fast){
19934 if(this.locked) return;
19936 var ds = this.grid.dataSource;
19937 var s = this.selections;
19938 s.each(function(r){
19939 this.deselectRow(ds.indexOfId(r.id));
19943 this.selections.clear();
19950 * Selects all rows.
19952 selectAll : function(){
19953 if(this.locked) return;
19954 this.selections.clear();
19955 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19956 this.selectRow(i, true);
19961 * Returns True if there is a selection.
19962 * @return {Boolean}
19964 hasSelection : function(){
19965 return this.selections.length > 0;
19969 * Returns True if the specified row is selected.
19970 * @param {Number/Record} record The record or index of the record to check
19971 * @return {Boolean}
19973 isSelected : function(index){
19974 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19975 return (r && this.selections.key(r.id) ? true : false);
19979 * Returns True if the specified record id is selected.
19980 * @param {String} id The id of record to check
19981 * @return {Boolean}
19983 isIdSelected : function(id){
19984 return (this.selections.key(id) ? true : false);
19988 handleMouseDown : function(e, t){
19989 var view = this.grid.getView(), rowIndex;
19990 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19993 if(e.shiftKey && this.last !== false){
19994 var last = this.last;
19995 this.selectRange(last, rowIndex, e.ctrlKey);
19996 this.last = last; // reset the last
19997 view.focusRow(rowIndex);
19999 var isSelected = this.isSelected(rowIndex);
20000 if(e.button !== 0 && isSelected){
20001 view.focusRow(rowIndex);
20002 }else if(e.ctrlKey && isSelected){
20003 this.deselectRow(rowIndex);
20004 }else if(!isSelected){
20005 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20006 view.focusRow(rowIndex);
20009 this.fireEvent("afterselectionchange", this);
20012 handleDragableRowClick : function(grid, rowIndex, e)
20014 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20015 this.selectRow(rowIndex, false);
20016 grid.view.focusRow(rowIndex);
20017 this.fireEvent("afterselectionchange", this);
20022 * Selects multiple rows.
20023 * @param {Array} rows Array of the indexes of the row to select
20024 * @param {Boolean} keepExisting (optional) True to keep existing selections
20026 selectRows : function(rows, keepExisting){
20028 this.clearSelections();
20030 for(var i = 0, len = rows.length; i < len; i++){
20031 this.selectRow(rows[i], true);
20036 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20037 * @param {Number} startRow The index of the first row in the range
20038 * @param {Number} endRow The index of the last row in the range
20039 * @param {Boolean} keepExisting (optional) True to retain existing selections
20041 selectRange : function(startRow, endRow, keepExisting){
20042 if(this.locked) return;
20044 this.clearSelections();
20046 if(startRow <= endRow){
20047 for(var i = startRow; i <= endRow; i++){
20048 this.selectRow(i, true);
20051 for(var i = startRow; i >= endRow; i--){
20052 this.selectRow(i, true);
20058 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20059 * @param {Number} startRow The index of the first row in the range
20060 * @param {Number} endRow The index of the last row in the range
20062 deselectRange : function(startRow, endRow, preventViewNotify){
20063 if(this.locked) return;
20064 for(var i = startRow; i <= endRow; i++){
20065 this.deselectRow(i, preventViewNotify);
20071 * @param {Number} row The index of the row to select
20072 * @param {Boolean} keepExisting (optional) True to keep existing selections
20074 selectRow : function(index, keepExisting, preventViewNotify){
20075 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20076 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20077 if(!keepExisting || this.singleSelect){
20078 this.clearSelections();
20080 var r = this.grid.dataSource.getAt(index);
20081 this.selections.add(r);
20082 this.last = this.lastActive = index;
20083 if(!preventViewNotify){
20084 this.grid.getView().onRowSelect(index);
20086 this.fireEvent("rowselect", this, index, r);
20087 this.fireEvent("selectionchange", this);
20093 * @param {Number} row The index of the row to deselect
20095 deselectRow : function(index, preventViewNotify){
20096 if(this.locked) return;
20097 if(this.last == index){
20100 if(this.lastActive == index){
20101 this.lastActive = false;
20103 var r = this.grid.dataSource.getAt(index);
20104 this.selections.remove(r);
20105 if(!preventViewNotify){
20106 this.grid.getView().onRowDeselect(index);
20108 this.fireEvent("rowdeselect", this, index);
20109 this.fireEvent("selectionchange", this);
20113 restoreLast : function(){
20115 this.last = this._last;
20120 acceptsNav : function(row, col, cm){
20121 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20125 onEditorKey : function(field, e){
20126 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20131 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20133 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20135 }else if(k == e.ENTER && !e.ctrlKey){
20139 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20141 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20143 }else if(k == e.ESC){
20147 g.startEditing(newCell[0], newCell[1]);
20152 * Ext JS Library 1.1.1
20153 * Copyright(c) 2006-2007, Ext JS, LLC.
20155 * Originally Released Under LGPL - original licence link has changed is not relivant.
20158 * <script type="text/javascript">
20162 * @class Roo.bootstrap.PagingToolbar
20164 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20166 * Create a new PagingToolbar
20167 * @param {Object} config The config object
20169 Roo.bootstrap.PagingToolbar = function(config)
20171 // old args format still supported... - xtype is prefered..
20172 // created from xtype...
20173 var ds = config.dataSource;
20174 this.toolbarItems = [];
20175 if (config.items) {
20176 this.toolbarItems = config.items;
20177 // config.items = [];
20180 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20187 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20191 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20193 * @cfg {Roo.data.Store} dataSource
20194 * The underlying data store providing the paged data
20197 * @cfg {String/HTMLElement/Element} container
20198 * container The id or element that will contain the toolbar
20201 * @cfg {Boolean} displayInfo
20202 * True to display the displayMsg (defaults to false)
20205 * @cfg {Number} pageSize
20206 * The number of records to display per page (defaults to 20)
20210 * @cfg {String} displayMsg
20211 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20213 displayMsg : 'Displaying {0} - {1} of {2}',
20215 * @cfg {String} emptyMsg
20216 * The message to display when no records are found (defaults to "No data to display")
20218 emptyMsg : 'No data to display',
20220 * Customizable piece of the default paging text (defaults to "Page")
20223 beforePageText : "Page",
20225 * Customizable piece of the default paging text (defaults to "of %0")
20228 afterPageText : "of {0}",
20230 * Customizable piece of the default paging text (defaults to "First Page")
20233 firstText : "First Page",
20235 * Customizable piece of the default paging text (defaults to "Previous Page")
20238 prevText : "Previous Page",
20240 * Customizable piece of the default paging text (defaults to "Next Page")
20243 nextText : "Next Page",
20245 * Customizable piece of the default paging text (defaults to "Last Page")
20248 lastText : "Last Page",
20250 * Customizable piece of the default paging text (defaults to "Refresh")
20253 refreshText : "Refresh",
20257 onRender : function(ct, position)
20259 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20260 this.navgroup.parentId = this.id;
20261 this.navgroup.onRender(this.el, null);
20262 // add the buttons to the navgroup
20264 if(this.displayInfo){
20265 Roo.log(this.el.select('ul.navbar-nav',true).first());
20266 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20267 this.displayEl = this.el.select('.x-paging-info', true).first();
20268 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20269 // this.displayEl = navel.el.select('span',true).first();
20275 Roo.each(_this.buttons, function(e){
20276 Roo.factory(e).onRender(_this.el, null);
20280 Roo.each(_this.toolbarItems, function(e) {
20281 _this.navgroup.addItem(e);
20285 this.first = this.navgroup.addItem({
20286 tooltip: this.firstText,
20288 icon : 'fa fa-backward',
20290 preventDefault: true,
20291 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20294 this.prev = this.navgroup.addItem({
20295 tooltip: this.prevText,
20297 icon : 'fa fa-step-backward',
20299 preventDefault: true,
20300 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20302 //this.addSeparator();
20305 var field = this.navgroup.addItem( {
20307 cls : 'x-paging-position',
20309 html : this.beforePageText +
20310 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20311 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20314 this.field = field.el.select('input', true).first();
20315 this.field.on("keydown", this.onPagingKeydown, this);
20316 this.field.on("focus", function(){this.dom.select();});
20319 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20320 //this.field.setHeight(18);
20321 //this.addSeparator();
20322 this.next = this.navgroup.addItem({
20323 tooltip: this.nextText,
20325 html : ' <i class="fa fa-step-forward">',
20327 preventDefault: true,
20328 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20330 this.last = this.navgroup.addItem({
20331 tooltip: this.lastText,
20332 icon : 'fa fa-forward',
20335 preventDefault: true,
20336 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20338 //this.addSeparator();
20339 this.loading = this.navgroup.addItem({
20340 tooltip: this.refreshText,
20341 icon: 'fa fa-refresh',
20342 preventDefault: true,
20343 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20349 updateInfo : function(){
20350 if(this.displayEl){
20351 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20352 var msg = count == 0 ?
20356 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20358 this.displayEl.update(msg);
20363 onLoad : function(ds, r, o){
20364 this.cursor = o.params ? o.params.start : 0;
20365 var d = this.getPageData(),
20369 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20370 this.field.dom.value = ap;
20371 this.first.setDisabled(ap == 1);
20372 this.prev.setDisabled(ap == 1);
20373 this.next.setDisabled(ap == ps);
20374 this.last.setDisabled(ap == ps);
20375 this.loading.enable();
20380 getPageData : function(){
20381 var total = this.ds.getTotalCount();
20384 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20385 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20390 onLoadError : function(){
20391 this.loading.enable();
20395 onPagingKeydown : function(e){
20396 var k = e.getKey();
20397 var d = this.getPageData();
20399 var v = this.field.dom.value, pageNum;
20400 if(!v || isNaN(pageNum = parseInt(v, 10))){
20401 this.field.dom.value = d.activePage;
20404 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20405 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20408 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))
20410 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20411 this.field.dom.value = pageNum;
20412 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20415 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20417 var v = this.field.dom.value, pageNum;
20418 var increment = (e.shiftKey) ? 10 : 1;
20419 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20421 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20422 this.field.dom.value = d.activePage;
20425 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20427 this.field.dom.value = parseInt(v, 10) + increment;
20428 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20429 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20436 beforeLoad : function(){
20438 this.loading.disable();
20443 onClick : function(which){
20452 ds.load({params:{start: 0, limit: this.pageSize}});
20455 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20458 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20461 var total = ds.getTotalCount();
20462 var extra = total % this.pageSize;
20463 var lastStart = extra ? (total - extra) : total-this.pageSize;
20464 ds.load({params:{start: lastStart, limit: this.pageSize}});
20467 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20473 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20474 * @param {Roo.data.Store} store The data store to unbind
20476 unbind : function(ds){
20477 ds.un("beforeload", this.beforeLoad, this);
20478 ds.un("load", this.onLoad, this);
20479 ds.un("loadexception", this.onLoadError, this);
20480 ds.un("remove", this.updateInfo, this);
20481 ds.un("add", this.updateInfo, this);
20482 this.ds = undefined;
20486 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20487 * @param {Roo.data.Store} store The data store to bind
20489 bind : function(ds){
20490 ds.on("beforeload", this.beforeLoad, this);
20491 ds.on("load", this.onLoad, this);
20492 ds.on("loadexception", this.onLoadError, this);
20493 ds.on("remove", this.updateInfo, this);
20494 ds.on("add", this.updateInfo, this);
20505 * @class Roo.bootstrap.MessageBar
20506 * @extends Roo.bootstrap.Component
20507 * Bootstrap MessageBar class
20508 * @cfg {String} html contents of the MessageBar
20509 * @cfg {String} weight (info | success | warning | danger) default info
20510 * @cfg {String} beforeClass insert the bar before the given class
20511 * @cfg {Boolean} closable (true | false) default false
20512 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20515 * Create a new Element
20516 * @param {Object} config The config object
20519 Roo.bootstrap.MessageBar = function(config){
20520 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20523 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20529 beforeClass: 'bootstrap-sticky-wrap',
20531 getAutoCreate : function(){
20535 cls: 'alert alert-dismissable alert-' + this.weight,
20540 html: this.html || ''
20546 cfg.cls += ' alert-messages-fixed';
20560 onRender : function(ct, position)
20562 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20565 var cfg = Roo.apply({}, this.getAutoCreate());
20569 cfg.cls += ' ' + this.cls;
20572 cfg.style = this.style;
20574 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20576 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20579 this.el.select('>button.close').on('click', this.hide, this);
20585 if (!this.rendered) {
20591 this.fireEvent('show', this);
20597 if (!this.rendered) {
20603 this.fireEvent('hide', this);
20606 update : function()
20608 // var e = this.el.dom.firstChild;
20610 // if(this.closable){
20611 // e = e.nextSibling;
20614 // e.data = this.html || '';
20616 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20632 * @class Roo.bootstrap.Graph
20633 * @extends Roo.bootstrap.Component
20634 * Bootstrap Graph class
20638 @cfg {String} graphtype bar | vbar | pie
20639 @cfg {number} g_x coodinator | centre x (pie)
20640 @cfg {number} g_y coodinator | centre y (pie)
20641 @cfg {number} g_r radius (pie)
20642 @cfg {number} g_height height of the chart (respected by all elements in the set)
20643 @cfg {number} g_width width of the chart (respected by all elements in the set)
20644 @cfg {Object} title The title of the chart
20647 -opts (object) options for the chart
20649 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20650 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20652 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.
20653 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20655 o stretch (boolean)
20657 -opts (object) options for the pie
20660 o startAngle (number)
20661 o endAngle (number)
20665 * Create a new Input
20666 * @param {Object} config The config object
20669 Roo.bootstrap.Graph = function(config){
20670 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20676 * The img click event for the img.
20677 * @param {Roo.EventObject} e
20683 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20694 //g_colors: this.colors,
20701 getAutoCreate : function(){
20712 onRender : function(ct,position){
20713 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20714 this.raphael = Raphael(this.el.dom);
20716 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20717 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20718 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20719 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20721 r.text(160, 10, "Single Series Chart").attr(txtattr);
20722 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20723 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20724 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20726 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20727 r.barchart(330, 10, 300, 220, data1);
20728 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20729 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20732 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20733 // r.barchart(30, 30, 560, 250, xdata, {
20734 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20735 // axis : "0 0 1 1",
20736 // axisxlabels : xdata
20737 // //yvalues : cols,
20740 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20742 // this.load(null,xdata,{
20743 // axis : "0 0 1 1",
20744 // axisxlabels : xdata
20749 load : function(graphtype,xdata,opts){
20750 this.raphael.clear();
20752 graphtype = this.graphtype;
20757 var r = this.raphael,
20758 fin = function () {
20759 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20761 fout = function () {
20762 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20764 pfin = function() {
20765 this.sector.stop();
20766 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20769 this.label[0].stop();
20770 this.label[0].attr({ r: 7.5 });
20771 this.label[1].attr({ "font-weight": 800 });
20774 pfout = function() {
20775 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20778 this.label[0].animate({ r: 5 }, 500, "bounce");
20779 this.label[1].attr({ "font-weight": 400 });
20785 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20788 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20791 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20792 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20794 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20801 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20806 setTitle: function(o)
20811 initEvents: function() {
20814 this.el.on('click', this.onClick, this);
20818 onClick : function(e)
20820 Roo.log('img onclick');
20821 this.fireEvent('click', this, e);
20833 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20836 * @class Roo.bootstrap.dash.NumberBox
20837 * @extends Roo.bootstrap.Component
20838 * Bootstrap NumberBox class
20839 * @cfg {String} headline Box headline
20840 * @cfg {String} content Box content
20841 * @cfg {String} icon Box icon
20842 * @cfg {String} footer Footer text
20843 * @cfg {String} fhref Footer href
20846 * Create a new NumberBox
20847 * @param {Object} config The config object
20851 Roo.bootstrap.dash.NumberBox = function(config){
20852 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20856 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20865 getAutoCreate : function(){
20869 cls : 'small-box ',
20877 cls : 'roo-headline',
20878 html : this.headline
20882 cls : 'roo-content',
20883 html : this.content
20897 cls : 'ion ' + this.icon
20906 cls : 'small-box-footer',
20907 href : this.fhref || '#',
20911 cfg.cn.push(footer);
20918 onRender : function(ct,position){
20919 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20926 setHeadline: function (value)
20928 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20931 setFooter: function (value, href)
20933 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20936 this.el.select('a.small-box-footer',true).first().attr('href', href);
20941 setContent: function (value)
20943 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20946 initEvents: function()
20960 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20963 * @class Roo.bootstrap.dash.TabBox
20964 * @extends Roo.bootstrap.Component
20965 * Bootstrap TabBox class
20966 * @cfg {String} title Title of the TabBox
20967 * @cfg {String} icon Icon of the TabBox
20968 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20969 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20972 * Create a new TabBox
20973 * @param {Object} config The config object
20977 Roo.bootstrap.dash.TabBox = function(config){
20978 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20983 * When a pane is added
20984 * @param {Roo.bootstrap.dash.TabPane} pane
20988 * @event activatepane
20989 * When a pane is activated
20990 * @param {Roo.bootstrap.dash.TabPane} pane
20992 "activatepane" : true
21000 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21005 tabScrollable : false,
21007 getChildContainer : function()
21009 return this.el.select('.tab-content', true).first();
21012 getAutoCreate : function(){
21016 cls: 'pull-left header',
21024 cls: 'fa ' + this.icon
21030 cls: 'nav nav-tabs pull-right',
21036 if(this.tabScrollable){
21043 cls: 'nav nav-tabs pull-right',
21054 cls: 'nav-tabs-custom',
21059 cls: 'tab-content no-padding',
21067 initEvents : function()
21069 //Roo.log('add add pane handler');
21070 this.on('addpane', this.onAddPane, this);
21073 * Updates the box title
21074 * @param {String} html to set the title to.
21076 setTitle : function(value)
21078 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21080 onAddPane : function(pane)
21082 this.panes.push(pane);
21083 //Roo.log('addpane');
21085 // tabs are rendere left to right..
21086 if(!this.showtabs){
21090 var ctr = this.el.select('.nav-tabs', true).first();
21093 var existing = ctr.select('.nav-tab',true);
21094 var qty = existing.getCount();;
21097 var tab = ctr.createChild({
21099 cls : 'nav-tab' + (qty ? '' : ' active'),
21107 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21110 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21112 pane.el.addClass('active');
21117 onTabClick : function(ev,un,ob,pane)
21119 //Roo.log('tab - prev default');
21120 ev.preventDefault();
21123 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21124 pane.tab.addClass('active');
21125 //Roo.log(pane.title);
21126 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21127 // technically we should have a deactivate event.. but maybe add later.
21128 // and it should not de-activate the selected tab...
21129 this.fireEvent('activatepane', pane);
21130 pane.el.addClass('active');
21131 pane.fireEvent('activate');
21136 getActivePane : function()
21139 Roo.each(this.panes, function(p) {
21140 if(p.el.hasClass('active')){
21161 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21163 * @class Roo.bootstrap.TabPane
21164 * @extends Roo.bootstrap.Component
21165 * Bootstrap TabPane class
21166 * @cfg {Boolean} active (false | true) Default false
21167 * @cfg {String} title title of panel
21171 * Create a new TabPane
21172 * @param {Object} config The config object
21175 Roo.bootstrap.dash.TabPane = function(config){
21176 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21182 * When a pane is activated
21183 * @param {Roo.bootstrap.dash.TabPane} pane
21190 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21195 // the tabBox that this is attached to.
21198 getAutoCreate : function()
21206 cfg.cls += ' active';
21211 initEvents : function()
21213 //Roo.log('trigger add pane handler');
21214 this.parent().fireEvent('addpane', this)
21218 * Updates the tab title
21219 * @param {String} html to set the title to.
21221 setTitle: function(str)
21227 this.tab.select('a', true).first().dom.innerHTML = str;
21244 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21247 * @class Roo.bootstrap.menu.Menu
21248 * @extends Roo.bootstrap.Component
21249 * Bootstrap Menu class - container for Menu
21250 * @cfg {String} html Text of the menu
21251 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21252 * @cfg {String} icon Font awesome icon
21253 * @cfg {String} pos Menu align to (top | bottom) default bottom
21257 * Create a new Menu
21258 * @param {Object} config The config object
21262 Roo.bootstrap.menu.Menu = function(config){
21263 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21267 * @event beforeshow
21268 * Fires before this menu is displayed
21269 * @param {Roo.bootstrap.menu.Menu} this
21273 * @event beforehide
21274 * Fires before this menu is hidden
21275 * @param {Roo.bootstrap.menu.Menu} this
21280 * Fires after this menu is displayed
21281 * @param {Roo.bootstrap.menu.Menu} this
21286 * Fires after this menu is hidden
21287 * @param {Roo.bootstrap.menu.Menu} this
21292 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21293 * @param {Roo.bootstrap.menu.Menu} this
21294 * @param {Roo.EventObject} e
21301 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21305 weight : 'default',
21310 getChildContainer : function() {
21311 if(this.isSubMenu){
21315 return this.el.select('ul.dropdown-menu', true).first();
21318 getAutoCreate : function()
21323 cls : 'roo-menu-text',
21331 cls : 'fa ' + this.icon
21342 cls : 'dropdown-button btn btn-' + this.weight,
21347 cls : 'dropdown-toggle btn btn-' + this.weight,
21357 cls : 'dropdown-menu'
21363 if(this.pos == 'top'){
21364 cfg.cls += ' dropup';
21367 if(this.isSubMenu){
21370 cls : 'dropdown-menu'
21377 onRender : function(ct, position)
21379 this.isSubMenu = ct.hasClass('dropdown-submenu');
21381 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21384 initEvents : function()
21386 if(this.isSubMenu){
21390 this.hidden = true;
21392 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21393 this.triggerEl.on('click', this.onTriggerPress, this);
21395 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21396 this.buttonEl.on('click', this.onClick, this);
21402 if(this.isSubMenu){
21406 return this.el.select('ul.dropdown-menu', true).first();
21409 onClick : function(e)
21411 this.fireEvent("click", this, e);
21414 onTriggerPress : function(e)
21416 if (this.isVisible()) {
21423 isVisible : function(){
21424 return !this.hidden;
21429 this.fireEvent("beforeshow", this);
21431 this.hidden = false;
21432 this.el.addClass('open');
21434 Roo.get(document).on("mouseup", this.onMouseUp, this);
21436 this.fireEvent("show", this);
21443 this.fireEvent("beforehide", this);
21445 this.hidden = true;
21446 this.el.removeClass('open');
21448 Roo.get(document).un("mouseup", this.onMouseUp);
21450 this.fireEvent("hide", this);
21453 onMouseUp : function()
21467 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21470 * @class Roo.bootstrap.menu.Item
21471 * @extends Roo.bootstrap.Component
21472 * Bootstrap MenuItem class
21473 * @cfg {Boolean} submenu (true | false) default false
21474 * @cfg {String} html text of the item
21475 * @cfg {String} href the link
21476 * @cfg {Boolean} disable (true | false) default false
21477 * @cfg {Boolean} preventDefault (true | false) default true
21478 * @cfg {String} icon Font awesome icon
21479 * @cfg {String} pos Submenu align to (left | right) default right
21483 * Create a new Item
21484 * @param {Object} config The config object
21488 Roo.bootstrap.menu.Item = function(config){
21489 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21493 * Fires when the mouse is hovering over this menu
21494 * @param {Roo.bootstrap.menu.Item} this
21495 * @param {Roo.EventObject} e
21500 * Fires when the mouse exits this menu
21501 * @param {Roo.bootstrap.menu.Item} this
21502 * @param {Roo.EventObject} e
21508 * The raw click event for the entire grid.
21509 * @param {Roo.EventObject} e
21515 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21520 preventDefault: true,
21525 getAutoCreate : function()
21530 cls : 'roo-menu-item-text',
21538 cls : 'fa ' + this.icon
21547 href : this.href || '#',
21554 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21558 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21560 if(this.pos == 'left'){
21561 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21568 initEvents : function()
21570 this.el.on('mouseover', this.onMouseOver, this);
21571 this.el.on('mouseout', this.onMouseOut, this);
21573 this.el.select('a', true).first().on('click', this.onClick, this);
21577 onClick : function(e)
21579 if(this.preventDefault){
21580 e.preventDefault();
21583 this.fireEvent("click", this, e);
21586 onMouseOver : function(e)
21588 if(this.submenu && this.pos == 'left'){
21589 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21592 this.fireEvent("mouseover", this, e);
21595 onMouseOut : function(e)
21597 this.fireEvent("mouseout", this, e);
21609 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21612 * @class Roo.bootstrap.menu.Separator
21613 * @extends Roo.bootstrap.Component
21614 * Bootstrap Separator class
21617 * Create a new Separator
21618 * @param {Object} config The config object
21622 Roo.bootstrap.menu.Separator = function(config){
21623 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21626 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21628 getAutoCreate : function(){
21649 * @class Roo.bootstrap.Tooltip
21650 * Bootstrap Tooltip class
21651 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21652 * to determine which dom element triggers the tooltip.
21654 * It needs to add support for additional attributes like tooltip-position
21657 * Create a new Toolti
21658 * @param {Object} config The config object
21661 Roo.bootstrap.Tooltip = function(config){
21662 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21665 Roo.apply(Roo.bootstrap.Tooltip, {
21667 * @function init initialize tooltip monitoring.
21671 currentTip : false,
21672 currentRegion : false,
21678 Roo.get(document).on('mouseover', this.enter ,this);
21679 Roo.get(document).on('mouseout', this.leave, this);
21682 this.currentTip = new Roo.bootstrap.Tooltip();
21685 enter : function(ev)
21687 var dom = ev.getTarget();
21688 //Roo.log(['enter',dom]);
21689 var el = Roo.fly(dom);
21690 if (this.currentEl) {
21692 //Roo.log(this.currentEl);
21693 //Roo.log(this.currentEl.contains(dom));
21694 if (this.currentEl == el) {
21697 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21705 if (this.currentTip.el) {
21706 this.currentTip.el.hide(); // force hiding...
21709 if (!el.attr('tooltip')) { // parents who have tip?
21712 this.currentEl = el;
21713 this.currentTip.bind(el);
21714 this.currentRegion = Roo.lib.Region.getRegion(dom);
21715 this.currentTip.enter();
21718 leave : function(ev)
21720 var dom = ev.getTarget();
21721 //Roo.log(['leave',dom]);
21722 if (!this.currentEl) {
21727 if (dom != this.currentEl.dom) {
21730 var xy = ev.getXY();
21731 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21734 // only activate leave if mouse cursor is outside... bounding box..
21739 if (this.currentTip) {
21740 this.currentTip.leave();
21742 //Roo.log('clear currentEl');
21743 this.currentEl = false;
21748 'left' : ['r-l', [-2,0], 'right'],
21749 'right' : ['l-r', [2,0], 'left'],
21750 'bottom' : ['t-b', [0,2], 'top'],
21751 'top' : [ 'b-t', [0,-2], 'bottom']
21757 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21762 delay : null, // can be { show : 300 , hide: 500}
21766 hoverState : null, //???
21768 placement : 'bottom',
21770 getAutoCreate : function(){
21777 cls : 'tooltip-arrow'
21780 cls : 'tooltip-inner'
21787 bind : function(el)
21793 enter : function () {
21795 if (this.timeout != null) {
21796 clearTimeout(this.timeout);
21799 this.hoverState = 'in';
21800 //Roo.log("enter - show");
21801 if (!this.delay || !this.delay.show) {
21806 this.timeout = setTimeout(function () {
21807 if (_t.hoverState == 'in') {
21810 }, this.delay.show);
21814 clearTimeout(this.timeout);
21816 this.hoverState = 'out';
21817 if (!this.delay || !this.delay.hide) {
21823 this.timeout = setTimeout(function () {
21824 //Roo.log("leave - timeout");
21826 if (_t.hoverState == 'out') {
21828 Roo.bootstrap.Tooltip.currentEl = false;
21836 this.render(document.body);
21839 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21840 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21842 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21844 var placement = typeof this.placement == 'function' ?
21845 this.placement.call(this, this.el, on_el) :
21848 var autoToken = /\s?auto?\s?/i;
21849 var autoPlace = autoToken.test(placement);
21851 placement = placement.replace(autoToken, '') || 'top';
21855 //this.el.setXY([0,0]);
21857 //this.el.dom.style.display='block';
21858 this.el.addClass(placement);
21860 //this.el.appendTo(on_el);
21862 var p = this.getPosition();
21863 var box = this.el.getBox();
21868 var align = Roo.bootstrap.Tooltip.alignment[placement];
21869 this.el.alignTo(this.bindEl, align[0],align[1]);
21870 //var arrow = this.el.select('.arrow',true).first();
21871 //arrow.set(align[2],
21873 this.el.addClass('in fade');
21874 this.hoverState = null;
21876 if (this.el.hasClass('fade')) {
21887 //this.el.setXY([0,0]);
21888 this.el.removeClass('in');
21904 * @class Roo.bootstrap.LocationPicker
21905 * @extends Roo.bootstrap.Component
21906 * Bootstrap LocationPicker class
21907 * @cfg {Number} latitude Position when init default 0
21908 * @cfg {Number} longitude Position when init default 0
21909 * @cfg {Number} zoom default 15
21910 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21911 * @cfg {Boolean} mapTypeControl default false
21912 * @cfg {Boolean} disableDoubleClickZoom default false
21913 * @cfg {Boolean} scrollwheel default true
21914 * @cfg {Boolean} streetViewControl default false
21915 * @cfg {Number} radius default 0
21916 * @cfg {String} locationName
21917 * @cfg {Boolean} draggable default true
21918 * @cfg {Boolean} enableAutocomplete default false
21919 * @cfg {Boolean} enableReverseGeocode default true
21920 * @cfg {String} markerTitle
21923 * Create a new LocationPicker
21924 * @param {Object} config The config object
21928 Roo.bootstrap.LocationPicker = function(config){
21930 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21935 * Fires when the picker initialized.
21936 * @param {Roo.bootstrap.LocationPicker} this
21937 * @param {Google Location} location
21941 * @event positionchanged
21942 * Fires when the picker position changed.
21943 * @param {Roo.bootstrap.LocationPicker} this
21944 * @param {Google Location} location
21946 positionchanged : true,
21949 * Fires when the map resize.
21950 * @param {Roo.bootstrap.LocationPicker} this
21955 * Fires when the map show.
21956 * @param {Roo.bootstrap.LocationPicker} this
21961 * Fires when the map hide.
21962 * @param {Roo.bootstrap.LocationPicker} this
21967 * Fires when click the map.
21968 * @param {Roo.bootstrap.LocationPicker} this
21969 * @param {Map event} e
21973 * @event mapRightClick
21974 * Fires when right click the map.
21975 * @param {Roo.bootstrap.LocationPicker} this
21976 * @param {Map event} e
21978 mapRightClick : true,
21980 * @event markerClick
21981 * Fires when click the marker.
21982 * @param {Roo.bootstrap.LocationPicker} this
21983 * @param {Map event} e
21985 markerClick : true,
21987 * @event markerRightClick
21988 * Fires when right click the marker.
21989 * @param {Roo.bootstrap.LocationPicker} this
21990 * @param {Map event} e
21992 markerRightClick : true,
21994 * @event OverlayViewDraw
21995 * Fires when OverlayView Draw
21996 * @param {Roo.bootstrap.LocationPicker} this
21998 OverlayViewDraw : true,
22000 * @event OverlayViewOnAdd
22001 * Fires when OverlayView Draw
22002 * @param {Roo.bootstrap.LocationPicker} this
22004 OverlayViewOnAdd : true,
22006 * @event OverlayViewOnRemove
22007 * Fires when OverlayView Draw
22008 * @param {Roo.bootstrap.LocationPicker} this
22010 OverlayViewOnRemove : true,
22012 * @event OverlayViewShow
22013 * Fires when OverlayView Draw
22014 * @param {Roo.bootstrap.LocationPicker} this
22015 * @param {Pixel} cpx
22017 OverlayViewShow : true,
22019 * @event OverlayViewHide
22020 * Fires when OverlayView Draw
22021 * @param {Roo.bootstrap.LocationPicker} this
22023 OverlayViewHide : true
22028 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22030 gMapContext: false,
22036 mapTypeControl: false,
22037 disableDoubleClickZoom: false,
22039 streetViewControl: false,
22043 enableAutocomplete: false,
22044 enableReverseGeocode: true,
22047 getAutoCreate: function()
22052 cls: 'roo-location-picker'
22058 initEvents: function(ct, position)
22060 if(!this.el.getWidth() || this.isApplied()){
22064 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22069 initial: function()
22071 if(!this.mapTypeId){
22072 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22075 this.gMapContext = this.GMapContext();
22077 this.initOverlayView();
22079 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22083 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22084 _this.setPosition(_this.gMapContext.marker.position);
22087 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22088 _this.fireEvent('mapClick', this, event);
22092 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22093 _this.fireEvent('mapRightClick', this, event);
22097 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22098 _this.fireEvent('markerClick', this, event);
22102 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22103 _this.fireEvent('markerRightClick', this, event);
22107 this.setPosition(this.gMapContext.location);
22109 this.fireEvent('initial', this, this.gMapContext.location);
22112 initOverlayView: function()
22116 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22120 _this.fireEvent('OverlayViewDraw', _this);
22125 _this.fireEvent('OverlayViewOnAdd', _this);
22128 onRemove: function()
22130 _this.fireEvent('OverlayViewOnRemove', _this);
22133 show: function(cpx)
22135 _this.fireEvent('OverlayViewShow', _this, cpx);
22140 _this.fireEvent('OverlayViewHide', _this);
22146 fromLatLngToContainerPixel: function(event)
22148 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22151 isApplied: function()
22153 return this.getGmapContext() == false ? false : true;
22156 getGmapContext: function()
22158 return this.gMapContext
22161 GMapContext: function()
22163 var _map = new google.maps.Map(this.el.dom, this);
22164 var _marker = new google.maps.Marker({
22165 position: new google.maps.LatLng(this.latitude, this.longitude),
22167 title: this.markerTitle,
22168 draggable: this.draggable
22175 location: _marker.position,
22176 radius: this.radius,
22177 locationName: this.locationName,
22178 addressComponents: {
22179 formatted_address: null,
22180 addressLine1: null,
22181 addressLine2: null,
22183 streetNumber: null,
22187 stateOrProvince: null
22190 domContainer: this.el.dom,
22191 geodecoder: new google.maps.Geocoder()
22195 drawCircle: function(center, radius, options)
22197 if (this.gMapContext.circle != null) {
22198 this.gMapContext.circle.setMap(null);
22202 options = Roo.apply({}, options, {
22203 strokeColor: "#0000FF",
22204 strokeOpacity: .35,
22206 fillColor: "#0000FF",
22210 options.map = this.gMapContext.map;
22211 options.radius = radius;
22212 options.center = center;
22213 this.gMapContext.circle = new google.maps.Circle(options);
22214 return this.gMapContext.circle;
22220 setPosition: function(location)
22222 this.gMapContext.location = location;
22223 this.gMapContext.marker.setPosition(location);
22224 this.gMapContext.map.panTo(location);
22225 this.drawCircle(location, this.gMapContext.radius, {});
22229 if (this.gMapContext.settings.enableReverseGeocode) {
22230 this.gMapContext.geodecoder.geocode({
22231 latLng: this.gMapContext.location
22232 }, function(results, status) {
22234 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22235 _this.gMapContext.locationName = results[0].formatted_address;
22236 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22238 _this.fireEvent('positionchanged', this, location);
22245 this.fireEvent('positionchanged', this, location);
22250 google.maps.event.trigger(this.gMapContext.map, "resize");
22252 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22254 this.fireEvent('resize', this);
22257 setPositionByLatLng: function(latitude, longitude)
22259 this.setPosition(new google.maps.LatLng(latitude, longitude));
22262 getCurrentPosition: function()
22265 latitude: this.gMapContext.location.lat(),
22266 longitude: this.gMapContext.location.lng()
22270 getAddressName: function()
22272 return this.gMapContext.locationName;
22275 getAddressComponents: function()
22277 return this.gMapContext.addressComponents;
22280 address_component_from_google_geocode: function(address_components)
22284 for (var i = 0; i < address_components.length; i++) {
22285 var component = address_components[i];
22286 if (component.types.indexOf("postal_code") >= 0) {
22287 result.postalCode = component.short_name;
22288 } else if (component.types.indexOf("street_number") >= 0) {
22289 result.streetNumber = component.short_name;
22290 } else if (component.types.indexOf("route") >= 0) {
22291 result.streetName = component.short_name;
22292 } else if (component.types.indexOf("neighborhood") >= 0) {
22293 result.city = component.short_name;
22294 } else if (component.types.indexOf("locality") >= 0) {
22295 result.city = component.short_name;
22296 } else if (component.types.indexOf("sublocality") >= 0) {
22297 result.district = component.short_name;
22298 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22299 result.stateOrProvince = component.short_name;
22300 } else if (component.types.indexOf("country") >= 0) {
22301 result.country = component.short_name;
22305 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22306 result.addressLine2 = "";
22310 setZoomLevel: function(zoom)
22312 this.gMapContext.map.setZoom(zoom);
22325 this.fireEvent('show', this);
22336 this.fireEvent('hide', this);
22341 Roo.apply(Roo.bootstrap.LocationPicker, {
22343 OverlayView : function(map, options)
22345 options = options || {};
22359 * @class Roo.bootstrap.Alert
22360 * @extends Roo.bootstrap.Component
22361 * Bootstrap Alert class
22362 * @cfg {String} title The title of alert
22363 * @cfg {String} html The content of alert
22364 * @cfg {String} weight ( success | info | warning | danger )
22365 * @cfg {String} faicon font-awesomeicon
22368 * Create a new alert
22369 * @param {Object} config The config object
22373 Roo.bootstrap.Alert = function(config){
22374 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22378 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22385 getAutoCreate : function()
22394 cls : 'roo-alert-icon'
22399 cls : 'roo-alert-title',
22404 cls : 'roo-alert-text',
22411 cfg.cn[0].cls += ' fa ' + this.faicon;
22415 cfg.cls += ' alert-' + this.weight;
22421 initEvents: function()
22423 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22426 setTitle : function(str)
22428 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22431 setText : function(str)
22433 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22436 setWeight : function(weight)
22439 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22442 this.weight = weight;
22444 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22447 setIcon : function(icon)
22450 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22455 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);