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);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
212 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
218 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
222 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
227 addxtypeChild : function (tree, cntr)
229 Roo.debug && Roo.log('addxtypeChild:' + cntr);
231 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
234 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
235 (typeof(tree['flexy:foreach']) != 'undefined');
239 skip_children = false;
240 // render the element if it's not BODY.
241 if (tree.xtype != 'Body') {
243 cn = Roo.factory(tree);
245 cn.parentType = this.xtype; //??
246 cn.parentId = this.id;
248 var build_from_html = Roo.XComponent.build_from_html;
251 // does the container contain child eleemnts with 'xtype' attributes.
252 // that match this xtype..
253 // note - when we render we create these as well..
254 // so we should check to see if body has xtype set.
255 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
257 var self_cntr_el = Roo.get(this[cntr](false));
258 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
261 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
262 // and are not displayed -this causes this to use up the wrong element when matching.
263 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
266 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
267 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
273 //echild.dom.removeAttribute('xtype');
275 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
276 Roo.debug && Roo.log(self_cntr_el);
277 Roo.debug && Roo.log(echild);
278 Roo.debug && Roo.log(cn);
284 // if object has flexy:if - then it may or may not be rendered.
285 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
286 // skip a flexy if element.
287 Roo.debug && Roo.log('skipping render');
288 Roo.debug && Roo.log(tree);
290 Roo.debug && Roo.log('skipping all children');
291 skip_children = true;
296 // actually if flexy:foreach is found, we really want to create
297 // multiple copies here...
299 //Roo.log(this[cntr]());
300 cn.render(this[cntr](true));
302 // then add the element..
310 if (typeof (tree.menu) != 'undefined') {
311 tree.menu.parentType = cn.xtype;
312 tree.menu.triggerEl = cn.el;
313 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
317 if (!tree.items || !tree.items.length) {
321 var items = tree.items;
324 //Roo.log(items.length);
326 if (!skip_children) {
327 for(var i =0;i < items.length;i++) {
328 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
334 this.fireEvent('childrenrendered', this);
350 * @class Roo.bootstrap.Body
351 * @extends Roo.bootstrap.Component
352 * Bootstrap Body class
356 * @param {Object} config The config object
359 Roo.bootstrap.Body = function(config){
360 Roo.bootstrap.Body.superclass.constructor.call(this, config);
361 this.el = Roo.get(document.body);
362 if (this.cls && this.cls.length) {
363 Roo.get(document.body).addClass(this.cls);
367 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
372 onRender : function(ct, position)
374 /* Roo.log("Roo.bootstrap.Body - onRender");
375 if (this.cls && this.cls.length) {
376 Roo.get(document.body).addClass(this.cls);
396 * @class Roo.bootstrap.ButtonGroup
397 * @extends Roo.bootstrap.Component
398 * Bootstrap ButtonGroup class
399 * @cfg {String} size lg | sm | xs (default empty normal)
400 * @cfg {String} align vertical | justified (default none)
401 * @cfg {String} direction up | down (default down)
402 * @cfg {Boolean} toolbar false | true
403 * @cfg {Boolean} btn true | false
408 * @param {Object} config The config object
411 Roo.bootstrap.ButtonGroup = function(config){
412 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
415 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
423 getAutoCreate : function(){
429 cfg.html = this.html || cfg.html;
440 if (['vertical','justified'].indexOf(this.align)!==-1) {
441 cfg.cls = 'btn-group-' + this.align;
443 if (this.align == 'justified') {
444 console.log(this.items);
448 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
449 cfg.cls += ' btn-group-' + this.size;
452 if (this.direction == 'up') {
453 cfg.cls += ' dropup' ;
469 * @class Roo.bootstrap.Button
470 * @extends Roo.bootstrap.Component
471 * Bootstrap Button class
472 * @cfg {String} html The button content
473 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
474 * @cfg {String} size ( lg | sm | xs)
475 * @cfg {String} tag ( a | input | submit)
476 * @cfg {String} href empty or href
477 * @cfg {Boolean} disabled default false;
478 * @cfg {Boolean} isClose default false;
479 * @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)
480 * @cfg {String} badge text for badge
481 * @cfg {String} theme default
482 * @cfg {Boolean} inverse
483 * @cfg {Boolean} toggle
484 * @cfg {String} ontext text for on toggle state
485 * @cfg {String} offtext text for off toggle state
486 * @cfg {Boolean} defaulton
487 * @cfg {Boolean} preventDefault default true
488 * @cfg {Boolean} removeClass remove the standard class..
489 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
492 * Create a new button
493 * @param {Object} config The config object
497 Roo.bootstrap.Button = function(config){
498 Roo.bootstrap.Button.superclass.constructor.call(this, config);
503 * When a butotn is pressed
504 * @param {Roo.EventObject} e
509 * After the button has been toggles
510 * @param {Roo.EventObject} e
511 * @param {boolean} pressed (also available as button.pressed)
517 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
535 preventDefault: true,
544 getAutoCreate : function(){
552 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
553 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
558 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
560 if (this.toggle == true) {
563 cls: 'slider-frame roo-button',
568 'data-off-text':'OFF',
569 cls: 'slider-button',
575 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
576 cfg.cls += ' '+this.weight;
585 cfg["aria-hidden"] = true;
587 cfg.html = "×";
593 if (this.theme==='default') {
594 cfg.cls = 'btn roo-button';
596 //if (this.parentType != 'Navbar') {
597 this.weight = this.weight.length ? this.weight : 'default';
599 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
601 cfg.cls += ' btn-' + this.weight;
603 } else if (this.theme==='glow') {
606 cfg.cls = 'btn-glow roo-button';
608 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
610 cfg.cls += ' ' + this.weight;
616 this.cls += ' inverse';
621 cfg.cls += ' active';
625 cfg.disabled = 'disabled';
629 Roo.log('changing to ul' );
631 this.glyphicon = 'caret';
634 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
636 //gsRoo.log(this.parentType);
637 if (this.parentType === 'Navbar' && !this.parent().bar) {
638 Roo.log('changing to li?');
647 href : this.href || '#'
650 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
651 cfg.cls += ' dropdown';
658 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
660 if (this.glyphicon) {
661 cfg.html = ' ' + cfg.html;
666 cls: 'glyphicon glyphicon-' + this.glyphicon
676 // cfg.cls='btn roo-button';
680 var value = cfg.html;
685 cls: 'glyphicon glyphicon-' + this.glyphicon,
704 cfg.cls += ' dropdown';
705 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
708 if (cfg.tag !== 'a' && this.href !== '') {
709 throw "Tag must be a to set href.";
710 } else if (this.href.length > 0) {
711 cfg.href = this.href;
714 if(this.removeClass){
719 cfg.target = this.target;
724 initEvents: function() {
725 // Roo.log('init events?');
726 // Roo.log(this.el.dom);
729 if (typeof (this.menu) != 'undefined') {
730 this.menu.parentType = this.xtype;
731 this.menu.triggerEl = this.el;
732 this.addxtype(Roo.apply({}, this.menu));
736 if (this.el.hasClass('roo-button')) {
737 this.el.on('click', this.onClick, this);
739 this.el.select('.roo-button').on('click', this.onClick, this);
742 if(this.removeClass){
743 this.el.on('click', this.onClick, this);
746 this.el.enableDisplayMode();
749 onClick : function(e)
756 Roo.log('button on click ');
757 if(this.preventDefault){
760 if (this.pressed === true || this.pressed === false) {
761 this.pressed = !this.pressed;
762 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
763 this.fireEvent('toggle', this, e, this.pressed);
767 this.fireEvent('click', this, e);
771 * Enables this button
775 this.disabled = false;
776 this.el.removeClass('disabled');
780 * Disable this button
784 this.disabled = true;
785 this.el.addClass('disabled');
788 * sets the active state on/off,
789 * @param {Boolean} state (optional) Force a particular state
791 setActive : function(v) {
793 this.el[v ? 'addClass' : 'removeClass']('active');
796 * toggles the current active state
798 toggleActive : function()
800 var active = this.el.hasClass('active');
801 this.setActive(!active);
805 setText : function(str)
807 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
811 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
834 * @class Roo.bootstrap.Column
835 * @extends Roo.bootstrap.Component
836 * Bootstrap Column class
837 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
838 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
839 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
840 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
841 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
842 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
843 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
844 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
847 * @cfg {Boolean} hidden (true|false) hide the element
848 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
849 * @cfg {String} fa (ban|check|...) font awesome icon
850 * @cfg {Number} fasize (1|2|....) font awsome size
852 * @cfg {String} icon (info-sign|check|...) glyphicon name
854 * @cfg {String} html content of column.
857 * Create a new Column
858 * @param {Object} config The config object
861 Roo.bootstrap.Column = function(config){
862 Roo.bootstrap.Column.superclass.constructor.call(this, config);
865 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
883 getAutoCreate : function(){
884 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
892 ['xs','sm','md','lg'].map(function(size){
893 //Roo.log( size + ':' + settings[size]);
895 if (settings[size+'off'] !== false) {
896 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
899 if (settings[size] === false) {
902 Roo.log(settings[size]);
903 if (!settings[size]) { // 0 = hidden
904 cfg.cls += ' hidden-' + size;
907 cfg.cls += ' col-' + size + '-' + settings[size];
912 cfg.cls += ' hidden';
915 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
916 cfg.cls +=' alert alert-' + this.alert;
920 if (this.html.length) {
921 cfg.html = this.html;
925 if (this.fasize > 1) {
926 fasize = ' fa-' + this.fasize + 'x';
928 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
933 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
952 * @class Roo.bootstrap.Container
953 * @extends Roo.bootstrap.Component
954 * Bootstrap Container class
955 * @cfg {Boolean} jumbotron is it a jumbotron element
956 * @cfg {String} html content of element
957 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
958 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
959 * @cfg {String} header content of header (for panel)
960 * @cfg {String} footer content of footer (for panel)
961 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
962 * @cfg {String} tag (header|aside|section) type of HTML tag.
963 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
964 * @cfg {String} fa (ban|check|...) font awesome icon
965 * @cfg {String} icon (info-sign|check|...) glyphicon name
966 * @cfg {Boolean} hidden (true|false) hide the element
970 * Create a new Container
971 * @param {Object} config The config object
974 Roo.bootstrap.Container = function(config){
975 Roo.bootstrap.Container.superclass.constructor.call(this, config);
978 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
992 getChildContainer : function() {
998 if (this.panel.length) {
999 return this.el.select('.panel-body',true).first();
1006 getAutoCreate : function(){
1009 tag : this.tag || 'div',
1013 if (this.jumbotron) {
1014 cfg.cls = 'jumbotron';
1019 // - this is applied by the parent..
1021 // cfg.cls = this.cls + '';
1024 if (this.sticky.length) {
1026 var bd = Roo.get(document.body);
1027 if (!bd.hasClass('bootstrap-sticky')) {
1028 bd.addClass('bootstrap-sticky');
1029 Roo.select('html',true).setStyle('height', '100%');
1032 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1036 if (this.well.length) {
1037 switch (this.well) {
1040 cfg.cls +=' well well-' +this.well;
1049 cfg.cls += ' hidden';
1053 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1054 cfg.cls +=' alert alert-' + this.alert;
1059 if (this.panel.length) {
1060 cfg.cls += ' panel panel-' + this.panel;
1062 if (this.header.length) {
1065 cls : 'panel-heading',
1068 cls : 'panel-title',
1081 if (this.footer.length) {
1083 cls : 'panel-footer',
1092 body.html = this.html || cfg.html;
1093 // prefix with the icons..
1095 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1098 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1103 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1104 cfg.cls = 'container';
1110 titleEl : function()
1112 if(!this.el || !this.panel.length || !this.header.length){
1116 return this.el.select('.panel-title',true).first();
1119 setTitle : function(v)
1121 var titleEl = this.titleEl();
1127 titleEl.dom.innerHTML = v;
1130 getTitle : function()
1133 var titleEl = this.titleEl();
1139 return titleEl.dom.innerHTML;
1143 this.el.removeClass('hidden');
1146 if (!this.el.hasClass('hidden')) {
1147 this.el.addClass('hidden');
1163 * @class Roo.bootstrap.Img
1164 * @extends Roo.bootstrap.Component
1165 * Bootstrap Img class
1166 * @cfg {Boolean} imgResponsive false | true
1167 * @cfg {String} border rounded | circle | thumbnail
1168 * @cfg {String} src image source
1169 * @cfg {String} alt image alternative text
1170 * @cfg {String} href a tag href
1171 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1174 * Create a new Input
1175 * @param {Object} config The config object
1178 Roo.bootstrap.Img = function(config){
1179 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1185 * The img click event for the img.
1186 * @param {Roo.EventObject} e
1192 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1194 imgResponsive: true,
1200 getAutoCreate : function(){
1204 cls: (this.imgResponsive) ? 'img-responsive' : '',
1208 cfg.html = this.html || cfg.html;
1210 cfg.src = this.src || cfg.src;
1212 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1213 cfg.cls += ' img-' + this.border;
1230 a.target = this.target;
1236 return (this.href) ? a : cfg;
1239 initEvents: function() {
1242 this.el.on('click', this.onClick, this);
1246 onClick : function(e)
1248 Roo.log('img onclick');
1249 this.fireEvent('click', this, e);
1263 * @class Roo.bootstrap.Link
1264 * @extends Roo.bootstrap.Component
1265 * Bootstrap Link Class
1266 * @cfg {String} alt image alternative text
1267 * @cfg {String} href a tag href
1268 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1269 * @cfg {String} html the content of the link.
1270 * @cfg {String} anchor name for the anchor link
1272 * @cfg {Boolean} preventDefault (true | false) default false
1276 * Create a new Input
1277 * @param {Object} config The config object
1280 Roo.bootstrap.Link = function(config){
1281 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1287 * The img click event for the img.
1288 * @param {Roo.EventObject} e
1294 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1298 preventDefault: false,
1302 getAutoCreate : function()
1308 // anchor's do not require html/href...
1309 if (this.anchor === false) {
1310 cfg.html = this.html || 'html-missing';
1311 cfg.href = this.href || '#';
1313 cfg.name = this.anchor;
1314 if (this.html !== false) {
1315 cfg.html = this.html;
1317 if (this.href !== false) {
1318 cfg.href = this.href;
1322 if(this.alt !== false){
1327 if(this.target !== false) {
1328 cfg.target = this.target;
1334 initEvents: function() {
1336 if(!this.href || this.preventDefault){
1337 this.el.on('click', this.onClick, this);
1341 onClick : function(e)
1343 if(this.preventDefault){
1346 //Roo.log('img onclick');
1347 this.fireEvent('click', this, e);
1360 * @class Roo.bootstrap.Header
1361 * @extends Roo.bootstrap.Component
1362 * Bootstrap Header class
1363 * @cfg {String} html content of header
1364 * @cfg {Number} level (1|2|3|4|5|6) default 1
1367 * Create a new Header
1368 * @param {Object} config The config object
1372 Roo.bootstrap.Header = function(config){
1373 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1376 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1384 getAutoCreate : function(){
1389 tag: 'h' + (1 *this.level),
1390 html: this.html || ''
1402 * Ext JS Library 1.1.1
1403 * Copyright(c) 2006-2007, Ext JS, LLC.
1405 * Originally Released Under LGPL - original licence link has changed is not relivant.
1408 * <script type="text/javascript">
1412 * @class Roo.bootstrap.MenuMgr
1413 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1416 Roo.bootstrap.MenuMgr = function(){
1417 var menus, active, groups = {}, attached = false, lastShow = new Date();
1419 // private - called when first menu is created
1422 active = new Roo.util.MixedCollection();
1423 Roo.get(document).addKeyListener(27, function(){
1424 if(active.length > 0){
1432 if(active && active.length > 0){
1433 var c = active.clone();
1443 if(active.length < 1){
1444 Roo.get(document).un("mouseup", onMouseDown);
1452 var last = active.last();
1453 lastShow = new Date();
1456 Roo.get(document).on("mouseup", onMouseDown);
1461 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1462 m.parentMenu.activeChild = m;
1463 }else if(last && last.isVisible()){
1464 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1469 function onBeforeHide(m){
1471 m.activeChild.hide();
1473 if(m.autoHideTimer){
1474 clearTimeout(m.autoHideTimer);
1475 delete m.autoHideTimer;
1480 function onBeforeShow(m){
1481 var pm = m.parentMenu;
1482 if(!pm && !m.allowOtherMenus){
1484 }else if(pm && pm.activeChild && active != m){
1485 pm.activeChild.hide();
1490 function onMouseDown(e){
1491 Roo.log("on MouseDown");
1492 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1500 function onBeforeCheck(mi, state){
1502 var g = groups[mi.group];
1503 for(var i = 0, l = g.length; i < l; i++){
1505 g[i].setChecked(false);
1514 * Hides all menus that are currently visible
1516 hideAll : function(){
1521 register : function(menu){
1525 menus[menu.id] = menu;
1526 menu.on("beforehide", onBeforeHide);
1527 menu.on("hide", onHide);
1528 menu.on("beforeshow", onBeforeShow);
1529 menu.on("show", onShow);
1531 if(g && menu.events["checkchange"]){
1535 groups[g].push(menu);
1536 menu.on("checkchange", onCheck);
1541 * Returns a {@link Roo.menu.Menu} object
1542 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1543 * be used to generate and return a new Menu instance.
1545 get : function(menu){
1546 if(typeof menu == "string"){ // menu id
1548 }else if(menu.events){ // menu instance
1551 /*else if(typeof menu.length == 'number'){ // array of menu items?
1552 return new Roo.bootstrap.Menu({items:menu});
1553 }else{ // otherwise, must be a config
1554 return new Roo.bootstrap.Menu(menu);
1561 unregister : function(menu){
1562 delete menus[menu.id];
1563 menu.un("beforehide", onBeforeHide);
1564 menu.un("hide", onHide);
1565 menu.un("beforeshow", onBeforeShow);
1566 menu.un("show", onShow);
1568 if(g && menu.events["checkchange"]){
1569 groups[g].remove(menu);
1570 menu.un("checkchange", onCheck);
1575 registerCheckable : function(menuItem){
1576 var g = menuItem.group;
1581 groups[g].push(menuItem);
1582 menuItem.on("beforecheckchange", onBeforeCheck);
1587 unregisterCheckable : function(menuItem){
1588 var g = menuItem.group;
1590 groups[g].remove(menuItem);
1591 menuItem.un("beforecheckchange", onBeforeCheck);
1603 * @class Roo.bootstrap.Menu
1604 * @extends Roo.bootstrap.Component
1605 * Bootstrap Menu class - container for MenuItems
1606 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1610 * @param {Object} config The config object
1614 Roo.bootstrap.Menu = function(config){
1615 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1616 if (this.registerMenu) {
1617 Roo.bootstrap.MenuMgr.register(this);
1622 * Fires before this menu is displayed
1623 * @param {Roo.menu.Menu} this
1628 * Fires before this menu is hidden
1629 * @param {Roo.menu.Menu} this
1634 * Fires after this menu is displayed
1635 * @param {Roo.menu.Menu} this
1640 * Fires after this menu is hidden
1641 * @param {Roo.menu.Menu} this
1646 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1647 * @param {Roo.menu.Menu} this
1648 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1649 * @param {Roo.EventObject} e
1654 * Fires when the mouse is hovering over this menu
1655 * @param {Roo.menu.Menu} this
1656 * @param {Roo.EventObject} e
1657 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1662 * Fires when the mouse exits this menu
1663 * @param {Roo.menu.Menu} this
1664 * @param {Roo.EventObject} e
1665 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1670 * Fires when a menu item contained in this menu is clicked
1671 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1672 * @param {Roo.EventObject} e
1676 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1679 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1683 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1686 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1688 registerMenu : true,
1690 menuItems :false, // stores the menu items..
1696 getChildContainer : function() {
1700 getAutoCreate : function(){
1702 //if (['right'].indexOf(this.align)!==-1) {
1703 // cfg.cn[1].cls += ' pull-right'
1709 cls : 'dropdown-menu' ,
1710 style : 'z-index:1000'
1714 if (this.type === 'submenu') {
1715 cfg.cls = 'submenu active';
1717 if (this.type === 'treeview') {
1718 cfg.cls = 'treeview-menu';
1723 initEvents : function() {
1725 // Roo.log("ADD event");
1726 // Roo.log(this.triggerEl.dom);
1727 this.triggerEl.on('click', this.onTriggerPress, this);
1728 this.triggerEl.addClass('dropdown-toggle');
1729 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1731 this.el.on("mouseover", this.onMouseOver, this);
1732 this.el.on("mouseout", this.onMouseOut, this);
1736 findTargetItem : function(e){
1737 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1741 //Roo.log(t); Roo.log(t.id);
1743 //Roo.log(this.menuitems);
1744 return this.menuitems.get(t.id);
1746 //return this.items.get(t.menuItemId);
1751 onClick : function(e){
1752 Roo.log("menu.onClick");
1753 var t = this.findTargetItem(e);
1754 if(!t || t.isContainer){
1759 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1760 if(t == this.activeItem && t.shouldDeactivate(e)){
1761 this.activeItem.deactivate();
1762 delete this.activeItem;
1766 this.setActiveItem(t, true);
1774 Roo.log('pass click event');
1778 this.fireEvent("click", this, t, e);
1782 onMouseOver : function(e){
1783 var t = this.findTargetItem(e);
1786 // if(t.canActivate && !t.disabled){
1787 // this.setActiveItem(t, true);
1791 this.fireEvent("mouseover", this, e, t);
1793 isVisible : function(){
1794 return !this.hidden;
1796 onMouseOut : function(e){
1797 var t = this.findTargetItem(e);
1800 // if(t == this.activeItem && t.shouldDeactivate(e)){
1801 // this.activeItem.deactivate();
1802 // delete this.activeItem;
1805 this.fireEvent("mouseout", this, e, t);
1810 * Displays this menu relative to another element
1811 * @param {String/HTMLElement/Roo.Element} element The element to align to
1812 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1813 * the element (defaults to this.defaultAlign)
1814 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1816 show : function(el, pos, parentMenu){
1817 this.parentMenu = parentMenu;
1821 this.fireEvent("beforeshow", this);
1822 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1825 * Displays this menu at a specific xy position
1826 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1827 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1829 showAt : function(xy, parentMenu, /* private: */_e){
1830 this.parentMenu = parentMenu;
1835 this.fireEvent("beforeshow", this);
1837 //xy = this.el.adjustForConstraints(xy);
1839 //this.el.setXY(xy);
1841 this.hideMenuItems();
1842 this.hidden = false;
1843 this.triggerEl.addClass('open');
1845 this.fireEvent("show", this);
1851 this.doFocus.defer(50, this);
1855 doFocus : function(){
1857 this.focusEl.focus();
1862 * Hides this menu and optionally all parent menus
1863 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1865 hide : function(deep){
1867 this.hideMenuItems();
1868 if(this.el && this.isVisible()){
1869 this.fireEvent("beforehide", this);
1870 if(this.activeItem){
1871 this.activeItem.deactivate();
1872 this.activeItem = null;
1874 this.triggerEl.removeClass('open');;
1876 this.fireEvent("hide", this);
1878 if(deep === true && this.parentMenu){
1879 this.parentMenu.hide(true);
1883 onTriggerPress : function(e)
1886 Roo.log('trigger press');
1887 //Roo.log(e.getTarget());
1888 // Roo.log(this.triggerEl.dom);
1889 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1892 if (this.isVisible()) {
1896 this.show(this.triggerEl, false, false);
1905 hideMenuItems : function()
1907 //$(backdrop).remove()
1908 Roo.select('.open',true).each(function(aa) {
1910 aa.removeClass('open');
1911 //var parent = getParent($(this))
1912 //var relatedTarget = { relatedTarget: this }
1914 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1915 //if (e.isDefaultPrevented()) return
1916 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1919 addxtypeChild : function (tree, cntr) {
1920 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1922 this.menuitems.add(comp);
1943 * @class Roo.bootstrap.MenuItem
1944 * @extends Roo.bootstrap.Component
1945 * Bootstrap MenuItem class
1946 * @cfg {String} html the menu label
1947 * @cfg {String} href the link
1948 * @cfg {Boolean} preventDefault (true | false) default true
1949 * @cfg {Boolean} isContainer (true | false) default false
1953 * Create a new MenuItem
1954 * @param {Object} config The config object
1958 Roo.bootstrap.MenuItem = function(config){
1959 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1964 * The raw click event for the entire grid.
1965 * @param {Roo.EventObject} e
1971 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1975 preventDefault: true,
1976 isContainer : false,
1978 getAutoCreate : function(){
1980 if(this.isContainer){
1983 cls: 'dropdown-menu-item'
1989 cls: 'dropdown-menu-item',
1998 if (this.parent().type == 'treeview') {
1999 cfg.cls = 'treeview-menu';
2002 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2003 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2007 initEvents: function() {
2009 //this.el.select('a').on('click', this.onClick, this);
2012 onClick : function(e)
2014 Roo.log('item on click ');
2015 //if(this.preventDefault){
2016 // e.preventDefault();
2018 //this.parent().hideMenuItems();
2020 this.fireEvent('click', this, e);
2039 * @class Roo.bootstrap.MenuSeparator
2040 * @extends Roo.bootstrap.Component
2041 * Bootstrap MenuSeparator class
2044 * Create a new MenuItem
2045 * @param {Object} config The config object
2049 Roo.bootstrap.MenuSeparator = function(config){
2050 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2053 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2055 getAutoCreate : function(){
2074 * @class Roo.bootstrap.Modal
2075 * @extends Roo.bootstrap.Component
2076 * Bootstrap Modal class
2077 * @cfg {String} title Title of dialog
2078 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2079 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2080 * @cfg {Boolean} specificTitle default false
2081 * @cfg {Array} buttons Array of buttons or standard button set..
2082 * @cfg {String} buttonPosition (left|right|center) default right
2083 * @cfg {Boolean} animate default true
2084 * @cfg {Boolean} allow_close default true
2087 * Create a new Modal Dialog
2088 * @param {Object} config The config object
2091 Roo.bootstrap.Modal = function(config){
2092 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2097 * The raw btnclick event for the button
2098 * @param {Roo.EventObject} e
2102 this.buttons = this.buttons || [];
2105 this.tmpl = Roo.factory(this.tmpl);
2110 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2112 title : 'test dialog',
2122 specificTitle: false,
2124 buttonPosition: 'right',
2138 onRender : function(ct, position)
2140 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2143 var cfg = Roo.apply({}, this.getAutoCreate());
2146 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2148 //if (!cfg.name.length) {
2152 cfg.cls += ' ' + this.cls;
2155 cfg.style = this.style;
2157 this.el = Roo.get(document.body).createChild(cfg, position);
2159 //var type = this.el.dom.type;
2164 if(this.tabIndex !== undefined){
2165 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2169 this.bodyEl = this.el.select('.modal-body',true).first();
2170 this.closeEl = this.el.select('.modal-header .close', true).first();
2171 this.footerEl = this.el.select('.modal-footer',true).first();
2172 this.titleEl = this.el.select('.modal-title',true).first();
2176 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2177 this.maskEl.enableDisplayMode("block");
2179 //this.el.addClass("x-dlg-modal");
2181 if (this.buttons.length) {
2182 Roo.each(this.buttons, function(bb) {
2183 b = Roo.apply({}, bb);
2184 b.xns = b.xns || Roo.bootstrap;
2185 b.xtype = b.xtype || 'Button';
2186 if (typeof(b.listeners) == 'undefined') {
2187 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2190 var btn = Roo.factory(b);
2192 btn.onRender(this.el.select('.modal-footer div').first());
2196 // render the children.
2199 if(typeof(this.items) != 'undefined'){
2200 var items = this.items;
2203 for(var i =0;i < items.length;i++) {
2204 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2208 this.items = nitems;
2210 // where are these used - they used to be body/close/footer
2214 //this.el.addClass([this.fieldClass, this.cls]);
2217 getAutoCreate : function(){
2222 html : this.html || ''
2227 cls : 'modal-title',
2231 if(this.specificTitle){
2237 if (this.allow_close) {
2248 style : 'display: none',
2251 cls: "modal-dialog",
2254 cls : "modal-content",
2257 cls : 'modal-header',
2262 cls : 'modal-footer',
2266 cls: 'btn-' + this.buttonPosition
2283 modal.cls += ' fade';
2289 getChildContainer : function() {
2294 getButtonContainer : function() {
2295 return this.el.select('.modal-footer div',true).first();
2298 initEvents : function()
2300 if (this.allow_close) {
2301 this.closeEl.on('click', this.hide, this);
2307 if (!this.rendered) {
2311 this.el.setStyle('display', 'block');
2315 (function(){ _this.el.addClass('in'); }).defer(50);
2317 this.el.addClass('in');
2320 // not sure how we can show data in here..
2322 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2325 Roo.get(document.body).addClass("x-body-masked");
2326 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2328 this.el.setStyle('zIndex', '10001');
2330 this.fireEvent('show', this);
2337 Roo.get(document.body).removeClass("x-body-masked");
2338 this.el.removeClass('in');
2342 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2344 this.el.setStyle('display', 'none');
2347 this.fireEvent('hide', this);
2350 addButton : function(str, cb)
2354 var b = Roo.apply({}, { html : str } );
2355 b.xns = b.xns || Roo.bootstrap;
2356 b.xtype = b.xtype || 'Button';
2357 if (typeof(b.listeners) == 'undefined') {
2358 b.listeners = { click : cb.createDelegate(this) };
2361 var btn = Roo.factory(b);
2363 btn.onRender(this.el.select('.modal-footer div').first());
2369 setDefaultButton : function(btn)
2371 //this.el.select('.modal-footer').()
2373 resizeTo: function(w,h)
2377 setContentSize : function(w, h)
2381 onButtonClick: function(btn,e)
2384 this.fireEvent('btnclick', btn.name, e);
2387 * Set the title of the Dialog
2388 * @param {String} str new Title
2390 setTitle: function(str) {
2391 this.titleEl.dom.innerHTML = str;
2394 * Set the body of the Dialog
2395 * @param {String} str new Title
2397 setBody: function(str) {
2398 this.bodyEl.dom.innerHTML = str;
2401 * Set the body of the Dialog using the template
2402 * @param {Obj} data - apply this data to the template and replace the body contents.
2404 applyBody: function(obj)
2407 Roo.log("Error - using apply Body without a template");
2410 this.tmpl.overwrite(this.bodyEl, obj);
2416 Roo.apply(Roo.bootstrap.Modal, {
2418 * Button config that displays a single OK button
2427 * Button config that displays Yes and No buttons
2443 * Button config that displays OK and Cancel buttons
2458 * Button config that displays Yes, No and Cancel buttons
2481 * messagebox - can be used as a replace
2485 * @class Roo.MessageBox
2486 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2490 Roo.Msg.alert('Status', 'Changes saved successfully.');
2492 // Prompt for user data:
2493 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2495 // process text value...
2499 // Show a dialog using config options:
2501 title:'Save Changes?',
2502 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2503 buttons: Roo.Msg.YESNOCANCEL,
2510 Roo.bootstrap.MessageBox = function(){
2511 var dlg, opt, mask, waitTimer;
2512 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2513 var buttons, activeTextEl, bwidth;
2517 var handleButton = function(button){
2519 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2523 var handleHide = function(){
2525 dlg.el.removeClass(opt.cls);
2528 // Roo.TaskMgr.stop(waitTimer);
2529 // waitTimer = null;
2534 var updateButtons = function(b){
2537 buttons["ok"].hide();
2538 buttons["cancel"].hide();
2539 buttons["yes"].hide();
2540 buttons["no"].hide();
2541 //dlg.footer.dom.style.display = 'none';
2544 dlg.footerEl.dom.style.display = '';
2545 for(var k in buttons){
2546 if(typeof buttons[k] != "function"){
2549 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2550 width += buttons[k].el.getWidth()+15;
2560 var handleEsc = function(d, k, e){
2561 if(opt && opt.closable !== false){
2571 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2572 * @return {Roo.BasicDialog} The BasicDialog element
2574 getDialog : function(){
2576 dlg = new Roo.bootstrap.Modal( {
2579 //constraintoviewport:false,
2581 //collapsible : false,
2586 //buttonAlign:"center",
2587 closeClick : function(){
2588 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2591 handleButton("cancel");
2596 dlg.on("hide", handleHide);
2598 //dlg.addKeyListener(27, handleEsc);
2600 this.buttons = buttons;
2601 var bt = this.buttonText;
2602 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2603 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2604 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2605 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2607 bodyEl = dlg.bodyEl.createChild({
2609 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2610 '<textarea class="roo-mb-textarea"></textarea>' +
2611 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2613 msgEl = bodyEl.dom.firstChild;
2614 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2615 textboxEl.enableDisplayMode();
2616 textboxEl.addKeyListener([10,13], function(){
2617 if(dlg.isVisible() && opt && opt.buttons){
2620 }else if(opt.buttons.yes){
2621 handleButton("yes");
2625 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2626 textareaEl.enableDisplayMode();
2627 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2628 progressEl.enableDisplayMode();
2629 var pf = progressEl.dom.firstChild;
2631 pp = Roo.get(pf.firstChild);
2632 pp.setHeight(pf.offsetHeight);
2640 * Updates the message box body text
2641 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2642 * the XHTML-compliant non-breaking space character '&#160;')
2643 * @return {Roo.MessageBox} This message box
2645 updateText : function(text){
2646 if(!dlg.isVisible() && !opt.width){
2647 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2649 msgEl.innerHTML = text || ' ';
2651 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2652 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2654 Math.min(opt.width || cw , this.maxWidth),
2655 Math.max(opt.minWidth || this.minWidth, bwidth)
2658 activeTextEl.setWidth(w);
2660 if(dlg.isVisible()){
2661 dlg.fixedcenter = false;
2663 // to big, make it scroll. = But as usual stupid IE does not support
2666 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2667 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2668 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2670 bodyEl.dom.style.height = '';
2671 bodyEl.dom.style.overflowY = '';
2674 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2676 bodyEl.dom.style.overflowX = '';
2679 dlg.setContentSize(w, bodyEl.getHeight());
2680 if(dlg.isVisible()){
2681 dlg.fixedcenter = true;
2687 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2688 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2689 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2690 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2691 * @return {Roo.MessageBox} This message box
2693 updateProgress : function(value, text){
2695 this.updateText(text);
2697 if (pp) { // weird bug on my firefox - for some reason this is not defined
2698 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2704 * Returns true if the message box is currently displayed
2705 * @return {Boolean} True if the message box is visible, else false
2707 isVisible : function(){
2708 return dlg && dlg.isVisible();
2712 * Hides the message box if it is displayed
2715 if(this.isVisible()){
2721 * Displays a new message box, or reinitializes an existing message box, based on the config options
2722 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2723 * The following config object properties are supported:
2725 Property Type Description
2726 ---------- --------------- ------------------------------------------------------------------------------------
2727 animEl String/Element An id or Element from which the message box should animate as it opens and
2728 closes (defaults to undefined)
2729 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2730 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2731 closable Boolean False to hide the top-right close button (defaults to true). Note that
2732 progress and wait dialogs will ignore this property and always hide the
2733 close button as they can only be closed programmatically.
2734 cls String A custom CSS class to apply to the message box element
2735 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2736 displayed (defaults to 75)
2737 fn Function A callback function to execute after closing the dialog. The arguments to the
2738 function will be btn (the name of the button that was clicked, if applicable,
2739 e.g. "ok"), and text (the value of the active text field, if applicable).
2740 Progress and wait dialogs will ignore this option since they do not respond to
2741 user actions and can only be closed programmatically, so any required function
2742 should be called by the same code after it closes the dialog.
2743 icon String A CSS class that provides a background image to be used as an icon for
2744 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2745 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2746 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2747 modal Boolean False to allow user interaction with the page while the message box is
2748 displayed (defaults to true)
2749 msg String A string that will replace the existing message box body text (defaults
2750 to the XHTML-compliant non-breaking space character ' ')
2751 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2752 progress Boolean True to display a progress bar (defaults to false)
2753 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2754 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2755 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2756 title String The title text
2757 value String The string value to set into the active textbox element if displayed
2758 wait Boolean True to display a progress bar (defaults to false)
2759 width Number The width of the dialog in pixels
2766 msg: 'Please enter your address:',
2768 buttons: Roo.MessageBox.OKCANCEL,
2771 animEl: 'addAddressBtn'
2774 * @param {Object} config Configuration options
2775 * @return {Roo.MessageBox} This message box
2777 show : function(options)
2780 // this causes nightmares if you show one dialog after another
2781 // especially on callbacks..
2783 if(this.isVisible()){
2786 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2787 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2788 Roo.log("New Dialog Message:" + options.msg )
2789 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2790 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2793 var d = this.getDialog();
2795 d.setTitle(opt.title || " ");
2796 d.closeEl.setDisplayed(opt.closable !== false);
2797 activeTextEl = textboxEl;
2798 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2803 textareaEl.setHeight(typeof opt.multiline == "number" ?
2804 opt.multiline : this.defaultTextHeight);
2805 activeTextEl = textareaEl;
2814 progressEl.setDisplayed(opt.progress === true);
2815 this.updateProgress(0);
2816 activeTextEl.dom.value = opt.value || "";
2818 dlg.setDefaultButton(activeTextEl);
2820 var bs = opt.buttons;
2824 }else if(bs && bs.yes){
2825 db = buttons["yes"];
2827 dlg.setDefaultButton(db);
2829 bwidth = updateButtons(opt.buttons);
2830 this.updateText(opt.msg);
2832 d.el.addClass(opt.cls);
2834 d.proxyDrag = opt.proxyDrag === true;
2835 d.modal = opt.modal !== false;
2836 d.mask = opt.modal !== false ? mask : false;
2838 // force it to the end of the z-index stack so it gets a cursor in FF
2839 document.body.appendChild(dlg.el.dom);
2840 d.animateTarget = null;
2841 d.show(options.animEl);
2847 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2848 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2849 * and closing the message box when the process is complete.
2850 * @param {String} title The title bar text
2851 * @param {String} msg The message box body text
2852 * @return {Roo.MessageBox} This message box
2854 progress : function(title, msg){
2861 minWidth: this.minProgressWidth,
2868 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2869 * If a callback function is passed it will be called after the user clicks the button, and the
2870 * id of the button that was clicked will be passed as the only parameter to the callback
2871 * (could also be the top-right close button).
2872 * @param {String} title The title bar text
2873 * @param {String} msg The message box body text
2874 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2875 * @param {Object} scope (optional) The scope of the callback function
2876 * @return {Roo.MessageBox} This message box
2878 alert : function(title, msg, fn, scope){
2891 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2892 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2893 * You are responsible for closing the message box when the process is complete.
2894 * @param {String} msg The message box body text
2895 * @param {String} title (optional) The title bar text
2896 * @return {Roo.MessageBox} This message box
2898 wait : function(msg, title){
2909 waitTimer = Roo.TaskMgr.start({
2911 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2919 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2920 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2921 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2922 * @param {String} title The title bar text
2923 * @param {String} msg The message box body text
2924 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2925 * @param {Object} scope (optional) The scope of the callback function
2926 * @return {Roo.MessageBox} This message box
2928 confirm : function(title, msg, fn, scope){
2932 buttons: this.YESNO,
2941 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2942 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2943 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2944 * (could also be the top-right close button) and the text that was entered will be passed as the two
2945 * parameters to the callback.
2946 * @param {String} title The title bar text
2947 * @param {String} msg The message box body text
2948 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2949 * @param {Object} scope (optional) The scope of the callback function
2950 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2951 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2952 * @return {Roo.MessageBox} This message box
2954 prompt : function(title, msg, fn, scope, multiline){
2958 buttons: this.OKCANCEL,
2963 multiline: multiline,
2970 * Button config that displays a single OK button
2975 * Button config that displays Yes and No buttons
2978 YESNO : {yes:true, no:true},
2980 * Button config that displays OK and Cancel buttons
2983 OKCANCEL : {ok:true, cancel:true},
2985 * Button config that displays Yes, No and Cancel buttons
2988 YESNOCANCEL : {yes:true, no:true, cancel:true},
2991 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2994 defaultTextHeight : 75,
2996 * The maximum width in pixels of the message box (defaults to 600)
3001 * The minimum width in pixels of the message box (defaults to 100)
3006 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3007 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3010 minProgressWidth : 250,
3012 * An object containing the default button text strings that can be overriden for localized language support.
3013 * Supported properties are: ok, cancel, yes and no.
3014 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3027 * Shorthand for {@link Roo.MessageBox}
3029 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3030 Roo.Msg = Roo.Msg || Roo.MessageBox;
3039 * @class Roo.bootstrap.Navbar
3040 * @extends Roo.bootstrap.Component
3041 * Bootstrap Navbar class
3044 * Create a new Navbar
3045 * @param {Object} config The config object
3049 Roo.bootstrap.Navbar = function(config){
3050 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3054 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3063 getAutoCreate : function(){
3066 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3070 initEvents :function ()
3072 //Roo.log(this.el.select('.navbar-toggle',true));
3073 this.el.select('.navbar-toggle',true).on('click', function() {
3074 // Roo.log('click');
3075 this.el.select('.navbar-collapse',true).toggleClass('in');
3083 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3085 var size = this.el.getSize();
3086 this.maskEl.setSize(size.width, size.height);
3087 this.maskEl.enableDisplayMode("block");
3096 getChildContainer : function()
3098 if (this.el.select('.collapse').getCount()) {
3099 return this.el.select('.collapse',true).first();
3132 * @class Roo.bootstrap.NavSimplebar
3133 * @extends Roo.bootstrap.Navbar
3134 * Bootstrap Sidebar class
3136 * @cfg {Boolean} inverse is inverted color
3138 * @cfg {String} type (nav | pills | tabs)
3139 * @cfg {Boolean} arrangement stacked | justified
3140 * @cfg {String} align (left | right) alignment
3142 * @cfg {Boolean} main (true|false) main nav bar? default false
3143 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3145 * @cfg {String} tag (header|footer|nav|div) default is nav
3151 * Create a new Sidebar
3152 * @param {Object} config The config object
3156 Roo.bootstrap.NavSimplebar = function(config){
3157 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3160 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3176 getAutoCreate : function(){
3180 tag : this.tag || 'div',
3193 this.type = this.type || 'nav';
3194 if (['tabs','pills'].indexOf(this.type)!==-1) {
3195 cfg.cn[0].cls += ' nav-' + this.type
3199 if (this.type!=='nav') {
3200 Roo.log('nav type must be nav/tabs/pills')
3202 cfg.cn[0].cls += ' navbar-nav'
3208 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3209 cfg.cn[0].cls += ' nav-' + this.arrangement;
3213 if (this.align === 'right') {
3214 cfg.cn[0].cls += ' navbar-right';
3218 cfg.cls += ' navbar-inverse';
3245 * @class Roo.bootstrap.NavHeaderbar
3246 * @extends Roo.bootstrap.NavSimplebar
3247 * Bootstrap Sidebar class
3249 * @cfg {String} brand what is brand
3250 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3251 * @cfg {String} brand_href href of the brand
3252 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3253 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3254 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3255 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3258 * Create a new Sidebar
3259 * @param {Object} config The config object
3263 Roo.bootstrap.NavHeaderbar = function(config){
3264 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3268 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3275 desktopCenter : false,
3278 getAutoCreate : function(){
3281 tag: this.nav || 'nav',
3288 if (this.desktopCenter) {
3289 cn.push({cls : 'container', cn : []});
3296 cls: 'navbar-header',
3301 cls: 'navbar-toggle',
3302 'data-toggle': 'collapse',
3307 html: 'Toggle navigation'
3329 cls: 'collapse navbar-collapse',
3333 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3335 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3336 cfg.cls += ' navbar-' + this.position;
3338 // tag can override this..
3340 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3343 if (this.brand !== '') {
3346 href: this.brand_href ? this.brand_href : '#',
3347 cls: 'navbar-brand',
3355 cfg.cls += ' main-nav';
3363 getHeaderChildContainer : function()
3365 if (this.el.select('.navbar-header').getCount()) {
3366 return this.el.select('.navbar-header',true).first();
3369 return this.getChildContainer();
3373 initEvents : function()
3375 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3377 if (this.autohide) {
3382 Roo.get(document).on('scroll',function(e) {
3383 var ns = Roo.get(document).getScroll().top;
3384 var os = prevScroll;
3388 ft.removeClass('slideDown');
3389 ft.addClass('slideUp');
3392 ft.removeClass('slideUp');
3393 ft.addClass('slideDown');
3417 * @class Roo.bootstrap.NavSidebar
3418 * @extends Roo.bootstrap.Navbar
3419 * Bootstrap Sidebar class
3422 * Create a new Sidebar
3423 * @param {Object} config The config object
3427 Roo.bootstrap.NavSidebar = function(config){
3428 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3431 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3433 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3435 getAutoCreate : function(){
3440 cls: 'sidebar sidebar-nav'
3462 * @class Roo.bootstrap.NavGroup
3463 * @extends Roo.bootstrap.Component
3464 * Bootstrap NavGroup class
3465 * @cfg {String} align left | right
3466 * @cfg {Boolean} inverse false | true
3467 * @cfg {String} type (nav|pills|tab) default nav
3468 * @cfg {String} navId - reference Id for navbar.
3472 * Create a new nav group
3473 * @param {Object} config The config object
3476 Roo.bootstrap.NavGroup = function(config){
3477 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3480 Roo.bootstrap.NavGroup.register(this);
3484 * Fires when the active item changes
3485 * @param {Roo.bootstrap.NavGroup} this
3486 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3487 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3494 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3505 getAutoCreate : function()
3507 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3514 if (['tabs','pills'].indexOf(this.type)!==-1) {
3515 cfg.cls += ' nav-' + this.type
3517 if (this.type!=='nav') {
3518 Roo.log('nav type must be nav/tabs/pills')
3520 cfg.cls += ' navbar-nav'
3523 if (this.parent().sidebar) {
3526 cls: 'dashboard-menu sidebar-menu'
3532 if (this.form === true) {
3538 if (this.align === 'right') {
3539 cfg.cls += ' navbar-right';
3541 cfg.cls += ' navbar-left';
3545 if (this.align === 'right') {
3546 cfg.cls += ' navbar-right';
3550 cfg.cls += ' navbar-inverse';
3558 * sets the active Navigation item
3559 * @param {Roo.bootstrap.NavItem} the new current navitem
3561 setActiveItem : function(item)
3564 Roo.each(this.navItems, function(v){
3569 v.setActive(false, true);
3576 item.setActive(true, true);
3577 this.fireEvent('changed', this, item, prev);
3582 * gets the active Navigation item
3583 * @return {Roo.bootstrap.NavItem} the current navitem
3585 getActive : function()
3589 Roo.each(this.navItems, function(v){
3600 indexOfNav : function()
3604 Roo.each(this.navItems, function(v,i){
3615 * adds a Navigation item
3616 * @param {Roo.bootstrap.NavItem} the navitem to add
3618 addItem : function(cfg)
3620 var cn = new Roo.bootstrap.NavItem(cfg);
3622 cn.parentId = this.id;
3623 cn.onRender(this.el, null);
3627 * register a Navigation item
3628 * @param {Roo.bootstrap.NavItem} the navitem to add
3630 register : function(item)
3632 this.navItems.push( item);
3633 item.navId = this.navId;
3638 * clear all the Navigation item
3641 clearAll : function()
3644 this.el.dom.innerHTML = '';
3647 getNavItem: function(tabId)
3650 Roo.each(this.navItems, function(e) {
3651 if (e.tabId == tabId) {
3661 setActiveNext : function()
3663 var i = this.indexOfNav(this.getActive());
3664 if (i > this.navItems.length) {
3667 this.setActiveItem(this.navItems[i+1]);
3669 setActivePrev : function()
3671 var i = this.indexOfNav(this.getActive());
3675 this.setActiveItem(this.navItems[i-1]);
3677 clearWasActive : function(except) {
3678 Roo.each(this.navItems, function(e) {
3679 if (e.tabId != except.tabId && e.was_active) {
3680 e.was_active = false;
3687 getWasActive : function ()
3690 Roo.each(this.navItems, function(e) {
3705 Roo.apply(Roo.bootstrap.NavGroup, {
3709 * register a Navigation Group
3710 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3712 register : function(navgrp)
3714 this.groups[navgrp.navId] = navgrp;
3718 * fetch a Navigation Group based on the navigation ID
3719 * @param {string} the navgroup to add
3720 * @returns {Roo.bootstrap.NavGroup} the navgroup
3722 get: function(navId) {
3723 if (typeof(this.groups[navId]) == 'undefined') {
3725 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3727 return this.groups[navId] ;
3742 * @class Roo.bootstrap.NavItem
3743 * @extends Roo.bootstrap.Component
3744 * Bootstrap Navbar.NavItem class
3745 * @cfg {String} href link to
3746 * @cfg {String} html content of button
3747 * @cfg {String} badge text inside badge
3748 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3749 * @cfg {String} glyphicon name of glyphicon
3750 * @cfg {String} icon name of font awesome icon
3751 * @cfg {Boolean} active Is item active
3752 * @cfg {Boolean} disabled Is item disabled
3754 * @cfg {Boolean} preventDefault (true | false) default false
3755 * @cfg {String} tabId the tab that this item activates.
3756 * @cfg {String} tagtype (a|span) render as a href or span?
3759 * Create a new Navbar Item
3760 * @param {Object} config The config object
3762 Roo.bootstrap.NavItem = function(config){
3763 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3768 * The raw click event for the entire grid.
3769 * @param {Roo.EventObject} e
3774 * Fires when the active item active state changes
3775 * @param {Roo.bootstrap.NavItem} this
3776 * @param {boolean} state the new state
3784 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3792 preventDefault : false,
3799 getAutoCreate : function(){
3807 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3809 if (this.disabled) {
3810 cfg.cls += ' disabled';
3813 if (this.href || this.html || this.glyphicon || this.icon) {
3817 href : this.href || "#",
3818 html: this.html || ''
3823 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3826 if(this.glyphicon) {
3827 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3832 cfg.cn[0].html += " <span class='caret'></span>";
3836 if (this.badge !== '') {
3838 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3846 initEvents: function()
3848 if (typeof (this.menu) != 'undefined') {
3849 this.menu.parentType = this.xtype;
3850 this.menu.triggerEl = this.el;
3851 this.menu = this.addxtype(Roo.apply({}, this.menu));
3854 this.el.select('a',true).on('click', this.onClick, this);
3856 if(this.tagtype == 'span'){
3857 this.el.select('span',true).on('click', this.onClick, this);
3860 // at this point parent should be available..
3861 this.parent().register(this);
3864 onClick : function(e)
3866 if(this.preventDefault || this.href == '#'){
3870 if (this.disabled) {
3874 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3875 if (tg && tg.transition) {
3876 Roo.log("waiting for the transitionend");
3880 Roo.log("fire event clicked");
3881 if(this.fireEvent('click', this, e) === false){
3885 if(this.tagtype == 'span'){
3889 var p = this.parent();
3890 if (['tabs','pills'].indexOf(p.type)!==-1) {
3891 if (typeof(p.setActiveItem) !== 'undefined') {
3892 p.setActiveItem(this);
3895 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3896 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3897 // remove the collapsed menu expand...
3898 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3903 isActive: function () {
3906 setActive : function(state, fire, is_was_active)
3908 if (this.active && !state & this.navId) {
3909 this.was_active = true;
3910 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3912 nv.clearWasActive(this);
3916 this.active = state;
3919 this.el.removeClass('active');
3920 } else if (!this.el.hasClass('active')) {
3921 this.el.addClass('active');
3924 this.fireEvent('changed', this, state);
3927 // show a panel if it's registered and related..
3929 if (!this.navId || !this.tabId || !state || is_was_active) {
3933 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3937 var pan = tg.getPanelByName(this.tabId);
3941 // if we can not flip to new panel - go back to old nav highlight..
3942 if (false == tg.showPanel(pan)) {
3943 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3945 var onav = nv.getWasActive();
3947 onav.setActive(true, false, true);
3956 // this should not be here...
3957 setDisabled : function(state)
3959 this.disabled = state;
3961 this.el.removeClass('disabled');
3962 } else if (!this.el.hasClass('disabled')) {
3963 this.el.addClass('disabled');
3969 * Fetch the element to display the tooltip on.
3970 * @return {Roo.Element} defaults to this.el
3972 tooltipEl : function()
3974 return this.el.select('' + this.tagtype + '', true).first();
3985 * <span> icon </span>
3986 * <span> text </span>
3987 * <span>badge </span>
3991 * @class Roo.bootstrap.NavSidebarItem
3992 * @extends Roo.bootstrap.NavItem
3993 * Bootstrap Navbar.NavSidebarItem class
3995 * Create a new Navbar Button
3996 * @param {Object} config The config object
3998 Roo.bootstrap.NavSidebarItem = function(config){
3999 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4004 * The raw click event for the entire grid.
4005 * @param {Roo.EventObject} e
4010 * Fires when the active item active state changes
4011 * @param {Roo.bootstrap.NavSidebarItem} this
4012 * @param {boolean} state the new state
4020 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4023 getAutoCreate : function(){
4028 href : this.href || '#',
4040 html : this.html || ''
4045 cfg.cls += ' active';
4049 if (this.glyphicon || this.icon) {
4050 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4051 a.cn.push({ tag : 'i', cls : c }) ;
4056 if (this.badge !== '') {
4057 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4061 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4062 a.cls += 'dropdown-toggle treeview' ;
4086 * @class Roo.bootstrap.Row
4087 * @extends Roo.bootstrap.Component
4088 * Bootstrap Row class (contains columns...)
4092 * @param {Object} config The config object
4095 Roo.bootstrap.Row = function(config){
4096 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4099 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4101 getAutoCreate : function(){
4120 * @class Roo.bootstrap.Element
4121 * @extends Roo.bootstrap.Component
4122 * Bootstrap Element class
4123 * @cfg {String} html contents of the element
4124 * @cfg {String} tag tag of the element
4125 * @cfg {String} cls class of the element
4128 * Create a new Element
4129 * @param {Object} config The config object
4132 Roo.bootstrap.Element = function(config){
4133 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4136 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4143 getAutoCreate : function(){
4168 * @class Roo.bootstrap.Pagination
4169 * @extends Roo.bootstrap.Component
4170 * Bootstrap Pagination class
4171 * @cfg {String} size xs | sm | md | lg
4172 * @cfg {Boolean} inverse false | true
4175 * Create a new Pagination
4176 * @param {Object} config The config object
4179 Roo.bootstrap.Pagination = function(config){
4180 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4183 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4189 getAutoCreate : function(){
4195 cfg.cls += ' inverse';
4201 cfg.cls += " " + this.cls;
4219 * @class Roo.bootstrap.PaginationItem
4220 * @extends Roo.bootstrap.Component
4221 * Bootstrap PaginationItem class
4222 * @cfg {String} html text
4223 * @cfg {String} href the link
4224 * @cfg {Boolean} preventDefault (true | false) default true
4225 * @cfg {Boolean} active (true | false) default false
4226 * @cfg {Boolean} disabled default false
4230 * Create a new PaginationItem
4231 * @param {Object} config The config object
4235 Roo.bootstrap.PaginationItem = function(config){
4236 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4241 * The raw click event for the entire grid.
4242 * @param {Roo.EventObject} e
4248 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4252 preventDefault: true,
4257 getAutoCreate : function(){
4263 href : this.href ? this.href : '#',
4264 html : this.html ? this.html : ''
4274 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4278 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4284 initEvents: function() {
4286 this.el.on('click', this.onClick, this);
4289 onClick : function(e)
4291 Roo.log('PaginationItem on click ');
4292 if(this.preventDefault){
4300 this.fireEvent('click', this, e);
4316 * @class Roo.bootstrap.Slider
4317 * @extends Roo.bootstrap.Component
4318 * Bootstrap Slider class
4321 * Create a new Slider
4322 * @param {Object} config The config object
4325 Roo.bootstrap.Slider = function(config){
4326 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4329 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4331 getAutoCreate : function(){
4335 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4339 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4351 * Ext JS Library 1.1.1
4352 * Copyright(c) 2006-2007, Ext JS, LLC.
4354 * Originally Released Under LGPL - original licence link has changed is not relivant.
4357 * <script type="text/javascript">
4362 * @class Roo.grid.ColumnModel
4363 * @extends Roo.util.Observable
4364 * This is the default implementation of a ColumnModel used by the Grid. It defines
4365 * the columns in the grid.
4368 var colModel = new Roo.grid.ColumnModel([
4369 {header: "Ticker", width: 60, sortable: true, locked: true},
4370 {header: "Company Name", width: 150, sortable: true},
4371 {header: "Market Cap.", width: 100, sortable: true},
4372 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4373 {header: "Employees", width: 100, sortable: true, resizable: false}
4378 * The config options listed for this class are options which may appear in each
4379 * individual column definition.
4380 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4382 * @param {Object} config An Array of column config objects. See this class's
4383 * config objects for details.
4385 Roo.grid.ColumnModel = function(config){
4387 * The config passed into the constructor
4389 this.config = config;
4392 // if no id, create one
4393 // if the column does not have a dataIndex mapping,
4394 // map it to the order it is in the config
4395 for(var i = 0, len = config.length; i < len; i++){
4397 if(typeof c.dataIndex == "undefined"){
4400 if(typeof c.renderer == "string"){
4401 c.renderer = Roo.util.Format[c.renderer];
4403 if(typeof c.id == "undefined"){
4406 if(c.editor && c.editor.xtype){
4407 c.editor = Roo.factory(c.editor, Roo.grid);
4409 if(c.editor && c.editor.isFormField){
4410 c.editor = new Roo.grid.GridEditor(c.editor);
4412 this.lookup[c.id] = c;
4416 * The width of columns which have no width specified (defaults to 100)
4419 this.defaultWidth = 100;
4422 * Default sortable of columns which have no sortable specified (defaults to false)
4425 this.defaultSortable = false;
4429 * @event widthchange
4430 * Fires when the width of a column changes.
4431 * @param {ColumnModel} this
4432 * @param {Number} columnIndex The column index
4433 * @param {Number} newWidth The new width
4435 "widthchange": true,
4437 * @event headerchange
4438 * Fires when the text of a header changes.
4439 * @param {ColumnModel} this
4440 * @param {Number} columnIndex The column index
4441 * @param {Number} newText The new header text
4443 "headerchange": true,
4445 * @event hiddenchange
4446 * Fires when a column is hidden or "unhidden".
4447 * @param {ColumnModel} this
4448 * @param {Number} columnIndex The column index
4449 * @param {Boolean} hidden true if hidden, false otherwise
4451 "hiddenchange": true,
4453 * @event columnmoved
4454 * Fires when a column is moved.
4455 * @param {ColumnModel} this
4456 * @param {Number} oldIndex
4457 * @param {Number} newIndex
4459 "columnmoved" : true,
4461 * @event columlockchange
4462 * Fires when a column's locked state is changed
4463 * @param {ColumnModel} this
4464 * @param {Number} colIndex
4465 * @param {Boolean} locked true if locked
4467 "columnlockchange" : true
4469 Roo.grid.ColumnModel.superclass.constructor.call(this);
4471 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4473 * @cfg {String} header The header text to display in the Grid view.
4476 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4477 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4478 * specified, the column's index is used as an index into the Record's data Array.
4481 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4482 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4485 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4486 * Defaults to the value of the {@link #defaultSortable} property.
4487 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4490 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4493 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4496 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4499 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4502 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4503 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4504 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4505 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4508 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4511 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4514 * @cfg {String} cursor (Optional)
4517 * @cfg {String} tooltip (Optional)
4520 * Returns the id of the column at the specified index.
4521 * @param {Number} index The column index
4522 * @return {String} the id
4524 getColumnId : function(index){
4525 return this.config[index].id;
4529 * Returns the column for a specified id.
4530 * @param {String} id The column id
4531 * @return {Object} the column
4533 getColumnById : function(id){
4534 return this.lookup[id];
4539 * Returns the column for a specified dataIndex.
4540 * @param {String} dataIndex The column dataIndex
4541 * @return {Object|Boolean} the column or false if not found
4543 getColumnByDataIndex: function(dataIndex){
4544 var index = this.findColumnIndex(dataIndex);
4545 return index > -1 ? this.config[index] : false;
4549 * Returns the index for a specified column id.
4550 * @param {String} id The column id
4551 * @return {Number} the index, or -1 if not found
4553 getIndexById : function(id){
4554 for(var i = 0, len = this.config.length; i < len; i++){
4555 if(this.config[i].id == id){
4563 * Returns the index for a specified column dataIndex.
4564 * @param {String} dataIndex The column dataIndex
4565 * @return {Number} the index, or -1 if not found
4568 findColumnIndex : function(dataIndex){
4569 for(var i = 0, len = this.config.length; i < len; i++){
4570 if(this.config[i].dataIndex == dataIndex){
4578 moveColumn : function(oldIndex, newIndex){
4579 var c = this.config[oldIndex];
4580 this.config.splice(oldIndex, 1);
4581 this.config.splice(newIndex, 0, c);
4582 this.dataMap = null;
4583 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4586 isLocked : function(colIndex){
4587 return this.config[colIndex].locked === true;
4590 setLocked : function(colIndex, value, suppressEvent){
4591 if(this.isLocked(colIndex) == value){
4594 this.config[colIndex].locked = value;
4596 this.fireEvent("columnlockchange", this, colIndex, value);
4600 getTotalLockedWidth : function(){
4602 for(var i = 0; i < this.config.length; i++){
4603 if(this.isLocked(i) && !this.isHidden(i)){
4604 this.totalWidth += this.getColumnWidth(i);
4610 getLockedCount : function(){
4611 for(var i = 0, len = this.config.length; i < len; i++){
4612 if(!this.isLocked(i)){
4619 * Returns the number of columns.
4622 getColumnCount : function(visibleOnly){
4623 if(visibleOnly === true){
4625 for(var i = 0, len = this.config.length; i < len; i++){
4626 if(!this.isHidden(i)){
4632 return this.config.length;
4636 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4637 * @param {Function} fn
4638 * @param {Object} scope (optional)
4639 * @return {Array} result
4641 getColumnsBy : function(fn, scope){
4643 for(var i = 0, len = this.config.length; i < len; i++){
4644 var c = this.config[i];
4645 if(fn.call(scope||this, c, i) === true){
4653 * Returns true if the specified column is sortable.
4654 * @param {Number} col The column index
4657 isSortable : function(col){
4658 if(typeof this.config[col].sortable == "undefined"){
4659 return this.defaultSortable;
4661 return this.config[col].sortable;
4665 * Returns the rendering (formatting) function defined for the column.
4666 * @param {Number} col The column index.
4667 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4669 getRenderer : function(col){
4670 if(!this.config[col].renderer){
4671 return Roo.grid.ColumnModel.defaultRenderer;
4673 return this.config[col].renderer;
4677 * Sets the rendering (formatting) function for a column.
4678 * @param {Number} col The column index
4679 * @param {Function} fn The function to use to process the cell's raw data
4680 * to return HTML markup for the grid view. The render function is called with
4681 * the following parameters:<ul>
4682 * <li>Data value.</li>
4683 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4684 * <li>css A CSS style string to apply to the table cell.</li>
4685 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4686 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4687 * <li>Row index</li>
4688 * <li>Column index</li>
4689 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4691 setRenderer : function(col, fn){
4692 this.config[col].renderer = fn;
4696 * Returns the width for the specified column.
4697 * @param {Number} col The column index
4700 getColumnWidth : function(col){
4701 return this.config[col].width * 1 || this.defaultWidth;
4705 * Sets the width for a column.
4706 * @param {Number} col The column index
4707 * @param {Number} width The new width
4709 setColumnWidth : function(col, width, suppressEvent){
4710 this.config[col].width = width;
4711 this.totalWidth = null;
4713 this.fireEvent("widthchange", this, col, width);
4718 * Returns the total width of all columns.
4719 * @param {Boolean} includeHidden True to include hidden column widths
4722 getTotalWidth : function(includeHidden){
4723 if(!this.totalWidth){
4724 this.totalWidth = 0;
4725 for(var i = 0, len = this.config.length; i < len; i++){
4726 if(includeHidden || !this.isHidden(i)){
4727 this.totalWidth += this.getColumnWidth(i);
4731 return this.totalWidth;
4735 * Returns the header for the specified column.
4736 * @param {Number} col The column index
4739 getColumnHeader : function(col){
4740 return this.config[col].header;
4744 * Sets the header for a column.
4745 * @param {Number} col The column index
4746 * @param {String} header The new header
4748 setColumnHeader : function(col, header){
4749 this.config[col].header = header;
4750 this.fireEvent("headerchange", this, col, header);
4754 * Returns the tooltip for the specified column.
4755 * @param {Number} col The column index
4758 getColumnTooltip : function(col){
4759 return this.config[col].tooltip;
4762 * Sets the tooltip for a column.
4763 * @param {Number} col The column index
4764 * @param {String} tooltip The new tooltip
4766 setColumnTooltip : function(col, tooltip){
4767 this.config[col].tooltip = tooltip;
4771 * Returns the dataIndex for the specified column.
4772 * @param {Number} col The column index
4775 getDataIndex : function(col){
4776 return this.config[col].dataIndex;
4780 * Sets the dataIndex for a column.
4781 * @param {Number} col The column index
4782 * @param {Number} dataIndex The new dataIndex
4784 setDataIndex : function(col, dataIndex){
4785 this.config[col].dataIndex = dataIndex;
4791 * Returns true if the cell is editable.
4792 * @param {Number} colIndex The column index
4793 * @param {Number} rowIndex The row index
4796 isCellEditable : function(colIndex, rowIndex){
4797 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4801 * Returns the editor defined for the cell/column.
4802 * return false or null to disable editing.
4803 * @param {Number} colIndex The column index
4804 * @param {Number} rowIndex The row index
4807 getCellEditor : function(colIndex, rowIndex){
4808 return this.config[colIndex].editor;
4812 * Sets if a column is editable.
4813 * @param {Number} col The column index
4814 * @param {Boolean} editable True if the column is editable
4816 setEditable : function(col, editable){
4817 this.config[col].editable = editable;
4822 * Returns true if the column is hidden.
4823 * @param {Number} colIndex The column index
4826 isHidden : function(colIndex){
4827 return this.config[colIndex].hidden;
4832 * Returns true if the column width cannot be changed
4834 isFixed : function(colIndex){
4835 return this.config[colIndex].fixed;
4839 * Returns true if the column can be resized
4842 isResizable : function(colIndex){
4843 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4846 * Sets if a column is hidden.
4847 * @param {Number} colIndex The column index
4848 * @param {Boolean} hidden True if the column is hidden
4850 setHidden : function(colIndex, hidden){
4851 this.config[colIndex].hidden = hidden;
4852 this.totalWidth = null;
4853 this.fireEvent("hiddenchange", this, colIndex, hidden);
4857 * Sets the editor for a column.
4858 * @param {Number} col The column index
4859 * @param {Object} editor The editor object
4861 setEditor : function(col, editor){
4862 this.config[col].editor = editor;
4866 Roo.grid.ColumnModel.defaultRenderer = function(value){
4867 if(typeof value == "string" && value.length < 1){
4873 // Alias for backwards compatibility
4874 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4877 * Ext JS Library 1.1.1
4878 * Copyright(c) 2006-2007, Ext JS, LLC.
4880 * Originally Released Under LGPL - original licence link has changed is not relivant.
4883 * <script type="text/javascript">
4887 * @class Roo.LoadMask
4888 * A simple utility class for generically masking elements while loading data. If the element being masked has
4889 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4890 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4891 * element's UpdateManager load indicator and will be destroyed after the initial load.
4893 * Create a new LoadMask
4894 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4895 * @param {Object} config The config object
4897 Roo.LoadMask = function(el, config){
4898 this.el = Roo.get(el);
4899 Roo.apply(this, config);
4901 this.store.on('beforeload', this.onBeforeLoad, this);
4902 this.store.on('load', this.onLoad, this);
4903 this.store.on('loadexception', this.onLoadException, this);
4904 this.removeMask = false;
4906 var um = this.el.getUpdateManager();
4907 um.showLoadIndicator = false; // disable the default indicator
4908 um.on('beforeupdate', this.onBeforeLoad, this);
4909 um.on('update', this.onLoad, this);
4910 um.on('failure', this.onLoad, this);
4911 this.removeMask = true;
4915 Roo.LoadMask.prototype = {
4917 * @cfg {Boolean} removeMask
4918 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4919 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4923 * The text to display in a centered loading message box (defaults to 'Loading...')
4927 * @cfg {String} msgCls
4928 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4930 msgCls : 'x-mask-loading',
4933 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4939 * Disables the mask to prevent it from being displayed
4941 disable : function(){
4942 this.disabled = true;
4946 * Enables the mask so that it can be displayed
4948 enable : function(){
4949 this.disabled = false;
4952 onLoadException : function()
4956 if (typeof(arguments[3]) != 'undefined') {
4957 Roo.MessageBox.alert("Error loading",arguments[3]);
4961 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4962 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4971 this.el.unmask(this.removeMask);
4976 this.el.unmask(this.removeMask);
4980 onBeforeLoad : function(){
4982 this.el.mask(this.msg, this.msgCls);
4987 destroy : function(){
4989 this.store.un('beforeload', this.onBeforeLoad, this);
4990 this.store.un('load', this.onLoad, this);
4991 this.store.un('loadexception', this.onLoadException, this);
4993 var um = this.el.getUpdateManager();
4994 um.un('beforeupdate', this.onBeforeLoad, this);
4995 um.un('update', this.onLoad, this);
4996 um.un('failure', this.onLoad, this);
5007 * @class Roo.bootstrap.Table
5008 * @extends Roo.bootstrap.Component
5009 * Bootstrap Table class
5010 * @cfg {String} cls table class
5011 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5012 * @cfg {String} bgcolor Specifies the background color for a table
5013 * @cfg {Number} border Specifies whether the table cells should have borders or not
5014 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5015 * @cfg {Number} cellspacing Specifies the space between cells
5016 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5017 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5018 * @cfg {String} sortable Specifies that the table should be sortable
5019 * @cfg {String} summary Specifies a summary of the content of a table
5020 * @cfg {Number} width Specifies the width of a table
5021 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5023 * @cfg {boolean} striped Should the rows be alternative striped
5024 * @cfg {boolean} bordered Add borders to the table
5025 * @cfg {boolean} hover Add hover highlighting
5026 * @cfg {boolean} condensed Format condensed
5027 * @cfg {boolean} responsive Format condensed
5028 * @cfg {Boolean} loadMask (true|false) default false
5029 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5030 * @cfg {Boolean} thead (true|false) generate thead, default true
5031 * @cfg {Boolean} RowSelection (true|false) default false
5032 * @cfg {Boolean} CellSelection (true|false) default false
5033 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5037 * Create a new Table
5038 * @param {Object} config The config object
5041 Roo.bootstrap.Table = function(config){
5042 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5045 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5046 this.sm = this.selModel;
5047 this.sm.xmodule = this.xmodule || false;
5049 if (this.cm && typeof(this.cm.config) == 'undefined') {
5050 this.colModel = new Roo.grid.ColumnModel(this.cm);
5051 this.cm = this.colModel;
5052 this.cm.xmodule = this.xmodule || false;
5055 this.store= Roo.factory(this.store, Roo.data);
5056 this.ds = this.store;
5057 this.ds.xmodule = this.xmodule || false;
5060 if (this.footer && this.store) {
5061 this.footer.dataSource = this.ds;
5062 this.footer = Roo.factory(this.footer);
5069 * Fires when a cell is clicked
5070 * @param {Roo.bootstrap.Table} this
5071 * @param {Roo.Element} el
5072 * @param {Number} rowIndex
5073 * @param {Number} columnIndex
5074 * @param {Roo.EventObject} e
5078 * @event celldblclick
5079 * Fires when a cell is double clicked
5080 * @param {Roo.bootstrap.Table} this
5081 * @param {Roo.Element} el
5082 * @param {Number} rowIndex
5083 * @param {Number} columnIndex
5084 * @param {Roo.EventObject} e
5086 "celldblclick" : true,
5089 * Fires when a row is clicked
5090 * @param {Roo.bootstrap.Table} this
5091 * @param {Roo.Element} el
5092 * @param {Number} rowIndex
5093 * @param {Roo.EventObject} e
5097 * @event rowdblclick
5098 * Fires when a row is double clicked
5099 * @param {Roo.bootstrap.Table} this
5100 * @param {Roo.Element} el
5101 * @param {Number} rowIndex
5102 * @param {Roo.EventObject} e
5104 "rowdblclick" : true,
5107 * Fires when a mouseover occur
5108 * @param {Roo.bootstrap.Table} this
5109 * @param {Roo.Element} el
5110 * @param {Number} rowIndex
5111 * @param {Number} columnIndex
5112 * @param {Roo.EventObject} e
5117 * Fires when a mouseout occur
5118 * @param {Roo.bootstrap.Table} this
5119 * @param {Roo.Element} el
5120 * @param {Number} rowIndex
5121 * @param {Number} columnIndex
5122 * @param {Roo.EventObject} e
5127 * Fires when a row is rendered, so you can change add a style to it.
5128 * @param {Roo.bootstrap.Table} this
5129 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5133 * @event rowsrendered
5134 * Fires when all the rows have been rendered
5135 * @param {Roo.bootstrap.Table} this
5137 'rowsrendered' : true
5142 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5166 RowSelection : false,
5167 CellSelection : false,
5170 // Roo.Element - the tbody
5173 getAutoCreate : function(){
5174 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5183 cfg.cls += ' table-striped';
5187 cfg.cls += ' table-hover';
5189 if (this.bordered) {
5190 cfg.cls += ' table-bordered';
5192 if (this.condensed) {
5193 cfg.cls += ' table-condensed';
5195 if (this.responsive) {
5196 cfg.cls += ' table-responsive';
5200 cfg.cls+= ' ' +this.cls;
5203 // this lot should be simplifed...
5206 cfg.align=this.align;
5209 cfg.bgcolor=this.bgcolor;
5212 cfg.border=this.border;
5214 if (this.cellpadding) {
5215 cfg.cellpadding=this.cellpadding;
5217 if (this.cellspacing) {
5218 cfg.cellspacing=this.cellspacing;
5221 cfg.frame=this.frame;
5224 cfg.rules=this.rules;
5226 if (this.sortable) {
5227 cfg.sortable=this.sortable;
5230 cfg.summary=this.summary;
5233 cfg.width=this.width;
5236 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5239 if(this.store || this.cm){
5241 cfg.cn.push(this.renderHeader());
5244 cfg.cn.push(this.renderBody());
5247 cfg.cn.push(this.renderFooter());
5250 cfg.cls+= ' TableGrid';
5253 return { cn : [ cfg ] };
5256 initEvents : function()
5258 if(!this.store || !this.cm){
5262 //Roo.log('initEvents with ds!!!!');
5264 this.mainBody = this.el.select('tbody', true).first();
5269 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5270 e.on('click', _this.sort, _this);
5273 this.el.on("click", this.onClick, this);
5274 this.el.on("dblclick", this.onDblClick, this);
5276 // why is this done????? = it breaks dialogs??
5277 //this.parent().el.setStyle('position', 'relative');
5281 this.footer.parentId = this.id;
5282 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5285 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5287 this.store.on('load', this.onLoad, this);
5288 this.store.on('beforeload', this.onBeforeLoad, this);
5289 this.store.on('update', this.onUpdate, this);
5290 this.store.on('add', this.onAdd, this);
5294 onMouseover : function(e, el)
5296 var cell = Roo.get(el);
5302 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5303 cell = cell.findParent('td', false, true);
5306 var row = cell.findParent('tr', false, true);
5307 var cellIndex = cell.dom.cellIndex;
5308 var rowIndex = row.dom.rowIndex - 1; // start from 0
5310 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5314 onMouseout : function(e, el)
5316 var cell = Roo.get(el);
5322 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5323 cell = cell.findParent('td', false, true);
5326 var row = cell.findParent('tr', false, true);
5327 var cellIndex = cell.dom.cellIndex;
5328 var rowIndex = row.dom.rowIndex - 1; // start from 0
5330 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5334 onClick : function(e, el)
5336 var cell = Roo.get(el);
5338 if(!cell || (!this.CellSelection && !this.RowSelection)){
5342 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5343 cell = cell.findParent('td', false, true);
5346 if(!cell || typeof(cell) == 'undefined'){
5350 var row = cell.findParent('tr', false, true);
5352 if(!row || typeof(row) == 'undefined'){
5356 var cellIndex = cell.dom.cellIndex;
5357 var rowIndex = this.getRowIndex(row);
5359 if(this.CellSelection){
5360 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5363 if(this.RowSelection){
5364 this.fireEvent('rowclick', this, row, rowIndex, e);
5370 onDblClick : function(e,el)
5372 var cell = Roo.get(el);
5374 if(!cell || (!this.CellSelection && !this.RowSelection)){
5378 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5379 cell = cell.findParent('td', false, true);
5382 if(!cell || typeof(cell) == 'undefined'){
5386 var row = cell.findParent('tr', false, true);
5388 if(!row || typeof(row) == 'undefined'){
5392 var cellIndex = cell.dom.cellIndex;
5393 var rowIndex = this.getRowIndex(row);
5395 if(this.CellSelection){
5396 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5399 if(this.RowSelection){
5400 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5404 sort : function(e,el)
5406 var col = Roo.get(el);
5408 if(!col.hasClass('sortable')){
5412 var sort = col.attr('sort');
5415 if(col.hasClass('glyphicon-arrow-up')){
5419 this.store.sortInfo = {field : sort, direction : dir};
5422 Roo.log("calling footer first");
5423 this.footer.onClick('first');
5426 this.store.load({ params : { start : 0 } });
5430 renderHeader : function()
5439 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5441 var config = cm.config[i];
5446 html: cm.getColumnHeader(i)
5449 if(typeof(config.tooltip) != 'undefined'){
5450 c.tooltip = config.tooltip;
5453 if(typeof(config.colspan) != 'undefined'){
5454 c.colspan = config.colspan;
5457 if(typeof(config.hidden) != 'undefined' && config.hidden){
5458 c.style += ' display:none;';
5461 if(typeof(config.dataIndex) != 'undefined'){
5462 c.sort = config.dataIndex;
5465 if(typeof(config.sortable) != 'undefined' && config.sortable){
5469 if(typeof(config.align) != 'undefined' && config.align.length){
5470 c.style += ' text-align:' + config.align + ';';
5473 if(typeof(config.width) != 'undefined'){
5474 c.style += ' width:' + config.width + 'px;';
5483 renderBody : function()
5493 colspan : this.cm.getColumnCount()
5503 renderFooter : function()
5513 colspan : this.cm.getColumnCount()
5527 Roo.log('ds onload');
5532 var ds = this.store;
5534 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5535 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5537 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5538 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5541 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5542 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5546 var tbody = this.mainBody;
5548 if(ds.getCount() > 0){
5549 ds.data.each(function(d,rowIndex){
5550 var row = this.renderRow(cm, ds, rowIndex);
5552 tbody.createChild(row);
5556 if(row.cellObjects.length){
5557 Roo.each(row.cellObjects, function(r){
5558 _this.renderCellObject(r);
5565 Roo.each(this.el.select('tbody td', true).elements, function(e){
5566 e.on('mouseover', _this.onMouseover, _this);
5569 Roo.each(this.el.select('tbody td', true).elements, function(e){
5570 e.on('mouseout', _this.onMouseout, _this);
5572 this.fireEvent('rowsrendered', this);
5573 //if(this.loadMask){
5574 // this.maskEl.hide();
5579 onUpdate : function(ds,record)
5581 this.refreshRow(record);
5584 onRemove : function(ds, record, index, isUpdate){
5585 if(isUpdate !== true){
5586 this.fireEvent("beforerowremoved", this, index, record);
5588 var bt = this.mainBody.dom;
5590 var rows = this.el.select('tbody > tr', true).elements;
5592 if(typeof(rows[index]) != 'undefined'){
5593 bt.removeChild(rows[index].dom);
5596 // if(bt.rows[index]){
5597 // bt.removeChild(bt.rows[index]);
5600 if(isUpdate !== true){
5601 //this.stripeRows(index);
5602 //this.syncRowHeights(index, index);
5604 this.fireEvent("rowremoved", this, index, record);
5608 onAdd : function(ds, records, rowIndex)
5610 //Roo.log('on Add called');
5611 // - note this does not handle multiple adding very well..
5612 var bt = this.mainBody.dom;
5613 for (var i =0 ; i < records.length;i++) {
5614 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5615 //Roo.log(records[i]);
5616 //Roo.log(this.store.getAt(rowIndex+i));
5617 this.insertRow(this.store, rowIndex + i, false);
5624 refreshRow : function(record){
5625 var ds = this.store, index;
5626 if(typeof record == 'number'){
5628 record = ds.getAt(index);
5630 index = ds.indexOf(record);
5632 this.insertRow(ds, index, true);
5633 this.onRemove(ds, record, index+1, true);
5634 //this.syncRowHeights(index, index);
5636 this.fireEvent("rowupdated", this, index, record);
5639 insertRow : function(dm, rowIndex, isUpdate){
5642 this.fireEvent("beforerowsinserted", this, rowIndex);
5644 //var s = this.getScrollState();
5645 var row = this.renderRow(this.cm, this.store, rowIndex);
5646 // insert before rowIndex..
5647 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5651 if(row.cellObjects.length){
5652 Roo.each(row.cellObjects, function(r){
5653 _this.renderCellObject(r);
5658 this.fireEvent("rowsinserted", this, rowIndex);
5659 //this.syncRowHeights(firstRow, lastRow);
5660 //this.stripeRows(firstRow);
5667 getRowDom : function(rowIndex)
5669 var rows = this.el.select('tbody > tr', true).elements;
5671 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5674 // returns the object tree for a tr..
5677 renderRow : function(cm, ds, rowIndex)
5680 var d = ds.getAt(rowIndex);
5687 var cellObjects = [];
5689 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5690 var config = cm.config[i];
5692 var renderer = cm.getRenderer(i);
5696 if(typeof(renderer) !== 'undefined'){
5697 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5699 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5700 // and are rendered into the cells after the row is rendered - using the id for the element.
5702 if(typeof(value) === 'object'){
5712 rowIndex : rowIndex,
5717 this.fireEvent('rowclass', this, rowcfg);
5721 cls : rowcfg.rowClass,
5723 html: (typeof(value) === 'object') ? '' : value
5730 if(typeof(config.colspan) != 'undefined'){
5731 td.colspan = config.colspan;
5734 if(typeof(config.hidden) != 'undefined' && config.hidden){
5735 td.style += ' display:none;';
5738 if(typeof(config.align) != 'undefined' && config.align.length){
5739 td.style += ' text-align:' + config.align + ';';
5742 if(typeof(config.width) != 'undefined'){
5743 td.style += ' width:' + config.width + 'px;';
5746 if(typeof(config.cursor) != 'undefined'){
5747 td.style += ' cursor:' + config.cursor + ';';
5754 row.cellObjects = cellObjects;
5762 onBeforeLoad : function()
5764 //Roo.log('ds onBeforeLoad');
5768 //if(this.loadMask){
5769 // this.maskEl.show();
5777 this.el.select('tbody', true).first().dom.innerHTML = '';
5780 * Show or hide a row.
5781 * @param {Number} rowIndex to show or hide
5782 * @param {Boolean} state hide
5784 setRowVisibility : function(rowIndex, state)
5786 var bt = this.mainBody.dom;
5788 var rows = this.el.select('tbody > tr', true).elements;
5790 if(typeof(rows[rowIndex]) == 'undefined'){
5793 rows[rowIndex].dom.style.display = state ? '' : 'none';
5797 getSelectionModel : function(){
5799 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5801 return this.selModel;
5804 * Render the Roo.bootstrap object from renderder
5806 renderCellObject : function(r)
5810 var t = r.cfg.render(r.container);
5813 Roo.each(r.cfg.cn, function(c){
5815 container: t.getChildContainer(),
5818 _this.renderCellObject(child);
5823 getRowIndex : function(row)
5827 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5850 * @class Roo.bootstrap.TableCell
5851 * @extends Roo.bootstrap.Component
5852 * Bootstrap TableCell class
5853 * @cfg {String} html cell contain text
5854 * @cfg {String} cls cell class
5855 * @cfg {String} tag cell tag (td|th) default td
5856 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5857 * @cfg {String} align Aligns the content in a cell
5858 * @cfg {String} axis Categorizes cells
5859 * @cfg {String} bgcolor Specifies the background color of a cell
5860 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5861 * @cfg {Number} colspan Specifies the number of columns a cell should span
5862 * @cfg {String} headers Specifies one or more header cells a cell is related to
5863 * @cfg {Number} height Sets the height of a cell
5864 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5865 * @cfg {Number} rowspan Sets the number of rows a cell should span
5866 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5867 * @cfg {String} valign Vertical aligns the content in a cell
5868 * @cfg {Number} width Specifies the width of a cell
5871 * Create a new TableCell
5872 * @param {Object} config The config object
5875 Roo.bootstrap.TableCell = function(config){
5876 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5879 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5899 getAutoCreate : function(){
5900 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5920 cfg.align=this.align
5926 cfg.bgcolor=this.bgcolor
5929 cfg.charoff=this.charoff
5932 cfg.colspan=this.colspan
5935 cfg.headers=this.headers
5938 cfg.height=this.height
5941 cfg.nowrap=this.nowrap
5944 cfg.rowspan=this.rowspan
5947 cfg.scope=this.scope
5950 cfg.valign=this.valign
5953 cfg.width=this.width
5972 * @class Roo.bootstrap.TableRow
5973 * @extends Roo.bootstrap.Component
5974 * Bootstrap TableRow class
5975 * @cfg {String} cls row class
5976 * @cfg {String} align Aligns the content in a table row
5977 * @cfg {String} bgcolor Specifies a background color for a table row
5978 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5979 * @cfg {String} valign Vertical aligns the content in a table row
5982 * Create a new TableRow
5983 * @param {Object} config The config object
5986 Roo.bootstrap.TableRow = function(config){
5987 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5990 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5998 getAutoCreate : function(){
5999 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6009 cfg.align = this.align;
6012 cfg.bgcolor = this.bgcolor;
6015 cfg.charoff = this.charoff;
6018 cfg.valign = this.valign;
6036 * @class Roo.bootstrap.TableBody
6037 * @extends Roo.bootstrap.Component
6038 * Bootstrap TableBody class
6039 * @cfg {String} cls element class
6040 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6041 * @cfg {String} align Aligns the content inside the element
6042 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6043 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6046 * Create a new TableBody
6047 * @param {Object} config The config object
6050 Roo.bootstrap.TableBody = function(config){
6051 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6054 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6062 getAutoCreate : function(){
6063 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6077 cfg.align = this.align;
6080 cfg.charoff = this.charoff;
6083 cfg.valign = this.valign;
6090 // initEvents : function()
6097 // this.store = Roo.factory(this.store, Roo.data);
6098 // this.store.on('load', this.onLoad, this);
6100 // this.store.load();
6104 // onLoad: function ()
6106 // this.fireEvent('load', this);
6116 * Ext JS Library 1.1.1
6117 * Copyright(c) 2006-2007, Ext JS, LLC.
6119 * Originally Released Under LGPL - original licence link has changed is not relivant.
6122 * <script type="text/javascript">
6125 // as we use this in bootstrap.
6126 Roo.namespace('Roo.form');
6128 * @class Roo.form.Action
6129 * Internal Class used to handle form actions
6131 * @param {Roo.form.BasicForm} el The form element or its id
6132 * @param {Object} config Configuration options
6137 // define the action interface
6138 Roo.form.Action = function(form, options){
6140 this.options = options || {};
6143 * Client Validation Failed
6146 Roo.form.Action.CLIENT_INVALID = 'client';
6148 * Server Validation Failed
6151 Roo.form.Action.SERVER_INVALID = 'server';
6153 * Connect to Server Failed
6156 Roo.form.Action.CONNECT_FAILURE = 'connect';
6158 * Reading Data from Server Failed
6161 Roo.form.Action.LOAD_FAILURE = 'load';
6163 Roo.form.Action.prototype = {
6165 failureType : undefined,
6166 response : undefined,
6170 run : function(options){
6175 success : function(response){
6180 handleResponse : function(response){
6184 // default connection failure
6185 failure : function(response){
6187 this.response = response;
6188 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6189 this.form.afterAction(this, false);
6192 processResponse : function(response){
6193 this.response = response;
6194 if(!response.responseText){
6197 this.result = this.handleResponse(response);
6201 // utility functions used internally
6202 getUrl : function(appendParams){
6203 var url = this.options.url || this.form.url || this.form.el.dom.action;
6205 var p = this.getParams();
6207 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6213 getMethod : function(){
6214 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6217 getParams : function(){
6218 var bp = this.form.baseParams;
6219 var p = this.options.params;
6221 if(typeof p == "object"){
6222 p = Roo.urlEncode(Roo.applyIf(p, bp));
6223 }else if(typeof p == 'string' && bp){
6224 p += '&' + Roo.urlEncode(bp);
6227 p = Roo.urlEncode(bp);
6232 createCallback : function(){
6234 success: this.success,
6235 failure: this.failure,
6237 timeout: (this.form.timeout*1000),
6238 upload: this.form.fileUpload ? this.success : undefined
6243 Roo.form.Action.Submit = function(form, options){
6244 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6247 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6250 haveProgress : false,
6251 uploadComplete : false,
6253 // uploadProgress indicator.
6254 uploadProgress : function()
6256 if (!this.form.progressUrl) {
6260 if (!this.haveProgress) {
6261 Roo.MessageBox.progress("Uploading", "Uploading");
6263 if (this.uploadComplete) {
6264 Roo.MessageBox.hide();
6268 this.haveProgress = true;
6270 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6272 var c = new Roo.data.Connection();
6274 url : this.form.progressUrl,
6279 success : function(req){
6280 //console.log(data);
6284 rdata = Roo.decode(req.responseText)
6286 Roo.log("Invalid data from server..");
6290 if (!rdata || !rdata.success) {
6292 Roo.MessageBox.alert(Roo.encode(rdata));
6295 var data = rdata.data;
6297 if (this.uploadComplete) {
6298 Roo.MessageBox.hide();
6303 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6304 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6307 this.uploadProgress.defer(2000,this);
6310 failure: function(data) {
6311 Roo.log('progress url failed ');
6322 // run get Values on the form, so it syncs any secondary forms.
6323 this.form.getValues();
6325 var o = this.options;
6326 var method = this.getMethod();
6327 var isPost = method == 'POST';
6328 if(o.clientValidation === false || this.form.isValid()){
6330 if (this.form.progressUrl) {
6331 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6332 (new Date() * 1) + '' + Math.random());
6337 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6338 form:this.form.el.dom,
6339 url:this.getUrl(!isPost),
6341 params:isPost ? this.getParams() : null,
6342 isUpload: this.form.fileUpload
6345 this.uploadProgress();
6347 }else if (o.clientValidation !== false){ // client validation failed
6348 this.failureType = Roo.form.Action.CLIENT_INVALID;
6349 this.form.afterAction(this, false);
6353 success : function(response)
6355 this.uploadComplete= true;
6356 if (this.haveProgress) {
6357 Roo.MessageBox.hide();
6361 var result = this.processResponse(response);
6362 if(result === true || result.success){
6363 this.form.afterAction(this, true);
6367 this.form.markInvalid(result.errors);
6368 this.failureType = Roo.form.Action.SERVER_INVALID;
6370 this.form.afterAction(this, false);
6372 failure : function(response)
6374 this.uploadComplete= true;
6375 if (this.haveProgress) {
6376 Roo.MessageBox.hide();
6379 this.response = response;
6380 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6381 this.form.afterAction(this, false);
6384 handleResponse : function(response){
6385 if(this.form.errorReader){
6386 var rs = this.form.errorReader.read(response);
6389 for(var i = 0, len = rs.records.length; i < len; i++) {
6390 var r = rs.records[i];
6394 if(errors.length < 1){
6398 success : rs.success,
6404 ret = Roo.decode(response.responseText);
6408 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6418 Roo.form.Action.Load = function(form, options){
6419 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6420 this.reader = this.form.reader;
6423 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6428 Roo.Ajax.request(Roo.apply(
6429 this.createCallback(), {
6430 method:this.getMethod(),
6431 url:this.getUrl(false),
6432 params:this.getParams()
6436 success : function(response){
6438 var result = this.processResponse(response);
6439 if(result === true || !result.success || !result.data){
6440 this.failureType = Roo.form.Action.LOAD_FAILURE;
6441 this.form.afterAction(this, false);
6444 this.form.clearInvalid();
6445 this.form.setValues(result.data);
6446 this.form.afterAction(this, true);
6449 handleResponse : function(response){
6450 if(this.form.reader){
6451 var rs = this.form.reader.read(response);
6452 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6454 success : rs.success,
6458 return Roo.decode(response.responseText);
6462 Roo.form.Action.ACTION_TYPES = {
6463 'load' : Roo.form.Action.Load,
6464 'submit' : Roo.form.Action.Submit
6473 * @class Roo.bootstrap.Form
6474 * @extends Roo.bootstrap.Component
6475 * Bootstrap Form class
6476 * @cfg {String} method GET | POST (default POST)
6477 * @cfg {String} labelAlign top | left (default top)
6478 * @cfg {String} align left | right - for navbars
6479 * @cfg {Boolean} loadMask load mask when submit (default true)
6484 * @param {Object} config The config object
6488 Roo.bootstrap.Form = function(config){
6489 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6492 * @event clientvalidation
6493 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6494 * @param {Form} this
6495 * @param {Boolean} valid true if the form has passed client-side validation
6497 clientvalidation: true,
6499 * @event beforeaction
6500 * Fires before any action is performed. Return false to cancel the action.
6501 * @param {Form} this
6502 * @param {Action} action The action to be performed
6506 * @event actionfailed
6507 * Fires when an action fails.
6508 * @param {Form} this
6509 * @param {Action} action The action that failed
6511 actionfailed : true,
6513 * @event actioncomplete
6514 * Fires when an action is completed.
6515 * @param {Form} this
6516 * @param {Action} action The action that completed
6518 actioncomplete : true
6523 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6526 * @cfg {String} method
6527 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6532 * The URL to use for form actions if one isn't supplied in the action options.
6535 * @cfg {Boolean} fileUpload
6536 * Set to true if this form is a file upload.
6540 * @cfg {Object} baseParams
6541 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6545 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6549 * @cfg {Sting} align (left|right) for navbar forms
6554 activeAction : null,
6557 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6558 * element by passing it or its id or mask the form itself by passing in true.
6561 waitMsgTarget : false,
6565 getAutoCreate : function(){
6569 method : this.method || 'POST',
6570 id : this.id || Roo.id(),
6573 if (this.parent().xtype.match(/^Nav/)) {
6574 cfg.cls = 'navbar-form navbar-' + this.align;
6578 if (this.labelAlign == 'left' ) {
6579 cfg.cls += ' form-horizontal';
6585 initEvents : function()
6587 this.el.on('submit', this.onSubmit, this);
6588 // this was added as random key presses on the form where triggering form submit.
6589 this.el.on('keypress', function(e) {
6590 if (e.getCharCode() != 13) {
6593 // we might need to allow it for textareas.. and some other items.
6594 // check e.getTarget().
6596 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6600 Roo.log("keypress blocked");
6608 onSubmit : function(e){
6613 * Returns true if client-side validation on the form is successful.
6616 isValid : function(){
6617 var items = this.getItems();
6619 items.each(function(f){
6628 * Returns true if any fields in this form have changed since their original load.
6631 isDirty : function(){
6633 var items = this.getItems();
6634 items.each(function(f){
6644 * Performs a predefined action (submit or load) or custom actions you define on this form.
6645 * @param {String} actionName The name of the action type
6646 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6647 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6648 * accept other config options):
6650 Property Type Description
6651 ---------------- --------------- ----------------------------------------------------------------------------------
6652 url String The url for the action (defaults to the form's url)
6653 method String The form method to use (defaults to the form's method, or POST if not defined)
6654 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6655 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6656 validate the form on the client (defaults to false)
6658 * @return {BasicForm} this
6660 doAction : function(action, options){
6661 if(typeof action == 'string'){
6662 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6664 if(this.fireEvent('beforeaction', this, action) !== false){
6665 this.beforeAction(action);
6666 action.run.defer(100, action);
6672 beforeAction : function(action){
6673 var o = action.options;
6676 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6678 // not really supported yet.. ??
6680 //if(this.waitMsgTarget === true){
6681 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6682 //}else if(this.waitMsgTarget){
6683 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6684 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6686 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6692 afterAction : function(action, success){
6693 this.activeAction = null;
6694 var o = action.options;
6696 //if(this.waitMsgTarget === true){
6698 //}else if(this.waitMsgTarget){
6699 // this.waitMsgTarget.unmask();
6701 // Roo.MessageBox.updateProgress(1);
6702 // Roo.MessageBox.hide();
6709 Roo.callback(o.success, o.scope, [this, action]);
6710 this.fireEvent('actioncomplete', this, action);
6714 // failure condition..
6715 // we have a scenario where updates need confirming.
6716 // eg. if a locking scenario exists..
6717 // we look for { errors : { needs_confirm : true }} in the response.
6719 (typeof(action.result) != 'undefined') &&
6720 (typeof(action.result.errors) != 'undefined') &&
6721 (typeof(action.result.errors.needs_confirm) != 'undefined')
6724 Roo.log("not supported yet");
6727 Roo.MessageBox.confirm(
6728 "Change requires confirmation",
6729 action.result.errorMsg,
6734 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6744 Roo.callback(o.failure, o.scope, [this, action]);
6745 // show an error message if no failed handler is set..
6746 if (!this.hasListener('actionfailed')) {
6747 Roo.log("need to add dialog support");
6749 Roo.MessageBox.alert("Error",
6750 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6751 action.result.errorMsg :
6752 "Saving Failed, please check your entries or try again"
6757 this.fireEvent('actionfailed', this, action);
6762 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6763 * @param {String} id The value to search for
6766 findField : function(id){
6767 var items = this.getItems();
6768 var field = items.get(id);
6770 items.each(function(f){
6771 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6778 return field || null;
6781 * Mark fields in this form invalid in bulk.
6782 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6783 * @return {BasicForm} this
6785 markInvalid : function(errors){
6786 if(errors instanceof Array){
6787 for(var i = 0, len = errors.length; i < len; i++){
6788 var fieldError = errors[i];
6789 var f = this.findField(fieldError.id);
6791 f.markInvalid(fieldError.msg);
6797 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6798 field.markInvalid(errors[id]);
6802 //Roo.each(this.childForms || [], function (f) {
6803 // f.markInvalid(errors);
6810 * Set values for fields in this form in bulk.
6811 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6812 * @return {BasicForm} this
6814 setValues : function(values){
6815 if(values instanceof Array){ // array of objects
6816 for(var i = 0, len = values.length; i < len; i++){
6818 var f = this.findField(v.id);
6820 f.setValue(v.value);
6821 if(this.trackResetOnLoad){
6822 f.originalValue = f.getValue();
6826 }else{ // object hash
6829 if(typeof values[id] != 'function' && (field = this.findField(id))){
6831 if (field.setFromData &&
6833 field.displayField &&
6834 // combos' with local stores can
6835 // be queried via setValue()
6836 // to set their value..
6837 (field.store && !field.store.isLocal)
6841 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6842 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6843 field.setFromData(sd);
6846 field.setValue(values[id]);
6850 if(this.trackResetOnLoad){
6851 field.originalValue = field.getValue();
6857 //Roo.each(this.childForms || [], function (f) {
6858 // f.setValues(values);
6865 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6866 * they are returned as an array.
6867 * @param {Boolean} asString
6870 getValues : function(asString){
6871 //if (this.childForms) {
6872 // copy values from the child forms
6873 // Roo.each(this.childForms, function (f) {
6874 // this.setValues(f.getValues());
6880 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6881 if(asString === true){
6884 return Roo.urlDecode(fs);
6888 * Returns the fields in this form as an object with key/value pairs.
6889 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6892 getFieldValues : function(with_hidden)
6894 var items = this.getItems();
6896 items.each(function(f){
6900 var v = f.getValue();
6901 if (f.inputType =='radio') {
6902 if (typeof(ret[f.getName()]) == 'undefined') {
6903 ret[f.getName()] = ''; // empty..
6906 if (!f.el.dom.checked) {
6914 // not sure if this supported any more..
6915 if ((typeof(v) == 'object') && f.getRawValue) {
6916 v = f.getRawValue() ; // dates..
6918 // combo boxes where name != hiddenName...
6919 if (f.name != f.getName()) {
6920 ret[f.name] = f.getRawValue();
6922 ret[f.getName()] = v;
6929 * Clears all invalid messages in this form.
6930 * @return {BasicForm} this
6932 clearInvalid : function(){
6933 var items = this.getItems();
6935 items.each(function(f){
6946 * @return {BasicForm} this
6949 var items = this.getItems();
6950 items.each(function(f){
6954 Roo.each(this.childForms || [], function (f) {
6961 getItems : function()
6963 var r=new Roo.util.MixedCollection(false, function(o){
6964 return o.id || (o.id = Roo.id());
6966 var iter = function(el) {
6973 Roo.each(el.items,function(e) {
6993 * Ext JS Library 1.1.1
6994 * Copyright(c) 2006-2007, Ext JS, LLC.
6996 * Originally Released Under LGPL - original licence link has changed is not relivant.
6999 * <script type="text/javascript">
7002 * @class Roo.form.VTypes
7003 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7006 Roo.form.VTypes = function(){
7007 // closure these in so they are only created once.
7008 var alpha = /^[a-zA-Z_]+$/;
7009 var alphanum = /^[a-zA-Z0-9_]+$/;
7010 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7011 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7013 // All these messages and functions are configurable
7016 * The function used to validate email addresses
7017 * @param {String} value The email address
7019 'email' : function(v){
7020 return email.test(v);
7023 * The error text to display when the email validation function returns false
7026 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7028 * The keystroke filter mask to be applied on email input
7031 'emailMask' : /[a-z0-9_\.\-@]/i,
7034 * The function used to validate URLs
7035 * @param {String} value The URL
7037 'url' : function(v){
7041 * The error text to display when the url validation function returns false
7044 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7047 * The function used to validate alpha values
7048 * @param {String} value The value
7050 'alpha' : function(v){
7051 return alpha.test(v);
7054 * The error text to display when the alpha validation function returns false
7057 'alphaText' : 'This field should only contain letters and _',
7059 * The keystroke filter mask to be applied on alpha input
7062 'alphaMask' : /[a-z_]/i,
7065 * The function used to validate alphanumeric values
7066 * @param {String} value The value
7068 'alphanum' : function(v){
7069 return alphanum.test(v);
7072 * The error text to display when the alphanumeric validation function returns false
7075 'alphanumText' : 'This field should only contain letters, numbers and _',
7077 * The keystroke filter mask to be applied on alphanumeric input
7080 'alphanumMask' : /[a-z0-9_]/i
7090 * @class Roo.bootstrap.Input
7091 * @extends Roo.bootstrap.Component
7092 * Bootstrap Input class
7093 * @cfg {Boolean} disabled is it disabled
7094 * @cfg {String} fieldLabel - the label associated
7095 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7096 * @cfg {String} name name of the input
7097 * @cfg {string} fieldLabel - the label associated
7098 * @cfg {string} inputType - input / file submit ...
7099 * @cfg {string} placeholder - placeholder to put in text.
7100 * @cfg {string} before - input group add on before
7101 * @cfg {string} after - input group add on after
7102 * @cfg {string} size - (lg|sm) or leave empty..
7103 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7104 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7105 * @cfg {Number} md colspan out of 12 for computer-sized screens
7106 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7107 * @cfg {string} value default value of the input
7108 * @cfg {Number} labelWidth set the width of label (0-12)
7109 * @cfg {String} labelAlign (top|left)
7110 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7111 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7113 * @cfg {String} align (left|center|right) Default left
7118 * Create a new Input
7119 * @param {Object} config The config object
7122 Roo.bootstrap.Input = function(config){
7123 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7128 * Fires when this field receives input focus.
7129 * @param {Roo.form.Field} this
7134 * Fires when this field loses input focus.
7135 * @param {Roo.form.Field} this
7140 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7141 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7142 * @param {Roo.form.Field} this
7143 * @param {Roo.EventObject} e The event object
7148 * Fires just before the field blurs if the field value has changed.
7149 * @param {Roo.form.Field} this
7150 * @param {Mixed} newValue The new value
7151 * @param {Mixed} oldValue The original value
7156 * Fires after the field has been marked as invalid.
7157 * @param {Roo.form.Field} this
7158 * @param {String} msg The validation message
7163 * Fires after the field has been validated with no errors.
7164 * @param {Roo.form.Field} this
7169 * Fires after the key up
7170 * @param {Roo.form.Field} this
7171 * @param {Roo.EventObject} e The event Object
7177 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7179 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7180 automatic validation (defaults to "keyup").
7182 validationEvent : "keyup",
7184 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7186 validateOnBlur : true,
7188 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7190 validationDelay : 250,
7192 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7194 focusClass : "x-form-focus", // not needed???
7198 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7200 invalidClass : "has-warning",
7203 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7205 validClass : "has-success",
7208 * @cfg {Boolean} hasFeedback (true|false) default true
7213 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7215 invalidFeedbackClass : "glyphicon-warning-sign",
7218 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7220 validFeedbackClass : "glyphicon-ok",
7223 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7225 selectOnFocus : false,
7228 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7232 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7237 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7239 disableKeyFilter : false,
7242 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7246 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7250 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7252 blankText : "This field is required",
7255 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7259 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7261 maxLength : Number.MAX_VALUE,
7263 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7265 minLengthText : "The minimum length for this field is {0}",
7267 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7269 maxLengthText : "The maximum length for this field is {0}",
7273 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7274 * If available, this function will be called only after the basic validators all return true, and will be passed the
7275 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7279 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7280 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7281 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7285 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7289 autocomplete: false,
7308 formatedValue : false,
7310 parentLabelAlign : function()
7313 while (parent.parent()) {
7314 parent = parent.parent();
7315 if (typeof(parent.labelAlign) !='undefined') {
7316 return parent.labelAlign;
7323 getAutoCreate : function(){
7325 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7331 if(this.inputType != 'hidden'){
7332 cfg.cls = 'form-group' //input-group
7338 type : this.inputType,
7340 cls : 'form-control',
7341 placeholder : this.placeholder || '',
7342 autocomplete : this.autocomplete || 'new-password'
7347 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7350 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7351 input.maxLength = this.maxLength;
7354 if (this.disabled) {
7355 input.disabled=true;
7358 if (this.readOnly) {
7359 input.readonly=true;
7363 input.name = this.name;
7366 input.cls += ' input-' + this.size;
7369 ['xs','sm','md','lg'].map(function(size){
7370 if (settings[size]) {
7371 cfg.cls += ' col-' + size + '-' + settings[size];
7375 var inputblock = input;
7377 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7381 cls: 'glyphicon form-control-feedback'
7385 cls : 'has-feedback',
7393 // var inputblock = input;
7395 if (this.before || this.after) {
7398 cls : 'input-group',
7402 if (this.before && typeof(this.before) == 'string') {
7404 inputblock.cn.push({
7406 cls : 'roo-input-before input-group-addon',
7410 if (this.before && typeof(this.before) == 'object') {
7411 this.before = Roo.factory(this.before);
7412 Roo.log(this.before);
7413 inputblock.cn.push({
7415 cls : 'roo-input-before input-group-' +
7416 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7420 inputblock.cn.push(input);
7422 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7423 inputblock.cls += ' has-feedback';
7424 inputblock.cn.push(feedback);
7427 if (this.after && typeof(this.after) == 'string') {
7428 inputblock.cn.push({
7430 cls : 'roo-input-after input-group-addon',
7434 if (this.after && typeof(this.after) == 'object') {
7435 this.after = Roo.factory(this.after);
7436 Roo.log(this.after);
7437 inputblock.cn.push({
7439 cls : 'roo-input-after input-group-' +
7440 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7445 if (align ==='left' && this.fieldLabel.length) {
7446 Roo.log("left and has label");
7452 cls : 'control-label col-sm-' + this.labelWidth,
7453 html : this.fieldLabel
7457 cls : "col-sm-" + (12 - this.labelWidth),
7464 } else if ( this.fieldLabel.length) {
7470 //cls : 'input-group-addon',
7471 html : this.fieldLabel
7481 Roo.log(" no label && no align");
7490 Roo.log('input-parentType: ' + this.parentType);
7492 if (this.parentType === 'Navbar' && this.parent().bar) {
7493 cfg.cls += ' navbar-form';
7501 * return the real input element.
7503 inputEl: function ()
7505 return this.el.select('input.form-control',true).first();
7508 tooltipEl : function()
7510 return this.inputEl();
7513 setDisabled : function(v)
7515 var i = this.inputEl().dom;
7517 i.removeAttribute('disabled');
7521 i.setAttribute('disabled','true');
7523 initEvents : function()
7526 this.inputEl().on("keydown" , this.fireKey, this);
7527 this.inputEl().on("focus", this.onFocus, this);
7528 this.inputEl().on("blur", this.onBlur, this);
7530 this.inputEl().relayEvent('keyup', this);
7532 // reference to original value for reset
7533 this.originalValue = this.getValue();
7534 //Roo.form.TextField.superclass.initEvents.call(this);
7535 if(this.validationEvent == 'keyup'){
7536 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7537 this.inputEl().on('keyup', this.filterValidation, this);
7539 else if(this.validationEvent !== false){
7540 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7543 if(this.selectOnFocus){
7544 this.on("focus", this.preFocus, this);
7547 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7548 this.inputEl().on("keypress", this.filterKeys, this);
7551 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7552 this.el.on("click", this.autoSize, this);
7555 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7556 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7559 if (typeof(this.before) == 'object') {
7560 this.before.render(this.el.select('.roo-input-before',true).first());
7562 if (typeof(this.after) == 'object') {
7563 this.after.render(this.el.select('.roo-input-after',true).first());
7568 filterValidation : function(e){
7569 if(!e.isNavKeyPress()){
7570 this.validationTask.delay(this.validationDelay);
7574 * Validates the field value
7575 * @return {Boolean} True if the value is valid, else false
7577 validate : function(){
7578 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7579 if(this.disabled || this.validateValue(this.getRawValue())){
7590 * Validates a value according to the field's validation rules and marks the field as invalid
7591 * if the validation fails
7592 * @param {Mixed} value The value to validate
7593 * @return {Boolean} True if the value is valid, else false
7595 validateValue : function(value){
7596 if(value.length < 1) { // if it's blank
7597 if(this.allowBlank){
7603 if(value.length < this.minLength){
7606 if(value.length > this.maxLength){
7610 var vt = Roo.form.VTypes;
7611 if(!vt[this.vtype](value, this)){
7615 if(typeof this.validator == "function"){
7616 var msg = this.validator(value);
7622 if(this.regex && !this.regex.test(value)){
7632 fireKey : function(e){
7633 //Roo.log('field ' + e.getKey());
7634 if(e.isNavKeyPress()){
7635 this.fireEvent("specialkey", this, e);
7638 focus : function (selectText){
7640 this.inputEl().focus();
7641 if(selectText === true){
7642 this.inputEl().dom.select();
7648 onFocus : function(){
7649 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7650 // this.el.addClass(this.focusClass);
7653 this.hasFocus = true;
7654 this.startValue = this.getValue();
7655 this.fireEvent("focus", this);
7659 beforeBlur : Roo.emptyFn,
7663 onBlur : function(){
7665 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7666 //this.el.removeClass(this.focusClass);
7668 this.hasFocus = false;
7669 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7672 var v = this.getValue();
7673 if(String(v) !== String(this.startValue)){
7674 this.fireEvent('change', this, v, this.startValue);
7676 this.fireEvent("blur", this);
7680 * Resets the current field value to the originally loaded value and clears any validation messages
7683 this.setValue(this.originalValue);
7687 * Returns the name of the field
7688 * @return {Mixed} name The name field
7690 getName: function(){
7694 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7695 * @return {Mixed} value The field value
7697 getValue : function(){
7699 var v = this.inputEl().getValue();
7704 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7705 * @return {Mixed} value The field value
7707 getRawValue : function(){
7708 var v = this.inputEl().getValue();
7714 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7715 * @param {Mixed} value The value to set
7717 setRawValue : function(v){
7718 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7721 selectText : function(start, end){
7722 var v = this.getRawValue();
7724 start = start === undefined ? 0 : start;
7725 end = end === undefined ? v.length : end;
7726 var d = this.inputEl().dom;
7727 if(d.setSelectionRange){
7728 d.setSelectionRange(start, end);
7729 }else if(d.createTextRange){
7730 var range = d.createTextRange();
7731 range.moveStart("character", start);
7732 range.moveEnd("character", v.length-end);
7739 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7740 * @param {Mixed} value The value to set
7742 setValue : function(v){
7745 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7751 processValue : function(value){
7752 if(this.stripCharsRe){
7753 var newValue = value.replace(this.stripCharsRe, '');
7754 if(newValue !== value){
7755 this.setRawValue(newValue);
7762 preFocus : function(){
7764 if(this.selectOnFocus){
7765 this.inputEl().dom.select();
7768 filterKeys : function(e){
7770 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7773 var c = e.getCharCode(), cc = String.fromCharCode(c);
7774 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7777 if(!this.maskRe.test(cc)){
7782 * Clear any invalid styles/messages for this field
7784 clearInvalid : function(){
7786 if(!this.el || this.preventMark){ // not rendered
7789 this.el.removeClass(this.invalidClass);
7791 this.fireEvent('valid', this);
7795 * Mark this field as valid
7797 markValid : function(){
7798 if(!this.el || this.preventMark){ // not rendered
7802 this.el.removeClass([this.invalidClass, this.validClass]);
7804 if(this.disabled || this.allowBlank){
7808 this.el.addClass(this.validClass);
7810 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7812 var feedback = this.el.select('.form-control-feedback', true).first();
7815 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7816 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7821 this.fireEvent('valid', this);
7825 * Mark this field as invalid
7826 * @param {String} msg The validation message
7828 markInvalid : function(msg){
7829 if(!this.el || this.preventMark){ // not rendered
7833 this.el.removeClass([this.invalidClass, this.validClass]);
7835 if(this.disabled || this.allowBlank){
7839 this.el.addClass(this.invalidClass);
7841 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7843 var feedback = this.el.select('.form-control-feedback', true).first();
7846 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7848 if(this.getValue().length){
7849 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7856 this.fireEvent('invalid', this, msg);
7859 SafariOnKeyDown : function(event)
7861 // this is a workaround for a password hang bug on chrome/ webkit.
7863 var isSelectAll = false;
7865 if(this.inputEl().dom.selectionEnd > 0){
7866 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7868 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7869 event.preventDefault();
7874 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7876 event.preventDefault();
7877 // this is very hacky as keydown always get's upper case.
7879 var cc = String.fromCharCode(event.getCharCode());
7880 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7884 adjustWidth : function(tag, w){
7885 tag = tag.toLowerCase();
7886 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7887 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7891 if(tag == 'textarea'){
7894 }else if(Roo.isOpera){
7898 if(tag == 'textarea'){
7917 * @class Roo.bootstrap.TextArea
7918 * @extends Roo.bootstrap.Input
7919 * Bootstrap TextArea class
7920 * @cfg {Number} cols Specifies the visible width of a text area
7921 * @cfg {Number} rows Specifies the visible number of lines in a text area
7922 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7923 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7924 * @cfg {string} html text
7927 * Create a new TextArea
7928 * @param {Object} config The config object
7931 Roo.bootstrap.TextArea = function(config){
7932 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7936 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7946 getAutoCreate : function(){
7948 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7959 value : this.value || '',
7960 html: this.html || '',
7961 cls : 'form-control',
7962 placeholder : this.placeholder || ''
7966 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7967 input.maxLength = this.maxLength;
7971 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7975 input.cols = this.cols;
7978 if (this.readOnly) {
7979 input.readonly = true;
7983 input.name = this.name;
7987 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7991 ['xs','sm','md','lg'].map(function(size){
7992 if (settings[size]) {
7993 cfg.cls += ' col-' + size + '-' + settings[size];
7997 var inputblock = input;
7999 if(this.hasFeedback && !this.allowBlank){
8003 cls: 'glyphicon form-control-feedback'
8007 cls : 'has-feedback',
8016 if (this.before || this.after) {
8019 cls : 'input-group',
8023 inputblock.cn.push({
8025 cls : 'input-group-addon',
8030 inputblock.cn.push(input);
8032 if(this.hasFeedback && !this.allowBlank){
8033 inputblock.cls += ' has-feedback';
8034 inputblock.cn.push(feedback);
8038 inputblock.cn.push({
8040 cls : 'input-group-addon',
8047 if (align ==='left' && this.fieldLabel.length) {
8048 Roo.log("left and has label");
8054 cls : 'control-label col-sm-' + this.labelWidth,
8055 html : this.fieldLabel
8059 cls : "col-sm-" + (12 - this.labelWidth),
8066 } else if ( this.fieldLabel.length) {
8072 //cls : 'input-group-addon',
8073 html : this.fieldLabel
8083 Roo.log(" no label && no align");
8093 if (this.disabled) {
8094 input.disabled=true;
8101 * return the real textarea element.
8103 inputEl: function ()
8105 return this.el.select('textarea.form-control',true).first();
8113 * trigger field - base class for combo..
8118 * @class Roo.bootstrap.TriggerField
8119 * @extends Roo.bootstrap.Input
8120 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8121 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8122 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8123 * for which you can provide a custom implementation. For example:
8125 var trigger = new Roo.bootstrap.TriggerField();
8126 trigger.onTriggerClick = myTriggerFn;
8127 trigger.applyTo('my-field');
8130 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8131 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8132 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8133 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8134 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8137 * Create a new TriggerField.
8138 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8139 * to the base TextField)
8141 Roo.bootstrap.TriggerField = function(config){
8142 this.mimicing = false;
8143 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8146 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8148 * @cfg {String} triggerClass A CSS class to apply to the trigger
8151 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8155 /** @cfg {Boolean} grow @hide */
8156 /** @cfg {Number} growMin @hide */
8157 /** @cfg {Number} growMax @hide */
8163 autoSize: Roo.emptyFn,
8170 actionMode : 'wrap',
8175 getAutoCreate : function(){
8177 var align = this.labelAlign || this.parentLabelAlign();
8182 cls: 'form-group' //input-group
8189 type : this.inputType,
8190 cls : 'form-control',
8191 autocomplete: 'new-password',
8192 placeholder : this.placeholder || ''
8196 input.name = this.name;
8199 input.cls += ' input-' + this.size;
8202 if (this.disabled) {
8203 input.disabled=true;
8206 var inputblock = input;
8208 if(this.hasFeedback && !this.allowBlank){
8212 cls: 'glyphicon form-control-feedback'
8216 cls : 'has-feedback',
8224 if (this.before || this.after) {
8227 cls : 'input-group',
8231 inputblock.cn.push({
8233 cls : 'input-group-addon',
8238 inputblock.cn.push(input);
8240 if(this.hasFeedback && !this.allowBlank){
8241 inputblock.cls += ' has-feedback';
8242 inputblock.cn.push(feedback);
8246 inputblock.cn.push({
8248 cls : 'input-group-addon',
8261 cls: 'form-hidden-field'
8269 Roo.log('multiple');
8277 cls: 'form-hidden-field'
8281 cls: 'select2-choices',
8285 cls: 'select2-search-field',
8298 cls: 'select2-container input-group',
8303 // cls: 'typeahead typeahead-long dropdown-menu',
8304 // style: 'display:none'
8309 if(!this.multiple && this.showToggleBtn){
8315 if (this.caret != false) {
8318 cls: 'fa fa-' + this.caret
8325 cls : 'input-group-addon btn dropdown-toggle',
8330 cls: 'combobox-clear',
8344 combobox.cls += ' select2-container-multi';
8347 if (align ==='left' && this.fieldLabel.length) {
8349 Roo.log("left and has label");
8355 cls : 'control-label col-sm-' + this.labelWidth,
8356 html : this.fieldLabel
8360 cls : "col-sm-" + (12 - this.labelWidth),
8367 } else if ( this.fieldLabel.length) {
8373 //cls : 'input-group-addon',
8374 html : this.fieldLabel
8384 Roo.log(" no label && no align");
8391 ['xs','sm','md','lg'].map(function(size){
8392 if (settings[size]) {
8393 cfg.cls += ' col-' + size + '-' + settings[size];
8404 onResize : function(w, h){
8405 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8406 // if(typeof w == 'number'){
8407 // var x = w - this.trigger.getWidth();
8408 // this.inputEl().setWidth(this.adjustWidth('input', x));
8409 // this.trigger.setStyle('left', x+'px');
8414 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8417 getResizeEl : function(){
8418 return this.inputEl();
8422 getPositionEl : function(){
8423 return this.inputEl();
8427 alignErrorIcon : function(){
8428 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8432 initEvents : function(){
8436 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8437 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8438 if(!this.multiple && this.showToggleBtn){
8439 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8440 if(this.hideTrigger){
8441 this.trigger.setDisplayed(false);
8443 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8447 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8450 //this.trigger.addClassOnOver('x-form-trigger-over');
8451 //this.trigger.addClassOnClick('x-form-trigger-click');
8454 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8458 createList : function()
8460 this.list = Roo.get(document.body).createChild({
8462 cls: 'typeahead typeahead-long dropdown-menu',
8463 style: 'display:none'
8466 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8471 initTrigger : function(){
8476 onDestroy : function(){
8478 this.trigger.removeAllListeners();
8479 // this.trigger.remove();
8482 // this.wrap.remove();
8484 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8488 onFocus : function(){
8489 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8492 this.wrap.addClass('x-trigger-wrap-focus');
8493 this.mimicing = true;
8494 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8495 if(this.monitorTab){
8496 this.el.on("keydown", this.checkTab, this);
8503 checkTab : function(e){
8504 if(e.getKey() == e.TAB){
8510 onBlur : function(){
8515 mimicBlur : function(e, t){
8517 if(!this.wrap.contains(t) && this.validateBlur()){
8524 triggerBlur : function(){
8525 this.mimicing = false;
8526 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8527 if(this.monitorTab){
8528 this.el.un("keydown", this.checkTab, this);
8530 //this.wrap.removeClass('x-trigger-wrap-focus');
8531 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8535 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8536 validateBlur : function(e, t){
8541 onDisable : function(){
8542 this.inputEl().dom.disabled = true;
8543 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8545 // this.wrap.addClass('x-item-disabled');
8550 onEnable : function(){
8551 this.inputEl().dom.disabled = false;
8552 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8554 // this.el.removeClass('x-item-disabled');
8559 onShow : function(){
8560 var ae = this.getActionEl();
8563 ae.dom.style.display = '';
8564 ae.dom.style.visibility = 'visible';
8570 onHide : function(){
8571 var ae = this.getActionEl();
8572 ae.dom.style.display = 'none';
8576 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8577 * by an implementing function.
8579 * @param {EventObject} e
8581 onTriggerClick : Roo.emptyFn
8585 * Ext JS Library 1.1.1
8586 * Copyright(c) 2006-2007, Ext JS, LLC.
8588 * Originally Released Under LGPL - original licence link has changed is not relivant.
8591 * <script type="text/javascript">
8596 * @class Roo.data.SortTypes
8598 * Defines the default sorting (casting?) comparison functions used when sorting data.
8600 Roo.data.SortTypes = {
8602 * Default sort that does nothing
8603 * @param {Mixed} s The value being converted
8604 * @return {Mixed} The comparison value
8611 * The regular expression used to strip tags
8615 stripTagsRE : /<\/?[^>]+>/gi,
8618 * Strips all HTML tags to sort on text only
8619 * @param {Mixed} s The value being converted
8620 * @return {String} The comparison value
8622 asText : function(s){
8623 return String(s).replace(this.stripTagsRE, "");
8627 * Strips all HTML tags to sort on text only - Case insensitive
8628 * @param {Mixed} s The value being converted
8629 * @return {String} The comparison value
8631 asUCText : function(s){
8632 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8636 * Case insensitive string
8637 * @param {Mixed} s The value being converted
8638 * @return {String} The comparison value
8640 asUCString : function(s) {
8641 return String(s).toUpperCase();
8646 * @param {Mixed} s The value being converted
8647 * @return {Number} The comparison value
8649 asDate : function(s) {
8653 if(s instanceof Date){
8656 return Date.parse(String(s));
8661 * @param {Mixed} s The value being converted
8662 * @return {Float} The comparison value
8664 asFloat : function(s) {
8665 var val = parseFloat(String(s).replace(/,/g, ""));
8666 if(isNaN(val)) val = 0;
8672 * @param {Mixed} s The value being converted
8673 * @return {Number} The comparison value
8675 asInt : function(s) {
8676 var val = parseInt(String(s).replace(/,/g, ""));
8677 if(isNaN(val)) val = 0;
8682 * Ext JS Library 1.1.1
8683 * Copyright(c) 2006-2007, Ext JS, LLC.
8685 * Originally Released Under LGPL - original licence link has changed is not relivant.
8688 * <script type="text/javascript">
8692 * @class Roo.data.Record
8693 * Instances of this class encapsulate both record <em>definition</em> information, and record
8694 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8695 * to access Records cached in an {@link Roo.data.Store} object.<br>
8697 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8698 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8701 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8703 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8704 * {@link #create}. The parameters are the same.
8705 * @param {Array} data An associative Array of data values keyed by the field name.
8706 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8707 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8708 * not specified an integer id is generated.
8710 Roo.data.Record = function(data, id){
8711 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8716 * Generate a constructor for a specific record layout.
8717 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8718 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8719 * Each field definition object may contain the following properties: <ul>
8720 * <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,
8721 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8722 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8723 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8724 * is being used, then this is a string containing the javascript expression to reference the data relative to
8725 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8726 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8727 * this may be omitted.</p></li>
8728 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8729 * <ul><li>auto (Default, implies no conversion)</li>
8734 * <li>date</li></ul></p></li>
8735 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8736 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8737 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8738 * by the Reader into an object that will be stored in the Record. It is passed the
8739 * following parameters:<ul>
8740 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8742 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8744 * <br>usage:<br><pre><code>
8745 var TopicRecord = Roo.data.Record.create(
8746 {name: 'title', mapping: 'topic_title'},
8747 {name: 'author', mapping: 'username'},
8748 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8749 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8750 {name: 'lastPoster', mapping: 'user2'},
8751 {name: 'excerpt', mapping: 'post_text'}
8754 var myNewRecord = new TopicRecord({
8755 title: 'Do my job please',
8758 lastPost: new Date(),
8759 lastPoster: 'Animal',
8760 excerpt: 'No way dude!'
8762 myStore.add(myNewRecord);
8767 Roo.data.Record.create = function(o){
8769 f.superclass.constructor.apply(this, arguments);
8771 Roo.extend(f, Roo.data.Record);
8772 var p = f.prototype;
8773 p.fields = new Roo.util.MixedCollection(false, function(field){
8776 for(var i = 0, len = o.length; i < len; i++){
8777 p.fields.add(new Roo.data.Field(o[i]));
8779 f.getField = function(name){
8780 return p.fields.get(name);
8785 Roo.data.Record.AUTO_ID = 1000;
8786 Roo.data.Record.EDIT = 'edit';
8787 Roo.data.Record.REJECT = 'reject';
8788 Roo.data.Record.COMMIT = 'commit';
8790 Roo.data.Record.prototype = {
8792 * Readonly flag - true if this record has been modified.
8801 join : function(store){
8806 * Set the named field to the specified value.
8807 * @param {String} name The name of the field to set.
8808 * @param {Object} value The value to set the field to.
8810 set : function(name, value){
8811 if(this.data[name] == value){
8818 if(typeof this.modified[name] == 'undefined'){
8819 this.modified[name] = this.data[name];
8821 this.data[name] = value;
8822 if(!this.editing && this.store){
8823 this.store.afterEdit(this);
8828 * Get the value of the named field.
8829 * @param {String} name The name of the field to get the value of.
8830 * @return {Object} The value of the field.
8832 get : function(name){
8833 return this.data[name];
8837 beginEdit : function(){
8838 this.editing = true;
8843 cancelEdit : function(){
8844 this.editing = false;
8845 delete this.modified;
8849 endEdit : function(){
8850 this.editing = false;
8851 if(this.dirty && this.store){
8852 this.store.afterEdit(this);
8857 * Usually called by the {@link Roo.data.Store} which owns the Record.
8858 * Rejects all changes made to the Record since either creation, or the last commit operation.
8859 * Modified fields are reverted to their original values.
8861 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8862 * of reject operations.
8864 reject : function(){
8865 var m = this.modified;
8867 if(typeof m[n] != "function"){
8868 this.data[n] = m[n];
8872 delete this.modified;
8873 this.editing = false;
8875 this.store.afterReject(this);
8880 * Usually called by the {@link Roo.data.Store} which owns the Record.
8881 * Commits all changes made to the Record since either creation, or the last commit operation.
8883 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8884 * of commit operations.
8886 commit : function(){
8888 delete this.modified;
8889 this.editing = false;
8891 this.store.afterCommit(this);
8896 hasError : function(){
8897 return this.error != null;
8901 clearError : function(){
8906 * Creates a copy of this record.
8907 * @param {String} id (optional) A new record id if you don't want to use this record's id
8910 copy : function(newId) {
8911 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8915 * Ext JS Library 1.1.1
8916 * Copyright(c) 2006-2007, Ext JS, LLC.
8918 * Originally Released Under LGPL - original licence link has changed is not relivant.
8921 * <script type="text/javascript">
8927 * @class Roo.data.Store
8928 * @extends Roo.util.Observable
8929 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8930 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8932 * 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
8933 * has no knowledge of the format of the data returned by the Proxy.<br>
8935 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8936 * instances from the data object. These records are cached and made available through accessor functions.
8938 * Creates a new Store.
8939 * @param {Object} config A config object containing the objects needed for the Store to access data,
8940 * and read the data into Records.
8942 Roo.data.Store = function(config){
8943 this.data = new Roo.util.MixedCollection(false);
8944 this.data.getKey = function(o){
8947 this.baseParams = {};
8954 "multisort" : "_multisort"
8957 if(config && config.data){
8958 this.inlineData = config.data;
8962 Roo.apply(this, config);
8964 if(this.reader){ // reader passed
8965 this.reader = Roo.factory(this.reader, Roo.data);
8966 this.reader.xmodule = this.xmodule || false;
8967 if(!this.recordType){
8968 this.recordType = this.reader.recordType;
8970 if(this.reader.onMetaChange){
8971 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8975 if(this.recordType){
8976 this.fields = this.recordType.prototype.fields;
8982 * @event datachanged
8983 * Fires when the data cache has changed, and a widget which is using this Store
8984 * as a Record cache should refresh its view.
8985 * @param {Store} this
8990 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8991 * @param {Store} this
8992 * @param {Object} meta The JSON metadata
8997 * Fires when Records have been added to the Store
8998 * @param {Store} this
8999 * @param {Roo.data.Record[]} records The array of Records added
9000 * @param {Number} index The index at which the record(s) were added
9005 * Fires when a Record has been removed from the Store
9006 * @param {Store} this
9007 * @param {Roo.data.Record} record The Record that was removed
9008 * @param {Number} index The index at which the record was removed
9013 * Fires when a Record has been updated
9014 * @param {Store} this
9015 * @param {Roo.data.Record} record The Record that was updated
9016 * @param {String} operation The update operation being performed. Value may be one of:
9018 Roo.data.Record.EDIT
9019 Roo.data.Record.REJECT
9020 Roo.data.Record.COMMIT
9026 * Fires when the data cache has been cleared.
9027 * @param {Store} this
9032 * Fires before a request is made for a new data object. If the beforeload handler returns false
9033 * the load action will be canceled.
9034 * @param {Store} this
9035 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9039 * @event beforeloadadd
9040 * Fires after a new set of Records has been loaded.
9041 * @param {Store} this
9042 * @param {Roo.data.Record[]} records The Records that were loaded
9043 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9045 beforeloadadd : true,
9048 * Fires after a new set of Records has been loaded, before they are added to the store.
9049 * @param {Store} this
9050 * @param {Roo.data.Record[]} records The Records that were loaded
9051 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9052 * @params {Object} return from reader
9056 * @event loadexception
9057 * Fires if an exception occurs in the Proxy during loading.
9058 * Called with the signature of the Proxy's "loadexception" event.
9059 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9062 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9063 * @param {Object} load options
9064 * @param {Object} jsonData from your request (normally this contains the Exception)
9066 loadexception : true
9070 this.proxy = Roo.factory(this.proxy, Roo.data);
9071 this.proxy.xmodule = this.xmodule || false;
9072 this.relayEvents(this.proxy, ["loadexception"]);
9074 this.sortToggle = {};
9075 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9077 Roo.data.Store.superclass.constructor.call(this);
9079 if(this.inlineData){
9080 this.loadData(this.inlineData);
9081 delete this.inlineData;
9085 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9087 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9088 * without a remote query - used by combo/forms at present.
9092 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9095 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9098 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9099 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9102 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9103 * on any HTTP request
9106 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9109 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9113 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9114 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9119 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9120 * loaded or when a record is removed. (defaults to false).
9122 pruneModifiedRecords : false,
9128 * Add Records to the Store and fires the add event.
9129 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9131 add : function(records){
9132 records = [].concat(records);
9133 for(var i = 0, len = records.length; i < len; i++){
9134 records[i].join(this);
9136 var index = this.data.length;
9137 this.data.addAll(records);
9138 this.fireEvent("add", this, records, index);
9142 * Remove a Record from the Store and fires the remove event.
9143 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9145 remove : function(record){
9146 var index = this.data.indexOf(record);
9147 this.data.removeAt(index);
9148 if(this.pruneModifiedRecords){
9149 this.modified.remove(record);
9151 this.fireEvent("remove", this, record, index);
9155 * Remove all Records from the Store and fires the clear event.
9157 removeAll : function(){
9159 if(this.pruneModifiedRecords){
9162 this.fireEvent("clear", this);
9166 * Inserts Records to the Store at the given index and fires the add event.
9167 * @param {Number} index The start index at which to insert the passed Records.
9168 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9170 insert : function(index, records){
9171 records = [].concat(records);
9172 for(var i = 0, len = records.length; i < len; i++){
9173 this.data.insert(index, records[i]);
9174 records[i].join(this);
9176 this.fireEvent("add", this, records, index);
9180 * Get the index within the cache of the passed Record.
9181 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9182 * @return {Number} The index of the passed Record. Returns -1 if not found.
9184 indexOf : function(record){
9185 return this.data.indexOf(record);
9189 * Get the index within the cache of the Record with the passed id.
9190 * @param {String} id The id of the Record to find.
9191 * @return {Number} The index of the Record. Returns -1 if not found.
9193 indexOfId : function(id){
9194 return this.data.indexOfKey(id);
9198 * Get the Record with the specified id.
9199 * @param {String} id The id of the Record to find.
9200 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9202 getById : function(id){
9203 return this.data.key(id);
9207 * Get the Record at the specified index.
9208 * @param {Number} index The index of the Record to find.
9209 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9211 getAt : function(index){
9212 return this.data.itemAt(index);
9216 * Returns a range of Records between specified indices.
9217 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9218 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9219 * @return {Roo.data.Record[]} An array of Records
9221 getRange : function(start, end){
9222 return this.data.getRange(start, end);
9226 storeOptions : function(o){
9227 o = Roo.apply({}, o);
9230 this.lastOptions = o;
9234 * Loads the Record cache from the configured Proxy using the configured Reader.
9236 * If using remote paging, then the first load call must specify the <em>start</em>
9237 * and <em>limit</em> properties in the options.params property to establish the initial
9238 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9240 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9241 * and this call will return before the new data has been loaded. Perform any post-processing
9242 * in a callback function, or in a "load" event handler.</strong>
9244 * @param {Object} options An object containing properties which control loading options:<ul>
9245 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9246 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9247 * passed the following arguments:<ul>
9248 * <li>r : Roo.data.Record[]</li>
9249 * <li>options: Options object from the load call</li>
9250 * <li>success: Boolean success indicator</li></ul></li>
9251 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9252 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9255 load : function(options){
9256 options = options || {};
9257 if(this.fireEvent("beforeload", this, options) !== false){
9258 this.storeOptions(options);
9259 var p = Roo.apply(options.params || {}, this.baseParams);
9260 // if meta was not loaded from remote source.. try requesting it.
9261 if (!this.reader.metaFromRemote) {
9264 if(this.sortInfo && this.remoteSort){
9265 var pn = this.paramNames;
9266 p[pn["sort"]] = this.sortInfo.field;
9267 p[pn["dir"]] = this.sortInfo.direction;
9269 if (this.multiSort) {
9270 var pn = this.paramNames;
9271 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9274 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9279 * Reloads the Record cache from the configured Proxy using the configured Reader and
9280 * the options from the last load operation performed.
9281 * @param {Object} options (optional) An object containing properties which may override the options
9282 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9283 * the most recently used options are reused).
9285 reload : function(options){
9286 this.load(Roo.applyIf(options||{}, this.lastOptions));
9290 // Called as a callback by the Reader during a load operation.
9291 loadRecords : function(o, options, success){
9292 if(!o || success === false){
9293 if(success !== false){
9294 this.fireEvent("load", this, [], options, o);
9296 if(options.callback){
9297 options.callback.call(options.scope || this, [], options, false);
9301 // if data returned failure - throw an exception.
9302 if (o.success === false) {
9303 // show a message if no listener is registered.
9304 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9305 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9307 // loadmask wil be hooked into this..
9308 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9311 var r = o.records, t = o.totalRecords || r.length;
9313 this.fireEvent("beforeloadadd", this, r, options, o);
9315 if(!options || options.add !== true){
9316 if(this.pruneModifiedRecords){
9319 for(var i = 0, len = r.length; i < len; i++){
9323 this.data = this.snapshot;
9324 delete this.snapshot;
9327 this.data.addAll(r);
9328 this.totalLength = t;
9330 this.fireEvent("datachanged", this);
9332 this.totalLength = Math.max(t, this.data.length+r.length);
9335 this.fireEvent("load", this, r, options, o);
9336 if(options.callback){
9337 options.callback.call(options.scope || this, r, options, true);
9343 * Loads data from a passed data block. A Reader which understands the format of the data
9344 * must have been configured in the constructor.
9345 * @param {Object} data The data block from which to read the Records. The format of the data expected
9346 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9347 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9349 loadData : function(o, append){
9350 var r = this.reader.readRecords(o);
9351 this.loadRecords(r, {add: append}, true);
9355 * Gets the number of cached records.
9357 * <em>If using paging, this may not be the total size of the dataset. If the data object
9358 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9359 * the data set size</em>
9361 getCount : function(){
9362 return this.data.length || 0;
9366 * Gets the total number of records in the dataset as returned by the server.
9368 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9369 * the dataset size</em>
9371 getTotalCount : function(){
9372 return this.totalLength || 0;
9376 * Returns the sort state of the Store as an object with two properties:
9378 field {String} The name of the field by which the Records are sorted
9379 direction {String} The sort order, "ASC" or "DESC"
9382 getSortState : function(){
9383 return this.sortInfo;
9387 applySort : function(){
9388 if(this.sortInfo && !this.remoteSort){
9389 var s = this.sortInfo, f = s.field;
9390 var st = this.fields.get(f).sortType;
9391 var fn = function(r1, r2){
9392 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9393 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9395 this.data.sort(s.direction, fn);
9396 if(this.snapshot && this.snapshot != this.data){
9397 this.snapshot.sort(s.direction, fn);
9403 * Sets the default sort column and order to be used by the next load operation.
9404 * @param {String} fieldName The name of the field to sort by.
9405 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9407 setDefaultSort : function(field, dir){
9408 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9413 * If remote sorting is used, the sort is performed on the server, and the cache is
9414 * reloaded. If local sorting is used, the cache is sorted internally.
9415 * @param {String} fieldName The name of the field to sort by.
9416 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9418 sort : function(fieldName, dir){
9419 var f = this.fields.get(fieldName);
9421 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9423 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9424 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9429 this.sortToggle[f.name] = dir;
9430 this.sortInfo = {field: f.name, direction: dir};
9431 if(!this.remoteSort){
9433 this.fireEvent("datachanged", this);
9435 this.load(this.lastOptions);
9440 * Calls the specified function for each of the Records in the cache.
9441 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9442 * Returning <em>false</em> aborts and exits the iteration.
9443 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9445 each : function(fn, scope){
9446 this.data.each(fn, scope);
9450 * Gets all records modified since the last commit. Modified records are persisted across load operations
9451 * (e.g., during paging).
9452 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9454 getModifiedRecords : function(){
9455 return this.modified;
9459 createFilterFn : function(property, value, anyMatch){
9460 if(!value.exec){ // not a regex
9461 value = String(value);
9462 if(value.length == 0){
9465 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9468 return value.test(r.data[property]);
9473 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9474 * @param {String} property A field on your records
9475 * @param {Number} start The record index to start at (defaults to 0)
9476 * @param {Number} end The last record index to include (defaults to length - 1)
9477 * @return {Number} The sum
9479 sum : function(property, start, end){
9480 var rs = this.data.items, v = 0;
9482 end = (end || end === 0) ? end : rs.length-1;
9484 for(var i = start; i <= end; i++){
9485 v += (rs[i].data[property] || 0);
9491 * Filter the records by a specified property.
9492 * @param {String} field A field on your records
9493 * @param {String/RegExp} value Either a string that the field
9494 * should start with or a RegExp to test against the field
9495 * @param {Boolean} anyMatch True to match any part not just the beginning
9497 filter : function(property, value, anyMatch){
9498 var fn = this.createFilterFn(property, value, anyMatch);
9499 return fn ? this.filterBy(fn) : this.clearFilter();
9503 * Filter by a function. The specified function will be called with each
9504 * record in this data source. If the function returns true the record is included,
9505 * otherwise it is filtered.
9506 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9507 * @param {Object} scope (optional) The scope of the function (defaults to this)
9509 filterBy : function(fn, scope){
9510 this.snapshot = this.snapshot || this.data;
9511 this.data = this.queryBy(fn, scope||this);
9512 this.fireEvent("datachanged", this);
9516 * Query the records by a specified property.
9517 * @param {String} field A field on your records
9518 * @param {String/RegExp} value Either a string that the field
9519 * should start with or a RegExp to test against the field
9520 * @param {Boolean} anyMatch True to match any part not just the beginning
9521 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9523 query : function(property, value, anyMatch){
9524 var fn = this.createFilterFn(property, value, anyMatch);
9525 return fn ? this.queryBy(fn) : this.data.clone();
9529 * Query by a function. The specified function will be called with each
9530 * record in this data source. If the function returns true the record is included
9532 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9533 * @param {Object} scope (optional) The scope of the function (defaults to this)
9534 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9536 queryBy : function(fn, scope){
9537 var data = this.snapshot || this.data;
9538 return data.filterBy(fn, scope||this);
9542 * Collects unique values for a particular dataIndex from this store.
9543 * @param {String} dataIndex The property to collect
9544 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9545 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9546 * @return {Array} An array of the unique values
9548 collect : function(dataIndex, allowNull, bypassFilter){
9549 var d = (bypassFilter === true && this.snapshot) ?
9550 this.snapshot.items : this.data.items;
9551 var v, sv, r = [], l = {};
9552 for(var i = 0, len = d.length; i < len; i++){
9553 v = d[i].data[dataIndex];
9555 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9564 * Revert to a view of the Record cache with no filtering applied.
9565 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9567 clearFilter : function(suppressEvent){
9568 if(this.snapshot && this.snapshot != this.data){
9569 this.data = this.snapshot;
9570 delete this.snapshot;
9571 if(suppressEvent !== true){
9572 this.fireEvent("datachanged", this);
9578 afterEdit : function(record){
9579 if(this.modified.indexOf(record) == -1){
9580 this.modified.push(record);
9582 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9586 afterReject : function(record){
9587 this.modified.remove(record);
9588 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9592 afterCommit : function(record){
9593 this.modified.remove(record);
9594 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9598 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9599 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9601 commitChanges : function(){
9602 var m = this.modified.slice(0);
9604 for(var i = 0, len = m.length; i < len; i++){
9610 * Cancel outstanding changes on all changed records.
9612 rejectChanges : function(){
9613 var m = this.modified.slice(0);
9615 for(var i = 0, len = m.length; i < len; i++){
9620 onMetaChange : function(meta, rtype, o){
9621 this.recordType = rtype;
9622 this.fields = rtype.prototype.fields;
9623 delete this.snapshot;
9624 this.sortInfo = meta.sortInfo || this.sortInfo;
9626 this.fireEvent('metachange', this, this.reader.meta);
9629 moveIndex : function(data, type)
9631 var index = this.indexOf(data);
9633 var newIndex = index + type;
9637 this.insert(newIndex, data);
9642 * Ext JS Library 1.1.1
9643 * Copyright(c) 2006-2007, Ext JS, LLC.
9645 * Originally Released Under LGPL - original licence link has changed is not relivant.
9648 * <script type="text/javascript">
9652 * @class Roo.data.SimpleStore
9653 * @extends Roo.data.Store
9654 * Small helper class to make creating Stores from Array data easier.
9655 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9656 * @cfg {Array} fields An array of field definition objects, or field name strings.
9657 * @cfg {Array} data The multi-dimensional array of data
9659 * @param {Object} config
9661 Roo.data.SimpleStore = function(config){
9662 Roo.data.SimpleStore.superclass.constructor.call(this, {
9664 reader: new Roo.data.ArrayReader({
9667 Roo.data.Record.create(config.fields)
9669 proxy : new Roo.data.MemoryProxy(config.data)
9673 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9675 * Ext JS Library 1.1.1
9676 * Copyright(c) 2006-2007, Ext JS, LLC.
9678 * Originally Released Under LGPL - original licence link has changed is not relivant.
9681 * <script type="text/javascript">
9686 * @extends Roo.data.Store
9687 * @class Roo.data.JsonStore
9688 * Small helper class to make creating Stores for JSON data easier. <br/>
9690 var store = new Roo.data.JsonStore({
9691 url: 'get-images.php',
9693 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9696 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9697 * JsonReader and HttpProxy (unless inline data is provided).</b>
9698 * @cfg {Array} fields An array of field definition objects, or field name strings.
9700 * @param {Object} config
9702 Roo.data.JsonStore = function(c){
9703 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9704 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9705 reader: new Roo.data.JsonReader(c, c.fields)
9708 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9710 * Ext JS Library 1.1.1
9711 * Copyright(c) 2006-2007, Ext JS, LLC.
9713 * Originally Released Under LGPL - original licence link has changed is not relivant.
9716 * <script type="text/javascript">
9720 Roo.data.Field = function(config){
9721 if(typeof config == "string"){
9722 config = {name: config};
9724 Roo.apply(this, config);
9730 var st = Roo.data.SortTypes;
9731 // named sortTypes are supported, here we look them up
9732 if(typeof this.sortType == "string"){
9733 this.sortType = st[this.sortType];
9736 // set default sortType for strings and dates
9740 this.sortType = st.asUCString;
9743 this.sortType = st.asDate;
9746 this.sortType = st.none;
9751 var stripRe = /[\$,%]/g;
9753 // prebuilt conversion function for this field, instead of
9754 // switching every time we're reading a value
9756 var cv, dateFormat = this.dateFormat;
9761 cv = function(v){ return v; };
9764 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9768 return v !== undefined && v !== null && v !== '' ?
9769 parseInt(String(v).replace(stripRe, ""), 10) : '';
9774 return v !== undefined && v !== null && v !== '' ?
9775 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9780 cv = function(v){ return v === true || v === "true" || v == 1; };
9787 if(v instanceof Date){
9791 if(dateFormat == "timestamp"){
9792 return new Date(v*1000);
9794 return Date.parseDate(v, dateFormat);
9796 var parsed = Date.parse(v);
9797 return parsed ? new Date(parsed) : null;
9806 Roo.data.Field.prototype = {
9814 * Ext JS Library 1.1.1
9815 * Copyright(c) 2006-2007, Ext JS, LLC.
9817 * Originally Released Under LGPL - original licence link has changed is not relivant.
9820 * <script type="text/javascript">
9823 // Base class for reading structured data from a data source. This class is intended to be
9824 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9827 * @class Roo.data.DataReader
9828 * Base class for reading structured data from a data source. This class is intended to be
9829 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9832 Roo.data.DataReader = function(meta, recordType){
9836 this.recordType = recordType instanceof Array ?
9837 Roo.data.Record.create(recordType) : recordType;
9840 Roo.data.DataReader.prototype = {
9842 * Create an empty record
9843 * @param {Object} data (optional) - overlay some values
9844 * @return {Roo.data.Record} record created.
9846 newRow : function(d) {
9848 this.recordType.prototype.fields.each(function(c) {
9850 case 'int' : da[c.name] = 0; break;
9851 case 'date' : da[c.name] = new Date(); break;
9852 case 'float' : da[c.name] = 0.0; break;
9853 case 'boolean' : da[c.name] = false; break;
9854 default : da[c.name] = ""; break;
9858 return new this.recordType(Roo.apply(da, d));
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">
9873 * @class Roo.data.DataProxy
9874 * @extends Roo.data.Observable
9875 * This class is an abstract base class for implementations which provide retrieval of
9876 * unformatted data objects.<br>
9878 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9879 * (of the appropriate type which knows how to parse the data object) to provide a block of
9880 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9882 * Custom implementations must implement the load method as described in
9883 * {@link Roo.data.HttpProxy#load}.
9885 Roo.data.DataProxy = function(){
9889 * Fires before a network request is made to retrieve a data object.
9890 * @param {Object} This DataProxy object.
9891 * @param {Object} params The params parameter to the load function.
9896 * Fires before the load method's callback is called.
9897 * @param {Object} This DataProxy object.
9898 * @param {Object} o The data object.
9899 * @param {Object} arg The callback argument object passed to the load function.
9903 * @event loadexception
9904 * Fires if an Exception occurs during data retrieval.
9905 * @param {Object} This DataProxy object.
9906 * @param {Object} o The data object.
9907 * @param {Object} arg The callback argument object passed to the load function.
9908 * @param {Object} e The Exception.
9910 loadexception : true
9912 Roo.data.DataProxy.superclass.constructor.call(this);
9915 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9918 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9922 * Ext JS Library 1.1.1
9923 * Copyright(c) 2006-2007, Ext JS, LLC.
9925 * Originally Released Under LGPL - original licence link has changed is not relivant.
9928 * <script type="text/javascript">
9931 * @class Roo.data.MemoryProxy
9932 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9933 * to the Reader when its load method is called.
9935 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9937 Roo.data.MemoryProxy = function(data){
9941 Roo.data.MemoryProxy.superclass.constructor.call(this);
9945 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9947 * Load data from the requested source (in this case an in-memory
9948 * data object passed to the constructor), read the data object into
9949 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9950 * process that block using the passed callback.
9951 * @param {Object} params This parameter is not used by the MemoryProxy class.
9952 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9953 * object into a block of Roo.data.Records.
9954 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9955 * The function must be passed <ul>
9956 * <li>The Record block object</li>
9957 * <li>The "arg" argument from the load function</li>
9958 * <li>A boolean success indicator</li>
9960 * @param {Object} scope The scope in which to call the callback
9961 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9963 load : function(params, reader, callback, scope, arg){
9964 params = params || {};
9967 result = reader.readRecords(this.data);
9969 this.fireEvent("loadexception", this, arg, null, e);
9970 callback.call(scope, null, arg, false);
9973 callback.call(scope, result, arg, true);
9977 update : function(params, records){
9982 * Ext JS Library 1.1.1
9983 * Copyright(c) 2006-2007, Ext JS, LLC.
9985 * Originally Released Under LGPL - original licence link has changed is not relivant.
9988 * <script type="text/javascript">
9991 * @class Roo.data.HttpProxy
9992 * @extends Roo.data.DataProxy
9993 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9994 * configured to reference a certain URL.<br><br>
9996 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9997 * from which the running page was served.<br><br>
9999 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10001 * Be aware that to enable the browser to parse an XML document, the server must set
10002 * the Content-Type header in the HTTP response to "text/xml".
10004 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10005 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10006 * will be used to make the request.
10008 Roo.data.HttpProxy = function(conn){
10009 Roo.data.HttpProxy.superclass.constructor.call(this);
10010 // is conn a conn config or a real conn?
10012 this.useAjax = !conn || !conn.events;
10016 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10017 // thse are take from connection...
10020 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10023 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10024 * extra parameters to each request made by this object. (defaults to undefined)
10027 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10028 * to each request made by this object. (defaults to undefined)
10031 * @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)
10034 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10037 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10043 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10047 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10048 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10049 * a finer-grained basis than the DataProxy events.
10051 getConnection : function(){
10052 return this.useAjax ? Roo.Ajax : this.conn;
10056 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10057 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10058 * process that block using the passed callback.
10059 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10060 * for the request to the remote server.
10061 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10062 * object into a block of Roo.data.Records.
10063 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10064 * The function must be passed <ul>
10065 * <li>The Record block object</li>
10066 * <li>The "arg" argument from the load function</li>
10067 * <li>A boolean success indicator</li>
10069 * @param {Object} scope The scope in which to call the callback
10070 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10072 load : function(params, reader, callback, scope, arg){
10073 if(this.fireEvent("beforeload", this, params) !== false){
10075 params : params || {},
10077 callback : callback,
10082 callback : this.loadResponse,
10086 Roo.applyIf(o, this.conn);
10087 if(this.activeRequest){
10088 Roo.Ajax.abort(this.activeRequest);
10090 this.activeRequest = Roo.Ajax.request(o);
10092 this.conn.request(o);
10095 callback.call(scope||this, null, arg, false);
10100 loadResponse : function(o, success, response){
10101 delete this.activeRequest;
10103 this.fireEvent("loadexception", this, o, response);
10104 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10109 result = o.reader.read(response);
10111 this.fireEvent("loadexception", this, o, response, e);
10112 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10116 this.fireEvent("load", this, o, o.request.arg);
10117 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10121 update : function(dataSet){
10126 updateResponse : function(dataSet){
10131 * Ext JS Library 1.1.1
10132 * Copyright(c) 2006-2007, Ext JS, LLC.
10134 * Originally Released Under LGPL - original licence link has changed is not relivant.
10137 * <script type="text/javascript">
10141 * @class Roo.data.ScriptTagProxy
10142 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10143 * other than the originating domain of the running page.<br><br>
10145 * <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
10146 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10148 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10149 * source code that is used as the source inside a <script> tag.<br><br>
10151 * In order for the browser to process the returned data, the server must wrap the data object
10152 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10153 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10154 * depending on whether the callback name was passed:
10157 boolean scriptTag = false;
10158 String cb = request.getParameter("callback");
10161 response.setContentType("text/javascript");
10163 response.setContentType("application/x-json");
10165 Writer out = response.getWriter();
10167 out.write(cb + "(");
10169 out.print(dataBlock.toJsonString());
10176 * @param {Object} config A configuration object.
10178 Roo.data.ScriptTagProxy = function(config){
10179 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10180 Roo.apply(this, config);
10181 this.head = document.getElementsByTagName("head")[0];
10184 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10186 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10188 * @cfg {String} url The URL from which to request the data object.
10191 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10195 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10196 * the server the name of the callback function set up by the load call to process the returned data object.
10197 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10198 * javascript output which calls this named function passing the data object as its only parameter.
10200 callbackParam : "callback",
10202 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10203 * name to the request.
10208 * Load data from the configured URL, read the data object into
10209 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10210 * process that block using the passed callback.
10211 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10212 * for the request to the remote server.
10213 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10214 * object into a block of Roo.data.Records.
10215 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10216 * The function must be passed <ul>
10217 * <li>The Record block object</li>
10218 * <li>The "arg" argument from the load function</li>
10219 * <li>A boolean success indicator</li>
10221 * @param {Object} scope The scope in which to call the callback
10222 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10224 load : function(params, reader, callback, scope, arg){
10225 if(this.fireEvent("beforeload", this, params) !== false){
10227 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10229 var url = this.url;
10230 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10232 url += "&_dc=" + (new Date().getTime());
10234 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10237 cb : "stcCallback"+transId,
10238 scriptId : "stcScript"+transId,
10242 callback : callback,
10248 window[trans.cb] = function(o){
10249 conn.handleResponse(o, trans);
10252 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10254 if(this.autoAbort !== false){
10258 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10260 var script = document.createElement("script");
10261 script.setAttribute("src", url);
10262 script.setAttribute("type", "text/javascript");
10263 script.setAttribute("id", trans.scriptId);
10264 this.head.appendChild(script);
10266 this.trans = trans;
10268 callback.call(scope||this, null, arg, false);
10273 isLoading : function(){
10274 return this.trans ? true : false;
10278 * Abort the current server request.
10280 abort : function(){
10281 if(this.isLoading()){
10282 this.destroyTrans(this.trans);
10287 destroyTrans : function(trans, isLoaded){
10288 this.head.removeChild(document.getElementById(trans.scriptId));
10289 clearTimeout(trans.timeoutId);
10291 window[trans.cb] = undefined;
10293 delete window[trans.cb];
10296 // if hasn't been loaded, wait for load to remove it to prevent script error
10297 window[trans.cb] = function(){
10298 window[trans.cb] = undefined;
10300 delete window[trans.cb];
10307 handleResponse : function(o, trans){
10308 this.trans = false;
10309 this.destroyTrans(trans, true);
10312 result = trans.reader.readRecords(o);
10314 this.fireEvent("loadexception", this, o, trans.arg, e);
10315 trans.callback.call(trans.scope||window, null, trans.arg, false);
10318 this.fireEvent("load", this, o, trans.arg);
10319 trans.callback.call(trans.scope||window, result, trans.arg, true);
10323 handleFailure : function(trans){
10324 this.trans = false;
10325 this.destroyTrans(trans, false);
10326 this.fireEvent("loadexception", this, null, trans.arg);
10327 trans.callback.call(trans.scope||window, null, trans.arg, false);
10331 * Ext JS Library 1.1.1
10332 * Copyright(c) 2006-2007, Ext JS, LLC.
10334 * Originally Released Under LGPL - original licence link has changed is not relivant.
10337 * <script type="text/javascript">
10341 * @class Roo.data.JsonReader
10342 * @extends Roo.data.DataReader
10343 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10344 * based on mappings in a provided Roo.data.Record constructor.
10346 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10347 * in the reply previously.
10352 var RecordDef = Roo.data.Record.create([
10353 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10354 {name: 'occupation'} // This field will use "occupation" as the mapping.
10356 var myReader = new Roo.data.JsonReader({
10357 totalProperty: "results", // The property which contains the total dataset size (optional)
10358 root: "rows", // The property which contains an Array of row objects
10359 id: "id" // The property within each row object that provides an ID for the record (optional)
10363 * This would consume a JSON file like this:
10365 { 'results': 2, 'rows': [
10366 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10367 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10370 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10371 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10372 * paged from the remote server.
10373 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10374 * @cfg {String} root name of the property which contains the Array of row objects.
10375 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10377 * Create a new JsonReader
10378 * @param {Object} meta Metadata configuration options
10379 * @param {Object} recordType Either an Array of field definition objects,
10380 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10382 Roo.data.JsonReader = function(meta, recordType){
10385 // set some defaults:
10386 Roo.applyIf(meta, {
10387 totalProperty: 'total',
10388 successProperty : 'success',
10393 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10395 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10398 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10399 * Used by Store query builder to append _requestMeta to params.
10402 metaFromRemote : false,
10404 * This method is only used by a DataProxy which has retrieved data from a remote server.
10405 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10406 * @return {Object} data A data block which is used by an Roo.data.Store object as
10407 * a cache of Roo.data.Records.
10409 read : function(response){
10410 var json = response.responseText;
10412 var o = /* eval:var:o */ eval("("+json+")");
10414 throw {message: "JsonReader.read: Json object not found"};
10420 this.metaFromRemote = true;
10421 this.meta = o.metaData;
10422 this.recordType = Roo.data.Record.create(o.metaData.fields);
10423 this.onMetaChange(this.meta, this.recordType, o);
10425 return this.readRecords(o);
10428 // private function a store will implement
10429 onMetaChange : function(meta, recordType, o){
10436 simpleAccess: function(obj, subsc) {
10443 getJsonAccessor: function(){
10445 return function(expr) {
10447 return(re.test(expr))
10448 ? new Function("obj", "return obj." + expr)
10453 return Roo.emptyFn;
10458 * Create a data block containing Roo.data.Records from an XML document.
10459 * @param {Object} o An object which contains an Array of row objects in the property specified
10460 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10461 * which contains the total size of the dataset.
10462 * @return {Object} data A data block which is used by an Roo.data.Store object as
10463 * a cache of Roo.data.Records.
10465 readRecords : function(o){
10467 * After any data loads, the raw JSON data is available for further custom processing.
10471 var s = this.meta, Record = this.recordType,
10472 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10474 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10476 if(s.totalProperty) {
10477 this.getTotal = this.getJsonAccessor(s.totalProperty);
10479 if(s.successProperty) {
10480 this.getSuccess = this.getJsonAccessor(s.successProperty);
10482 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10484 var g = this.getJsonAccessor(s.id);
10485 this.getId = function(rec) {
10487 return (r === undefined || r === "") ? null : r;
10490 this.getId = function(){return null;};
10493 for(var jj = 0; jj < fl; jj++){
10495 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10496 this.ef[jj] = this.getJsonAccessor(map);
10500 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10501 if(s.totalProperty){
10502 var vt = parseInt(this.getTotal(o), 10);
10507 if(s.successProperty){
10508 var vs = this.getSuccess(o);
10509 if(vs === false || vs === 'false'){
10514 for(var i = 0; i < c; i++){
10517 var id = this.getId(n);
10518 for(var j = 0; j < fl; j++){
10520 var v = this.ef[j](n);
10522 Roo.log('missing convert for ' + f.name);
10526 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10528 var record = new Record(values, id);
10530 records[i] = record;
10536 totalRecords : totalRecords
10541 * Ext JS Library 1.1.1
10542 * Copyright(c) 2006-2007, Ext JS, LLC.
10544 * Originally Released Under LGPL - original licence link has changed is not relivant.
10547 * <script type="text/javascript">
10551 * @class Roo.data.ArrayReader
10552 * @extends Roo.data.DataReader
10553 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10554 * Each element of that Array represents a row of data fields. The
10555 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10556 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10560 var RecordDef = Roo.data.Record.create([
10561 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10562 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10564 var myReader = new Roo.data.ArrayReader({
10565 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10569 * This would consume an Array like this:
10571 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10573 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10575 * Create a new JsonReader
10576 * @param {Object} meta Metadata configuration options.
10577 * @param {Object} recordType Either an Array of field definition objects
10578 * as specified to {@link Roo.data.Record#create},
10579 * or an {@link Roo.data.Record} object
10580 * created using {@link Roo.data.Record#create}.
10582 Roo.data.ArrayReader = function(meta, recordType){
10583 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10586 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10588 * Create a data block containing Roo.data.Records from an XML document.
10589 * @param {Object} o An Array of row objects which represents the dataset.
10590 * @return {Object} data A data block which is used by an Roo.data.Store object as
10591 * a cache of Roo.data.Records.
10593 readRecords : function(o){
10594 var sid = this.meta ? this.meta.id : null;
10595 var recordType = this.recordType, fields = recordType.prototype.fields;
10598 for(var i = 0; i < root.length; i++){
10601 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10602 for(var j = 0, jlen = fields.length; j < jlen; j++){
10603 var f = fields.items[j];
10604 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10605 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10607 values[f.name] = v;
10609 var record = new recordType(values, id);
10611 records[records.length] = record;
10615 totalRecords : records.length
10624 * @class Roo.bootstrap.ComboBox
10625 * @extends Roo.bootstrap.TriggerField
10626 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10627 * @cfg {Boolean} append (true|false) default false
10628 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10629 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10630 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10631 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10632 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10634 * Create a new ComboBox.
10635 * @param {Object} config Configuration options
10637 Roo.bootstrap.ComboBox = function(config){
10638 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10642 * Fires when the dropdown list is expanded
10643 * @param {Roo.bootstrap.ComboBox} combo This combo box
10648 * Fires when the dropdown list is collapsed
10649 * @param {Roo.bootstrap.ComboBox} combo This combo box
10653 * @event beforeselect
10654 * Fires before a list item is selected. Return false to cancel the selection.
10655 * @param {Roo.bootstrap.ComboBox} combo This combo box
10656 * @param {Roo.data.Record} record The data record returned from the underlying store
10657 * @param {Number} index The index of the selected item in the dropdown list
10659 'beforeselect' : true,
10662 * Fires when a list item is selected
10663 * @param {Roo.bootstrap.ComboBox} combo This combo box
10664 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10665 * @param {Number} index The index of the selected item in the dropdown list
10669 * @event beforequery
10670 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10671 * The event object passed has these properties:
10672 * @param {Roo.bootstrap.ComboBox} combo This combo box
10673 * @param {String} query The query
10674 * @param {Boolean} forceAll true to force "all" query
10675 * @param {Boolean} cancel true to cancel the query
10676 * @param {Object} e The query event object
10678 'beforequery': true,
10681 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10682 * @param {Roo.bootstrap.ComboBox} combo This combo box
10687 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10688 * @param {Roo.bootstrap.ComboBox} combo This combo box
10689 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10694 * Fires when the remove value from the combobox array
10695 * @param {Roo.bootstrap.ComboBox} combo This combo box
10702 this.tickItems = [];
10704 this.selectedIndex = -1;
10705 if(this.mode == 'local'){
10706 if(config.queryDelay === undefined){
10707 this.queryDelay = 10;
10709 if(config.minChars === undefined){
10715 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10718 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10719 * rendering into an Roo.Editor, defaults to false)
10722 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10723 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10726 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10729 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10730 * the dropdown list (defaults to undefined, with no header element)
10734 * @cfg {String/Roo.Template} tpl The template to use to render the output
10738 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10740 listWidth: undefined,
10742 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10743 * mode = 'remote' or 'text' if mode = 'local')
10745 displayField: undefined,
10747 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10748 * mode = 'remote' or 'value' if mode = 'local').
10749 * Note: use of a valueField requires the user make a selection
10750 * in order for a value to be mapped.
10752 valueField: undefined,
10756 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10757 * field's data value (defaults to the underlying DOM element's name)
10759 hiddenName: undefined,
10761 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10765 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10767 selectedClass: 'active',
10770 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10774 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10775 * anchor positions (defaults to 'tl-bl')
10777 listAlign: 'tl-bl?',
10779 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10783 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10784 * query specified by the allQuery config option (defaults to 'query')
10786 triggerAction: 'query',
10788 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10789 * (defaults to 4, does not apply if editable = false)
10793 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10794 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10798 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10799 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10803 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10804 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10808 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10809 * when editable = true (defaults to false)
10811 selectOnFocus:false,
10813 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10815 queryParam: 'query',
10817 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10818 * when mode = 'remote' (defaults to 'Loading...')
10820 loadingText: 'Loading...',
10822 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10826 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10830 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10831 * traditional select (defaults to true)
10835 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10839 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10843 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10844 * listWidth has a higher value)
10848 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10849 * allow the user to set arbitrary text into the field (defaults to false)
10851 forceSelection:false,
10853 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10854 * if typeAhead = true (defaults to 250)
10856 typeAheadDelay : 250,
10858 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10859 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10861 valueNotFoundText : undefined,
10863 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10865 blockFocus : false,
10868 * @cfg {Boolean} disableClear Disable showing of clear button.
10870 disableClear : false,
10872 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10874 alwaysQuery : false,
10877 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10882 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10884 invalidClass : "has-warning",
10887 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10889 validClass : "has-success",
10892 * @cfg {Boolean} loadonce (true|false) load one time, then filter the records, default false
10906 btnPosition : 'right',
10907 triggerList : true,
10908 showToggleBtn : true,
10909 // element that contains real text value.. (when hidden is used..)
10911 getAutoCreate : function()
10918 if(!this.tickable){
10919 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10924 * ComboBox with tickable selections
10927 var align = this.labelAlign || this.parentLabelAlign();
10930 cls : 'form-group roo-combobox-tickable' //input-group
10935 cls : 'tickable-buttons',
10940 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10947 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10954 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10961 buttons.cn.unshift({
10963 cls: 'select2-search-field-input'
10969 Roo.each(buttons.cn, function(c){
10971 c.cls += ' btn-' + _this.size;
10974 if (_this.disabled) {
10985 cls: 'form-hidden-field'
10989 cls: 'select2-choices',
10993 cls: 'select2-search-field',
11005 cls: 'select2-container input-group select2-container-multi',
11010 // cls: 'typeahead typeahead-long dropdown-menu',
11011 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11016 if(this.hasFeedback && !this.allowBlank){
11020 cls: 'glyphicon form-control-feedback'
11023 combobox.cn.push(feedback);
11026 if (align ==='left' && this.fieldLabel.length) {
11028 Roo.log("left and has label");
11034 cls : 'control-label col-sm-' + this.labelWidth,
11035 html : this.fieldLabel
11039 cls : "col-sm-" + (12 - this.labelWidth),
11046 } else if ( this.fieldLabel.length) {
11052 //cls : 'input-group-addon',
11053 html : this.fieldLabel
11063 Roo.log(" no label && no align");
11070 ['xs','sm','md','lg'].map(function(size){
11071 if (settings[size]) {
11072 cfg.cls += ' col-' + size + '-' + settings[size];
11081 initEvents: function()
11085 throw "can not find store for combo";
11087 this.store = Roo.factory(this.store, Roo.data);
11090 this.initTickableEvents();
11094 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11096 if(this.hiddenName){
11098 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11100 this.hiddenField.dom.value =
11101 this.hiddenValue !== undefined ? this.hiddenValue :
11102 this.value !== undefined ? this.value : '';
11104 // prevent input submission
11105 this.el.dom.removeAttribute('name');
11106 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11111 // this.el.dom.setAttribute('autocomplete', 'off');
11114 var cls = 'x-combo-list';
11116 //this.list = new Roo.Layer({
11117 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11123 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11124 _this.list.setWidth(lw);
11127 this.list.on('mouseover', this.onViewOver, this);
11128 this.list.on('mousemove', this.onViewMove, this);
11130 this.list.on('scroll', this.onViewScroll, this);
11133 this.list.swallowEvent('mousewheel');
11134 this.assetHeight = 0;
11137 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11138 this.assetHeight += this.header.getHeight();
11141 this.innerList = this.list.createChild({cls:cls+'-inner'});
11142 this.innerList.on('mouseover', this.onViewOver, this);
11143 this.innerList.on('mousemove', this.onViewMove, this);
11144 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11146 if(this.allowBlank && !this.pageSize && !this.disableClear){
11147 this.footer = this.list.createChild({cls:cls+'-ft'});
11148 this.pageTb = new Roo.Toolbar(this.footer);
11152 this.footer = this.list.createChild({cls:cls+'-ft'});
11153 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11154 {pageSize: this.pageSize});
11158 if (this.pageTb && this.allowBlank && !this.disableClear) {
11160 this.pageTb.add(new Roo.Toolbar.Fill(), {
11161 cls: 'x-btn-icon x-btn-clear',
11163 handler: function()
11166 _this.clearValue();
11167 _this.onSelect(false, -1);
11172 this.assetHeight += this.footer.getHeight();
11177 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11180 this.view = new Roo.View(this.list, this.tpl, {
11181 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11183 //this.view.wrapEl.setDisplayed(false);
11184 this.view.on('click', this.onViewClick, this);
11188 this.store.on('beforeload', this.onBeforeLoad, this);
11189 this.store.on('load', this.onLoad, this);
11190 this.store.on('loadexception', this.onLoadException, this);
11192 if(this.resizable){
11193 this.resizer = new Roo.Resizable(this.list, {
11194 pinned:true, handles:'se'
11196 this.resizer.on('resize', function(r, w, h){
11197 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11198 this.listWidth = w;
11199 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11200 this.restrictHeight();
11202 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11205 if(!this.editable){
11206 this.editable = true;
11207 this.setEditable(false);
11212 if (typeof(this.events.add.listeners) != 'undefined') {
11214 this.addicon = this.wrap.createChild(
11215 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11217 this.addicon.on('click', function(e) {
11218 this.fireEvent('add', this);
11221 if (typeof(this.events.edit.listeners) != 'undefined') {
11223 this.editicon = this.wrap.createChild(
11224 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11225 if (this.addicon) {
11226 this.editicon.setStyle('margin-left', '40px');
11228 this.editicon.on('click', function(e) {
11230 // we fire even if inothing is selected..
11231 this.fireEvent('edit', this, this.lastData );
11237 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11238 "up" : function(e){
11239 this.inKeyMode = true;
11243 "down" : function(e){
11244 if(!this.isExpanded()){
11245 this.onTriggerClick();
11247 this.inKeyMode = true;
11252 "enter" : function(e){
11253 // this.onViewClick();
11257 if(this.fireEvent("specialkey", this, e)){
11258 this.onViewClick(false);
11264 "esc" : function(e){
11268 "tab" : function(e){
11271 if(this.fireEvent("specialkey", this, e)){
11272 this.onViewClick(false);
11280 doRelay : function(foo, bar, hname){
11281 if(hname == 'down' || this.scope.isExpanded()){
11282 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11291 this.queryDelay = Math.max(this.queryDelay || 10,
11292 this.mode == 'local' ? 10 : 250);
11295 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11297 if(this.typeAhead){
11298 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11300 if(this.editable !== false){
11301 this.inputEl().on("keyup", this.onKeyUp, this);
11303 if(this.forceSelection){
11304 this.inputEl().on('blur', this.doForce, this);
11308 this.choices = this.el.select('ul.select2-choices', true).first();
11309 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11313 initTickableEvents: function()
11317 if(this.hiddenName){
11319 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11321 this.hiddenField.dom.value =
11322 this.hiddenValue !== undefined ? this.hiddenValue :
11323 this.value !== undefined ? this.value : '';
11325 // prevent input submission
11326 this.el.dom.removeAttribute('name');
11327 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11332 // this.list = this.el.select('ul.dropdown-menu',true).first();
11334 this.choices = this.el.select('ul.select2-choices', true).first();
11335 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11336 if(this.triggerList){
11337 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11340 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11341 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11343 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11344 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11346 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11347 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11349 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11350 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11351 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11354 this.cancelBtn.hide();
11359 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11360 _this.list.setWidth(lw);
11363 this.list.on('mouseover', this.onViewOver, this);
11364 this.list.on('mousemove', this.onViewMove, this);
11366 this.list.on('scroll', this.onViewScroll, this);
11369 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>';
11372 this.view = new Roo.View(this.list, this.tpl, {
11373 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11376 //this.view.wrapEl.setDisplayed(false);
11377 this.view.on('click', this.onViewClick, this);
11381 this.store.on('beforeload', this.onBeforeLoad, this);
11382 this.store.on('load', this.onLoad, this);
11383 this.store.on('loadexception', this.onLoadException, this);
11386 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11387 "up" : function(e){
11388 this.inKeyMode = true;
11392 "down" : function(e){
11393 this.inKeyMode = true;
11397 "enter" : function(e){
11398 if(this.fireEvent("specialkey", this, e)){
11399 this.onViewClick(false);
11405 "esc" : function(e){
11406 this.onTickableFooterButtonClick(e, false, false);
11409 "tab" : function(e){
11410 this.fireEvent("specialkey", this, e);
11412 this.onTickableFooterButtonClick(e, false, false);
11419 doRelay : function(e, fn, key){
11420 if(this.scope.isExpanded()){
11421 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11430 this.queryDelay = Math.max(this.queryDelay || 10,
11431 this.mode == 'local' ? 10 : 250);
11434 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11436 if(this.typeAhead){
11437 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11440 if(this.editable !== false){
11441 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11446 onDestroy : function(){
11448 this.view.setStore(null);
11449 this.view.el.removeAllListeners();
11450 this.view.el.remove();
11451 this.view.purgeListeners();
11454 this.list.dom.innerHTML = '';
11458 this.store.un('beforeload', this.onBeforeLoad, this);
11459 this.store.un('load', this.onLoad, this);
11460 this.store.un('loadexception', this.onLoadException, this);
11462 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11466 fireKey : function(e){
11467 if(e.isNavKeyPress() && !this.list.isVisible()){
11468 this.fireEvent("specialkey", this, e);
11473 onResize: function(w, h){
11474 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11476 // if(typeof w != 'number'){
11477 // // we do not handle it!?!?
11480 // var tw = this.trigger.getWidth();
11481 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11482 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11484 // this.inputEl().setWidth( this.adjustWidth('input', x));
11486 // //this.trigger.setStyle('left', x+'px');
11488 // if(this.list && this.listWidth === undefined){
11489 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11490 // this.list.setWidth(lw);
11491 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11499 * Allow or prevent the user from directly editing the field text. If false is passed,
11500 * the user will only be able to select from the items defined in the dropdown list. This method
11501 * is the runtime equivalent of setting the 'editable' config option at config time.
11502 * @param {Boolean} value True to allow the user to directly edit the field text
11504 setEditable : function(value){
11505 if(value == this.editable){
11508 this.editable = value;
11510 this.inputEl().dom.setAttribute('readOnly', true);
11511 this.inputEl().on('mousedown', this.onTriggerClick, this);
11512 this.inputEl().addClass('x-combo-noedit');
11514 this.inputEl().dom.setAttribute('readOnly', false);
11515 this.inputEl().un('mousedown', this.onTriggerClick, this);
11516 this.inputEl().removeClass('x-combo-noedit');
11522 onBeforeLoad : function(combo,opts){
11523 if(!this.hasFocus){
11527 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11529 this.restrictHeight();
11530 this.selectedIndex = -1;
11534 onLoad : function(){
11536 this.hasQuery = false;
11538 if(!this.hasFocus){
11542 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11543 this.loading.hide();
11546 if(this.store.getCount() > 0){
11548 this.restrictHeight();
11549 if(this.lastQuery == this.allQuery){
11550 if(this.editable && !this.tickable){
11551 this.inputEl().dom.select();
11555 !this.selectByValue(this.value, true) &&
11558 !this.store.lastOptions ||
11559 typeof(this.store.lastOptions.add) == 'undefined' ||
11560 this.store.lastOptions.add != true
11563 this.select(0, true);
11566 if(this.autoFocus){
11569 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11570 this.taTask.delay(this.typeAheadDelay);
11574 this.onEmptyResults();
11580 onLoadException : function()
11582 this.hasQuery = false;
11584 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11585 this.loading.hide();
11588 if(this.tickable && this.editable){
11594 Roo.log(this.store.reader.jsonData);
11595 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11597 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11603 onTypeAhead : function(){
11604 if(this.store.getCount() > 0){
11605 var r = this.store.getAt(0);
11606 var newValue = r.data[this.displayField];
11607 var len = newValue.length;
11608 var selStart = this.getRawValue().length;
11610 if(selStart != len){
11611 this.setRawValue(newValue);
11612 this.selectText(selStart, newValue.length);
11618 onSelect : function(record, index){
11620 if(this.fireEvent('beforeselect', this, record, index) !== false){
11622 this.setFromData(index > -1 ? record.data : false);
11625 this.fireEvent('select', this, record, index);
11630 * Returns the currently selected field value or empty string if no value is set.
11631 * @return {String} value The selected value
11633 getValue : function(){
11636 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11639 if(this.valueField){
11640 return typeof this.value != 'undefined' ? this.value : '';
11642 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11647 * Clears any text/value currently set in the field
11649 clearValue : function(){
11650 if(this.hiddenField){
11651 this.hiddenField.dom.value = '';
11654 this.setRawValue('');
11655 this.lastSelectionText = '';
11656 this.lastData = false;
11661 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11662 * will be displayed in the field. If the value does not match the data value of an existing item,
11663 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11664 * Otherwise the field will be blank (although the value will still be set).
11665 * @param {String} value The value to match
11667 setValue : function(v){
11674 if(this.valueField){
11675 var r = this.findRecord(this.valueField, v);
11677 text = r.data[this.displayField];
11678 }else if(this.valueNotFoundText !== undefined){
11679 text = this.valueNotFoundText;
11682 this.lastSelectionText = text;
11683 if(this.hiddenField){
11684 this.hiddenField.dom.value = v;
11686 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11690 * @property {Object} the last set data for the element
11695 * Sets the value of the field based on a object which is related to the record format for the store.
11696 * @param {Object} value the value to set as. or false on reset?
11698 setFromData : function(o){
11705 var dv = ''; // display value
11706 var vv = ''; // value value..
11708 if (this.displayField) {
11709 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11711 // this is an error condition!!!
11712 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11715 if(this.valueField){
11716 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11719 if(this.hiddenField){
11720 this.hiddenField.dom.value = vv;
11722 this.lastSelectionText = dv;
11723 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11727 // no hidden field.. - we store the value in 'value', but still display
11728 // display field!!!!
11729 this.lastSelectionText = dv;
11730 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11736 reset : function(){
11737 // overridden so that last data is reset..
11738 this.setValue(this.originalValue);
11739 this.clearInvalid();
11740 this.lastData = false;
11742 this.view.clearSelections();
11746 findRecord : function(prop, value){
11748 if(this.store.getCount() > 0){
11749 this.store.each(function(r){
11750 if(r.data[prop] == value){
11760 getName: function()
11762 // returns hidden if it's set..
11763 if (!this.rendered) {return ''};
11764 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11768 onViewMove : function(e, t){
11769 this.inKeyMode = false;
11773 onViewOver : function(e, t){
11774 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11777 var item = this.view.findItemFromChild(t);
11780 var index = this.view.indexOf(item);
11781 this.select(index, false);
11786 onViewClick : function(view, doFocus, el, e)
11788 var index = this.view.getSelectedIndexes()[0];
11790 var r = this.store.getAt(index);
11794 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11801 Roo.each(this.tickItems, function(v,k){
11803 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11804 _this.tickItems.splice(k, 1);
11806 if(typeof(e) == 'undefined' && view == false){
11807 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11819 this.tickItems.push(r.data);
11821 if(typeof(e) == 'undefined' && view == false){
11822 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11829 this.onSelect(r, index);
11831 if(doFocus !== false && !this.blockFocus){
11832 this.inputEl().focus();
11837 restrictHeight : function(){
11838 //this.innerList.dom.style.height = '';
11839 //var inner = this.innerList.dom;
11840 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11841 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11842 //this.list.beginUpdate();
11843 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11844 this.list.alignTo(this.inputEl(), this.listAlign);
11845 this.list.alignTo(this.inputEl(), this.listAlign);
11846 //this.list.endUpdate();
11850 onEmptyResults : function(){
11852 if(this.tickable && this.editable){
11853 this.restrictHeight();
11861 * Returns true if the dropdown list is expanded, else false.
11863 isExpanded : function(){
11864 return this.list.isVisible();
11868 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11869 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11870 * @param {String} value The data value of the item to select
11871 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11872 * selected item if it is not currently in view (defaults to true)
11873 * @return {Boolean} True if the value matched an item in the list, else false
11875 selectByValue : function(v, scrollIntoView){
11876 if(v !== undefined && v !== null){
11877 var r = this.findRecord(this.valueField || this.displayField, v);
11879 this.select(this.store.indexOf(r), scrollIntoView);
11887 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11888 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11889 * @param {Number} index The zero-based index of the list item to select
11890 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11891 * selected item if it is not currently in view (defaults to true)
11893 select : function(index, scrollIntoView){
11894 this.selectedIndex = index;
11895 this.view.select(index);
11896 if(scrollIntoView !== false){
11897 var el = this.view.getNode(index);
11899 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11902 this.list.scrollChildIntoView(el, false);
11908 selectNext : function(){
11909 var ct = this.store.getCount();
11911 if(this.selectedIndex == -1){
11913 }else if(this.selectedIndex < ct-1){
11914 this.select(this.selectedIndex+1);
11920 selectPrev : function(){
11921 var ct = this.store.getCount();
11923 if(this.selectedIndex == -1){
11925 }else if(this.selectedIndex != 0){
11926 this.select(this.selectedIndex-1);
11932 onKeyUp : function(e){
11933 if(this.editable !== false && !e.isSpecialKey()){
11934 this.lastKey = e.getKey();
11935 this.dqTask.delay(this.queryDelay);
11940 validateBlur : function(){
11941 return !this.list || !this.list.isVisible();
11945 initQuery : function(){
11947 var v = this.getRawValue();
11949 if(this.tickable && this.editable){
11950 v = this.tickableInputEl().getValue();
11957 doForce : function(){
11958 if(this.inputEl().dom.value.length > 0){
11959 this.inputEl().dom.value =
11960 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11966 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11967 * query allowing the query action to be canceled if needed.
11968 * @param {String} query The SQL query to execute
11969 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11970 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11971 * saved in the current store (defaults to false)
11973 doQuery : function(q, forceAll){
11975 if(q === undefined || q === null){
11980 forceAll: forceAll,
11984 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11989 forceAll = qe.forceAll;
11990 if(forceAll === true || (q.length >= this.minChars)){
11992 this.hasQuery = true;
11994 if(this.lastQuery != q || this.alwaysQuery){
11995 this.lastQuery = q;
11996 if(this.mode == 'local'){
11997 this.selectedIndex = -1;
11999 this.store.clearFilter();
12001 this.store.filter(this.displayField, q);
12005 this.store.baseParams[this.queryParam] = q;
12007 var options = {params : this.getParams(q)};
12010 options.add = true;
12011 options.params.start = this.page * this.pageSize;
12014 if(this.loadonce && this.store.getCount() > 0){
12015 this.selectedIndex = -1;
12017 this.store.clearFilter();
12019 this.store.filter(this.displayField, q);
12025 this.store.load(options);
12028 * this code will make the page width larger, at the beginning, the list not align correctly,
12029 * we should expand the list on onLoad
12030 * so command out it
12035 this.selectedIndex = -1;
12040 this.loadNext = false;
12044 getParams : function(q){
12046 //p[this.queryParam] = q;
12050 p.limit = this.pageSize;
12056 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12058 collapse : function(){
12059 if(!this.isExpanded()){
12066 this.hasFocus = false;
12068 this.cancelBtn.hide();
12069 this.trigger.show();
12072 this.tickableInputEl().dom.value = '';
12073 this.tickableInputEl().blur();
12078 Roo.get(document).un('mousedown', this.collapseIf, this);
12079 Roo.get(document).un('mousewheel', this.collapseIf, this);
12080 if (!this.editable) {
12081 Roo.get(document).un('keydown', this.listKeyPress, this);
12083 this.fireEvent('collapse', this);
12087 collapseIf : function(e){
12088 var in_combo = e.within(this.el);
12089 var in_list = e.within(this.list);
12090 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12092 if (in_combo || in_list || is_list) {
12093 //e.stopPropagation();
12098 this.onTickableFooterButtonClick(e, false, false);
12106 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12108 expand : function(){
12110 if(this.isExpanded() || !this.hasFocus){
12114 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12115 this.list.setWidth(lw);
12122 this.restrictHeight();
12126 this.tickItems = Roo.apply([], this.item);
12129 this.cancelBtn.show();
12130 this.trigger.hide();
12133 this.tickableInputEl().focus();
12138 Roo.get(document).on('mousedown', this.collapseIf, this);
12139 Roo.get(document).on('mousewheel', this.collapseIf, this);
12140 if (!this.editable) {
12141 Roo.get(document).on('keydown', this.listKeyPress, this);
12144 this.fireEvent('expand', this);
12148 // Implements the default empty TriggerField.onTriggerClick function
12149 onTriggerClick : function(e)
12151 Roo.log('trigger click');
12153 if(this.disabled || !this.triggerList){
12158 this.loadNext = false;
12160 if(this.isExpanded()){
12162 if (!this.blockFocus) {
12163 this.inputEl().focus();
12167 this.hasFocus = true;
12168 if(this.triggerAction == 'all') {
12169 this.doQuery(this.allQuery, true);
12171 this.doQuery(this.getRawValue());
12173 if (!this.blockFocus) {
12174 this.inputEl().focus();
12179 onTickableTriggerClick : function(e)
12186 this.loadNext = false;
12187 this.hasFocus = true;
12189 if(this.triggerAction == 'all') {
12190 this.doQuery(this.allQuery, true);
12192 this.doQuery(this.getRawValue());
12196 onSearchFieldClick : function(e)
12198 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12199 this.onTickableFooterButtonClick(e, false, false);
12203 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12208 this.loadNext = false;
12209 this.hasFocus = true;
12211 if(this.triggerAction == 'all') {
12212 this.doQuery(this.allQuery, true);
12214 this.doQuery(this.getRawValue());
12218 listKeyPress : function(e)
12220 //Roo.log('listkeypress');
12221 // scroll to first matching element based on key pres..
12222 if (e.isSpecialKey()) {
12225 var k = String.fromCharCode(e.getKey()).toUpperCase();
12228 var csel = this.view.getSelectedNodes();
12229 var cselitem = false;
12231 var ix = this.view.indexOf(csel[0]);
12232 cselitem = this.store.getAt(ix);
12233 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12239 this.store.each(function(v) {
12241 // start at existing selection.
12242 if (cselitem.id == v.id) {
12248 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12249 match = this.store.indexOf(v);
12255 if (match === false) {
12256 return true; // no more action?
12259 this.view.select(match);
12260 var sn = Roo.get(this.view.getSelectedNodes()[0])
12261 sn.scrollIntoView(sn.dom.parentNode, false);
12264 onViewScroll : function(e, t){
12266 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){
12270 this.hasQuery = true;
12272 this.loading = this.list.select('.loading', true).first();
12274 if(this.loading === null){
12275 this.list.createChild({
12277 cls: 'loading select2-more-results select2-active',
12278 html: 'Loading more results...'
12281 this.loading = this.list.select('.loading', true).first();
12283 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12285 this.loading.hide();
12288 this.loading.show();
12293 this.loadNext = true;
12295 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12300 addItem : function(o)
12302 var dv = ''; // display value
12304 if (this.displayField) {
12305 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12307 // this is an error condition!!!
12308 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12315 var choice = this.choices.createChild({
12317 cls: 'select2-search-choice',
12326 cls: 'select2-search-choice-close',
12331 }, this.searchField);
12333 var close = choice.select('a.select2-search-choice-close', true).first()
12335 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12343 this.inputEl().dom.value = '';
12348 onRemoveItem : function(e, _self, o)
12350 e.preventDefault();
12352 this.lastItem = Roo.apply([], this.item);
12354 var index = this.item.indexOf(o.data) * 1;
12357 Roo.log('not this item?!');
12361 this.item.splice(index, 1);
12366 this.fireEvent('remove', this, e);
12372 syncValue : function()
12374 if(!this.item.length){
12381 Roo.each(this.item, function(i){
12382 if(_this.valueField){
12383 value.push(i[_this.valueField]);
12390 this.value = value.join(',');
12392 if(this.hiddenField){
12393 this.hiddenField.dom.value = this.value;
12397 clearItem : function()
12399 if(!this.multiple){
12405 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12414 inputEl: function ()
12417 return this.searchField;
12419 return this.el.select('input.form-control',true).first();
12423 onTickableFooterButtonClick : function(e, btn, el)
12425 e.preventDefault();
12427 this.lastItem = Roo.apply([], this.item);
12429 if(btn && btn.name == 'cancel'){
12430 this.tickItems = Roo.apply([], this.item);
12439 Roo.each(this.tickItems, function(o){
12447 validate : function()
12449 var v = this.getRawValue();
12452 v = this.getValue();
12455 if(this.disabled || this.allowBlank || v.length){
12460 this.markInvalid();
12464 tickableInputEl : function()
12466 if(!this.tickable || !this.editable){
12467 return this.inputEl();
12470 return this.inputEl().select('.select2-search-field-input', true).first();
12476 * @cfg {Boolean} grow
12480 * @cfg {Number} growMin
12484 * @cfg {Number} growMax
12494 * Ext JS Library 1.1.1
12495 * Copyright(c) 2006-2007, Ext JS, LLC.
12497 * Originally Released Under LGPL - original licence link has changed is not relivant.
12500 * <script type="text/javascript">
12505 * @extends Roo.util.Observable
12506 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12507 * This class also supports single and multi selection modes. <br>
12508 * Create a data model bound view:
12510 var store = new Roo.data.Store(...);
12512 var view = new Roo.View({
12514 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12516 singleSelect: true,
12517 selectedClass: "ydataview-selected",
12521 // listen for node click?
12522 view.on("click", function(vw, index, node, e){
12523 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12527 dataModel.load("foobar.xml");
12529 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12531 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12532 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12534 * Note: old style constructor is still suported (container, template, config)
12537 * Create a new View
12538 * @param {Object} config The config object
12541 Roo.View = function(config, depreciated_tpl, depreciated_config){
12543 this.parent = false;
12545 if (typeof(depreciated_tpl) == 'undefined') {
12546 // new way.. - universal constructor.
12547 Roo.apply(this, config);
12548 this.el = Roo.get(this.el);
12551 this.el = Roo.get(config);
12552 this.tpl = depreciated_tpl;
12553 Roo.apply(this, depreciated_config);
12555 this.wrapEl = this.el.wrap().wrap();
12556 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12559 if(typeof(this.tpl) == "string"){
12560 this.tpl = new Roo.Template(this.tpl);
12562 // support xtype ctors..
12563 this.tpl = new Roo.factory(this.tpl, Roo);
12567 this.tpl.compile();
12572 * @event beforeclick
12573 * Fires before a click is processed. Returns false to cancel the default action.
12574 * @param {Roo.View} this
12575 * @param {Number} index The index of the target node
12576 * @param {HTMLElement} node The target node
12577 * @param {Roo.EventObject} e The raw event object
12579 "beforeclick" : true,
12582 * Fires when a template node is clicked.
12583 * @param {Roo.View} this
12584 * @param {Number} index The index of the target node
12585 * @param {HTMLElement} node The target node
12586 * @param {Roo.EventObject} e The raw event object
12591 * Fires when a template node is double clicked.
12592 * @param {Roo.View} this
12593 * @param {Number} index The index of the target node
12594 * @param {HTMLElement} node The target node
12595 * @param {Roo.EventObject} e The raw event object
12599 * @event contextmenu
12600 * Fires when a template node is right clicked.
12601 * @param {Roo.View} this
12602 * @param {Number} index The index of the target node
12603 * @param {HTMLElement} node The target node
12604 * @param {Roo.EventObject} e The raw event object
12606 "contextmenu" : true,
12608 * @event selectionchange
12609 * Fires when the selected nodes change.
12610 * @param {Roo.View} this
12611 * @param {Array} selections Array of the selected nodes
12613 "selectionchange" : true,
12616 * @event beforeselect
12617 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12618 * @param {Roo.View} this
12619 * @param {HTMLElement} node The node to be selected
12620 * @param {Array} selections Array of currently selected nodes
12622 "beforeselect" : true,
12624 * @event preparedata
12625 * Fires on every row to render, to allow you to change the data.
12626 * @param {Roo.View} this
12627 * @param {Object} data to be rendered (change this)
12629 "preparedata" : true
12637 "click": this.onClick,
12638 "dblclick": this.onDblClick,
12639 "contextmenu": this.onContextMenu,
12643 this.selections = [];
12645 this.cmp = new Roo.CompositeElementLite([]);
12647 this.store = Roo.factory(this.store, Roo.data);
12648 this.setStore(this.store, true);
12651 if ( this.footer && this.footer.xtype) {
12653 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12655 this.footer.dataSource = this.store
12656 this.footer.container = fctr;
12657 this.footer = Roo.factory(this.footer, Roo);
12658 fctr.insertFirst(this.el);
12660 // this is a bit insane - as the paging toolbar seems to detach the el..
12661 // dom.parentNode.parentNode.parentNode
12662 // they get detached?
12666 Roo.View.superclass.constructor.call(this);
12671 Roo.extend(Roo.View, Roo.util.Observable, {
12674 * @cfg {Roo.data.Store} store Data store to load data from.
12679 * @cfg {String|Roo.Element} el The container element.
12684 * @cfg {String|Roo.Template} tpl The template used by this View
12688 * @cfg {String} dataName the named area of the template to use as the data area
12689 * Works with domtemplates roo-name="name"
12693 * @cfg {String} selectedClass The css class to add to selected nodes
12695 selectedClass : "x-view-selected",
12697 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12702 * @cfg {String} text to display on mask (default Loading)
12706 * @cfg {Boolean} multiSelect Allow multiple selection
12708 multiSelect : false,
12710 * @cfg {Boolean} singleSelect Allow single selection
12712 singleSelect: false,
12715 * @cfg {Boolean} toggleSelect - selecting
12717 toggleSelect : false,
12720 * @cfg {Boolean} tickable - selecting
12725 * Returns the element this view is bound to.
12726 * @return {Roo.Element}
12728 getEl : function(){
12729 return this.wrapEl;
12735 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12737 refresh : function(){
12738 //Roo.log('refresh');
12741 // if we are using something like 'domtemplate', then
12742 // the what gets used is:
12743 // t.applySubtemplate(NAME, data, wrapping data..)
12744 // the outer template then get' applied with
12745 // the store 'extra data'
12746 // and the body get's added to the
12747 // roo-name="data" node?
12748 // <span class='roo-tpl-{name}'></span> ?????
12752 this.clearSelections();
12753 this.el.update("");
12755 var records = this.store.getRange();
12756 if(records.length < 1) {
12758 // is this valid?? = should it render a template??
12760 this.el.update(this.emptyText);
12764 if (this.dataName) {
12765 this.el.update(t.apply(this.store.meta)); //????
12766 el = this.el.child('.roo-tpl-' + this.dataName);
12769 for(var i = 0, len = records.length; i < len; i++){
12770 var data = this.prepareData(records[i].data, i, records[i]);
12771 this.fireEvent("preparedata", this, data, i, records[i]);
12773 var d = Roo.apply({}, data);
12776 Roo.apply(d, {'roo-id' : Roo.id()});
12780 Roo.each(this.parent.item, function(item){
12781 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12784 Roo.apply(d, {'roo-data-checked' : 'checked'});
12788 html[html.length] = Roo.util.Format.trim(
12790 t.applySubtemplate(this.dataName, d, this.store.meta) :
12797 el.update(html.join(""));
12798 this.nodes = el.dom.childNodes;
12799 this.updateIndexes(0);
12804 * Function to override to reformat the data that is sent to
12805 * the template for each node.
12806 * DEPRICATED - use the preparedata event handler.
12807 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12808 * a JSON object for an UpdateManager bound view).
12810 prepareData : function(data, index, record)
12812 this.fireEvent("preparedata", this, data, index, record);
12816 onUpdate : function(ds, record){
12817 // Roo.log('on update');
12818 this.clearSelections();
12819 var index = this.store.indexOf(record);
12820 var n = this.nodes[index];
12821 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12822 n.parentNode.removeChild(n);
12823 this.updateIndexes(index, index);
12829 onAdd : function(ds, records, index)
12831 //Roo.log(['on Add', ds, records, index] );
12832 this.clearSelections();
12833 if(this.nodes.length == 0){
12837 var n = this.nodes[index];
12838 for(var i = 0, len = records.length; i < len; i++){
12839 var d = this.prepareData(records[i].data, i, records[i]);
12841 this.tpl.insertBefore(n, d);
12844 this.tpl.append(this.el, d);
12847 this.updateIndexes(index);
12850 onRemove : function(ds, record, index){
12851 // Roo.log('onRemove');
12852 this.clearSelections();
12853 var el = this.dataName ?
12854 this.el.child('.roo-tpl-' + this.dataName) :
12857 el.dom.removeChild(this.nodes[index]);
12858 this.updateIndexes(index);
12862 * Refresh an individual node.
12863 * @param {Number} index
12865 refreshNode : function(index){
12866 this.onUpdate(this.store, this.store.getAt(index));
12869 updateIndexes : function(startIndex, endIndex){
12870 var ns = this.nodes;
12871 startIndex = startIndex || 0;
12872 endIndex = endIndex || ns.length - 1;
12873 for(var i = startIndex; i <= endIndex; i++){
12874 ns[i].nodeIndex = i;
12879 * Changes the data store this view uses and refresh the view.
12880 * @param {Store} store
12882 setStore : function(store, initial){
12883 if(!initial && this.store){
12884 this.store.un("datachanged", this.refresh);
12885 this.store.un("add", this.onAdd);
12886 this.store.un("remove", this.onRemove);
12887 this.store.un("update", this.onUpdate);
12888 this.store.un("clear", this.refresh);
12889 this.store.un("beforeload", this.onBeforeLoad);
12890 this.store.un("load", this.onLoad);
12891 this.store.un("loadexception", this.onLoad);
12895 store.on("datachanged", this.refresh, this);
12896 store.on("add", this.onAdd, this);
12897 store.on("remove", this.onRemove, this);
12898 store.on("update", this.onUpdate, this);
12899 store.on("clear", this.refresh, this);
12900 store.on("beforeload", this.onBeforeLoad, this);
12901 store.on("load", this.onLoad, this);
12902 store.on("loadexception", this.onLoad, this);
12910 * onbeforeLoad - masks the loading area.
12913 onBeforeLoad : function(store,opts)
12915 //Roo.log('onBeforeLoad');
12917 this.el.update("");
12919 this.el.mask(this.mask ? this.mask : "Loading" );
12921 onLoad : function ()
12928 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12929 * @param {HTMLElement} node
12930 * @return {HTMLElement} The template node
12932 findItemFromChild : function(node){
12933 var el = this.dataName ?
12934 this.el.child('.roo-tpl-' + this.dataName,true) :
12937 if(!node || node.parentNode == el){
12940 var p = node.parentNode;
12941 while(p && p != el){
12942 if(p.parentNode == el){
12951 onClick : function(e){
12952 var item = this.findItemFromChild(e.getTarget());
12954 var index = this.indexOf(item);
12955 if(this.onItemClick(item, index, e) !== false){
12956 this.fireEvent("click", this, index, item, e);
12959 this.clearSelections();
12964 onContextMenu : function(e){
12965 var item = this.findItemFromChild(e.getTarget());
12967 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12972 onDblClick : function(e){
12973 var item = this.findItemFromChild(e.getTarget());
12975 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12979 onItemClick : function(item, index, e)
12981 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12984 if (this.toggleSelect) {
12985 var m = this.isSelected(item) ? 'unselect' : 'select';
12988 _t[m](item, true, false);
12991 if(this.multiSelect || this.singleSelect){
12992 if(this.multiSelect && e.shiftKey && this.lastSelection){
12993 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12995 this.select(item, this.multiSelect && e.ctrlKey);
12996 this.lastSelection = item;
12999 if(!this.tickable){
13000 e.preventDefault();
13008 * Get the number of selected nodes.
13011 getSelectionCount : function(){
13012 return this.selections.length;
13016 * Get the currently selected nodes.
13017 * @return {Array} An array of HTMLElements
13019 getSelectedNodes : function(){
13020 return this.selections;
13024 * Get the indexes of the selected nodes.
13027 getSelectedIndexes : function(){
13028 var indexes = [], s = this.selections;
13029 for(var i = 0, len = s.length; i < len; i++){
13030 indexes.push(s[i].nodeIndex);
13036 * Clear all selections
13037 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13039 clearSelections : function(suppressEvent){
13040 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13041 this.cmp.elements = this.selections;
13042 this.cmp.removeClass(this.selectedClass);
13043 this.selections = [];
13044 if(!suppressEvent){
13045 this.fireEvent("selectionchange", this, this.selections);
13051 * Returns true if the passed node is selected
13052 * @param {HTMLElement/Number} node The node or node index
13053 * @return {Boolean}
13055 isSelected : function(node){
13056 var s = this.selections;
13060 node = this.getNode(node);
13061 return s.indexOf(node) !== -1;
13066 * @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
13067 * @param {Boolean} keepExisting (optional) true to keep existing selections
13068 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13070 select : function(nodeInfo, keepExisting, suppressEvent){
13071 if(nodeInfo instanceof Array){
13073 this.clearSelections(true);
13075 for(var i = 0, len = nodeInfo.length; i < len; i++){
13076 this.select(nodeInfo[i], true, true);
13080 var node = this.getNode(nodeInfo);
13081 if(!node || this.isSelected(node)){
13082 return; // already selected.
13085 this.clearSelections(true);
13088 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13089 Roo.fly(node).addClass(this.selectedClass);
13090 this.selections.push(node);
13091 if(!suppressEvent){
13092 this.fireEvent("selectionchange", this, this.selections);
13100 * @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
13101 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13102 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13104 unselect : function(nodeInfo, keepExisting, suppressEvent)
13106 if(nodeInfo instanceof Array){
13107 Roo.each(this.selections, function(s) {
13108 this.unselect(s, nodeInfo);
13112 var node = this.getNode(nodeInfo);
13113 if(!node || !this.isSelected(node)){
13114 //Roo.log("not selected");
13115 return; // not selected.
13119 Roo.each(this.selections, function(s) {
13121 Roo.fly(node).removeClass(this.selectedClass);
13128 this.selections= ns;
13129 this.fireEvent("selectionchange", this, this.selections);
13133 * Gets a template node.
13134 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13135 * @return {HTMLElement} The node or null if it wasn't found
13137 getNode : function(nodeInfo){
13138 if(typeof nodeInfo == "string"){
13139 return document.getElementById(nodeInfo);
13140 }else if(typeof nodeInfo == "number"){
13141 return this.nodes[nodeInfo];
13147 * Gets a range template nodes.
13148 * @param {Number} startIndex
13149 * @param {Number} endIndex
13150 * @return {Array} An array of nodes
13152 getNodes : function(start, end){
13153 var ns = this.nodes;
13154 start = start || 0;
13155 end = typeof end == "undefined" ? ns.length - 1 : end;
13158 for(var i = start; i <= end; i++){
13162 for(var i = start; i >= end; i--){
13170 * Finds the index of the passed node
13171 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13172 * @return {Number} The index of the node or -1
13174 indexOf : function(node){
13175 node = this.getNode(node);
13176 if(typeof node.nodeIndex == "number"){
13177 return node.nodeIndex;
13179 var ns = this.nodes;
13180 for(var i = 0, len = ns.length; i < len; i++){
13191 * based on jquery fullcalendar
13195 Roo.bootstrap = Roo.bootstrap || {};
13197 * @class Roo.bootstrap.Calendar
13198 * @extends Roo.bootstrap.Component
13199 * Bootstrap Calendar class
13200 * @cfg {Boolean} loadMask (true|false) default false
13201 * @cfg {Object} header generate the user specific header of the calendar, default false
13204 * Create a new Container
13205 * @param {Object} config The config object
13210 Roo.bootstrap.Calendar = function(config){
13211 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13215 * Fires when a date is selected
13216 * @param {DatePicker} this
13217 * @param {Date} date The selected date
13221 * @event monthchange
13222 * Fires when the displayed month changes
13223 * @param {DatePicker} this
13224 * @param {Date} date The selected month
13226 'monthchange': true,
13228 * @event evententer
13229 * Fires when mouse over an event
13230 * @param {Calendar} this
13231 * @param {event} Event
13233 'evententer': true,
13235 * @event eventleave
13236 * Fires when the mouse leaves an
13237 * @param {Calendar} this
13240 'eventleave': true,
13242 * @event eventclick
13243 * Fires when the mouse click an
13244 * @param {Calendar} this
13253 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13256 * @cfg {Number} startDay
13257 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13265 getAutoCreate : function(){
13268 var fc_button = function(name, corner, style, content ) {
13269 return Roo.apply({},{
13271 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13273 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13276 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13287 style : 'width:100%',
13294 cls : 'fc-header-left',
13296 fc_button('prev', 'left', 'arrow', '‹' ),
13297 fc_button('next', 'right', 'arrow', '›' ),
13298 { tag: 'span', cls: 'fc-header-space' },
13299 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13307 cls : 'fc-header-center',
13311 cls: 'fc-header-title',
13314 html : 'month / year'
13322 cls : 'fc-header-right',
13324 /* fc_button('month', 'left', '', 'month' ),
13325 fc_button('week', '', '', 'week' ),
13326 fc_button('day', 'right', '', 'day' )
13338 header = this.header;
13341 var cal_heads = function() {
13343 // fixme - handle this.
13345 for (var i =0; i < Date.dayNames.length; i++) {
13346 var d = Date.dayNames[i];
13349 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13350 html : d.substring(0,3)
13354 ret[0].cls += ' fc-first';
13355 ret[6].cls += ' fc-last';
13358 var cal_cell = function(n) {
13361 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13366 cls: 'fc-day-number',
13370 cls: 'fc-day-content',
13374 style: 'position: relative;' // height: 17px;
13386 var cal_rows = function() {
13389 for (var r = 0; r < 6; r++) {
13396 for (var i =0; i < Date.dayNames.length; i++) {
13397 var d = Date.dayNames[i];
13398 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13401 row.cn[0].cls+=' fc-first';
13402 row.cn[0].cn[0].style = 'min-height:90px';
13403 row.cn[6].cls+=' fc-last';
13407 ret[0].cls += ' fc-first';
13408 ret[4].cls += ' fc-prev-last';
13409 ret[5].cls += ' fc-last';
13416 cls: 'fc-border-separate',
13417 style : 'width:100%',
13425 cls : 'fc-first fc-last',
13443 cls : 'fc-content',
13444 style : "position: relative;",
13447 cls : 'fc-view fc-view-month fc-grid',
13448 style : 'position: relative',
13449 unselectable : 'on',
13452 cls : 'fc-event-container',
13453 style : 'position:absolute;z-index:8;top:0;left:0;'
13471 initEvents : function()
13474 throw "can not find store for calendar";
13480 style: "text-align:center",
13484 style: "background-color:white;width:50%;margin:250 auto",
13488 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13499 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13501 var size = this.el.select('.fc-content', true).first().getSize();
13502 this.maskEl.setSize(size.width, size.height);
13503 this.maskEl.enableDisplayMode("block");
13504 if(!this.loadMask){
13505 this.maskEl.hide();
13508 this.store = Roo.factory(this.store, Roo.data);
13509 this.store.on('load', this.onLoad, this);
13510 this.store.on('beforeload', this.onBeforeLoad, this);
13514 this.cells = this.el.select('.fc-day',true);
13515 //Roo.log(this.cells);
13516 this.textNodes = this.el.query('.fc-day-number');
13517 this.cells.addClassOnOver('fc-state-hover');
13519 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13520 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13521 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13522 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13524 this.on('monthchange', this.onMonthChange, this);
13526 this.update(new Date().clearTime());
13529 resize : function() {
13530 var sz = this.el.getSize();
13532 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13533 this.el.select('.fc-day-content div',true).setHeight(34);
13538 showPrevMonth : function(e){
13539 this.update(this.activeDate.add("mo", -1));
13541 showToday : function(e){
13542 this.update(new Date().clearTime());
13545 showNextMonth : function(e){
13546 this.update(this.activeDate.add("mo", 1));
13550 showPrevYear : function(){
13551 this.update(this.activeDate.add("y", -1));
13555 showNextYear : function(){
13556 this.update(this.activeDate.add("y", 1));
13561 update : function(date)
13563 var vd = this.activeDate;
13564 this.activeDate = date;
13565 // if(vd && this.el){
13566 // var t = date.getTime();
13567 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13568 // Roo.log('using add remove');
13570 // this.fireEvent('monthchange', this, date);
13572 // this.cells.removeClass("fc-state-highlight");
13573 // this.cells.each(function(c){
13574 // if(c.dateValue == t){
13575 // c.addClass("fc-state-highlight");
13576 // setTimeout(function(){
13577 // try{c.dom.firstChild.focus();}catch(e){}
13587 var days = date.getDaysInMonth();
13589 var firstOfMonth = date.getFirstDateOfMonth();
13590 var startingPos = firstOfMonth.getDay()-this.startDay;
13592 if(startingPos < this.startDay){
13596 var pm = date.add(Date.MONTH, -1);
13597 var prevStart = pm.getDaysInMonth()-startingPos;
13599 this.cells = this.el.select('.fc-day',true);
13600 this.textNodes = this.el.query('.fc-day-number');
13601 this.cells.addClassOnOver('fc-state-hover');
13603 var cells = this.cells.elements;
13604 var textEls = this.textNodes;
13606 Roo.each(cells, function(cell){
13607 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13610 days += startingPos;
13612 // convert everything to numbers so it's fast
13613 var day = 86400000;
13614 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13617 //Roo.log(prevStart);
13619 var today = new Date().clearTime().getTime();
13620 var sel = date.clearTime().getTime();
13621 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13622 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13623 var ddMatch = this.disabledDatesRE;
13624 var ddText = this.disabledDatesText;
13625 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13626 var ddaysText = this.disabledDaysText;
13627 var format = this.format;
13629 var setCellClass = function(cal, cell){
13633 //Roo.log('set Cell Class');
13635 var t = d.getTime();
13639 cell.dateValue = t;
13641 cell.className += " fc-today";
13642 cell.className += " fc-state-highlight";
13643 cell.title = cal.todayText;
13646 // disable highlight in other month..
13647 //cell.className += " fc-state-highlight";
13652 cell.className = " fc-state-disabled";
13653 cell.title = cal.minText;
13657 cell.className = " fc-state-disabled";
13658 cell.title = cal.maxText;
13662 if(ddays.indexOf(d.getDay()) != -1){
13663 cell.title = ddaysText;
13664 cell.className = " fc-state-disabled";
13667 if(ddMatch && format){
13668 var fvalue = d.dateFormat(format);
13669 if(ddMatch.test(fvalue)){
13670 cell.title = ddText.replace("%0", fvalue);
13671 cell.className = " fc-state-disabled";
13675 if (!cell.initialClassName) {
13676 cell.initialClassName = cell.dom.className;
13679 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13684 for(; i < startingPos; i++) {
13685 textEls[i].innerHTML = (++prevStart);
13686 d.setDate(d.getDate()+1);
13688 cells[i].className = "fc-past fc-other-month";
13689 setCellClass(this, cells[i]);
13694 for(; i < days; i++){
13695 intDay = i - startingPos + 1;
13696 textEls[i].innerHTML = (intDay);
13697 d.setDate(d.getDate()+1);
13699 cells[i].className = ''; // "x-date-active";
13700 setCellClass(this, cells[i]);
13704 for(; i < 42; i++) {
13705 textEls[i].innerHTML = (++extraDays);
13706 d.setDate(d.getDate()+1);
13708 cells[i].className = "fc-future fc-other-month";
13709 setCellClass(this, cells[i]);
13712 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13714 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13716 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13717 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13719 if(totalRows != 6){
13720 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13721 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13724 this.fireEvent('monthchange', this, date);
13728 if(!this.internalRender){
13729 var main = this.el.dom.firstChild;
13730 var w = main.offsetWidth;
13731 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13732 Roo.fly(main).setWidth(w);
13733 this.internalRender = true;
13734 // opera does not respect the auto grow header center column
13735 // then, after it gets a width opera refuses to recalculate
13736 // without a second pass
13737 if(Roo.isOpera && !this.secondPass){
13738 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13739 this.secondPass = true;
13740 this.update.defer(10, this, [date]);
13747 findCell : function(dt) {
13748 dt = dt.clearTime().getTime();
13750 this.cells.each(function(c){
13751 //Roo.log("check " +c.dateValue + '?=' + dt);
13752 if(c.dateValue == dt){
13762 findCells : function(ev) {
13763 var s = ev.start.clone().clearTime().getTime();
13765 var e= ev.end.clone().clearTime().getTime();
13768 this.cells.each(function(c){
13769 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13771 if(c.dateValue > e){
13774 if(c.dateValue < s){
13783 // findBestRow: function(cells)
13787 // for (var i =0 ; i < cells.length;i++) {
13788 // ret = Math.max(cells[i].rows || 0,ret);
13795 addItem : function(ev)
13797 // look for vertical location slot in
13798 var cells = this.findCells(ev);
13800 // ev.row = this.findBestRow(cells);
13802 // work out the location.
13806 for(var i =0; i < cells.length; i++) {
13808 cells[i].row = cells[0].row;
13811 cells[i].row = cells[i].row + 1;
13821 if (crow.start.getY() == cells[i].getY()) {
13823 crow.end = cells[i];
13840 cells[0].events.push(ev);
13842 this.calevents.push(ev);
13845 clearEvents: function() {
13847 if(!this.calevents){
13851 Roo.each(this.cells.elements, function(c){
13857 Roo.each(this.calevents, function(e) {
13858 Roo.each(e.els, function(el) {
13859 el.un('mouseenter' ,this.onEventEnter, this);
13860 el.un('mouseleave' ,this.onEventLeave, this);
13865 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13871 renderEvents: function()
13875 this.cells.each(function(c) {
13884 if(c.row != c.events.length){
13885 r = 4 - (4 - (c.row - c.events.length));
13888 c.events = ev.slice(0, r);
13889 c.more = ev.slice(r);
13891 if(c.more.length && c.more.length == 1){
13892 c.events.push(c.more.pop());
13895 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13899 this.cells.each(function(c) {
13901 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13904 for (var e = 0; e < c.events.length; e++){
13905 var ev = c.events[e];
13906 var rows = ev.rows;
13908 for(var i = 0; i < rows.length; i++) {
13910 // how many rows should it span..
13913 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13914 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13916 unselectable : "on",
13919 cls: 'fc-event-inner',
13923 // cls: 'fc-event-time',
13924 // html : cells.length > 1 ? '' : ev.time
13928 cls: 'fc-event-title',
13929 html : String.format('{0}', ev.title)
13936 cls: 'ui-resizable-handle ui-resizable-e',
13937 html : '  '
13944 cfg.cls += ' fc-event-start';
13946 if ((i+1) == rows.length) {
13947 cfg.cls += ' fc-event-end';
13950 var ctr = _this.el.select('.fc-event-container',true).first();
13951 var cg = ctr.createChild(cfg);
13953 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13954 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13956 var r = (c.more.length) ? 1 : 0;
13957 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13958 cg.setWidth(ebox.right - sbox.x -2);
13960 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13961 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13962 cg.on('click', _this.onEventClick, _this, ev);
13973 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13974 style : 'position: absolute',
13975 unselectable : "on",
13978 cls: 'fc-event-inner',
13982 cls: 'fc-event-title',
13990 cls: 'ui-resizable-handle ui-resizable-e',
13991 html : '  '
13997 var ctr = _this.el.select('.fc-event-container',true).first();
13998 var cg = ctr.createChild(cfg);
14000 var sbox = c.select('.fc-day-content',true).first().getBox();
14001 var ebox = c.select('.fc-day-content',true).first().getBox();
14003 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14004 cg.setWidth(ebox.right - sbox.x -2);
14006 cg.on('click', _this.onMoreEventClick, _this, c.more);
14016 onEventEnter: function (e, el,event,d) {
14017 this.fireEvent('evententer', this, el, event);
14020 onEventLeave: function (e, el,event,d) {
14021 this.fireEvent('eventleave', this, el, event);
14024 onEventClick: function (e, el,event,d) {
14025 this.fireEvent('eventclick', this, el, event);
14028 onMonthChange: function () {
14032 onMoreEventClick: function(e, el, more)
14036 this.calpopover.placement = 'right';
14037 this.calpopover.setTitle('More');
14039 this.calpopover.setContent('');
14041 var ctr = this.calpopover.el.select('.popover-content', true).first();
14043 Roo.each(more, function(m){
14045 cls : 'fc-event-hori fc-event-draggable',
14048 var cg = ctr.createChild(cfg);
14050 cg.on('click', _this.onEventClick, _this, m);
14053 this.calpopover.show(el);
14058 onLoad: function ()
14060 this.calevents = [];
14063 if(this.store.getCount() > 0){
14064 this.store.data.each(function(d){
14067 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14068 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14069 time : d.data.start_time,
14070 title : d.data.title,
14071 description : d.data.description,
14072 venue : d.data.venue
14077 this.renderEvents();
14079 if(this.calevents.length && this.loadMask){
14080 this.maskEl.hide();
14084 onBeforeLoad: function()
14086 this.clearEvents();
14088 this.maskEl.show();
14102 * @class Roo.bootstrap.Popover
14103 * @extends Roo.bootstrap.Component
14104 * Bootstrap Popover class
14105 * @cfg {String} html contents of the popover (or false to use children..)
14106 * @cfg {String} title of popover (or false to hide)
14107 * @cfg {String} placement how it is placed
14108 * @cfg {String} trigger click || hover (or false to trigger manually)
14109 * @cfg {String} over what (parent or false to trigger manually.)
14110 * @cfg {Number} delay - delay before showing
14113 * Create a new Popover
14114 * @param {Object} config The config object
14117 Roo.bootstrap.Popover = function(config){
14118 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14121 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14123 title: 'Fill in a title',
14126 placement : 'right',
14127 trigger : 'hover', // hover
14133 can_build_overlaid : false,
14135 getChildContainer : function()
14137 return this.el.select('.popover-content',true).first();
14140 getAutoCreate : function(){
14141 Roo.log('make popover?');
14143 cls : 'popover roo-dynamic',
14144 style: 'display:block',
14150 cls : 'popover-inner',
14154 cls: 'popover-title',
14158 cls : 'popover-content',
14169 setTitle: function(str)
14171 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14173 setContent: function(str)
14175 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14177 // as it get's added to the bottom of the page.
14178 onRender : function(ct, position)
14180 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14182 var cfg = Roo.apply({}, this.getAutoCreate());
14186 cfg.cls += ' ' + this.cls;
14189 cfg.style = this.style;
14191 Roo.log("adding to ")
14192 this.el = Roo.get(document.body).createChild(cfg, position);
14198 initEvents : function()
14200 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14201 this.el.enableDisplayMode('block');
14203 if (this.over === false) {
14206 if (this.triggers === false) {
14209 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14210 var triggers = this.trigger ? this.trigger.split(' ') : [];
14211 Roo.each(triggers, function(trigger) {
14213 if (trigger == 'click') {
14214 on_el.on('click', this.toggle, this);
14215 } else if (trigger != 'manual') {
14216 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14217 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14219 on_el.on(eventIn ,this.enter, this);
14220 on_el.on(eventOut, this.leave, this);
14231 toggle : function () {
14232 this.hoverState == 'in' ? this.leave() : this.enter();
14235 enter : function () {
14238 clearTimeout(this.timeout);
14240 this.hoverState = 'in';
14242 if (!this.delay || !this.delay.show) {
14247 this.timeout = setTimeout(function () {
14248 if (_t.hoverState == 'in') {
14251 }, this.delay.show)
14253 leave : function() {
14254 clearTimeout(this.timeout);
14256 this.hoverState = 'out';
14258 if (!this.delay || !this.delay.hide) {
14263 this.timeout = setTimeout(function () {
14264 if (_t.hoverState == 'out') {
14267 }, this.delay.hide)
14270 show : function (on_el)
14273 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14276 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14277 if (this.html !== false) {
14278 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14280 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14281 if (!this.title.length) {
14282 this.el.select('.popover-title',true).hide();
14285 var placement = typeof this.placement == 'function' ?
14286 this.placement.call(this, this.el, on_el) :
14289 var autoToken = /\s?auto?\s?/i;
14290 var autoPlace = autoToken.test(placement);
14292 placement = placement.replace(autoToken, '') || 'top';
14296 //this.el.setXY([0,0]);
14298 this.el.dom.style.display='block';
14299 this.el.addClass(placement);
14301 //this.el.appendTo(on_el);
14303 var p = this.getPosition();
14304 var box = this.el.getBox();
14309 var align = Roo.bootstrap.Popover.alignment[placement];
14310 this.el.alignTo(on_el, align[0],align[1]);
14311 //var arrow = this.el.select('.arrow',true).first();
14312 //arrow.set(align[2],
14314 this.el.addClass('in');
14315 this.hoverState = null;
14317 if (this.el.hasClass('fade')) {
14324 this.el.setXY([0,0]);
14325 this.el.removeClass('in');
14332 Roo.bootstrap.Popover.alignment = {
14333 'left' : ['r-l', [-10,0], 'right'],
14334 'right' : ['l-r', [10,0], 'left'],
14335 'bottom' : ['t-b', [0,10], 'top'],
14336 'top' : [ 'b-t', [0,-10], 'bottom']
14347 * @class Roo.bootstrap.Progress
14348 * @extends Roo.bootstrap.Component
14349 * Bootstrap Progress class
14350 * @cfg {Boolean} striped striped of the progress bar
14351 * @cfg {Boolean} active animated of the progress bar
14355 * Create a new Progress
14356 * @param {Object} config The config object
14359 Roo.bootstrap.Progress = function(config){
14360 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14363 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14368 getAutoCreate : function(){
14376 cfg.cls += ' progress-striped';
14380 cfg.cls += ' active';
14399 * @class Roo.bootstrap.ProgressBar
14400 * @extends Roo.bootstrap.Component
14401 * Bootstrap ProgressBar class
14402 * @cfg {Number} aria_valuenow aria-value now
14403 * @cfg {Number} aria_valuemin aria-value min
14404 * @cfg {Number} aria_valuemax aria-value max
14405 * @cfg {String} label label for the progress bar
14406 * @cfg {String} panel (success | info | warning | danger )
14407 * @cfg {String} role role of the progress bar
14408 * @cfg {String} sr_only text
14412 * Create a new ProgressBar
14413 * @param {Object} config The config object
14416 Roo.bootstrap.ProgressBar = function(config){
14417 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14420 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14424 aria_valuemax : 100,
14430 getAutoCreate : function()
14435 cls: 'progress-bar',
14436 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14448 cfg.role = this.role;
14451 if(this.aria_valuenow){
14452 cfg['aria-valuenow'] = this.aria_valuenow;
14455 if(this.aria_valuemin){
14456 cfg['aria-valuemin'] = this.aria_valuemin;
14459 if(this.aria_valuemax){
14460 cfg['aria-valuemax'] = this.aria_valuemax;
14463 if(this.label && !this.sr_only){
14464 cfg.html = this.label;
14468 cfg.cls += ' progress-bar-' + this.panel;
14474 update : function(aria_valuenow)
14476 this.aria_valuenow = aria_valuenow;
14478 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14493 * @class Roo.bootstrap.TabGroup
14494 * @extends Roo.bootstrap.Column
14495 * Bootstrap Column class
14496 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14497 * @cfg {Boolean} carousel true to make the group behave like a carousel
14500 * Create a new TabGroup
14501 * @param {Object} config The config object
14504 Roo.bootstrap.TabGroup = function(config){
14505 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14507 this.navId = Roo.id();
14510 Roo.bootstrap.TabGroup.register(this);
14514 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14517 transition : false,
14519 getAutoCreate : function()
14521 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14523 cfg.cls += ' tab-content';
14525 if (this.carousel) {
14526 cfg.cls += ' carousel slide';
14528 cls : 'carousel-inner'
14535 getChildContainer : function()
14537 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14541 * register a Navigation item
14542 * @param {Roo.bootstrap.NavItem} the navitem to add
14544 register : function(item)
14546 this.tabs.push( item);
14547 item.navId = this.navId; // not really needed..
14551 getActivePanel : function()
14554 Roo.each(this.tabs, function(t) {
14564 getPanelByName : function(n)
14567 Roo.each(this.tabs, function(t) {
14568 if (t.tabId == n) {
14576 indexOfPanel : function(p)
14579 Roo.each(this.tabs, function(t,i) {
14580 if (t.tabId == p.tabId) {
14589 * show a specific panel
14590 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14591 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14593 showPanel : function (pan)
14596 if (typeof(pan) == 'number') {
14597 pan = this.tabs[pan];
14599 if (typeof(pan) == 'string') {
14600 pan = this.getPanelByName(pan);
14602 if (pan.tabId == this.getActivePanel().tabId) {
14605 var cur = this.getActivePanel();
14607 if (false === cur.fireEvent('beforedeactivate')) {
14611 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14613 this.transition = true;
14614 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14615 var lr = dir == 'next' ? 'left' : 'right';
14616 pan.el.addClass(dir); // or prev
14617 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14618 cur.el.addClass(lr); // or right
14619 pan.el.addClass(lr);
14622 cur.el.on('transitionend', function() {
14623 Roo.log("trans end?");
14625 pan.el.removeClass([lr,dir]);
14626 pan.setActive(true);
14628 cur.el.removeClass([lr]);
14629 cur.setActive(false);
14631 _this.transition = false;
14633 }, this, { single: true } );
14637 cur.setActive(false);
14638 pan.setActive(true);
14642 showPanelNext : function()
14644 var i = this.indexOfPanel(this.getActivePanel());
14645 if (i > this.tabs.length) {
14648 this.showPanel(this.tabs[i+1]);
14650 showPanelPrev : function()
14652 var i = this.indexOfPanel(this.getActivePanel());
14656 this.showPanel(this.tabs[i-1]);
14667 Roo.apply(Roo.bootstrap.TabGroup, {
14671 * register a Navigation Group
14672 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14674 register : function(navgrp)
14676 this.groups[navgrp.navId] = navgrp;
14680 * fetch a Navigation Group based on the navigation ID
14681 * if one does not exist , it will get created.
14682 * @param {string} the navgroup to add
14683 * @returns {Roo.bootstrap.NavGroup} the navgroup
14685 get: function(navId) {
14686 if (typeof(this.groups[navId]) == 'undefined') {
14687 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14689 return this.groups[navId] ;
14704 * @class Roo.bootstrap.TabPanel
14705 * @extends Roo.bootstrap.Component
14706 * Bootstrap TabPanel class
14707 * @cfg {Boolean} active panel active
14708 * @cfg {String} html panel content
14709 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14710 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14714 * Create a new TabPanel
14715 * @param {Object} config The config object
14718 Roo.bootstrap.TabPanel = function(config){
14719 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14723 * Fires when the active status changes
14724 * @param {Roo.bootstrap.TabPanel} this
14725 * @param {Boolean} state the new state
14730 * @event beforedeactivate
14731 * Fires before a tab is de-activated - can be used to do validation on a form.
14732 * @param {Roo.bootstrap.TabPanel} this
14733 * @return {Boolean} false if there is an error
14736 'beforedeactivate': true
14739 this.tabId = this.tabId || Roo.id();
14743 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14750 getAutoCreate : function(){
14753 // item is needed for carousel - not sure if it has any effect otherwise
14754 cls: 'tab-pane item',
14755 html: this.html || ''
14759 cfg.cls += ' active';
14763 cfg.tabId = this.tabId;
14770 initEvents: function()
14772 Roo.log('-------- init events on tab panel ---------');
14774 var p = this.parent();
14775 this.navId = this.navId || p.navId;
14777 if (typeof(this.navId) != 'undefined') {
14778 // not really needed.. but just in case.. parent should be a NavGroup.
14779 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14780 Roo.log(['register', tg, this]);
14786 onRender : function(ct, position)
14788 // Roo.log("Call onRender: " + this.xtype);
14790 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14798 setActive: function(state)
14800 Roo.log("panel - set active " + this.tabId + "=" + state);
14802 this.active = state;
14804 this.el.removeClass('active');
14806 } else if (!this.el.hasClass('active')) {
14807 this.el.addClass('active');
14809 this.fireEvent('changed', this, state);
14826 * @class Roo.bootstrap.DateField
14827 * @extends Roo.bootstrap.Input
14828 * Bootstrap DateField class
14829 * @cfg {Number} weekStart default 0
14830 * @cfg {String} viewMode default empty, (months|years)
14831 * @cfg {String} minViewMode default empty, (months|years)
14832 * @cfg {Number} startDate default -Infinity
14833 * @cfg {Number} endDate default Infinity
14834 * @cfg {Boolean} todayHighlight default false
14835 * @cfg {Boolean} todayBtn default false
14836 * @cfg {Boolean} calendarWeeks default false
14837 * @cfg {Object} daysOfWeekDisabled default empty
14838 * @cfg {Boolean} singleMode default false (true | false)
14840 * @cfg {Boolean} keyboardNavigation default true
14841 * @cfg {String} language default en
14844 * Create a new DateField
14845 * @param {Object} config The config object
14848 Roo.bootstrap.DateField = function(config){
14849 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14853 * Fires when this field show.
14854 * @param {Roo.bootstrap.DateField} this
14855 * @param {Mixed} date The date value
14860 * Fires when this field hide.
14861 * @param {Roo.bootstrap.DateField} this
14862 * @param {Mixed} date The date value
14867 * Fires when select a date.
14868 * @param {Roo.bootstrap.DateField} this
14869 * @param {Mixed} date The date value
14875 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14878 * @cfg {String} format
14879 * The default date format string which can be overriden for localization support. The format must be
14880 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14884 * @cfg {String} altFormats
14885 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14886 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14888 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14896 todayHighlight : false,
14902 keyboardNavigation: true,
14904 calendarWeeks: false,
14906 startDate: -Infinity,
14910 daysOfWeekDisabled: [],
14914 singleMode : false,
14916 UTCDate: function()
14918 return new Date(Date.UTC.apply(Date, arguments));
14921 UTCToday: function()
14923 var today = new Date();
14924 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14927 getDate: function() {
14928 var d = this.getUTCDate();
14929 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14932 getUTCDate: function() {
14936 setDate: function(d) {
14937 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14940 setUTCDate: function(d) {
14942 this.setValue(this.formatDate(this.date));
14945 onRender: function(ct, position)
14948 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14950 this.language = this.language || 'en';
14951 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14952 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14954 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14955 this.format = this.format || 'm/d/y';
14956 this.isInline = false;
14957 this.isInput = true;
14958 this.component = this.el.select('.add-on', true).first() || false;
14959 this.component = (this.component && this.component.length === 0) ? false : this.component;
14960 this.hasInput = this.component && this.inputEL().length;
14962 if (typeof(this.minViewMode === 'string')) {
14963 switch (this.minViewMode) {
14965 this.minViewMode = 1;
14968 this.minViewMode = 2;
14971 this.minViewMode = 0;
14976 if (typeof(this.viewMode === 'string')) {
14977 switch (this.viewMode) {
14990 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14992 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14994 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14996 this.picker().on('mousedown', this.onMousedown, this);
14997 this.picker().on('click', this.onClick, this);
14999 this.picker().addClass('datepicker-dropdown');
15001 this.startViewMode = this.viewMode;
15003 if(this.singleMode){
15004 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15005 v.setVisibilityMode(Roo.Element.DISPLAY)
15009 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15010 v.setStyle('width', '189px');
15014 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15015 if(!this.calendarWeeks){
15020 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15021 v.attr('colspan', function(i, val){
15022 return parseInt(val) + 1;
15027 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15029 this.setStartDate(this.startDate);
15030 this.setEndDate(this.endDate);
15032 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15039 if(this.isInline) {
15044 picker : function()
15046 return this.pickerEl;
15047 // return this.el.select('.datepicker', true).first();
15050 fillDow: function()
15052 var dowCnt = this.weekStart;
15061 if(this.calendarWeeks){
15069 while (dowCnt < this.weekStart + 7) {
15073 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15077 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15080 fillMonths: function()
15083 var months = this.picker().select('>.datepicker-months td', true).first();
15085 months.dom.innerHTML = '';
15091 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15094 months.createChild(month);
15101 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;
15103 if (this.date < this.startDate) {
15104 this.viewDate = new Date(this.startDate);
15105 } else if (this.date > this.endDate) {
15106 this.viewDate = new Date(this.endDate);
15108 this.viewDate = new Date(this.date);
15116 var d = new Date(this.viewDate),
15117 year = d.getUTCFullYear(),
15118 month = d.getUTCMonth(),
15119 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15120 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15121 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15122 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15123 currentDate = this.date && this.date.valueOf(),
15124 today = this.UTCToday();
15126 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15128 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15130 // this.picker.select('>tfoot th.today').
15131 // .text(dates[this.language].today)
15132 // .toggle(this.todayBtn !== false);
15134 this.updateNavArrows();
15137 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15139 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15141 prevMonth.setUTCDate(day);
15143 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15145 var nextMonth = new Date(prevMonth);
15147 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15149 nextMonth = nextMonth.valueOf();
15151 var fillMonths = false;
15153 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15155 while(prevMonth.valueOf() < nextMonth) {
15158 if (prevMonth.getUTCDay() === this.weekStart) {
15160 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15168 if(this.calendarWeeks){
15169 // ISO 8601: First week contains first thursday.
15170 // ISO also states week starts on Monday, but we can be more abstract here.
15172 // Start of current week: based on weekstart/current date
15173 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15174 // Thursday of this week
15175 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15176 // First Thursday of year, year from thursday
15177 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15178 // Calendar week: ms between thursdays, div ms per day, div 7 days
15179 calWeek = (th - yth) / 864e5 / 7 + 1;
15181 fillMonths.cn.push({
15189 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15191 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15194 if (this.todayHighlight &&
15195 prevMonth.getUTCFullYear() == today.getFullYear() &&
15196 prevMonth.getUTCMonth() == today.getMonth() &&
15197 prevMonth.getUTCDate() == today.getDate()) {
15198 clsName += ' today';
15201 if (currentDate && prevMonth.valueOf() === currentDate) {
15202 clsName += ' active';
15205 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15206 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15207 clsName += ' disabled';
15210 fillMonths.cn.push({
15212 cls: 'day ' + clsName,
15213 html: prevMonth.getDate()
15216 prevMonth.setDate(prevMonth.getDate()+1);
15219 var currentYear = this.date && this.date.getUTCFullYear();
15220 var currentMonth = this.date && this.date.getUTCMonth();
15222 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15224 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15225 v.removeClass('active');
15227 if(currentYear === year && k === currentMonth){
15228 v.addClass('active');
15231 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15232 v.addClass('disabled');
15238 year = parseInt(year/10, 10) * 10;
15240 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15242 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15245 for (var i = -1; i < 11; i++) {
15246 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15248 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15256 showMode: function(dir)
15259 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15262 Roo.each(this.picker().select('>div',true).elements, function(v){
15263 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15266 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15271 if(this.isInline) return;
15273 this.picker().removeClass(['bottom', 'top']);
15275 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15277 * place to the top of element!
15281 this.picker().addClass('top');
15282 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15287 this.picker().addClass('bottom');
15289 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15292 parseDate : function(value)
15294 if(!value || value instanceof Date){
15297 var v = Date.parseDate(value, this.format);
15298 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15299 v = Date.parseDate(value, 'Y-m-d');
15301 if(!v && this.altFormats){
15302 if(!this.altFormatsArray){
15303 this.altFormatsArray = this.altFormats.split("|");
15305 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15306 v = Date.parseDate(value, this.altFormatsArray[i]);
15312 formatDate : function(date, fmt)
15314 return (!date || !(date instanceof Date)) ?
15315 date : date.dateFormat(fmt || this.format);
15318 onFocus : function()
15320 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15324 onBlur : function()
15326 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15328 var d = this.inputEl().getValue();
15337 this.picker().show();
15341 this.fireEvent('show', this, this.date);
15346 if(this.isInline) return;
15347 this.picker().hide();
15348 this.viewMode = this.startViewMode;
15351 this.fireEvent('hide', this, this.date);
15355 onMousedown: function(e)
15357 e.stopPropagation();
15358 e.preventDefault();
15363 Roo.bootstrap.DateField.superclass.keyup.call(this);
15367 setValue: function(v)
15370 // v can be a string or a date..
15373 var d = new Date(this.parseDate(v) ).clearTime();
15375 if(isNaN(d.getTime())){
15376 this.date = this.viewDate = '';
15377 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15381 v = this.formatDate(d);
15383 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15385 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15389 this.fireEvent('select', this, this.date);
15393 getValue: function()
15395 return this.formatDate(this.date);
15398 fireKey: function(e)
15400 if (!this.picker().isVisible()){
15401 if (e.keyCode == 27) // allow escape to hide and re-show picker
15406 var dateChanged = false,
15408 newDate, newViewDate;
15413 e.preventDefault();
15417 if (!this.keyboardNavigation) break;
15418 dir = e.keyCode == 37 ? -1 : 1;
15421 newDate = this.moveYear(this.date, dir);
15422 newViewDate = this.moveYear(this.viewDate, dir);
15423 } else if (e.shiftKey){
15424 newDate = this.moveMonth(this.date, dir);
15425 newViewDate = this.moveMonth(this.viewDate, dir);
15427 newDate = new Date(this.date);
15428 newDate.setUTCDate(this.date.getUTCDate() + dir);
15429 newViewDate = new Date(this.viewDate);
15430 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15432 if (this.dateWithinRange(newDate)){
15433 this.date = newDate;
15434 this.viewDate = newViewDate;
15435 this.setValue(this.formatDate(this.date));
15437 e.preventDefault();
15438 dateChanged = true;
15443 if (!this.keyboardNavigation) break;
15444 dir = e.keyCode == 38 ? -1 : 1;
15446 newDate = this.moveYear(this.date, dir);
15447 newViewDate = this.moveYear(this.viewDate, dir);
15448 } else if (e.shiftKey){
15449 newDate = this.moveMonth(this.date, dir);
15450 newViewDate = this.moveMonth(this.viewDate, dir);
15452 newDate = new Date(this.date);
15453 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15454 newViewDate = new Date(this.viewDate);
15455 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15457 if (this.dateWithinRange(newDate)){
15458 this.date = newDate;
15459 this.viewDate = newViewDate;
15460 this.setValue(this.formatDate(this.date));
15462 e.preventDefault();
15463 dateChanged = true;
15467 this.setValue(this.formatDate(this.date));
15469 e.preventDefault();
15472 this.setValue(this.formatDate(this.date));
15486 onClick: function(e)
15488 e.stopPropagation();
15489 e.preventDefault();
15491 var target = e.getTarget();
15493 if(target.nodeName.toLowerCase() === 'i'){
15494 target = Roo.get(target).dom.parentNode;
15497 var nodeName = target.nodeName;
15498 var className = target.className;
15499 var html = target.innerHTML;
15500 //Roo.log(nodeName);
15502 switch(nodeName.toLowerCase()) {
15504 switch(className) {
15510 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15511 switch(this.viewMode){
15513 this.viewDate = this.moveMonth(this.viewDate, dir);
15517 this.viewDate = this.moveYear(this.viewDate, dir);
15523 var date = new Date();
15524 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15526 this.setValue(this.formatDate(this.date));
15533 if (className.indexOf('disabled') < 0) {
15534 this.viewDate.setUTCDate(1);
15535 if (className.indexOf('month') > -1) {
15536 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15538 var year = parseInt(html, 10) || 0;
15539 this.viewDate.setUTCFullYear(year);
15543 if(this.singleMode){
15544 this.setValue(this.formatDate(this.viewDate));
15555 //Roo.log(className);
15556 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15557 var day = parseInt(html, 10) || 1;
15558 var year = this.viewDate.getUTCFullYear(),
15559 month = this.viewDate.getUTCMonth();
15561 if (className.indexOf('old') > -1) {
15568 } else if (className.indexOf('new') > -1) {
15576 //Roo.log([year,month,day]);
15577 this.date = this.UTCDate(year, month, day,0,0,0,0);
15578 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15580 //Roo.log(this.formatDate(this.date));
15581 this.setValue(this.formatDate(this.date));
15588 setStartDate: function(startDate)
15590 this.startDate = startDate || -Infinity;
15591 if (this.startDate !== -Infinity) {
15592 this.startDate = this.parseDate(this.startDate);
15595 this.updateNavArrows();
15598 setEndDate: function(endDate)
15600 this.endDate = endDate || Infinity;
15601 if (this.endDate !== Infinity) {
15602 this.endDate = this.parseDate(this.endDate);
15605 this.updateNavArrows();
15608 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15610 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15611 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15612 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15614 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15615 return parseInt(d, 10);
15618 this.updateNavArrows();
15621 updateNavArrows: function()
15623 if(this.singleMode){
15627 var d = new Date(this.viewDate),
15628 year = d.getUTCFullYear(),
15629 month = d.getUTCMonth();
15631 Roo.each(this.picker().select('.prev', true).elements, function(v){
15633 switch (this.viewMode) {
15636 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15642 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15649 Roo.each(this.picker().select('.next', true).elements, function(v){
15651 switch (this.viewMode) {
15654 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15660 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15668 moveMonth: function(date, dir)
15670 if (!dir) return date;
15671 var new_date = new Date(date.valueOf()),
15672 day = new_date.getUTCDate(),
15673 month = new_date.getUTCMonth(),
15674 mag = Math.abs(dir),
15676 dir = dir > 0 ? 1 : -1;
15679 // If going back one month, make sure month is not current month
15680 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15682 return new_date.getUTCMonth() == month;
15684 // If going forward one month, make sure month is as expected
15685 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15687 return new_date.getUTCMonth() != new_month;
15689 new_month = month + dir;
15690 new_date.setUTCMonth(new_month);
15691 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15692 if (new_month < 0 || new_month > 11)
15693 new_month = (new_month + 12) % 12;
15695 // For magnitudes >1, move one month at a time...
15696 for (var i=0; i<mag; i++)
15697 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15698 new_date = this.moveMonth(new_date, dir);
15699 // ...then reset the day, keeping it in the new month
15700 new_month = new_date.getUTCMonth();
15701 new_date.setUTCDate(day);
15703 return new_month != new_date.getUTCMonth();
15706 // Common date-resetting loop -- if date is beyond end of month, make it
15709 new_date.setUTCDate(--day);
15710 new_date.setUTCMonth(new_month);
15715 moveYear: function(date, dir)
15717 return this.moveMonth(date, dir*12);
15720 dateWithinRange: function(date)
15722 return date >= this.startDate && date <= this.endDate;
15728 this.picker().remove();
15733 Roo.apply(Roo.bootstrap.DateField, {
15744 html: '<i class="fa fa-arrow-left"/>'
15754 html: '<i class="fa fa-arrow-right"/>'
15796 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15797 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15798 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15799 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15800 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15813 navFnc: 'FullYear',
15818 navFnc: 'FullYear',
15823 Roo.apply(Roo.bootstrap.DateField, {
15827 cls: 'datepicker dropdown-menu roo-dynamic',
15831 cls: 'datepicker-days',
15835 cls: 'table-condensed',
15837 Roo.bootstrap.DateField.head,
15841 Roo.bootstrap.DateField.footer
15848 cls: 'datepicker-months',
15852 cls: 'table-condensed',
15854 Roo.bootstrap.DateField.head,
15855 Roo.bootstrap.DateField.content,
15856 Roo.bootstrap.DateField.footer
15863 cls: 'datepicker-years',
15867 cls: 'table-condensed',
15869 Roo.bootstrap.DateField.head,
15870 Roo.bootstrap.DateField.content,
15871 Roo.bootstrap.DateField.footer
15890 * @class Roo.bootstrap.TimeField
15891 * @extends Roo.bootstrap.Input
15892 * Bootstrap DateField class
15896 * Create a new TimeField
15897 * @param {Object} config The config object
15900 Roo.bootstrap.TimeField = function(config){
15901 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15905 * Fires when this field show.
15906 * @param {Roo.bootstrap.DateField} thisthis
15907 * @param {Mixed} date The date value
15912 * Fires when this field hide.
15913 * @param {Roo.bootstrap.DateField} this
15914 * @param {Mixed} date The date value
15919 * Fires when select a date.
15920 * @param {Roo.bootstrap.DateField} this
15921 * @param {Mixed} date The date value
15927 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15930 * @cfg {String} format
15931 * The default time format string which can be overriden for localization support. The format must be
15932 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15936 onRender: function(ct, position)
15939 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15941 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15943 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15945 this.pop = this.picker().select('>.datepicker-time',true).first();
15946 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15948 this.picker().on('mousedown', this.onMousedown, this);
15949 this.picker().on('click', this.onClick, this);
15951 this.picker().addClass('datepicker-dropdown');
15956 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15957 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15958 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15959 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15960 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15961 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15965 fireKey: function(e){
15966 if (!this.picker().isVisible()){
15967 if (e.keyCode == 27) { // allow escape to hide and re-show picker
15973 e.preventDefault();
15981 this.onTogglePeriod();
15984 this.onIncrementMinutes();
15987 this.onDecrementMinutes();
15996 onClick: function(e) {
15997 e.stopPropagation();
15998 e.preventDefault();
16001 picker : function()
16003 return this.el.select('.datepicker', true).first();
16006 fillTime: function()
16008 var time = this.pop.select('tbody', true).first();
16010 time.dom.innerHTML = '';
16025 cls: 'hours-up glyphicon glyphicon-chevron-up'
16045 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16066 cls: 'timepicker-hour',
16081 cls: 'timepicker-minute',
16096 cls: 'btn btn-primary period',
16118 cls: 'hours-down glyphicon glyphicon-chevron-down'
16138 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16156 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16163 var hours = this.time.getHours();
16164 var minutes = this.time.getMinutes();
16177 hours = hours - 12;
16181 hours = '0' + hours;
16185 minutes = '0' + minutes;
16188 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16189 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16190 this.pop.select('button', true).first().dom.innerHTML = period;
16196 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16198 var cls = ['bottom'];
16200 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16207 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16212 this.picker().addClass(cls.join('-'));
16216 Roo.each(cls, function(c){
16218 _this.picker().setTop(_this.inputEl().getHeight());
16222 _this.picker().setTop(0 - _this.picker().getHeight());
16227 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16231 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16238 onFocus : function()
16240 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16244 onBlur : function()
16246 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16252 this.picker().show();
16257 this.fireEvent('show', this, this.date);
16262 this.picker().hide();
16265 this.fireEvent('hide', this, this.date);
16268 setTime : function()
16271 this.setValue(this.time.format(this.format));
16273 this.fireEvent('select', this, this.date);
16278 onMousedown: function(e){
16279 e.stopPropagation();
16280 e.preventDefault();
16283 onIncrementHours: function()
16285 Roo.log('onIncrementHours');
16286 this.time = this.time.add(Date.HOUR, 1);
16291 onDecrementHours: function()
16293 Roo.log('onDecrementHours');
16294 this.time = this.time.add(Date.HOUR, -1);
16298 onIncrementMinutes: function()
16300 Roo.log('onIncrementMinutes');
16301 this.time = this.time.add(Date.MINUTE, 1);
16305 onDecrementMinutes: function()
16307 Roo.log('onDecrementMinutes');
16308 this.time = this.time.add(Date.MINUTE, -1);
16312 onTogglePeriod: function()
16314 Roo.log('onTogglePeriod');
16315 this.time = this.time.add(Date.HOUR, 12);
16322 Roo.apply(Roo.bootstrap.TimeField, {
16352 cls: 'btn btn-info ok',
16364 Roo.apply(Roo.bootstrap.TimeField, {
16368 cls: 'datepicker dropdown-menu',
16372 cls: 'datepicker-time',
16376 cls: 'table-condensed',
16378 Roo.bootstrap.TimeField.content,
16379 Roo.bootstrap.TimeField.footer
16398 * @class Roo.bootstrap.MonthField
16399 * @extends Roo.bootstrap.Input
16400 * Bootstrap MonthField class
16402 * @cfg {String} language default en
16405 * Create a new MonthField
16406 * @param {Object} config The config object
16409 Roo.bootstrap.MonthField = function(config){
16410 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16415 * Fires when this field show.
16416 * @param {Roo.bootstrap.MonthField} this
16417 * @param {Mixed} date The date value
16422 * Fires when this field hide.
16423 * @param {Roo.bootstrap.MonthField} this
16424 * @param {Mixed} date The date value
16429 * Fires when select a date.
16430 * @param {Roo.bootstrap.MonthField} this
16431 * @param {String} oldvalue The old value
16432 * @param {String} newvalue The new value
16438 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16440 onRender: function(ct, position)
16443 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16445 this.language = this.language || 'en';
16446 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16447 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16449 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16450 this.isInline = false;
16451 this.isInput = true;
16452 this.component = this.el.select('.add-on', true).first() || false;
16453 this.component = (this.component && this.component.length === 0) ? false : this.component;
16454 this.hasInput = this.component && this.inputEL().length;
16456 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16458 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16460 this.picker().on('mousedown', this.onMousedown, this);
16461 this.picker().on('click', this.onClick, this);
16463 this.picker().addClass('datepicker-dropdown');
16465 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16466 v.setStyle('width', '189px');
16473 if(this.isInline) {
16479 setValue: function(v, suppressEvent)
16481 var o = this.getValue();
16483 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16487 if(suppressEvent !== true){
16488 this.fireEvent('select', this, o, v);
16493 getValue: function()
16498 onClick: function(e)
16500 e.stopPropagation();
16501 e.preventDefault();
16503 var target = e.getTarget();
16505 if(target.nodeName.toLowerCase() === 'i'){
16506 target = Roo.get(target).dom.parentNode;
16509 var nodeName = target.nodeName;
16510 var className = target.className;
16511 var html = target.innerHTML;
16513 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16517 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16519 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16525 picker : function()
16527 return this.pickerEl;
16530 fillMonths: function()
16533 var months = this.picker().select('>.datepicker-months td', true).first();
16535 months.dom.innerHTML = '';
16541 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16544 months.createChild(month);
16553 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16554 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16557 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16558 e.removeClass('active');
16560 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16561 e.addClass('active');
16568 if(this.isInline) return;
16570 this.picker().removeClass(['bottom', 'top']);
16572 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16574 * place to the top of element!
16578 this.picker().addClass('top');
16579 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16584 this.picker().addClass('bottom');
16586 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16589 onFocus : function()
16591 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16595 onBlur : function()
16597 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16599 var d = this.inputEl().getValue();
16608 this.picker().show();
16609 this.picker().select('>.datepicker-months', true).first().show();
16613 this.fireEvent('show', this, this.date);
16618 if(this.isInline) return;
16619 this.picker().hide();
16620 this.fireEvent('hide', this, this.date);
16624 onMousedown: function(e)
16626 e.stopPropagation();
16627 e.preventDefault();
16632 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16636 fireKey: function(e)
16638 if (!this.picker().isVisible()){
16639 if (e.keyCode == 27) // allow escape to hide and re-show picker
16649 e.preventDefault();
16653 dir = e.keyCode == 37 ? -1 : 1;
16655 this.vIndex = this.vIndex + dir;
16657 if(this.vIndex < 0){
16661 if(this.vIndex > 11){
16665 if(isNaN(this.vIndex)){
16669 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16675 dir = e.keyCode == 38 ? -1 : 1;
16677 this.vIndex = this.vIndex + dir * 4;
16679 if(this.vIndex < 0){
16683 if(this.vIndex > 11){
16687 if(isNaN(this.vIndex)){
16691 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16696 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16697 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16701 e.preventDefault();
16704 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16705 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16721 this.picker().remove();
16726 Roo.apply(Roo.bootstrap.MonthField, {
16745 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16746 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16751 Roo.apply(Roo.bootstrap.MonthField, {
16755 cls: 'datepicker dropdown-menu roo-dynamic',
16759 cls: 'datepicker-months',
16763 cls: 'table-condensed',
16765 Roo.bootstrap.DateField.content
16785 * @class Roo.bootstrap.CheckBox
16786 * @extends Roo.bootstrap.Input
16787 * Bootstrap CheckBox class
16789 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16790 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16791 * @cfg {String} boxLabel The text that appears beside the checkbox
16792 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16793 * @cfg {Boolean} checked initnal the element
16794 * @cfg {Boolean} inline inline the element (default false)
16795 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16798 * Create a new CheckBox
16799 * @param {Object} config The config object
16802 Roo.bootstrap.CheckBox = function(config){
16803 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16808 * Fires when the element is checked or unchecked.
16809 * @param {Roo.bootstrap.CheckBox} this This input
16810 * @param {Boolean} checked The new checked value
16817 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16819 inputType: 'checkbox',
16827 getAutoCreate : function()
16829 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16835 cfg.cls = 'form-group ' + this.inputType; //input-group
16838 cfg.cls += ' ' + this.inputType + '-inline';
16844 type : this.inputType,
16845 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16846 cls : 'roo-' + this.inputType, //'form-box',
16847 placeholder : this.placeholder || ''
16851 if (this.weight) { // Validity check?
16852 cfg.cls += " " + this.inputType + "-" + this.weight;
16855 if (this.disabled) {
16856 input.disabled=true;
16860 input.checked = this.checked;
16864 input.name = this.name;
16868 input.cls += ' input-' + this.size;
16873 ['xs','sm','md','lg'].map(function(size){
16874 if (settings[size]) {
16875 cfg.cls += ' col-' + size + '-' + settings[size];
16879 var inputblock = input;
16881 if (this.before || this.after) {
16884 cls : 'input-group',
16889 inputblock.cn.push({
16891 cls : 'input-group-addon',
16896 inputblock.cn.push(input);
16899 inputblock.cn.push({
16901 cls : 'input-group-addon',
16908 if (align ==='left' && this.fieldLabel.length) {
16909 Roo.log("left and has label");
16915 cls : 'control-label col-md-' + this.labelWidth,
16916 html : this.fieldLabel
16920 cls : "col-md-" + (12 - this.labelWidth),
16927 } else if ( this.fieldLabel.length) {
16932 tag: this.boxLabel ? 'span' : 'label',
16934 cls: 'control-label box-input-label',
16935 //cls : 'input-group-addon',
16936 html : this.fieldLabel
16946 Roo.log(" no label && no align");
16947 cfg.cn = [ inputblock ] ;
16952 var boxLabelCfg = {
16954 //'for': id, // box label is handled by onclick - so no for...
16956 html: this.boxLabel
16960 boxLabelCfg.tooltip = this.tooltip;
16963 cfg.cn.push(boxLabelCfg);
16973 * return the real input element.
16975 inputEl: function ()
16977 return this.el.select('input.roo-' + this.inputType,true).first();
16980 labelEl: function()
16982 return this.el.select('label.control-label',true).first();
16984 /* depricated... */
16988 return this.labelEl();
16991 initEvents : function()
16993 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16995 this.inputEl().on('click', this.onClick, this);
16997 if (this.boxLabel) {
16998 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17001 this.startValue = this.getValue();
17004 Roo.bootstrap.CheckBox.register(this);
17008 onClick : function()
17010 this.setChecked(!this.checked);
17013 setChecked : function(state,suppressEvent)
17015 this.startValue = this.getValue();
17017 if(this.inputType == 'radio'){
17019 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17020 e.dom.checked = false;
17023 this.inputEl().dom.checked = true;
17025 this.inputEl().dom.value = this.inputValue;
17027 if(suppressEvent !== true){
17028 this.fireEvent('check', this, true);
17036 this.checked = state;
17038 this.inputEl().dom.checked = state;
17040 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17042 if(suppressEvent !== true){
17043 this.fireEvent('check', this, state);
17049 getValue : function()
17051 if(this.inputType == 'radio'){
17052 return this.getGroupValue();
17055 return this.inputEl().getValue();
17059 getGroupValue : function()
17061 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17065 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17068 setValue : function(v,suppressEvent)
17070 if(this.inputType == 'radio'){
17071 this.setGroupValue(v, suppressEvent);
17075 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17080 setGroupValue : function(v, suppressEvent)
17082 this.startValue = this.getValue();
17084 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17085 e.dom.checked = false;
17087 if(e.dom.value == v){
17088 e.dom.checked = true;
17092 if(suppressEvent !== true){
17093 this.fireEvent('check', this, true);
17101 validate : function()
17105 (this.inputType == 'radio' && this.validateRadio()) ||
17106 (this.inputType == 'checkbox' && this.validateCheckbox())
17112 this.markInvalid();
17116 validateRadio : function()
17120 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17121 if(!e.dom.checked){
17133 validateCheckbox : function()
17136 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17139 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17147 for(var i in group){
17152 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17159 * Mark this field as valid
17161 markValid : function()
17163 if(this.allowBlank){
17169 this.fireEvent('valid', this);
17171 if(this.inputType == 'radio'){
17172 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17173 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17174 e.findParent('.form-group', false, true).addClass(_this.validClass);
17181 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17182 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17186 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17192 for(var i in group){
17193 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17194 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17199 * Mark this field as invalid
17200 * @param {String} msg The validation message
17202 markInvalid : function(msg)
17204 if(this.allowBlank){
17210 this.fireEvent('invalid', this, msg);
17212 if(this.inputType == 'radio'){
17213 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17214 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17215 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17222 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17223 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17227 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17233 for(var i in group){
17234 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17235 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17242 Roo.apply(Roo.bootstrap.CheckBox, {
17247 * register a CheckBox Group
17248 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17250 register : function(checkbox)
17252 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17253 this.groups[checkbox.groupId] = {};
17256 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17260 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17264 * fetch a CheckBox Group based on the group ID
17265 * @param {string} the group ID
17266 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17268 get: function(groupId) {
17269 if (typeof(this.groups[groupId]) == 'undefined') {
17273 return this.groups[groupId] ;
17285 *<div class="radio">
17287 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17288 Option one is this and that—be sure to include why it's great
17295 *<label class="radio-inline">fieldLabel</label>
17296 *<label class="radio-inline">
17297 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17305 * @class Roo.bootstrap.Radio
17306 * @extends Roo.bootstrap.CheckBox
17307 * Bootstrap Radio class
17310 * Create a new Radio
17311 * @param {Object} config The config object
17314 Roo.bootstrap.Radio = function(config){
17315 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17319 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17321 inputType: 'radio',
17325 getAutoCreate : function()
17327 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17328 align = align || 'left'; // default...
17335 tag : this.inline ? 'span' : 'div',
17340 var inline = this.inline ? ' radio-inline' : '';
17344 // does not need for, as we wrap the input with it..
17346 cls : 'control-label box-label' + inline,
17349 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17353 //cls : 'control-label' + inline,
17354 html : this.fieldLabel,
17355 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17364 type : this.inputType,
17365 //value : (!this.checked) ? this.valueOff : this.inputValue,
17366 value : this.inputValue,
17368 placeholder : this.placeholder || '' // ?? needed????
17371 if (this.weight) { // Validity check?
17372 input.cls += " radio-" + this.weight;
17374 if (this.disabled) {
17375 input.disabled=true;
17379 input.checked = this.checked;
17383 input.name = this.name;
17387 input.cls += ' input-' + this.size;
17390 //?? can span's inline have a width??
17393 ['xs','sm','md','lg'].map(function(size){
17394 if (settings[size]) {
17395 cfg.cls += ' col-' + size + '-' + settings[size];
17399 var inputblock = input;
17401 if (this.before || this.after) {
17404 cls : 'input-group',
17409 inputblock.cn.push({
17411 cls : 'input-group-addon',
17415 inputblock.cn.push(input);
17417 inputblock.cn.push({
17419 cls : 'input-group-addon',
17427 if (this.fieldLabel && this.fieldLabel.length) {
17428 cfg.cn.push(fieldLabel);
17431 // normal bootstrap puts the input inside the label.
17432 // however with our styled version - it has to go after the input.
17434 //lbl.cn.push(inputblock);
17438 cls: 'radio' + inline,
17445 cfg.cn.push( lblwrap);
17450 html: this.boxLabel
17459 initEvents : function()
17461 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17463 this.inputEl().on('click', this.onClick, this);
17464 if (this.boxLabel) {
17465 Roo.log('find label')
17466 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17471 inputEl: function ()
17473 return this.el.select('input.roo-radio',true).first();
17475 onClick : function()
17478 this.setChecked(true);
17481 setChecked : function(state,suppressEvent)
17484 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17485 v.dom.checked = false;
17488 Roo.log(this.inputEl().dom);
17489 this.checked = state;
17490 this.inputEl().dom.checked = state;
17492 if(suppressEvent !== true){
17493 this.fireEvent('check', this, state);
17496 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17500 getGroupValue : function()
17503 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17504 if(v.dom.checked == true){
17505 value = v.dom.value;
17513 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17514 * @return {Mixed} value The field value
17516 getValue : function(){
17517 return this.getGroupValue();
17523 //<script type="text/javascript">
17526 * Based Ext JS Library 1.1.1
17527 * Copyright(c) 2006-2007, Ext JS, LLC.
17533 * @class Roo.HtmlEditorCore
17534 * @extends Roo.Component
17535 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17537 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17540 Roo.HtmlEditorCore = function(config){
17543 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17548 * @event initialize
17549 * Fires when the editor is fully initialized (including the iframe)
17550 * @param {Roo.HtmlEditorCore} this
17555 * Fires when the editor is first receives the focus. Any insertion must wait
17556 * until after this event.
17557 * @param {Roo.HtmlEditorCore} this
17561 * @event beforesync
17562 * Fires before the textarea is updated with content from the editor iframe. Return false
17563 * to cancel the sync.
17564 * @param {Roo.HtmlEditorCore} this
17565 * @param {String} html
17569 * @event beforepush
17570 * Fires before the iframe editor is updated with content from the textarea. Return false
17571 * to cancel the push.
17572 * @param {Roo.HtmlEditorCore} this
17573 * @param {String} html
17578 * Fires when the textarea is updated with content from the editor iframe.
17579 * @param {Roo.HtmlEditorCore} this
17580 * @param {String} html
17585 * Fires when the iframe editor is updated with content from the textarea.
17586 * @param {Roo.HtmlEditorCore} this
17587 * @param {String} html
17592 * @event editorevent
17593 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17594 * @param {Roo.HtmlEditorCore} this
17600 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17602 // defaults : white / black...
17603 this.applyBlacklists();
17610 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17614 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17620 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17625 * @cfg {Number} height (in pixels)
17629 * @cfg {Number} width (in pixels)
17634 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17637 stylesheets: false,
17642 // private properties
17643 validationEvent : false,
17645 initialized : false,
17647 sourceEditMode : false,
17648 onFocus : Roo.emptyFn,
17650 hideMode:'offsets',
17654 // blacklist + whitelisted elements..
17661 * Protected method that will not generally be called directly. It
17662 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17663 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17665 getDocMarkup : function(){
17669 // inherit styels from page...??
17670 if (this.stylesheets === false) {
17672 Roo.get(document.head).select('style').each(function(node) {
17673 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17676 Roo.get(document.head).select('link').each(function(node) {
17677 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17680 } else if (!this.stylesheets.length) {
17682 st = '<style type="text/css">' +
17683 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17689 st += '<style type="text/css">' +
17690 'IMG { cursor: pointer } ' +
17694 return '<html><head>' + st +
17695 //<style type="text/css">' +
17696 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17698 ' </head><body class="roo-htmleditor-body"></body></html>';
17702 onRender : function(ct, position)
17705 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17706 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17709 this.el.dom.style.border = '0 none';
17710 this.el.dom.setAttribute('tabIndex', -1);
17711 this.el.addClass('x-hidden hide');
17715 if(Roo.isIE){ // fix IE 1px bogus margin
17716 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17720 this.frameId = Roo.id();
17724 var iframe = this.owner.wrap.createChild({
17726 cls: 'form-control', // bootstrap..
17728 name: this.frameId,
17729 frameBorder : 'no',
17730 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17735 this.iframe = iframe.dom;
17737 this.assignDocWin();
17739 this.doc.designMode = 'on';
17742 this.doc.write(this.getDocMarkup());
17746 var task = { // must defer to wait for browser to be ready
17748 //console.log("run task?" + this.doc.readyState);
17749 this.assignDocWin();
17750 if(this.doc.body || this.doc.readyState == 'complete'){
17752 this.doc.designMode="on";
17756 Roo.TaskMgr.stop(task);
17757 this.initEditor.defer(10, this);
17764 Roo.TaskMgr.start(task);
17769 onResize : function(w, h)
17771 Roo.log('resize: ' +w + ',' + h );
17772 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17776 if(typeof w == 'number'){
17778 this.iframe.style.width = w + 'px';
17780 if(typeof h == 'number'){
17782 this.iframe.style.height = h + 'px';
17784 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17791 * Toggles the editor between standard and source edit mode.
17792 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17794 toggleSourceEdit : function(sourceEditMode){
17796 this.sourceEditMode = sourceEditMode === true;
17798 if(this.sourceEditMode){
17800 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17803 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17804 //this.iframe.className = '';
17807 //this.setSize(this.owner.wrap.getSize());
17808 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17815 * Protected method that will not generally be called directly. If you need/want
17816 * custom HTML cleanup, this is the method you should override.
17817 * @param {String} html The HTML to be cleaned
17818 * return {String} The cleaned HTML
17820 cleanHtml : function(html){
17821 html = String(html);
17822 if(html.length > 5){
17823 if(Roo.isSafari){ // strip safari nonsense
17824 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17827 if(html == ' '){
17834 * HTML Editor -> Textarea
17835 * Protected method that will not generally be called directly. Syncs the contents
17836 * of the editor iframe with the textarea.
17838 syncValue : function(){
17839 if(this.initialized){
17840 var bd = (this.doc.body || this.doc.documentElement);
17841 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17842 var html = bd.innerHTML;
17844 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17845 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17847 html = '<div style="'+m[0]+'">' + html + '</div>';
17850 html = this.cleanHtml(html);
17851 // fix up the special chars.. normaly like back quotes in word...
17852 // however we do not want to do this with chinese..
17853 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17854 var cc = b.charCodeAt();
17856 (cc >= 0x4E00 && cc < 0xA000 ) ||
17857 (cc >= 0x3400 && cc < 0x4E00 ) ||
17858 (cc >= 0xf900 && cc < 0xfb00 )
17864 if(this.owner.fireEvent('beforesync', this, html) !== false){
17865 this.el.dom.value = html;
17866 this.owner.fireEvent('sync', this, html);
17872 * Protected method that will not generally be called directly. Pushes the value of the textarea
17873 * into the iframe editor.
17875 pushValue : function(){
17876 if(this.initialized){
17877 var v = this.el.dom.value.trim();
17879 // if(v.length < 1){
17883 if(this.owner.fireEvent('beforepush', this, v) !== false){
17884 var d = (this.doc.body || this.doc.documentElement);
17886 this.cleanUpPaste();
17887 this.el.dom.value = d.innerHTML;
17888 this.owner.fireEvent('push', this, v);
17894 deferFocus : function(){
17895 this.focus.defer(10, this);
17899 focus : function(){
17900 if(this.win && !this.sourceEditMode){
17907 assignDocWin: function()
17909 var iframe = this.iframe;
17912 this.doc = iframe.contentWindow.document;
17913 this.win = iframe.contentWindow;
17915 // if (!Roo.get(this.frameId)) {
17918 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17919 // this.win = Roo.get(this.frameId).dom.contentWindow;
17921 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17925 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17926 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17931 initEditor : function(){
17932 //console.log("INIT EDITOR");
17933 this.assignDocWin();
17937 this.doc.designMode="on";
17939 this.doc.write(this.getDocMarkup());
17942 var dbody = (this.doc.body || this.doc.documentElement);
17943 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17944 // this copies styles from the containing element into thsi one..
17945 // not sure why we need all of this..
17946 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17948 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17949 //ss['background-attachment'] = 'fixed'; // w3c
17950 dbody.bgProperties = 'fixed'; // ie
17951 //Roo.DomHelper.applyStyles(dbody, ss);
17952 Roo.EventManager.on(this.doc, {
17953 //'mousedown': this.onEditorEvent,
17954 'mouseup': this.onEditorEvent,
17955 'dblclick': this.onEditorEvent,
17956 'click': this.onEditorEvent,
17957 'keyup': this.onEditorEvent,
17962 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17964 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17965 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17967 this.initialized = true;
17969 this.owner.fireEvent('initialize', this);
17974 onDestroy : function(){
17980 //for (var i =0; i < this.toolbars.length;i++) {
17981 // // fixme - ask toolbars for heights?
17982 // this.toolbars[i].onDestroy();
17985 //this.wrap.dom.innerHTML = '';
17986 //this.wrap.remove();
17991 onFirstFocus : function(){
17993 this.assignDocWin();
17996 this.activated = true;
17999 if(Roo.isGecko){ // prevent silly gecko errors
18001 var s = this.win.getSelection();
18002 if(!s.focusNode || s.focusNode.nodeType != 3){
18003 var r = s.getRangeAt(0);
18004 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18009 this.execCmd('useCSS', true);
18010 this.execCmd('styleWithCSS', false);
18013 this.owner.fireEvent('activate', this);
18017 adjustFont: function(btn){
18018 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18019 //if(Roo.isSafari){ // safari
18022 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18023 if(Roo.isSafari){ // safari
18024 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18025 v = (v < 10) ? 10 : v;
18026 v = (v > 48) ? 48 : v;
18027 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18032 v = Math.max(1, v+adjust);
18034 this.execCmd('FontSize', v );
18037 onEditorEvent : function(e){
18038 this.owner.fireEvent('editorevent', this, e);
18039 // this.updateToolbar();
18040 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18043 insertTag : function(tg)
18045 // could be a bit smarter... -> wrap the current selected tRoo..
18046 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18048 range = this.createRange(this.getSelection());
18049 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18050 wrappingNode.appendChild(range.extractContents());
18051 range.insertNode(wrappingNode);
18058 this.execCmd("formatblock", tg);
18062 insertText : function(txt)
18066 var range = this.createRange();
18067 range.deleteContents();
18068 //alert(Sender.getAttribute('label'));
18070 range.insertNode(this.doc.createTextNode(txt));
18076 * Executes a Midas editor command on the editor document and performs necessary focus and
18077 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18078 * @param {String} cmd The Midas command
18079 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18081 relayCmd : function(cmd, value){
18083 this.execCmd(cmd, value);
18084 this.owner.fireEvent('editorevent', this);
18085 //this.updateToolbar();
18086 this.owner.deferFocus();
18090 * Executes a Midas editor command directly on the editor document.
18091 * For visual commands, you should use {@link #relayCmd} instead.
18092 * <b>This should only be called after the editor is initialized.</b>
18093 * @param {String} cmd The Midas command
18094 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18096 execCmd : function(cmd, value){
18097 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18104 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18106 * @param {String} text | dom node..
18108 insertAtCursor : function(text)
18113 if(!this.activated){
18119 var r = this.doc.selection.createRange();
18130 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18134 // from jquery ui (MIT licenced)
18136 var win = this.win;
18138 if (win.getSelection && win.getSelection().getRangeAt) {
18139 range = win.getSelection().getRangeAt(0);
18140 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18141 range.insertNode(node);
18142 } else if (win.document.selection && win.document.selection.createRange) {
18143 // no firefox support
18144 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18145 win.document.selection.createRange().pasteHTML(txt);
18147 // no firefox support
18148 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18149 this.execCmd('InsertHTML', txt);
18158 mozKeyPress : function(e){
18160 var c = e.getCharCode(), cmd;
18163 c = String.fromCharCode(c).toLowerCase();
18177 this.cleanUpPaste.defer(100, this);
18185 e.preventDefault();
18193 fixKeys : function(){ // load time branching for fastest keydown performance
18195 return function(e){
18196 var k = e.getKey(), r;
18199 r = this.doc.selection.createRange();
18202 r.pasteHTML('    ');
18209 r = this.doc.selection.createRange();
18211 var target = r.parentElement();
18212 if(!target || target.tagName.toLowerCase() != 'li'){
18214 r.pasteHTML('<br />');
18220 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18221 this.cleanUpPaste.defer(100, this);
18227 }else if(Roo.isOpera){
18228 return function(e){
18229 var k = e.getKey();
18233 this.execCmd('InsertHTML','    ');
18236 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18237 this.cleanUpPaste.defer(100, this);
18242 }else if(Roo.isSafari){
18243 return function(e){
18244 var k = e.getKey();
18248 this.execCmd('InsertText','\t');
18252 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18253 this.cleanUpPaste.defer(100, this);
18261 getAllAncestors: function()
18263 var p = this.getSelectedNode();
18266 a.push(p); // push blank onto stack..
18267 p = this.getParentElement();
18271 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18275 a.push(this.doc.body);
18279 lastSelNode : false,
18282 getSelection : function()
18284 this.assignDocWin();
18285 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18288 getSelectedNode: function()
18290 // this may only work on Gecko!!!
18292 // should we cache this!!!!
18297 var range = this.createRange(this.getSelection()).cloneRange();
18300 var parent = range.parentElement();
18302 var testRange = range.duplicate();
18303 testRange.moveToElementText(parent);
18304 if (testRange.inRange(range)) {
18307 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18310 parent = parent.parentElement;
18315 // is ancestor a text element.
18316 var ac = range.commonAncestorContainer;
18317 if (ac.nodeType == 3) {
18318 ac = ac.parentNode;
18321 var ar = ac.childNodes;
18324 var other_nodes = [];
18325 var has_other_nodes = false;
18326 for (var i=0;i<ar.length;i++) {
18327 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18330 // fullly contained node.
18332 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18337 // probably selected..
18338 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18339 other_nodes.push(ar[i]);
18343 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18348 has_other_nodes = true;
18350 if (!nodes.length && other_nodes.length) {
18351 nodes= other_nodes;
18353 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18359 createRange: function(sel)
18361 // this has strange effects when using with
18362 // top toolbar - not sure if it's a great idea.
18363 //this.editor.contentWindow.focus();
18364 if (typeof sel != "undefined") {
18366 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18368 return this.doc.createRange();
18371 return this.doc.createRange();
18374 getParentElement: function()
18377 this.assignDocWin();
18378 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18380 var range = this.createRange(sel);
18383 var p = range.commonAncestorContainer;
18384 while (p.nodeType == 3) { // text node
18395 * Range intersection.. the hard stuff...
18399 * [ -- selected range --- ]
18403 * if end is before start or hits it. fail.
18404 * if start is after end or hits it fail.
18406 * if either hits (but other is outside. - then it's not
18412 // @see http://www.thismuchiknow.co.uk/?p=64.
18413 rangeIntersectsNode : function(range, node)
18415 var nodeRange = node.ownerDocument.createRange();
18417 nodeRange.selectNode(node);
18419 nodeRange.selectNodeContents(node);
18422 var rangeStartRange = range.cloneRange();
18423 rangeStartRange.collapse(true);
18425 var rangeEndRange = range.cloneRange();
18426 rangeEndRange.collapse(false);
18428 var nodeStartRange = nodeRange.cloneRange();
18429 nodeStartRange.collapse(true);
18431 var nodeEndRange = nodeRange.cloneRange();
18432 nodeEndRange.collapse(false);
18434 return rangeStartRange.compareBoundaryPoints(
18435 Range.START_TO_START, nodeEndRange) == -1 &&
18436 rangeEndRange.compareBoundaryPoints(
18437 Range.START_TO_START, nodeStartRange) == 1;
18441 rangeCompareNode : function(range, node)
18443 var nodeRange = node.ownerDocument.createRange();
18445 nodeRange.selectNode(node);
18447 nodeRange.selectNodeContents(node);
18451 range.collapse(true);
18453 nodeRange.collapse(true);
18455 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18456 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18458 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18460 var nodeIsBefore = ss == 1;
18461 var nodeIsAfter = ee == -1;
18463 if (nodeIsBefore && nodeIsAfter)
18465 if (!nodeIsBefore && nodeIsAfter)
18466 return 1; //right trailed.
18468 if (nodeIsBefore && !nodeIsAfter)
18469 return 2; // left trailed.
18474 // private? - in a new class?
18475 cleanUpPaste : function()
18477 // cleans up the whole document..
18478 Roo.log('cleanuppaste');
18480 this.cleanUpChildren(this.doc.body);
18481 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18482 if (clean != this.doc.body.innerHTML) {
18483 this.doc.body.innerHTML = clean;
18488 cleanWordChars : function(input) {// change the chars to hex code
18489 var he = Roo.HtmlEditorCore;
18491 var output = input;
18492 Roo.each(he.swapCodes, function(sw) {
18493 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18495 output = output.replace(swapper, sw[1]);
18502 cleanUpChildren : function (n)
18504 if (!n.childNodes.length) {
18507 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18508 this.cleanUpChild(n.childNodes[i]);
18515 cleanUpChild : function (node)
18518 //console.log(node);
18519 if (node.nodeName == "#text") {
18520 // clean up silly Windows -- stuff?
18523 if (node.nodeName == "#comment") {
18524 node.parentNode.removeChild(node);
18525 // clean up silly Windows -- stuff?
18528 var lcname = node.tagName.toLowerCase();
18529 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18530 // whitelist of tags..
18532 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18534 node.parentNode.removeChild(node);
18539 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18541 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18542 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18544 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18545 // remove_keep_children = true;
18548 if (remove_keep_children) {
18549 this.cleanUpChildren(node);
18550 // inserts everything just before this node...
18551 while (node.childNodes.length) {
18552 var cn = node.childNodes[0];
18553 node.removeChild(cn);
18554 node.parentNode.insertBefore(cn, node);
18556 node.parentNode.removeChild(node);
18560 if (!node.attributes || !node.attributes.length) {
18561 this.cleanUpChildren(node);
18565 function cleanAttr(n,v)
18568 if (v.match(/^\./) || v.match(/^\//)) {
18571 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18574 if (v.match(/^#/)) {
18577 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18578 node.removeAttribute(n);
18582 var cwhite = this.cwhite;
18583 var cblack = this.cblack;
18585 function cleanStyle(n,v)
18587 if (v.match(/expression/)) { //XSS?? should we even bother..
18588 node.removeAttribute(n);
18592 var parts = v.split(/;/);
18595 Roo.each(parts, function(p) {
18596 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18600 var l = p.split(':').shift().replace(/\s+/g,'');
18601 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18603 if ( cwhite.length && cblack.indexOf(l) > -1) {
18604 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18605 //node.removeAttribute(n);
18609 // only allow 'c whitelisted system attributes'
18610 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18611 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18612 //node.removeAttribute(n);
18622 if (clean.length) {
18623 node.setAttribute(n, clean.join(';'));
18625 node.removeAttribute(n);
18631 for (var i = node.attributes.length-1; i > -1 ; i--) {
18632 var a = node.attributes[i];
18635 if (a.name.toLowerCase().substr(0,2)=='on') {
18636 node.removeAttribute(a.name);
18639 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18640 node.removeAttribute(a.name);
18643 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18644 cleanAttr(a.name,a.value); // fixme..
18647 if (a.name == 'style') {
18648 cleanStyle(a.name,a.value);
18651 /// clean up MS crap..
18652 // tecnically this should be a list of valid class'es..
18655 if (a.name == 'class') {
18656 if (a.value.match(/^Mso/)) {
18657 node.className = '';
18660 if (a.value.match(/body/)) {
18661 node.className = '';
18672 this.cleanUpChildren(node);
18677 * Clean up MS wordisms...
18679 cleanWord : function(node)
18682 var cleanWordChildren = function()
18684 if (!node.childNodes.length) {
18687 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18688 _t.cleanWord(node.childNodes[i]);
18694 this.cleanWord(this.doc.body);
18697 if (node.nodeName == "#text") {
18698 // clean up silly Windows -- stuff?
18701 if (node.nodeName == "#comment") {
18702 node.parentNode.removeChild(node);
18703 // clean up silly Windows -- stuff?
18707 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18708 node.parentNode.removeChild(node);
18712 // remove - but keep children..
18713 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18714 while (node.childNodes.length) {
18715 var cn = node.childNodes[0];
18716 node.removeChild(cn);
18717 node.parentNode.insertBefore(cn, node);
18719 node.parentNode.removeChild(node);
18720 cleanWordChildren();
18724 if (node.className.length) {
18726 var cn = node.className.split(/\W+/);
18728 Roo.each(cn, function(cls) {
18729 if (cls.match(/Mso[a-zA-Z]+/)) {
18734 node.className = cna.length ? cna.join(' ') : '';
18736 node.removeAttribute("class");
18740 if (node.hasAttribute("lang")) {
18741 node.removeAttribute("lang");
18744 if (node.hasAttribute("style")) {
18746 var styles = node.getAttribute("style").split(";");
18748 Roo.each(styles, function(s) {
18749 if (!s.match(/:/)) {
18752 var kv = s.split(":");
18753 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18756 // what ever is left... we allow.
18759 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18760 if (!nstyle.length) {
18761 node.removeAttribute('style');
18765 cleanWordChildren();
18769 domToHTML : function(currentElement, depth, nopadtext) {
18771 depth = depth || 0;
18772 nopadtext = nopadtext || false;
18774 if (!currentElement) {
18775 return this.domToHTML(this.doc.body);
18778 //Roo.log(currentElement);
18780 var allText = false;
18781 var nodeName = currentElement.nodeName;
18782 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18784 if (nodeName == '#text') {
18786 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18791 if (nodeName != 'BODY') {
18794 // Prints the node tagName, such as <A>, <IMG>, etc
18797 for(i = 0; i < currentElement.attributes.length;i++) {
18799 var aname = currentElement.attributes.item(i).name;
18800 if (!currentElement.attributes.item(i).value.length) {
18803 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18806 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18815 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18818 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18823 // Traverse the tree
18825 var currentElementChild = currentElement.childNodes.item(i);
18826 var allText = true;
18827 var innerHTML = '';
18829 while (currentElementChild) {
18830 // Formatting code (indent the tree so it looks nice on the screen)
18831 var nopad = nopadtext;
18832 if (lastnode == 'SPAN') {
18836 if (currentElementChild.nodeName == '#text') {
18837 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18838 toadd = nopadtext ? toadd : toadd.trim();
18839 if (!nopad && toadd.length > 80) {
18840 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18842 innerHTML += toadd;
18845 currentElementChild = currentElement.childNodes.item(i);
18851 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18853 // Recursively traverse the tree structure of the child node
18854 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18855 lastnode = currentElementChild.nodeName;
18857 currentElementChild=currentElement.childNodes.item(i);
18863 // The remaining code is mostly for formatting the tree
18864 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18869 ret+= "</"+tagName+">";
18875 applyBlacklists : function()
18877 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18878 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18882 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18883 if (b.indexOf(tag) > -1) {
18886 this.white.push(tag);
18890 Roo.each(w, function(tag) {
18891 if (b.indexOf(tag) > -1) {
18894 if (this.white.indexOf(tag) > -1) {
18897 this.white.push(tag);
18902 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18903 if (w.indexOf(tag) > -1) {
18906 this.black.push(tag);
18910 Roo.each(b, function(tag) {
18911 if (w.indexOf(tag) > -1) {
18914 if (this.black.indexOf(tag) > -1) {
18917 this.black.push(tag);
18922 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18923 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18927 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18928 if (b.indexOf(tag) > -1) {
18931 this.cwhite.push(tag);
18935 Roo.each(w, function(tag) {
18936 if (b.indexOf(tag) > -1) {
18939 if (this.cwhite.indexOf(tag) > -1) {
18942 this.cwhite.push(tag);
18947 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18948 if (w.indexOf(tag) > -1) {
18951 this.cblack.push(tag);
18955 Roo.each(b, function(tag) {
18956 if (w.indexOf(tag) > -1) {
18959 if (this.cblack.indexOf(tag) > -1) {
18962 this.cblack.push(tag);
18967 setStylesheets : function(stylesheets)
18969 if(typeof(stylesheets) == 'string'){
18970 Roo.get(this.iframe.contentDocument.head).createChild({
18972 rel : 'stylesheet',
18981 Roo.each(stylesheets, function(s) {
18986 Roo.get(_this.iframe.contentDocument.head).createChild({
18988 rel : 'stylesheet',
18997 removeStylesheets : function()
19001 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19006 // hide stuff that is not compatible
19020 * @event specialkey
19024 * @cfg {String} fieldClass @hide
19027 * @cfg {String} focusClass @hide
19030 * @cfg {String} autoCreate @hide
19033 * @cfg {String} inputType @hide
19036 * @cfg {String} invalidClass @hide
19039 * @cfg {String} invalidText @hide
19042 * @cfg {String} msgFx @hide
19045 * @cfg {String} validateOnBlur @hide
19049 Roo.HtmlEditorCore.white = [
19050 'area', 'br', 'img', 'input', 'hr', 'wbr',
19052 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19053 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19054 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19055 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19056 'table', 'ul', 'xmp',
19058 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19061 'dir', 'menu', 'ol', 'ul', 'dl',
19067 Roo.HtmlEditorCore.black = [
19068 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19070 'base', 'basefont', 'bgsound', 'blink', 'body',
19071 'frame', 'frameset', 'head', 'html', 'ilayer',
19072 'iframe', 'layer', 'link', 'meta', 'object',
19073 'script', 'style' ,'title', 'xml' // clean later..
19075 Roo.HtmlEditorCore.clean = [
19076 'script', 'style', 'title', 'xml'
19078 Roo.HtmlEditorCore.remove = [
19083 Roo.HtmlEditorCore.ablack = [
19087 Roo.HtmlEditorCore.aclean = [
19088 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19092 Roo.HtmlEditorCore.pwhite= [
19093 'http', 'https', 'mailto'
19096 // white listed style attributes.
19097 Roo.HtmlEditorCore.cwhite= [
19098 // 'text-align', /// default is to allow most things..
19104 // black listed style attributes.
19105 Roo.HtmlEditorCore.cblack= [
19106 // 'font-size' -- this can be set by the project
19110 Roo.HtmlEditorCore.swapCodes =[
19129 * @class Roo.bootstrap.HtmlEditor
19130 * @extends Roo.bootstrap.TextArea
19131 * Bootstrap HtmlEditor class
19134 * Create a new HtmlEditor
19135 * @param {Object} config The config object
19138 Roo.bootstrap.HtmlEditor = function(config){
19139 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19140 if (!this.toolbars) {
19141 this.toolbars = [];
19143 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19146 * @event initialize
19147 * Fires when the editor is fully initialized (including the iframe)
19148 * @param {HtmlEditor} this
19153 * Fires when the editor is first receives the focus. Any insertion must wait
19154 * until after this event.
19155 * @param {HtmlEditor} this
19159 * @event beforesync
19160 * Fires before the textarea is updated with content from the editor iframe. Return false
19161 * to cancel the sync.
19162 * @param {HtmlEditor} this
19163 * @param {String} html
19167 * @event beforepush
19168 * Fires before the iframe editor is updated with content from the textarea. Return false
19169 * to cancel the push.
19170 * @param {HtmlEditor} this
19171 * @param {String} html
19176 * Fires when the textarea is updated with content from the editor iframe.
19177 * @param {HtmlEditor} this
19178 * @param {String} html
19183 * Fires when the iframe editor is updated with content from the textarea.
19184 * @param {HtmlEditor} this
19185 * @param {String} html
19189 * @event editmodechange
19190 * Fires when the editor switches edit modes
19191 * @param {HtmlEditor} this
19192 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19194 editmodechange: true,
19196 * @event editorevent
19197 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19198 * @param {HtmlEditor} this
19202 * @event firstfocus
19203 * Fires when on first focus - needed by toolbars..
19204 * @param {HtmlEditor} this
19209 * Auto save the htmlEditor value as a file into Events
19210 * @param {HtmlEditor} this
19214 * @event savedpreview
19215 * preview the saved version of htmlEditor
19216 * @param {HtmlEditor} this
19223 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19227 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19232 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19237 * @cfg {Number} height (in pixels)
19241 * @cfg {Number} width (in pixels)
19246 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19249 stylesheets: false,
19254 // private properties
19255 validationEvent : false,
19257 initialized : false,
19260 onFocus : Roo.emptyFn,
19262 hideMode:'offsets',
19265 tbContainer : false,
19267 toolbarContainer :function() {
19268 return this.wrap.select('.x-html-editor-tb',true).first();
19272 * Protected method that will not generally be called directly. It
19273 * is called when the editor creates its toolbar. Override this method if you need to
19274 * add custom toolbar buttons.
19275 * @param {HtmlEditor} editor
19277 createToolbar : function(){
19279 Roo.log("create toolbars");
19281 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19282 this.toolbars[0].render(this.toolbarContainer());
19286 // if (!editor.toolbars || !editor.toolbars.length) {
19287 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19290 // for (var i =0 ; i < editor.toolbars.length;i++) {
19291 // editor.toolbars[i] = Roo.factory(
19292 // typeof(editor.toolbars[i]) == 'string' ?
19293 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19294 // Roo.bootstrap.HtmlEditor);
19295 // editor.toolbars[i].init(editor);
19301 onRender : function(ct, position)
19303 // Roo.log("Call onRender: " + this.xtype);
19305 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19307 this.wrap = this.inputEl().wrap({
19308 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19311 this.editorcore.onRender(ct, position);
19313 if (this.resizable) {
19314 this.resizeEl = new Roo.Resizable(this.wrap, {
19318 minHeight : this.height,
19319 height: this.height,
19320 handles : this.resizable,
19323 resize : function(r, w, h) {
19324 _t.onResize(w,h); // -something
19330 this.createToolbar(this);
19333 if(!this.width && this.resizable){
19334 this.setSize(this.wrap.getSize());
19336 if (this.resizeEl) {
19337 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19338 // should trigger onReize..
19344 onResize : function(w, h)
19346 Roo.log('resize: ' +w + ',' + h );
19347 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19351 if(this.inputEl() ){
19352 if(typeof w == 'number'){
19353 var aw = w - this.wrap.getFrameWidth('lr');
19354 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19357 if(typeof h == 'number'){
19358 var tbh = -11; // fixme it needs to tool bar size!
19359 for (var i =0; i < this.toolbars.length;i++) {
19360 // fixme - ask toolbars for heights?
19361 tbh += this.toolbars[i].el.getHeight();
19362 //if (this.toolbars[i].footer) {
19363 // tbh += this.toolbars[i].footer.el.getHeight();
19371 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19372 ah -= 5; // knock a few pixes off for look..
19373 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19377 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19378 this.editorcore.onResize(ew,eh);
19383 * Toggles the editor between standard and source edit mode.
19384 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19386 toggleSourceEdit : function(sourceEditMode)
19388 this.editorcore.toggleSourceEdit(sourceEditMode);
19390 if(this.editorcore.sourceEditMode){
19391 Roo.log('editor - showing textarea');
19394 // Roo.log(this.syncValue());
19396 this.inputEl().removeClass(['hide', 'x-hidden']);
19397 this.inputEl().dom.removeAttribute('tabIndex');
19398 this.inputEl().focus();
19400 Roo.log('editor - hiding textarea');
19402 // Roo.log(this.pushValue());
19405 this.inputEl().addClass(['hide', 'x-hidden']);
19406 this.inputEl().dom.setAttribute('tabIndex', -1);
19407 //this.deferFocus();
19410 if(this.resizable){
19411 this.setSize(this.wrap.getSize());
19414 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19417 // private (for BoxComponent)
19418 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19420 // private (for BoxComponent)
19421 getResizeEl : function(){
19425 // private (for BoxComponent)
19426 getPositionEl : function(){
19431 initEvents : function(){
19432 this.originalValue = this.getValue();
19436 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19439 // markInvalid : Roo.emptyFn,
19441 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19444 // clearInvalid : Roo.emptyFn,
19446 setValue : function(v){
19447 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19448 this.editorcore.pushValue();
19453 deferFocus : function(){
19454 this.focus.defer(10, this);
19458 focus : function(){
19459 this.editorcore.focus();
19465 onDestroy : function(){
19471 for (var i =0; i < this.toolbars.length;i++) {
19472 // fixme - ask toolbars for heights?
19473 this.toolbars[i].onDestroy();
19476 this.wrap.dom.innerHTML = '';
19477 this.wrap.remove();
19482 onFirstFocus : function(){
19483 //Roo.log("onFirstFocus");
19484 this.editorcore.onFirstFocus();
19485 for (var i =0; i < this.toolbars.length;i++) {
19486 this.toolbars[i].onFirstFocus();
19492 syncValue : function()
19494 this.editorcore.syncValue();
19497 pushValue : function()
19499 this.editorcore.pushValue();
19503 // hide stuff that is not compatible
19517 * @event specialkey
19521 * @cfg {String} fieldClass @hide
19524 * @cfg {String} focusClass @hide
19527 * @cfg {String} autoCreate @hide
19530 * @cfg {String} inputType @hide
19533 * @cfg {String} invalidClass @hide
19536 * @cfg {String} invalidText @hide
19539 * @cfg {String} msgFx @hide
19542 * @cfg {String} validateOnBlur @hide
19551 Roo.namespace('Roo.bootstrap.htmleditor');
19553 * @class Roo.bootstrap.HtmlEditorToolbar1
19558 new Roo.bootstrap.HtmlEditor({
19561 new Roo.bootstrap.HtmlEditorToolbar1({
19562 disable : { fonts: 1 , format: 1, ..., ... , ...],
19568 * @cfg {Object} disable List of elements to disable..
19569 * @cfg {Array} btns List of additional buttons.
19573 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19576 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19579 Roo.apply(this, config);
19581 // default disabled, based on 'good practice'..
19582 this.disable = this.disable || {};
19583 Roo.applyIf(this.disable, {
19586 specialElements : true
19588 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19590 this.editor = config.editor;
19591 this.editorcore = config.editor.editorcore;
19593 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19595 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19596 // dont call parent... till later.
19598 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19603 editorcore : false,
19608 "h1","h2","h3","h4","h5","h6",
19610 "abbr", "acronym", "address", "cite", "samp", "var",
19614 onRender : function(ct, position)
19616 // Roo.log("Call onRender: " + this.xtype);
19618 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19620 this.el.dom.style.marginBottom = '0';
19622 var editorcore = this.editorcore;
19623 var editor= this.editor;
19626 var btn = function(id,cmd , toggle, handler){
19628 var event = toggle ? 'toggle' : 'click';
19633 xns: Roo.bootstrap,
19636 enableToggle:toggle !== false,
19638 pressed : toggle ? false : null,
19641 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19642 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19651 xns: Roo.bootstrap,
19652 glyphicon : 'font',
19656 xns: Roo.bootstrap,
19660 Roo.each(this.formats, function(f) {
19661 style.menu.items.push({
19663 xns: Roo.bootstrap,
19664 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19669 editorcore.insertTag(this.tagname);
19676 children.push(style);
19679 btn('bold',false,true);
19680 btn('italic',false,true);
19681 btn('align-left', 'justifyleft',true);
19682 btn('align-center', 'justifycenter',true);
19683 btn('align-right' , 'justifyright',true);
19684 btn('link', false, false, function(btn) {
19685 //Roo.log("create link?");
19686 var url = prompt(this.createLinkText, this.defaultLinkValue);
19687 if(url && url != 'http:/'+'/'){
19688 this.editorcore.relayCmd('createlink', url);
19691 btn('list','insertunorderedlist',true);
19692 btn('pencil', false,true, function(btn){
19695 this.toggleSourceEdit(btn.pressed);
19701 xns: Roo.bootstrap,
19706 xns: Roo.bootstrap,
19711 cog.menu.items.push({
19713 xns: Roo.bootstrap,
19714 html : Clean styles,
19719 editorcore.insertTag(this.tagname);
19728 this.xtype = 'NavSimplebar';
19730 for(var i=0;i< children.length;i++) {
19732 this.buttons.add(this.addxtypeChild(children[i]));
19736 editor.on('editorevent', this.updateToolbar, this);
19738 onBtnClick : function(id)
19740 this.editorcore.relayCmd(id);
19741 this.editorcore.focus();
19745 * Protected method that will not generally be called directly. It triggers
19746 * a toolbar update by reading the markup state of the current selection in the editor.
19748 updateToolbar: function(){
19750 if(!this.editorcore.activated){
19751 this.editor.onFirstFocus(); // is this neeed?
19755 var btns = this.buttons;
19756 var doc = this.editorcore.doc;
19757 btns.get('bold').setActive(doc.queryCommandState('bold'));
19758 btns.get('italic').setActive(doc.queryCommandState('italic'));
19759 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19761 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19762 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19763 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19765 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19766 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19769 var ans = this.editorcore.getAllAncestors();
19770 if (this.formatCombo) {
19773 var store = this.formatCombo.store;
19774 this.formatCombo.setValue("");
19775 for (var i =0; i < ans.length;i++) {
19776 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19778 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19786 // hides menus... - so this cant be on a menu...
19787 Roo.bootstrap.MenuMgr.hideAll();
19789 Roo.bootstrap.MenuMgr.hideAll();
19790 //this.editorsyncValue();
19792 onFirstFocus: function() {
19793 this.buttons.each(function(item){
19797 toggleSourceEdit : function(sourceEditMode){
19800 if(sourceEditMode){
19801 Roo.log("disabling buttons");
19802 this.buttons.each( function(item){
19803 if(item.cmd != 'pencil'){
19809 Roo.log("enabling buttons");
19810 if(this.editorcore.initialized){
19811 this.buttons.each( function(item){
19817 Roo.log("calling toggole on editor");
19818 // tell the editor that it's been pressed..
19819 this.editor.toggleSourceEdit(sourceEditMode);
19829 * @class Roo.bootstrap.Table.AbstractSelectionModel
19830 * @extends Roo.util.Observable
19831 * Abstract base class for grid SelectionModels. It provides the interface that should be
19832 * implemented by descendant classes. This class should not be directly instantiated.
19835 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19836 this.locked = false;
19837 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19841 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19842 /** @ignore Called by the grid automatically. Do not call directly. */
19843 init : function(grid){
19849 * Locks the selections.
19852 this.locked = true;
19856 * Unlocks the selections.
19858 unlock : function(){
19859 this.locked = false;
19863 * Returns true if the selections are locked.
19864 * @return {Boolean}
19866 isLocked : function(){
19867 return this.locked;
19871 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19872 * @class Roo.bootstrap.Table.RowSelectionModel
19873 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19874 * It supports multiple selections and keyboard selection/navigation.
19876 * @param {Object} config
19879 Roo.bootstrap.Table.RowSelectionModel = function(config){
19880 Roo.apply(this, config);
19881 this.selections = new Roo.util.MixedCollection(false, function(o){
19886 this.lastActive = false;
19890 * @event selectionchange
19891 * Fires when the selection changes
19892 * @param {SelectionModel} this
19894 "selectionchange" : true,
19896 * @event afterselectionchange
19897 * Fires after the selection changes (eg. by key press or clicking)
19898 * @param {SelectionModel} this
19900 "afterselectionchange" : true,
19902 * @event beforerowselect
19903 * Fires when a row is selected being selected, return false to cancel.
19904 * @param {SelectionModel} this
19905 * @param {Number} rowIndex The selected index
19906 * @param {Boolean} keepExisting False if other selections will be cleared
19908 "beforerowselect" : true,
19911 * Fires when a row is selected.
19912 * @param {SelectionModel} this
19913 * @param {Number} rowIndex The selected index
19914 * @param {Roo.data.Record} r The record
19916 "rowselect" : true,
19918 * @event rowdeselect
19919 * Fires when a row is deselected.
19920 * @param {SelectionModel} this
19921 * @param {Number} rowIndex The selected index
19923 "rowdeselect" : true
19925 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19926 this.locked = false;
19929 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19931 * @cfg {Boolean} singleSelect
19932 * True to allow selection of only one row at a time (defaults to false)
19934 singleSelect : false,
19937 initEvents : function(){
19939 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19940 this.grid.on("mousedown", this.handleMouseDown, this);
19941 }else{ // allow click to work like normal
19942 this.grid.on("rowclick", this.handleDragableRowClick, this);
19945 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19946 "up" : function(e){
19948 this.selectPrevious(e.shiftKey);
19949 }else if(this.last !== false && this.lastActive !== false){
19950 var last = this.last;
19951 this.selectRange(this.last, this.lastActive-1);
19952 this.grid.getView().focusRow(this.lastActive);
19953 if(last !== false){
19957 this.selectFirstRow();
19959 this.fireEvent("afterselectionchange", this);
19961 "down" : function(e){
19963 this.selectNext(e.shiftKey);
19964 }else if(this.last !== false && this.lastActive !== false){
19965 var last = this.last;
19966 this.selectRange(this.last, this.lastActive+1);
19967 this.grid.getView().focusRow(this.lastActive);
19968 if(last !== false){
19972 this.selectFirstRow();
19974 this.fireEvent("afterselectionchange", this);
19979 var view = this.grid.view;
19980 view.on("refresh", this.onRefresh, this);
19981 view.on("rowupdated", this.onRowUpdated, this);
19982 view.on("rowremoved", this.onRemove, this);
19986 onRefresh : function(){
19987 var ds = this.grid.dataSource, i, v = this.grid.view;
19988 var s = this.selections;
19989 s.each(function(r){
19990 if((i = ds.indexOfId(r.id)) != -1){
19999 onRemove : function(v, index, r){
20000 this.selections.remove(r);
20004 onRowUpdated : function(v, index, r){
20005 if(this.isSelected(r)){
20006 v.onRowSelect(index);
20012 * @param {Array} records The records to select
20013 * @param {Boolean} keepExisting (optional) True to keep existing selections
20015 selectRecords : function(records, keepExisting){
20017 this.clearSelections();
20019 var ds = this.grid.dataSource;
20020 for(var i = 0, len = records.length; i < len; i++){
20021 this.selectRow(ds.indexOf(records[i]), true);
20026 * Gets the number of selected rows.
20029 getCount : function(){
20030 return this.selections.length;
20034 * Selects the first row in the grid.
20036 selectFirstRow : function(){
20041 * Select the last row.
20042 * @param {Boolean} keepExisting (optional) True to keep existing selections
20044 selectLastRow : function(keepExisting){
20045 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20049 * Selects the row immediately following the last selected row.
20050 * @param {Boolean} keepExisting (optional) True to keep existing selections
20052 selectNext : function(keepExisting){
20053 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20054 this.selectRow(this.last+1, keepExisting);
20055 this.grid.getView().focusRow(this.last);
20060 * Selects the row that precedes the last selected row.
20061 * @param {Boolean} keepExisting (optional) True to keep existing selections
20063 selectPrevious : function(keepExisting){
20065 this.selectRow(this.last-1, keepExisting);
20066 this.grid.getView().focusRow(this.last);
20071 * Returns the selected records
20072 * @return {Array} Array of selected records
20074 getSelections : function(){
20075 return [].concat(this.selections.items);
20079 * Returns the first selected record.
20082 getSelected : function(){
20083 return this.selections.itemAt(0);
20088 * Clears all selections.
20090 clearSelections : function(fast){
20091 if(this.locked) return;
20093 var ds = this.grid.dataSource;
20094 var s = this.selections;
20095 s.each(function(r){
20096 this.deselectRow(ds.indexOfId(r.id));
20100 this.selections.clear();
20107 * Selects all rows.
20109 selectAll : function(){
20110 if(this.locked) return;
20111 this.selections.clear();
20112 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20113 this.selectRow(i, true);
20118 * Returns True if there is a selection.
20119 * @return {Boolean}
20121 hasSelection : function(){
20122 return this.selections.length > 0;
20126 * Returns True if the specified row is selected.
20127 * @param {Number/Record} record The record or index of the record to check
20128 * @return {Boolean}
20130 isSelected : function(index){
20131 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20132 return (r && this.selections.key(r.id) ? true : false);
20136 * Returns True if the specified record id is selected.
20137 * @param {String} id The id of record to check
20138 * @return {Boolean}
20140 isIdSelected : function(id){
20141 return (this.selections.key(id) ? true : false);
20145 handleMouseDown : function(e, t){
20146 var view = this.grid.getView(), rowIndex;
20147 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20150 if(e.shiftKey && this.last !== false){
20151 var last = this.last;
20152 this.selectRange(last, rowIndex, e.ctrlKey);
20153 this.last = last; // reset the last
20154 view.focusRow(rowIndex);
20156 var isSelected = this.isSelected(rowIndex);
20157 if(e.button !== 0 && isSelected){
20158 view.focusRow(rowIndex);
20159 }else if(e.ctrlKey && isSelected){
20160 this.deselectRow(rowIndex);
20161 }else if(!isSelected){
20162 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20163 view.focusRow(rowIndex);
20166 this.fireEvent("afterselectionchange", this);
20169 handleDragableRowClick : function(grid, rowIndex, e)
20171 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20172 this.selectRow(rowIndex, false);
20173 grid.view.focusRow(rowIndex);
20174 this.fireEvent("afterselectionchange", this);
20179 * Selects multiple rows.
20180 * @param {Array} rows Array of the indexes of the row to select
20181 * @param {Boolean} keepExisting (optional) True to keep existing selections
20183 selectRows : function(rows, keepExisting){
20185 this.clearSelections();
20187 for(var i = 0, len = rows.length; i < len; i++){
20188 this.selectRow(rows[i], true);
20193 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20194 * @param {Number} startRow The index of the first row in the range
20195 * @param {Number} endRow The index of the last row in the range
20196 * @param {Boolean} keepExisting (optional) True to retain existing selections
20198 selectRange : function(startRow, endRow, keepExisting){
20199 if(this.locked) return;
20201 this.clearSelections();
20203 if(startRow <= endRow){
20204 for(var i = startRow; i <= endRow; i++){
20205 this.selectRow(i, true);
20208 for(var i = startRow; i >= endRow; i--){
20209 this.selectRow(i, true);
20215 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20216 * @param {Number} startRow The index of the first row in the range
20217 * @param {Number} endRow The index of the last row in the range
20219 deselectRange : function(startRow, endRow, preventViewNotify){
20220 if(this.locked) return;
20221 for(var i = startRow; i <= endRow; i++){
20222 this.deselectRow(i, preventViewNotify);
20228 * @param {Number} row The index of the row to select
20229 * @param {Boolean} keepExisting (optional) True to keep existing selections
20231 selectRow : function(index, keepExisting, preventViewNotify){
20232 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20233 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20234 if(!keepExisting || this.singleSelect){
20235 this.clearSelections();
20237 var r = this.grid.dataSource.getAt(index);
20238 this.selections.add(r);
20239 this.last = this.lastActive = index;
20240 if(!preventViewNotify){
20241 this.grid.getView().onRowSelect(index);
20243 this.fireEvent("rowselect", this, index, r);
20244 this.fireEvent("selectionchange", this);
20250 * @param {Number} row The index of the row to deselect
20252 deselectRow : function(index, preventViewNotify){
20253 if(this.locked) return;
20254 if(this.last == index){
20257 if(this.lastActive == index){
20258 this.lastActive = false;
20260 var r = this.grid.dataSource.getAt(index);
20261 this.selections.remove(r);
20262 if(!preventViewNotify){
20263 this.grid.getView().onRowDeselect(index);
20265 this.fireEvent("rowdeselect", this, index);
20266 this.fireEvent("selectionchange", this);
20270 restoreLast : function(){
20272 this.last = this._last;
20277 acceptsNav : function(row, col, cm){
20278 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20282 onEditorKey : function(field, e){
20283 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20288 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20290 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20292 }else if(k == e.ENTER && !e.ctrlKey){
20296 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20298 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20300 }else if(k == e.ESC){
20304 g.startEditing(newCell[0], newCell[1]);
20309 * Ext JS Library 1.1.1
20310 * Copyright(c) 2006-2007, Ext JS, LLC.
20312 * Originally Released Under LGPL - original licence link has changed is not relivant.
20315 * <script type="text/javascript">
20319 * @class Roo.bootstrap.PagingToolbar
20321 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20323 * Create a new PagingToolbar
20324 * @param {Object} config The config object
20326 Roo.bootstrap.PagingToolbar = function(config)
20328 // old args format still supported... - xtype is prefered..
20329 // created from xtype...
20330 var ds = config.dataSource;
20331 this.toolbarItems = [];
20332 if (config.items) {
20333 this.toolbarItems = config.items;
20334 // config.items = [];
20337 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20344 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20348 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20350 * @cfg {Roo.data.Store} dataSource
20351 * The underlying data store providing the paged data
20354 * @cfg {String/HTMLElement/Element} container
20355 * container The id or element that will contain the toolbar
20358 * @cfg {Boolean} displayInfo
20359 * True to display the displayMsg (defaults to false)
20362 * @cfg {Number} pageSize
20363 * The number of records to display per page (defaults to 20)
20367 * @cfg {String} displayMsg
20368 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20370 displayMsg : 'Displaying {0} - {1} of {2}',
20372 * @cfg {String} emptyMsg
20373 * The message to display when no records are found (defaults to "No data to display")
20375 emptyMsg : 'No data to display',
20377 * Customizable piece of the default paging text (defaults to "Page")
20380 beforePageText : "Page",
20382 * Customizable piece of the default paging text (defaults to "of %0")
20385 afterPageText : "of {0}",
20387 * Customizable piece of the default paging text (defaults to "First Page")
20390 firstText : "First Page",
20392 * Customizable piece of the default paging text (defaults to "Previous Page")
20395 prevText : "Previous Page",
20397 * Customizable piece of the default paging text (defaults to "Next Page")
20400 nextText : "Next Page",
20402 * Customizable piece of the default paging text (defaults to "Last Page")
20405 lastText : "Last Page",
20407 * Customizable piece of the default paging text (defaults to "Refresh")
20410 refreshText : "Refresh",
20414 onRender : function(ct, position)
20416 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20417 this.navgroup.parentId = this.id;
20418 this.navgroup.onRender(this.el, null);
20419 // add the buttons to the navgroup
20421 if(this.displayInfo){
20422 Roo.log(this.el.select('ul.navbar-nav',true).first());
20423 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20424 this.displayEl = this.el.select('.x-paging-info', true).first();
20425 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20426 // this.displayEl = navel.el.select('span',true).first();
20432 Roo.each(_this.buttons, function(e){
20433 Roo.factory(e).onRender(_this.el, null);
20437 Roo.each(_this.toolbarItems, function(e) {
20438 _this.navgroup.addItem(e);
20442 this.first = this.navgroup.addItem({
20443 tooltip: this.firstText,
20445 icon : 'fa fa-backward',
20447 preventDefault: true,
20448 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20451 this.prev = this.navgroup.addItem({
20452 tooltip: this.prevText,
20454 icon : 'fa fa-step-backward',
20456 preventDefault: true,
20457 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20459 //this.addSeparator();
20462 var field = this.navgroup.addItem( {
20464 cls : 'x-paging-position',
20466 html : this.beforePageText +
20467 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20468 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20471 this.field = field.el.select('input', true).first();
20472 this.field.on("keydown", this.onPagingKeydown, this);
20473 this.field.on("focus", function(){this.dom.select();});
20476 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20477 //this.field.setHeight(18);
20478 //this.addSeparator();
20479 this.next = this.navgroup.addItem({
20480 tooltip: this.nextText,
20482 html : ' <i class="fa fa-step-forward">',
20484 preventDefault: true,
20485 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20487 this.last = this.navgroup.addItem({
20488 tooltip: this.lastText,
20489 icon : 'fa fa-forward',
20492 preventDefault: true,
20493 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20495 //this.addSeparator();
20496 this.loading = this.navgroup.addItem({
20497 tooltip: this.refreshText,
20498 icon: 'fa fa-refresh',
20499 preventDefault: true,
20500 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20506 updateInfo : function(){
20507 if(this.displayEl){
20508 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20509 var msg = count == 0 ?
20513 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20515 this.displayEl.update(msg);
20520 onLoad : function(ds, r, o){
20521 this.cursor = o.params ? o.params.start : 0;
20522 var d = this.getPageData(),
20526 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20527 this.field.dom.value = ap;
20528 this.first.setDisabled(ap == 1);
20529 this.prev.setDisabled(ap == 1);
20530 this.next.setDisabled(ap == ps);
20531 this.last.setDisabled(ap == ps);
20532 this.loading.enable();
20537 getPageData : function(){
20538 var total = this.ds.getTotalCount();
20541 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20542 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20547 onLoadError : function(){
20548 this.loading.enable();
20552 onPagingKeydown : function(e){
20553 var k = e.getKey();
20554 var d = this.getPageData();
20556 var v = this.field.dom.value, pageNum;
20557 if(!v || isNaN(pageNum = parseInt(v, 10))){
20558 this.field.dom.value = d.activePage;
20561 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20562 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20565 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))
20567 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20568 this.field.dom.value = pageNum;
20569 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20572 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20574 var v = this.field.dom.value, pageNum;
20575 var increment = (e.shiftKey) ? 10 : 1;
20576 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20578 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20579 this.field.dom.value = d.activePage;
20582 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20584 this.field.dom.value = parseInt(v, 10) + increment;
20585 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20586 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20593 beforeLoad : function(){
20595 this.loading.disable();
20600 onClick : function(which){
20609 ds.load({params:{start: 0, limit: this.pageSize}});
20612 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20615 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20618 var total = ds.getTotalCount();
20619 var extra = total % this.pageSize;
20620 var lastStart = extra ? (total - extra) : total-this.pageSize;
20621 ds.load({params:{start: lastStart, limit: this.pageSize}});
20624 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20630 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20631 * @param {Roo.data.Store} store The data store to unbind
20633 unbind : function(ds){
20634 ds.un("beforeload", this.beforeLoad, this);
20635 ds.un("load", this.onLoad, this);
20636 ds.un("loadexception", this.onLoadError, this);
20637 ds.un("remove", this.updateInfo, this);
20638 ds.un("add", this.updateInfo, this);
20639 this.ds = undefined;
20643 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20644 * @param {Roo.data.Store} store The data store to bind
20646 bind : function(ds){
20647 ds.on("beforeload", this.beforeLoad, this);
20648 ds.on("load", this.onLoad, this);
20649 ds.on("loadexception", this.onLoadError, this);
20650 ds.on("remove", this.updateInfo, this);
20651 ds.on("add", this.updateInfo, this);
20662 * @class Roo.bootstrap.MessageBar
20663 * @extends Roo.bootstrap.Component
20664 * Bootstrap MessageBar class
20665 * @cfg {String} html contents of the MessageBar
20666 * @cfg {String} weight (info | success | warning | danger) default info
20667 * @cfg {String} beforeClass insert the bar before the given class
20668 * @cfg {Boolean} closable (true | false) default false
20669 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20672 * Create a new Element
20673 * @param {Object} config The config object
20676 Roo.bootstrap.MessageBar = function(config){
20677 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20680 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20686 beforeClass: 'bootstrap-sticky-wrap',
20688 getAutoCreate : function(){
20692 cls: 'alert alert-dismissable alert-' + this.weight,
20697 html: this.html || ''
20703 cfg.cls += ' alert-messages-fixed';
20717 onRender : function(ct, position)
20719 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20722 var cfg = Roo.apply({}, this.getAutoCreate());
20726 cfg.cls += ' ' + this.cls;
20729 cfg.style = this.style;
20731 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20733 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20736 this.el.select('>button.close').on('click', this.hide, this);
20742 if (!this.rendered) {
20748 this.fireEvent('show', this);
20754 if (!this.rendered) {
20760 this.fireEvent('hide', this);
20763 update : function()
20765 // var e = this.el.dom.firstChild;
20767 // if(this.closable){
20768 // e = e.nextSibling;
20771 // e.data = this.html || '';
20773 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20789 * @class Roo.bootstrap.Graph
20790 * @extends Roo.bootstrap.Component
20791 * Bootstrap Graph class
20795 @cfg {String} graphtype bar | vbar | pie
20796 @cfg {number} g_x coodinator | centre x (pie)
20797 @cfg {number} g_y coodinator | centre y (pie)
20798 @cfg {number} g_r radius (pie)
20799 @cfg {number} g_height height of the chart (respected by all elements in the set)
20800 @cfg {number} g_width width of the chart (respected by all elements in the set)
20801 @cfg {Object} title The title of the chart
20804 -opts (object) options for the chart
20806 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20807 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20809 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.
20810 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20812 o stretch (boolean)
20814 -opts (object) options for the pie
20817 o startAngle (number)
20818 o endAngle (number)
20822 * Create a new Input
20823 * @param {Object} config The config object
20826 Roo.bootstrap.Graph = function(config){
20827 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20833 * The img click event for the img.
20834 * @param {Roo.EventObject} e
20840 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20851 //g_colors: this.colors,
20858 getAutoCreate : function(){
20869 onRender : function(ct,position){
20870 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20871 this.raphael = Raphael(this.el.dom);
20873 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20874 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20875 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20876 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20878 r.text(160, 10, "Single Series Chart").attr(txtattr);
20879 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20880 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20881 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20883 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20884 r.barchart(330, 10, 300, 220, data1);
20885 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20886 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20889 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20890 // r.barchart(30, 30, 560, 250, xdata, {
20891 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20892 // axis : "0 0 1 1",
20893 // axisxlabels : xdata
20894 // //yvalues : cols,
20897 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20899 // this.load(null,xdata,{
20900 // axis : "0 0 1 1",
20901 // axisxlabels : xdata
20906 load : function(graphtype,xdata,opts){
20907 this.raphael.clear();
20909 graphtype = this.graphtype;
20914 var r = this.raphael,
20915 fin = function () {
20916 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20918 fout = function () {
20919 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20921 pfin = function() {
20922 this.sector.stop();
20923 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20926 this.label[0].stop();
20927 this.label[0].attr({ r: 7.5 });
20928 this.label[1].attr({ "font-weight": 800 });
20931 pfout = function() {
20932 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20935 this.label[0].animate({ r: 5 }, 500, "bounce");
20936 this.label[1].attr({ "font-weight": 400 });
20942 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20945 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20948 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20949 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20951 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20958 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20963 setTitle: function(o)
20968 initEvents: function() {
20971 this.el.on('click', this.onClick, this);
20975 onClick : function(e)
20977 Roo.log('img onclick');
20978 this.fireEvent('click', this, e);
20990 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20993 * @class Roo.bootstrap.dash.NumberBox
20994 * @extends Roo.bootstrap.Component
20995 * Bootstrap NumberBox class
20996 * @cfg {String} headline Box headline
20997 * @cfg {String} content Box content
20998 * @cfg {String} icon Box icon
20999 * @cfg {String} footer Footer text
21000 * @cfg {String} fhref Footer href
21003 * Create a new NumberBox
21004 * @param {Object} config The config object
21008 Roo.bootstrap.dash.NumberBox = function(config){
21009 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21013 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21022 getAutoCreate : function(){
21026 cls : 'small-box ',
21034 cls : 'roo-headline',
21035 html : this.headline
21039 cls : 'roo-content',
21040 html : this.content
21054 cls : 'ion ' + this.icon
21063 cls : 'small-box-footer',
21064 href : this.fhref || '#',
21068 cfg.cn.push(footer);
21075 onRender : function(ct,position){
21076 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21083 setHeadline: function (value)
21085 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21088 setFooter: function (value, href)
21090 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21093 this.el.select('a.small-box-footer',true).first().attr('href', href);
21098 setContent: function (value)
21100 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21103 initEvents: function()
21117 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21120 * @class Roo.bootstrap.dash.TabBox
21121 * @extends Roo.bootstrap.Component
21122 * Bootstrap TabBox class
21123 * @cfg {String} title Title of the TabBox
21124 * @cfg {String} icon Icon of the TabBox
21125 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21126 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21129 * Create a new TabBox
21130 * @param {Object} config The config object
21134 Roo.bootstrap.dash.TabBox = function(config){
21135 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21140 * When a pane is added
21141 * @param {Roo.bootstrap.dash.TabPane} pane
21145 * @event activatepane
21146 * When a pane is activated
21147 * @param {Roo.bootstrap.dash.TabPane} pane
21149 "activatepane" : true
21157 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21162 tabScrollable : false,
21164 getChildContainer : function()
21166 return this.el.select('.tab-content', true).first();
21169 getAutoCreate : function(){
21173 cls: 'pull-left header',
21181 cls: 'fa ' + this.icon
21187 cls: 'nav nav-tabs pull-right',
21193 if(this.tabScrollable){
21200 cls: 'nav nav-tabs pull-right',
21211 cls: 'nav-tabs-custom',
21216 cls: 'tab-content no-padding',
21224 initEvents : function()
21226 //Roo.log('add add pane handler');
21227 this.on('addpane', this.onAddPane, this);
21230 * Updates the box title
21231 * @param {String} html to set the title to.
21233 setTitle : function(value)
21235 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21237 onAddPane : function(pane)
21239 this.panes.push(pane);
21240 //Roo.log('addpane');
21242 // tabs are rendere left to right..
21243 if(!this.showtabs){
21247 var ctr = this.el.select('.nav-tabs', true).first();
21250 var existing = ctr.select('.nav-tab',true);
21251 var qty = existing.getCount();;
21254 var tab = ctr.createChild({
21256 cls : 'nav-tab' + (qty ? '' : ' active'),
21264 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21267 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21269 pane.el.addClass('active');
21274 onTabClick : function(ev,un,ob,pane)
21276 //Roo.log('tab - prev default');
21277 ev.preventDefault();
21280 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21281 pane.tab.addClass('active');
21282 //Roo.log(pane.title);
21283 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21284 // technically we should have a deactivate event.. but maybe add later.
21285 // and it should not de-activate the selected tab...
21286 this.fireEvent('activatepane', pane);
21287 pane.el.addClass('active');
21288 pane.fireEvent('activate');
21293 getActivePane : function()
21296 Roo.each(this.panes, function(p) {
21297 if(p.el.hasClass('active')){
21318 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21320 * @class Roo.bootstrap.TabPane
21321 * @extends Roo.bootstrap.Component
21322 * Bootstrap TabPane class
21323 * @cfg {Boolean} active (false | true) Default false
21324 * @cfg {String} title title of panel
21328 * Create a new TabPane
21329 * @param {Object} config The config object
21332 Roo.bootstrap.dash.TabPane = function(config){
21333 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21339 * When a pane is activated
21340 * @param {Roo.bootstrap.dash.TabPane} pane
21347 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21352 // the tabBox that this is attached to.
21355 getAutoCreate : function()
21363 cfg.cls += ' active';
21368 initEvents : function()
21370 //Roo.log('trigger add pane handler');
21371 this.parent().fireEvent('addpane', this)
21375 * Updates the tab title
21376 * @param {String} html to set the title to.
21378 setTitle: function(str)
21384 this.tab.select('a', true).first().dom.innerHTML = str;
21401 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21404 * @class Roo.bootstrap.menu.Menu
21405 * @extends Roo.bootstrap.Component
21406 * Bootstrap Menu class - container for Menu
21407 * @cfg {String} html Text of the menu
21408 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21409 * @cfg {String} icon Font awesome icon
21410 * @cfg {String} pos Menu align to (top | bottom) default bottom
21414 * Create a new Menu
21415 * @param {Object} config The config object
21419 Roo.bootstrap.menu.Menu = function(config){
21420 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21424 * @event beforeshow
21425 * Fires before this menu is displayed
21426 * @param {Roo.bootstrap.menu.Menu} this
21430 * @event beforehide
21431 * Fires before this menu is hidden
21432 * @param {Roo.bootstrap.menu.Menu} this
21437 * Fires after this menu is displayed
21438 * @param {Roo.bootstrap.menu.Menu} this
21443 * Fires after this menu is hidden
21444 * @param {Roo.bootstrap.menu.Menu} this
21449 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21450 * @param {Roo.bootstrap.menu.Menu} this
21451 * @param {Roo.EventObject} e
21458 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21462 weight : 'default',
21467 getChildContainer : function() {
21468 if(this.isSubMenu){
21472 return this.el.select('ul.dropdown-menu', true).first();
21475 getAutoCreate : function()
21480 cls : 'roo-menu-text',
21488 cls : 'fa ' + this.icon
21499 cls : 'dropdown-button btn btn-' + this.weight,
21504 cls : 'dropdown-toggle btn btn-' + this.weight,
21514 cls : 'dropdown-menu'
21520 if(this.pos == 'top'){
21521 cfg.cls += ' dropup';
21524 if(this.isSubMenu){
21527 cls : 'dropdown-menu'
21534 onRender : function(ct, position)
21536 this.isSubMenu = ct.hasClass('dropdown-submenu');
21538 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21541 initEvents : function()
21543 if(this.isSubMenu){
21547 this.hidden = true;
21549 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21550 this.triggerEl.on('click', this.onTriggerPress, this);
21552 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21553 this.buttonEl.on('click', this.onClick, this);
21559 if(this.isSubMenu){
21563 return this.el.select('ul.dropdown-menu', true).first();
21566 onClick : function(e)
21568 this.fireEvent("click", this, e);
21571 onTriggerPress : function(e)
21573 if (this.isVisible()) {
21580 isVisible : function(){
21581 return !this.hidden;
21586 this.fireEvent("beforeshow", this);
21588 this.hidden = false;
21589 this.el.addClass('open');
21591 Roo.get(document).on("mouseup", this.onMouseUp, this);
21593 this.fireEvent("show", this);
21600 this.fireEvent("beforehide", this);
21602 this.hidden = true;
21603 this.el.removeClass('open');
21605 Roo.get(document).un("mouseup", this.onMouseUp);
21607 this.fireEvent("hide", this);
21610 onMouseUp : function()
21624 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21627 * @class Roo.bootstrap.menu.Item
21628 * @extends Roo.bootstrap.Component
21629 * Bootstrap MenuItem class
21630 * @cfg {Boolean} submenu (true | false) default false
21631 * @cfg {String} html text of the item
21632 * @cfg {String} href the link
21633 * @cfg {Boolean} disable (true | false) default false
21634 * @cfg {Boolean} preventDefault (true | false) default true
21635 * @cfg {String} icon Font awesome icon
21636 * @cfg {String} pos Submenu align to (left | right) default right
21640 * Create a new Item
21641 * @param {Object} config The config object
21645 Roo.bootstrap.menu.Item = function(config){
21646 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21650 * Fires when the mouse is hovering over this menu
21651 * @param {Roo.bootstrap.menu.Item} this
21652 * @param {Roo.EventObject} e
21657 * Fires when the mouse exits this menu
21658 * @param {Roo.bootstrap.menu.Item} this
21659 * @param {Roo.EventObject} e
21665 * The raw click event for the entire grid.
21666 * @param {Roo.EventObject} e
21672 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21677 preventDefault: true,
21682 getAutoCreate : function()
21687 cls : 'roo-menu-item-text',
21695 cls : 'fa ' + this.icon
21704 href : this.href || '#',
21711 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21715 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21717 if(this.pos == 'left'){
21718 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21725 initEvents : function()
21727 this.el.on('mouseover', this.onMouseOver, this);
21728 this.el.on('mouseout', this.onMouseOut, this);
21730 this.el.select('a', true).first().on('click', this.onClick, this);
21734 onClick : function(e)
21736 if(this.preventDefault){
21737 e.preventDefault();
21740 this.fireEvent("click", this, e);
21743 onMouseOver : function(e)
21745 if(this.submenu && this.pos == 'left'){
21746 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21749 this.fireEvent("mouseover", this, e);
21752 onMouseOut : function(e)
21754 this.fireEvent("mouseout", this, e);
21766 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21769 * @class Roo.bootstrap.menu.Separator
21770 * @extends Roo.bootstrap.Component
21771 * Bootstrap Separator class
21774 * Create a new Separator
21775 * @param {Object} config The config object
21779 Roo.bootstrap.menu.Separator = function(config){
21780 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21783 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21785 getAutoCreate : function(){
21806 * @class Roo.bootstrap.Tooltip
21807 * Bootstrap Tooltip class
21808 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21809 * to determine which dom element triggers the tooltip.
21811 * It needs to add support for additional attributes like tooltip-position
21814 * Create a new Toolti
21815 * @param {Object} config The config object
21818 Roo.bootstrap.Tooltip = function(config){
21819 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21822 Roo.apply(Roo.bootstrap.Tooltip, {
21824 * @function init initialize tooltip monitoring.
21828 currentTip : false,
21829 currentRegion : false,
21835 Roo.get(document).on('mouseover', this.enter ,this);
21836 Roo.get(document).on('mouseout', this.leave, this);
21839 this.currentTip = new Roo.bootstrap.Tooltip();
21842 enter : function(ev)
21844 var dom = ev.getTarget();
21846 //Roo.log(['enter',dom]);
21847 var el = Roo.fly(dom);
21848 if (this.currentEl) {
21850 //Roo.log(this.currentEl);
21851 //Roo.log(this.currentEl.contains(dom));
21852 if (this.currentEl == el) {
21855 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21863 if (this.currentTip.el) {
21864 this.currentTip.el.hide(); // force hiding...
21869 // you can not look for children, as if el is the body.. then everythign is the child..
21870 if (!el.attr('tooltip')) { //
21871 if (!el.select("[tooltip]").elements.length) {
21874 // is the mouse over this child...?
21875 bindEl = el.select("[tooltip]").first();
21876 var xy = ev.getXY();
21877 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21878 //Roo.log("not in region.");
21881 //Roo.log("child element over..");
21884 this.currentEl = bindEl;
21885 this.currentTip.bind(bindEl);
21886 this.currentRegion = Roo.lib.Region.getRegion(dom);
21887 this.currentTip.enter();
21890 leave : function(ev)
21892 var dom = ev.getTarget();
21893 //Roo.log(['leave',dom]);
21894 if (!this.currentEl) {
21899 if (dom != this.currentEl.dom) {
21902 var xy = ev.getXY();
21903 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21906 // only activate leave if mouse cursor is outside... bounding box..
21911 if (this.currentTip) {
21912 this.currentTip.leave();
21914 //Roo.log('clear currentEl');
21915 this.currentEl = false;
21920 'left' : ['r-l', [-2,0], 'right'],
21921 'right' : ['l-r', [2,0], 'left'],
21922 'bottom' : ['t-b', [0,2], 'top'],
21923 'top' : [ 'b-t', [0,-2], 'bottom']
21929 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21934 delay : null, // can be { show : 300 , hide: 500}
21938 hoverState : null, //???
21940 placement : 'bottom',
21942 getAutoCreate : function(){
21949 cls : 'tooltip-arrow'
21952 cls : 'tooltip-inner'
21959 bind : function(el)
21965 enter : function () {
21967 if (this.timeout != null) {
21968 clearTimeout(this.timeout);
21971 this.hoverState = 'in';
21972 //Roo.log("enter - show");
21973 if (!this.delay || !this.delay.show) {
21978 this.timeout = setTimeout(function () {
21979 if (_t.hoverState == 'in') {
21982 }, this.delay.show);
21986 clearTimeout(this.timeout);
21988 this.hoverState = 'out';
21989 if (!this.delay || !this.delay.hide) {
21995 this.timeout = setTimeout(function () {
21996 //Roo.log("leave - timeout");
21998 if (_t.hoverState == 'out') {
22000 Roo.bootstrap.Tooltip.currentEl = false;
22008 this.render(document.body);
22011 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22013 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22015 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22017 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22019 var placement = typeof this.placement == 'function' ?
22020 this.placement.call(this, this.el, on_el) :
22023 var autoToken = /\s?auto?\s?/i;
22024 var autoPlace = autoToken.test(placement);
22026 placement = placement.replace(autoToken, '') || 'top';
22030 //this.el.setXY([0,0]);
22032 //this.el.dom.style.display='block';
22033 this.el.addClass(placement);
22035 //this.el.appendTo(on_el);
22037 var p = this.getPosition();
22038 var box = this.el.getBox();
22043 var align = Roo.bootstrap.Tooltip.alignment[placement];
22044 this.el.alignTo(this.bindEl, align[0],align[1]);
22045 //var arrow = this.el.select('.arrow',true).first();
22046 //arrow.set(align[2],
22048 this.el.addClass('in fade');
22049 this.hoverState = null;
22051 if (this.el.hasClass('fade')) {
22062 //this.el.setXY([0,0]);
22063 this.el.removeClass('in');
22079 * @class Roo.bootstrap.LocationPicker
22080 * @extends Roo.bootstrap.Component
22081 * Bootstrap LocationPicker class
22082 * @cfg {Number} latitude Position when init default 0
22083 * @cfg {Number} longitude Position when init default 0
22084 * @cfg {Number} zoom default 15
22085 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22086 * @cfg {Boolean} mapTypeControl default false
22087 * @cfg {Boolean} disableDoubleClickZoom default false
22088 * @cfg {Boolean} scrollwheel default true
22089 * @cfg {Boolean} streetViewControl default false
22090 * @cfg {Number} radius default 0
22091 * @cfg {String} locationName
22092 * @cfg {Boolean} draggable default true
22093 * @cfg {Boolean} enableAutocomplete default false
22094 * @cfg {Boolean} enableReverseGeocode default true
22095 * @cfg {String} markerTitle
22098 * Create a new LocationPicker
22099 * @param {Object} config The config object
22103 Roo.bootstrap.LocationPicker = function(config){
22105 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22110 * Fires when the picker initialized.
22111 * @param {Roo.bootstrap.LocationPicker} this
22112 * @param {Google Location} location
22116 * @event positionchanged
22117 * Fires when the picker position changed.
22118 * @param {Roo.bootstrap.LocationPicker} this
22119 * @param {Google Location} location
22121 positionchanged : true,
22124 * Fires when the map resize.
22125 * @param {Roo.bootstrap.LocationPicker} this
22130 * Fires when the map show.
22131 * @param {Roo.bootstrap.LocationPicker} this
22136 * Fires when the map hide.
22137 * @param {Roo.bootstrap.LocationPicker} this
22142 * Fires when click the map.
22143 * @param {Roo.bootstrap.LocationPicker} this
22144 * @param {Map event} e
22148 * @event mapRightClick
22149 * Fires when right click the map.
22150 * @param {Roo.bootstrap.LocationPicker} this
22151 * @param {Map event} e
22153 mapRightClick : true,
22155 * @event markerClick
22156 * Fires when click the marker.
22157 * @param {Roo.bootstrap.LocationPicker} this
22158 * @param {Map event} e
22160 markerClick : true,
22162 * @event markerRightClick
22163 * Fires when right click the marker.
22164 * @param {Roo.bootstrap.LocationPicker} this
22165 * @param {Map event} e
22167 markerRightClick : true,
22169 * @event OverlayViewDraw
22170 * Fires when OverlayView Draw
22171 * @param {Roo.bootstrap.LocationPicker} this
22173 OverlayViewDraw : true,
22175 * @event OverlayViewOnAdd
22176 * Fires when OverlayView Draw
22177 * @param {Roo.bootstrap.LocationPicker} this
22179 OverlayViewOnAdd : true,
22181 * @event OverlayViewOnRemove
22182 * Fires when OverlayView Draw
22183 * @param {Roo.bootstrap.LocationPicker} this
22185 OverlayViewOnRemove : true,
22187 * @event OverlayViewShow
22188 * Fires when OverlayView Draw
22189 * @param {Roo.bootstrap.LocationPicker} this
22190 * @param {Pixel} cpx
22192 OverlayViewShow : true,
22194 * @event OverlayViewHide
22195 * Fires when OverlayView Draw
22196 * @param {Roo.bootstrap.LocationPicker} this
22198 OverlayViewHide : true
22203 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22205 gMapContext: false,
22211 mapTypeControl: false,
22212 disableDoubleClickZoom: false,
22214 streetViewControl: false,
22218 enableAutocomplete: false,
22219 enableReverseGeocode: true,
22222 getAutoCreate: function()
22227 cls: 'roo-location-picker'
22233 initEvents: function(ct, position)
22235 if(!this.el.getWidth() || this.isApplied()){
22239 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22244 initial: function()
22246 if(!this.mapTypeId){
22247 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22250 this.gMapContext = this.GMapContext();
22252 this.initOverlayView();
22254 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22258 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22259 _this.setPosition(_this.gMapContext.marker.position);
22262 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22263 _this.fireEvent('mapClick', this, event);
22267 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22268 _this.fireEvent('mapRightClick', this, event);
22272 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22273 _this.fireEvent('markerClick', this, event);
22277 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22278 _this.fireEvent('markerRightClick', this, event);
22282 this.setPosition(this.gMapContext.location);
22284 this.fireEvent('initial', this, this.gMapContext.location);
22287 initOverlayView: function()
22291 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22295 _this.fireEvent('OverlayViewDraw', _this);
22300 _this.fireEvent('OverlayViewOnAdd', _this);
22303 onRemove: function()
22305 _this.fireEvent('OverlayViewOnRemove', _this);
22308 show: function(cpx)
22310 _this.fireEvent('OverlayViewShow', _this, cpx);
22315 _this.fireEvent('OverlayViewHide', _this);
22321 fromLatLngToContainerPixel: function(event)
22323 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22326 isApplied: function()
22328 return this.getGmapContext() == false ? false : true;
22331 getGmapContext: function()
22333 return this.gMapContext
22336 GMapContext: function()
22338 var position = new google.maps.LatLng(this.latitude, this.longitude);
22340 var _map = new google.maps.Map(this.el.dom, {
22343 mapTypeId: this.mapTypeId,
22344 mapTypeControl: this.mapTypeControl,
22345 disableDoubleClickZoom: this.disableDoubleClickZoom,
22346 scrollwheel: this.scrollwheel,
22347 streetViewControl: this.streetViewControl,
22348 locationName: this.locationName,
22349 draggable: this.draggable,
22350 enableAutocomplete: this.enableAutocomplete,
22351 enableReverseGeocode: this.enableReverseGeocode
22354 var _marker = new google.maps.Marker({
22355 position: position,
22357 title: this.markerTitle,
22358 draggable: this.draggable
22365 location: position,
22366 radius: this.radius,
22367 locationName: this.locationName,
22368 addressComponents: {
22369 formatted_address: null,
22370 addressLine1: null,
22371 addressLine2: null,
22373 streetNumber: null,
22377 stateOrProvince: null
22380 domContainer: this.el.dom,
22381 geodecoder: new google.maps.Geocoder()
22385 drawCircle: function(center, radius, options)
22387 if (this.gMapContext.circle != null) {
22388 this.gMapContext.circle.setMap(null);
22392 options = Roo.apply({}, options, {
22393 strokeColor: "#0000FF",
22394 strokeOpacity: .35,
22396 fillColor: "#0000FF",
22400 options.map = this.gMapContext.map;
22401 options.radius = radius;
22402 options.center = center;
22403 this.gMapContext.circle = new google.maps.Circle(options);
22404 return this.gMapContext.circle;
22410 setPosition: function(location)
22412 this.gMapContext.location = location;
22413 this.gMapContext.marker.setPosition(location);
22414 this.gMapContext.map.panTo(location);
22415 this.drawCircle(location, this.gMapContext.radius, {});
22419 if (this.gMapContext.settings.enableReverseGeocode) {
22420 this.gMapContext.geodecoder.geocode({
22421 latLng: this.gMapContext.location
22422 }, function(results, status) {
22424 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22425 _this.gMapContext.locationName = results[0].formatted_address;
22426 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22428 _this.fireEvent('positionchanged', this, location);
22435 this.fireEvent('positionchanged', this, location);
22440 google.maps.event.trigger(this.gMapContext.map, "resize");
22442 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22444 this.fireEvent('resize', this);
22447 setPositionByLatLng: function(latitude, longitude)
22449 this.setPosition(new google.maps.LatLng(latitude, longitude));
22452 getCurrentPosition: function()
22455 latitude: this.gMapContext.location.lat(),
22456 longitude: this.gMapContext.location.lng()
22460 getAddressName: function()
22462 return this.gMapContext.locationName;
22465 getAddressComponents: function()
22467 return this.gMapContext.addressComponents;
22470 address_component_from_google_geocode: function(address_components)
22474 for (var i = 0; i < address_components.length; i++) {
22475 var component = address_components[i];
22476 if (component.types.indexOf("postal_code") >= 0) {
22477 result.postalCode = component.short_name;
22478 } else if (component.types.indexOf("street_number") >= 0) {
22479 result.streetNumber = component.short_name;
22480 } else if (component.types.indexOf("route") >= 0) {
22481 result.streetName = component.short_name;
22482 } else if (component.types.indexOf("neighborhood") >= 0) {
22483 result.city = component.short_name;
22484 } else if (component.types.indexOf("locality") >= 0) {
22485 result.city = component.short_name;
22486 } else if (component.types.indexOf("sublocality") >= 0) {
22487 result.district = component.short_name;
22488 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22489 result.stateOrProvince = component.short_name;
22490 } else if (component.types.indexOf("country") >= 0) {
22491 result.country = component.short_name;
22495 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22496 result.addressLine2 = "";
22500 setZoomLevel: function(zoom)
22502 this.gMapContext.map.setZoom(zoom);
22515 this.fireEvent('show', this);
22526 this.fireEvent('hide', this);
22531 Roo.apply(Roo.bootstrap.LocationPicker, {
22533 OverlayView : function(map, options)
22535 options = options || {};
22549 * @class Roo.bootstrap.Alert
22550 * @extends Roo.bootstrap.Component
22551 * Bootstrap Alert class
22552 * @cfg {String} title The title of alert
22553 * @cfg {String} html The content of alert
22554 * @cfg {String} weight ( success | info | warning | danger )
22555 * @cfg {String} faicon font-awesomeicon
22558 * Create a new alert
22559 * @param {Object} config The config object
22563 Roo.bootstrap.Alert = function(config){
22564 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22568 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22575 getAutoCreate : function()
22584 cls : 'roo-alert-icon'
22589 cls : 'roo-alert-title',
22594 cls : 'roo-alert-text',
22601 cfg.cn[0].cls += ' fa ' + this.faicon;
22605 cfg.cls += ' alert-' + this.weight;
22611 initEvents: function()
22613 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22616 setTitle : function(str)
22618 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22621 setText : function(str)
22623 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22626 setWeight : function(weight)
22629 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22632 this.weight = weight;
22634 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22637 setIcon : function(icon)
22640 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22645 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);