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",
10901 btnPosition : 'right',
10902 triggerList : true,
10903 showToggleBtn : true,
10904 // element that contains real text value.. (when hidden is used..)
10906 getAutoCreate : function()
10913 if(!this.tickable){
10914 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10919 * ComboBox with tickable selections
10922 var align = this.labelAlign || this.parentLabelAlign();
10925 cls : 'form-group roo-combobox-tickable' //input-group
10931 cls : 'tickable-buttons',
10936 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10943 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10950 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10957 Roo.each(buttons.cn, function(c){
10959 c.cls += ' btn-' + _this.size;
10962 if (_this.disabled) {
10973 cls: 'form-hidden-field'
10977 cls: 'select2-choices',
10981 cls: 'select2-search-field',
10993 cls: 'select2-container input-group select2-container-multi',
10998 // cls: 'typeahead typeahead-long dropdown-menu',
10999 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11004 if(this.hasFeedback && !this.allowBlank){
11008 cls: 'glyphicon form-control-feedback'
11011 combobox.cn.push(feedback);
11014 if (align ==='left' && this.fieldLabel.length) {
11016 Roo.log("left and has label");
11022 cls : 'control-label col-sm-' + this.labelWidth,
11023 html : this.fieldLabel
11027 cls : "col-sm-" + (12 - this.labelWidth),
11034 } else if ( this.fieldLabel.length) {
11040 //cls : 'input-group-addon',
11041 html : this.fieldLabel
11051 Roo.log(" no label && no align");
11058 ['xs','sm','md','lg'].map(function(size){
11059 if (settings[size]) {
11060 cfg.cls += ' col-' + size + '-' + settings[size];
11069 initEvents: function()
11073 throw "can not find store for combo";
11075 this.store = Roo.factory(this.store, Roo.data);
11078 this.initTickableEvents();
11082 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11084 if(this.hiddenName){
11086 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11088 this.hiddenField.dom.value =
11089 this.hiddenValue !== undefined ? this.hiddenValue :
11090 this.value !== undefined ? this.value : '';
11092 // prevent input submission
11093 this.el.dom.removeAttribute('name');
11094 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11099 // this.el.dom.setAttribute('autocomplete', 'off');
11102 var cls = 'x-combo-list';
11104 //this.list = new Roo.Layer({
11105 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11111 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11112 _this.list.setWidth(lw);
11115 this.list.on('mouseover', this.onViewOver, this);
11116 this.list.on('mousemove', this.onViewMove, this);
11118 this.list.on('scroll', this.onViewScroll, this);
11121 this.list.swallowEvent('mousewheel');
11122 this.assetHeight = 0;
11125 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11126 this.assetHeight += this.header.getHeight();
11129 this.innerList = this.list.createChild({cls:cls+'-inner'});
11130 this.innerList.on('mouseover', this.onViewOver, this);
11131 this.innerList.on('mousemove', this.onViewMove, this);
11132 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11134 if(this.allowBlank && !this.pageSize && !this.disableClear){
11135 this.footer = this.list.createChild({cls:cls+'-ft'});
11136 this.pageTb = new Roo.Toolbar(this.footer);
11140 this.footer = this.list.createChild({cls:cls+'-ft'});
11141 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11142 {pageSize: this.pageSize});
11146 if (this.pageTb && this.allowBlank && !this.disableClear) {
11148 this.pageTb.add(new Roo.Toolbar.Fill(), {
11149 cls: 'x-btn-icon x-btn-clear',
11151 handler: function()
11154 _this.clearValue();
11155 _this.onSelect(false, -1);
11160 this.assetHeight += this.footer.getHeight();
11165 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11168 this.view = new Roo.View(this.list, this.tpl, {
11169 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11171 //this.view.wrapEl.setDisplayed(false);
11172 this.view.on('click', this.onViewClick, this);
11176 this.store.on('beforeload', this.onBeforeLoad, this);
11177 this.store.on('load', this.onLoad, this);
11178 this.store.on('loadexception', this.onLoadException, this);
11180 if(this.resizable){
11181 this.resizer = new Roo.Resizable(this.list, {
11182 pinned:true, handles:'se'
11184 this.resizer.on('resize', function(r, w, h){
11185 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11186 this.listWidth = w;
11187 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11188 this.restrictHeight();
11190 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11193 if(!this.editable){
11194 this.editable = true;
11195 this.setEditable(false);
11200 if (typeof(this.events.add.listeners) != 'undefined') {
11202 this.addicon = this.wrap.createChild(
11203 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11205 this.addicon.on('click', function(e) {
11206 this.fireEvent('add', this);
11209 if (typeof(this.events.edit.listeners) != 'undefined') {
11211 this.editicon = this.wrap.createChild(
11212 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11213 if (this.addicon) {
11214 this.editicon.setStyle('margin-left', '40px');
11216 this.editicon.on('click', function(e) {
11218 // we fire even if inothing is selected..
11219 this.fireEvent('edit', this, this.lastData );
11225 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11226 "up" : function(e){
11227 this.inKeyMode = true;
11231 "down" : function(e){
11232 if(!this.isExpanded()){
11233 this.onTriggerClick();
11235 this.inKeyMode = true;
11240 "enter" : function(e){
11241 // this.onViewClick();
11245 if(this.fireEvent("specialkey", this, e)){
11246 this.onViewClick(false);
11252 "esc" : function(e){
11256 "tab" : function(e){
11259 if(this.fireEvent("specialkey", this, e)){
11260 this.onViewClick(false);
11268 doRelay : function(foo, bar, hname){
11269 if(hname == 'down' || this.scope.isExpanded()){
11270 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11279 this.queryDelay = Math.max(this.queryDelay || 10,
11280 this.mode == 'local' ? 10 : 250);
11283 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11285 if(this.typeAhead){
11286 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11288 if(this.editable !== false){
11289 this.inputEl().on("keyup", this.onKeyUp, this);
11291 if(this.forceSelection){
11292 this.inputEl().on('blur', this.doForce, this);
11296 this.choices = this.el.select('ul.select2-choices', true).first();
11297 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11301 initTickableEvents: function()
11305 if(this.hiddenName){
11307 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11309 this.hiddenField.dom.value =
11310 this.hiddenValue !== undefined ? this.hiddenValue :
11311 this.value !== undefined ? this.value : '';
11313 // prevent input submission
11314 this.el.dom.removeAttribute('name');
11315 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11320 // this.list = this.el.select('ul.dropdown-menu',true).first();
11322 this.choices = this.el.select('ul.select2-choices', true).first();
11323 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11324 if(this.triggerList){
11325 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11328 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11329 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11331 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11332 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11334 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11335 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11337 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11338 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11339 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11342 this.cancelBtn.hide();
11347 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11348 _this.list.setWidth(lw);
11351 this.list.on('mouseover', this.onViewOver, this);
11352 this.list.on('mousemove', this.onViewMove, this);
11354 this.list.on('scroll', this.onViewScroll, this);
11357 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>';
11360 this.view = new Roo.View(this.list, this.tpl, {
11361 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11364 //this.view.wrapEl.setDisplayed(false);
11365 this.view.on('click', this.onViewClick, this);
11369 this.store.on('beforeload', this.onBeforeLoad, this);
11370 this.store.on('load', this.onLoad, this);
11371 this.store.on('loadexception', this.onLoadException, this);
11373 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11374 // "up" : function(e){
11375 // this.inKeyMode = true;
11376 // this.selectPrev();
11379 // "down" : function(e){
11380 // if(!this.isExpanded()){
11381 // this.onTriggerClick();
11383 // this.inKeyMode = true;
11384 // this.selectNext();
11388 // "enter" : function(e){
11389 //// this.onViewClick();
11391 // this.collapse();
11393 // if(this.fireEvent("specialkey", this, e)){
11394 // this.onViewClick(false);
11400 // "esc" : function(e){
11401 // this.collapse();
11404 // "tab" : function(e){
11405 // this.collapse();
11407 // if(this.fireEvent("specialkey", this, e)){
11408 // this.onViewClick(false);
11416 // doRelay : function(foo, bar, hname){
11417 // if(hname == 'down' || this.scope.isExpanded()){
11418 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11423 // forceKeyDown: true
11427 this.queryDelay = Math.max(this.queryDelay || 10,
11428 this.mode == 'local' ? 10 : 250);
11431 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11433 if(this.typeAhead){
11434 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11439 onDestroy : function(){
11441 this.view.setStore(null);
11442 this.view.el.removeAllListeners();
11443 this.view.el.remove();
11444 this.view.purgeListeners();
11447 this.list.dom.innerHTML = '';
11451 this.store.un('beforeload', this.onBeforeLoad, this);
11452 this.store.un('load', this.onLoad, this);
11453 this.store.un('loadexception', this.onLoadException, this);
11455 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11459 fireKey : function(e){
11460 if(e.isNavKeyPress() && !this.list.isVisible()){
11461 this.fireEvent("specialkey", this, e);
11466 onResize: function(w, h){
11467 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11469 // if(typeof w != 'number'){
11470 // // we do not handle it!?!?
11473 // var tw = this.trigger.getWidth();
11474 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11475 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11477 // this.inputEl().setWidth( this.adjustWidth('input', x));
11479 // //this.trigger.setStyle('left', x+'px');
11481 // if(this.list && this.listWidth === undefined){
11482 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11483 // this.list.setWidth(lw);
11484 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11492 * Allow or prevent the user from directly editing the field text. If false is passed,
11493 * the user will only be able to select from the items defined in the dropdown list. This method
11494 * is the runtime equivalent of setting the 'editable' config option at config time.
11495 * @param {Boolean} value True to allow the user to directly edit the field text
11497 setEditable : function(value){
11498 if(value == this.editable){
11501 this.editable = value;
11503 this.inputEl().dom.setAttribute('readOnly', true);
11504 this.inputEl().on('mousedown', this.onTriggerClick, this);
11505 this.inputEl().addClass('x-combo-noedit');
11507 this.inputEl().dom.setAttribute('readOnly', false);
11508 this.inputEl().un('mousedown', this.onTriggerClick, this);
11509 this.inputEl().removeClass('x-combo-noedit');
11515 onBeforeLoad : function(combo,opts){
11516 if(!this.hasFocus){
11520 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11522 this.restrictHeight();
11523 this.selectedIndex = -1;
11527 onLoad : function(){
11529 this.hasQuery = false;
11531 if(!this.hasFocus){
11535 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11536 this.loading.hide();
11539 if(this.store.getCount() > 0){
11541 // this.restrictHeight();
11542 if(this.lastQuery == this.allQuery){
11543 if(this.editable && !this.tickable){
11544 this.inputEl().dom.select();
11548 !this.selectByValue(this.value, true) &&
11549 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11550 this.store.lastOptions.add != true)
11552 this.select(0, true);
11555 if(this.autoFocus){
11558 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11559 this.taTask.delay(this.typeAheadDelay);
11563 this.onEmptyResults();
11569 onLoadException : function()
11571 this.hasQuery = false;
11573 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11574 this.loading.hide();
11578 Roo.log(this.store.reader.jsonData);
11579 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11581 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11587 onTypeAhead : function(){
11588 if(this.store.getCount() > 0){
11589 var r = this.store.getAt(0);
11590 var newValue = r.data[this.displayField];
11591 var len = newValue.length;
11592 var selStart = this.getRawValue().length;
11594 if(selStart != len){
11595 this.setRawValue(newValue);
11596 this.selectText(selStart, newValue.length);
11602 onSelect : function(record, index){
11604 if(this.fireEvent('beforeselect', this, record, index) !== false){
11606 this.setFromData(index > -1 ? record.data : false);
11609 this.fireEvent('select', this, record, index);
11614 * Returns the currently selected field value or empty string if no value is set.
11615 * @return {String} value The selected value
11617 getValue : function(){
11620 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11623 if(this.valueField){
11624 return typeof this.value != 'undefined' ? this.value : '';
11626 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11631 * Clears any text/value currently set in the field
11633 clearValue : function(){
11634 if(this.hiddenField){
11635 this.hiddenField.dom.value = '';
11638 this.setRawValue('');
11639 this.lastSelectionText = '';
11640 this.lastData = false;
11645 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11646 * will be displayed in the field. If the value does not match the data value of an existing item,
11647 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11648 * Otherwise the field will be blank (although the value will still be set).
11649 * @param {String} value The value to match
11651 setValue : function(v){
11658 if(this.valueField){
11659 var r = this.findRecord(this.valueField, v);
11661 text = r.data[this.displayField];
11662 }else if(this.valueNotFoundText !== undefined){
11663 text = this.valueNotFoundText;
11666 this.lastSelectionText = text;
11667 if(this.hiddenField){
11668 this.hiddenField.dom.value = v;
11670 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11674 * @property {Object} the last set data for the element
11679 * Sets the value of the field based on a object which is related to the record format for the store.
11680 * @param {Object} value the value to set as. or false on reset?
11682 setFromData : function(o){
11689 var dv = ''; // display value
11690 var vv = ''; // value value..
11692 if (this.displayField) {
11693 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11695 // this is an error condition!!!
11696 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11699 if(this.valueField){
11700 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11703 if(this.hiddenField){
11704 this.hiddenField.dom.value = vv;
11706 this.lastSelectionText = dv;
11707 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11711 // no hidden field.. - we store the value in 'value', but still display
11712 // display field!!!!
11713 this.lastSelectionText = dv;
11714 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11720 reset : function(){
11721 // overridden so that last data is reset..
11722 this.setValue(this.originalValue);
11723 this.clearInvalid();
11724 this.lastData = false;
11726 this.view.clearSelections();
11730 findRecord : function(prop, value){
11732 if(this.store.getCount() > 0){
11733 this.store.each(function(r){
11734 if(r.data[prop] == value){
11744 getName: function()
11746 // returns hidden if it's set..
11747 if (!this.rendered) {return ''};
11748 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11752 onViewMove : function(e, t){
11753 this.inKeyMode = false;
11757 onViewOver : function(e, t){
11758 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11761 var item = this.view.findItemFromChild(t);
11764 var index = this.view.indexOf(item);
11765 this.select(index, false);
11770 onViewClick : function(view, doFocus, el, e)
11772 var index = this.view.getSelectedIndexes()[0];
11774 var r = this.store.getAt(index);
11778 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11785 Roo.each(this.tickItems, function(v,k){
11787 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11788 _this.tickItems.splice(k, 1);
11798 this.tickItems.push(r.data);
11803 this.onSelect(r, index);
11805 if(doFocus !== false && !this.blockFocus){
11806 this.inputEl().focus();
11811 restrictHeight : function(){
11812 //this.innerList.dom.style.height = '';
11813 //var inner = this.innerList.dom;
11814 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11815 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11816 //this.list.beginUpdate();
11817 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11818 this.list.alignTo(this.inputEl(), this.listAlign);
11819 this.list.alignTo(this.inputEl(), this.listAlign);
11820 //this.list.endUpdate();
11824 onEmptyResults : function(){
11829 * Returns true if the dropdown list is expanded, else false.
11831 isExpanded : function(){
11832 return this.list.isVisible();
11836 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11837 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11838 * @param {String} value The data value of the item to select
11839 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11840 * selected item if it is not currently in view (defaults to true)
11841 * @return {Boolean} True if the value matched an item in the list, else false
11843 selectByValue : function(v, scrollIntoView){
11844 if(v !== undefined && v !== null){
11845 var r = this.findRecord(this.valueField || this.displayField, v);
11847 this.select(this.store.indexOf(r), scrollIntoView);
11855 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11856 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11857 * @param {Number} index The zero-based index of the list item to select
11858 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11859 * selected item if it is not currently in view (defaults to true)
11861 select : function(index, scrollIntoView){
11862 this.selectedIndex = index;
11863 this.view.select(index);
11864 if(scrollIntoView !== false){
11865 var el = this.view.getNode(index);
11866 if(el && !this.multiple && !this.tickable){
11867 this.list.scrollChildIntoView(el, false);
11873 selectNext : function(){
11874 var ct = this.store.getCount();
11876 if(this.selectedIndex == -1){
11878 }else if(this.selectedIndex < ct-1){
11879 this.select(this.selectedIndex+1);
11885 selectPrev : function(){
11886 var ct = this.store.getCount();
11888 if(this.selectedIndex == -1){
11890 }else if(this.selectedIndex != 0){
11891 this.select(this.selectedIndex-1);
11897 onKeyUp : function(e){
11898 if(this.editable !== false && !e.isSpecialKey()){
11899 this.lastKey = e.getKey();
11900 this.dqTask.delay(this.queryDelay);
11905 validateBlur : function(){
11906 return !this.list || !this.list.isVisible();
11910 initQuery : function(){
11911 this.doQuery(this.getRawValue());
11915 doForce : function(){
11916 if(this.inputEl().dom.value.length > 0){
11917 this.inputEl().dom.value =
11918 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11924 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11925 * query allowing the query action to be canceled if needed.
11926 * @param {String} query The SQL query to execute
11927 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11928 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11929 * saved in the current store (defaults to false)
11931 doQuery : function(q, forceAll){
11933 if(q === undefined || q === null){
11938 forceAll: forceAll,
11942 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11947 forceAll = qe.forceAll;
11948 if(forceAll === true || (q.length >= this.minChars)){
11950 this.hasQuery = true;
11952 if(this.lastQuery != q || this.alwaysQuery){
11953 this.lastQuery = q;
11954 if(this.mode == 'local'){
11955 this.selectedIndex = -1;
11957 this.store.clearFilter();
11959 this.store.filter(this.displayField, q);
11963 this.store.baseParams[this.queryParam] = q;
11965 var options = {params : this.getParams(q)};
11968 options.add = true;
11969 options.params.start = this.page * this.pageSize;
11972 this.store.load(options);
11974 * this code will make the page width larger, at the beginning, the list not align correctly,
11975 * we should expand the list on onLoad
11976 * so command out it
11981 this.selectedIndex = -1;
11986 this.loadNext = false;
11990 getParams : function(q){
11992 //p[this.queryParam] = q;
11996 p.limit = this.pageSize;
12002 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12004 collapse : function(){
12005 if(!this.isExpanded()){
12012 this.hasFocus = false;
12014 this.cancelBtn.hide();
12015 this.trigger.show();
12018 Roo.get(document).un('mousedown', this.collapseIf, this);
12019 Roo.get(document).un('mousewheel', this.collapseIf, this);
12020 if (!this.editable) {
12021 Roo.get(document).un('keydown', this.listKeyPress, this);
12023 this.fireEvent('collapse', this);
12027 collapseIf : function(e){
12028 var in_combo = e.within(this.el);
12029 var in_list = e.within(this.list);
12030 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12032 if (in_combo || in_list || is_list) {
12033 //e.stopPropagation();
12038 this.onTickableFooterButtonClick(e, false, false);
12046 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12048 expand : function(){
12050 if(this.isExpanded() || !this.hasFocus){
12054 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12055 this.list.setWidth(lw);
12062 this.restrictHeight();
12066 this.tickItems = Roo.apply([], this.item);
12069 this.cancelBtn.show();
12070 this.trigger.hide();
12074 Roo.get(document).on('mousedown', this.collapseIf, this);
12075 Roo.get(document).on('mousewheel', this.collapseIf, this);
12076 if (!this.editable) {
12077 Roo.get(document).on('keydown', this.listKeyPress, this);
12080 this.fireEvent('expand', this);
12084 // Implements the default empty TriggerField.onTriggerClick function
12085 onTriggerClick : function(e)
12087 Roo.log('trigger click');
12089 if(this.disabled || !this.triggerList){
12094 this.loadNext = false;
12096 if(this.isExpanded()){
12098 if (!this.blockFocus) {
12099 this.inputEl().focus();
12103 this.hasFocus = true;
12104 if(this.triggerAction == 'all') {
12105 this.doQuery(this.allQuery, true);
12107 this.doQuery(this.getRawValue());
12109 if (!this.blockFocus) {
12110 this.inputEl().focus();
12115 onTickableTriggerClick : function(e)
12122 this.loadNext = false;
12123 this.hasFocus = true;
12125 if(this.triggerAction == 'all') {
12126 this.doQuery(this.allQuery, true);
12128 this.doQuery(this.getRawValue());
12132 onSearchFieldClick : function(e)
12134 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12135 this.onTickableFooterButtonClick(e, false, false);
12139 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12144 this.loadNext = false;
12145 this.hasFocus = true;
12147 if(this.triggerAction == 'all') {
12148 this.doQuery(this.allQuery, true);
12150 this.doQuery(this.getRawValue());
12154 listKeyPress : function(e)
12156 //Roo.log('listkeypress');
12157 // scroll to first matching element based on key pres..
12158 if (e.isSpecialKey()) {
12161 var k = String.fromCharCode(e.getKey()).toUpperCase();
12164 var csel = this.view.getSelectedNodes();
12165 var cselitem = false;
12167 var ix = this.view.indexOf(csel[0]);
12168 cselitem = this.store.getAt(ix);
12169 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12175 this.store.each(function(v) {
12177 // start at existing selection.
12178 if (cselitem.id == v.id) {
12184 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12185 match = this.store.indexOf(v);
12191 if (match === false) {
12192 return true; // no more action?
12195 this.view.select(match);
12196 var sn = Roo.get(this.view.getSelectedNodes()[0])
12197 sn.scrollIntoView(sn.dom.parentNode, false);
12200 onViewScroll : function(e, t){
12202 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){
12206 this.hasQuery = true;
12208 this.loading = this.list.select('.loading', true).first();
12210 if(this.loading === null){
12211 this.list.createChild({
12213 cls: 'loading select2-more-results select2-active',
12214 html: 'Loading more results...'
12217 this.loading = this.list.select('.loading', true).first();
12219 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12221 this.loading.hide();
12224 this.loading.show();
12229 this.loadNext = true;
12231 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12236 addItem : function(o)
12238 var dv = ''; // display value
12240 if (this.displayField) {
12241 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12243 // this is an error condition!!!
12244 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12251 var choice = this.choices.createChild({
12253 cls: 'select2-search-choice',
12262 cls: 'select2-search-choice-close',
12267 }, this.searchField);
12269 var close = choice.select('a.select2-search-choice-close', true).first()
12271 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12279 this.inputEl().dom.value = '';
12284 onRemoveItem : function(e, _self, o)
12286 e.preventDefault();
12288 this.lastItem = Roo.apply([], this.item);
12290 var index = this.item.indexOf(o.data) * 1;
12293 Roo.log('not this item?!');
12297 this.item.splice(index, 1);
12302 this.fireEvent('remove', this, e);
12308 syncValue : function()
12310 if(!this.item.length){
12317 Roo.each(this.item, function(i){
12318 if(_this.valueField){
12319 value.push(i[_this.valueField]);
12326 this.value = value.join(',');
12328 if(this.hiddenField){
12329 this.hiddenField.dom.value = this.value;
12333 clearItem : function()
12335 if(!this.multiple){
12341 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12350 inputEl: function ()
12353 return this.searchField;
12355 return this.el.select('input.form-control',true).first();
12359 onTickableFooterButtonClick : function(e, btn, el)
12361 e.preventDefault();
12363 this.lastItem = Roo.apply([], this.item);
12365 if(btn && btn.name == 'cancel'){
12366 this.tickItems = Roo.apply([], this.item);
12375 Roo.each(this.tickItems, function(o){
12383 validate : function()
12385 var v = this.getRawValue();
12388 v = this.getValue();
12391 if(this.disabled || this.allowBlank || v.length){
12396 this.markInvalid();
12403 * @cfg {Boolean} grow
12407 * @cfg {Number} growMin
12411 * @cfg {Number} growMax
12421 * Ext JS Library 1.1.1
12422 * Copyright(c) 2006-2007, Ext JS, LLC.
12424 * Originally Released Under LGPL - original licence link has changed is not relivant.
12427 * <script type="text/javascript">
12432 * @extends Roo.util.Observable
12433 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12434 * This class also supports single and multi selection modes. <br>
12435 * Create a data model bound view:
12437 var store = new Roo.data.Store(...);
12439 var view = new Roo.View({
12441 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12443 singleSelect: true,
12444 selectedClass: "ydataview-selected",
12448 // listen for node click?
12449 view.on("click", function(vw, index, node, e){
12450 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12454 dataModel.load("foobar.xml");
12456 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12458 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12459 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12461 * Note: old style constructor is still suported (container, template, config)
12464 * Create a new View
12465 * @param {Object} config The config object
12468 Roo.View = function(config, depreciated_tpl, depreciated_config){
12470 this.parent = false;
12472 if (typeof(depreciated_tpl) == 'undefined') {
12473 // new way.. - universal constructor.
12474 Roo.apply(this, config);
12475 this.el = Roo.get(this.el);
12478 this.el = Roo.get(config);
12479 this.tpl = depreciated_tpl;
12480 Roo.apply(this, depreciated_config);
12482 this.wrapEl = this.el.wrap().wrap();
12483 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12486 if(typeof(this.tpl) == "string"){
12487 this.tpl = new Roo.Template(this.tpl);
12489 // support xtype ctors..
12490 this.tpl = new Roo.factory(this.tpl, Roo);
12494 this.tpl.compile();
12499 * @event beforeclick
12500 * Fires before a click is processed. Returns false to cancel the default action.
12501 * @param {Roo.View} this
12502 * @param {Number} index The index of the target node
12503 * @param {HTMLElement} node The target node
12504 * @param {Roo.EventObject} e The raw event object
12506 "beforeclick" : true,
12509 * Fires when a template node is clicked.
12510 * @param {Roo.View} this
12511 * @param {Number} index The index of the target node
12512 * @param {HTMLElement} node The target node
12513 * @param {Roo.EventObject} e The raw event object
12518 * Fires when a template node is double clicked.
12519 * @param {Roo.View} this
12520 * @param {Number} index The index of the target node
12521 * @param {HTMLElement} node The target node
12522 * @param {Roo.EventObject} e The raw event object
12526 * @event contextmenu
12527 * Fires when a template node is right clicked.
12528 * @param {Roo.View} this
12529 * @param {Number} index The index of the target node
12530 * @param {HTMLElement} node The target node
12531 * @param {Roo.EventObject} e The raw event object
12533 "contextmenu" : true,
12535 * @event selectionchange
12536 * Fires when the selected nodes change.
12537 * @param {Roo.View} this
12538 * @param {Array} selections Array of the selected nodes
12540 "selectionchange" : true,
12543 * @event beforeselect
12544 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12545 * @param {Roo.View} this
12546 * @param {HTMLElement} node The node to be selected
12547 * @param {Array} selections Array of currently selected nodes
12549 "beforeselect" : true,
12551 * @event preparedata
12552 * Fires on every row to render, to allow you to change the data.
12553 * @param {Roo.View} this
12554 * @param {Object} data to be rendered (change this)
12556 "preparedata" : true
12564 "click": this.onClick,
12565 "dblclick": this.onDblClick,
12566 "contextmenu": this.onContextMenu,
12570 this.selections = [];
12572 this.cmp = new Roo.CompositeElementLite([]);
12574 this.store = Roo.factory(this.store, Roo.data);
12575 this.setStore(this.store, true);
12578 if ( this.footer && this.footer.xtype) {
12580 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12582 this.footer.dataSource = this.store
12583 this.footer.container = fctr;
12584 this.footer = Roo.factory(this.footer, Roo);
12585 fctr.insertFirst(this.el);
12587 // this is a bit insane - as the paging toolbar seems to detach the el..
12588 // dom.parentNode.parentNode.parentNode
12589 // they get detached?
12593 Roo.View.superclass.constructor.call(this);
12598 Roo.extend(Roo.View, Roo.util.Observable, {
12601 * @cfg {Roo.data.Store} store Data store to load data from.
12606 * @cfg {String|Roo.Element} el The container element.
12611 * @cfg {String|Roo.Template} tpl The template used by this View
12615 * @cfg {String} dataName the named area of the template to use as the data area
12616 * Works with domtemplates roo-name="name"
12620 * @cfg {String} selectedClass The css class to add to selected nodes
12622 selectedClass : "x-view-selected",
12624 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12629 * @cfg {String} text to display on mask (default Loading)
12633 * @cfg {Boolean} multiSelect Allow multiple selection
12635 multiSelect : false,
12637 * @cfg {Boolean} singleSelect Allow single selection
12639 singleSelect: false,
12642 * @cfg {Boolean} toggleSelect - selecting
12644 toggleSelect : false,
12647 * @cfg {Boolean} tickable - selecting
12652 * Returns the element this view is bound to.
12653 * @return {Roo.Element}
12655 getEl : function(){
12656 return this.wrapEl;
12662 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12664 refresh : function(){
12665 //Roo.log('refresh');
12668 // if we are using something like 'domtemplate', then
12669 // the what gets used is:
12670 // t.applySubtemplate(NAME, data, wrapping data..)
12671 // the outer template then get' applied with
12672 // the store 'extra data'
12673 // and the body get's added to the
12674 // roo-name="data" node?
12675 // <span class='roo-tpl-{name}'></span> ?????
12679 this.clearSelections();
12680 this.el.update("");
12682 var records = this.store.getRange();
12683 if(records.length < 1) {
12685 // is this valid?? = should it render a template??
12687 this.el.update(this.emptyText);
12691 if (this.dataName) {
12692 this.el.update(t.apply(this.store.meta)); //????
12693 el = this.el.child('.roo-tpl-' + this.dataName);
12696 for(var i = 0, len = records.length; i < len; i++){
12697 var data = this.prepareData(records[i].data, i, records[i]);
12698 this.fireEvent("preparedata", this, data, i, records[i]);
12700 var d = Roo.apply({}, data);
12703 Roo.apply(d, {'roo-id' : Roo.id()});
12707 Roo.each(this.parent.item, function(item){
12708 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12711 Roo.apply(d, {'roo-data-checked' : 'checked'});
12715 html[html.length] = Roo.util.Format.trim(
12717 t.applySubtemplate(this.dataName, d, this.store.meta) :
12724 el.update(html.join(""));
12725 this.nodes = el.dom.childNodes;
12726 this.updateIndexes(0);
12731 * Function to override to reformat the data that is sent to
12732 * the template for each node.
12733 * DEPRICATED - use the preparedata event handler.
12734 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12735 * a JSON object for an UpdateManager bound view).
12737 prepareData : function(data, index, record)
12739 this.fireEvent("preparedata", this, data, index, record);
12743 onUpdate : function(ds, record){
12744 // Roo.log('on update');
12745 this.clearSelections();
12746 var index = this.store.indexOf(record);
12747 var n = this.nodes[index];
12748 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12749 n.parentNode.removeChild(n);
12750 this.updateIndexes(index, index);
12756 onAdd : function(ds, records, index)
12758 //Roo.log(['on Add', ds, records, index] );
12759 this.clearSelections();
12760 if(this.nodes.length == 0){
12764 var n = this.nodes[index];
12765 for(var i = 0, len = records.length; i < len; i++){
12766 var d = this.prepareData(records[i].data, i, records[i]);
12768 this.tpl.insertBefore(n, d);
12771 this.tpl.append(this.el, d);
12774 this.updateIndexes(index);
12777 onRemove : function(ds, record, index){
12778 // Roo.log('onRemove');
12779 this.clearSelections();
12780 var el = this.dataName ?
12781 this.el.child('.roo-tpl-' + this.dataName) :
12784 el.dom.removeChild(this.nodes[index]);
12785 this.updateIndexes(index);
12789 * Refresh an individual node.
12790 * @param {Number} index
12792 refreshNode : function(index){
12793 this.onUpdate(this.store, this.store.getAt(index));
12796 updateIndexes : function(startIndex, endIndex){
12797 var ns = this.nodes;
12798 startIndex = startIndex || 0;
12799 endIndex = endIndex || ns.length - 1;
12800 for(var i = startIndex; i <= endIndex; i++){
12801 ns[i].nodeIndex = i;
12806 * Changes the data store this view uses and refresh the view.
12807 * @param {Store} store
12809 setStore : function(store, initial){
12810 if(!initial && this.store){
12811 this.store.un("datachanged", this.refresh);
12812 this.store.un("add", this.onAdd);
12813 this.store.un("remove", this.onRemove);
12814 this.store.un("update", this.onUpdate);
12815 this.store.un("clear", this.refresh);
12816 this.store.un("beforeload", this.onBeforeLoad);
12817 this.store.un("load", this.onLoad);
12818 this.store.un("loadexception", this.onLoad);
12822 store.on("datachanged", this.refresh, this);
12823 store.on("add", this.onAdd, this);
12824 store.on("remove", this.onRemove, this);
12825 store.on("update", this.onUpdate, this);
12826 store.on("clear", this.refresh, this);
12827 store.on("beforeload", this.onBeforeLoad, this);
12828 store.on("load", this.onLoad, this);
12829 store.on("loadexception", this.onLoad, this);
12837 * onbeforeLoad - masks the loading area.
12840 onBeforeLoad : function(store,opts)
12842 //Roo.log('onBeforeLoad');
12844 this.el.update("");
12846 this.el.mask(this.mask ? this.mask : "Loading" );
12848 onLoad : function ()
12855 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12856 * @param {HTMLElement} node
12857 * @return {HTMLElement} The template node
12859 findItemFromChild : function(node){
12860 var el = this.dataName ?
12861 this.el.child('.roo-tpl-' + this.dataName,true) :
12864 if(!node || node.parentNode == el){
12867 var p = node.parentNode;
12868 while(p && p != el){
12869 if(p.parentNode == el){
12878 onClick : function(e){
12879 var item = this.findItemFromChild(e.getTarget());
12881 var index = this.indexOf(item);
12882 if(this.onItemClick(item, index, e) !== false){
12883 this.fireEvent("click", this, index, item, e);
12886 this.clearSelections();
12891 onContextMenu : function(e){
12892 var item = this.findItemFromChild(e.getTarget());
12894 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12899 onDblClick : function(e){
12900 var item = this.findItemFromChild(e.getTarget());
12902 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12906 onItemClick : function(item, index, e)
12908 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12911 if (this.toggleSelect) {
12912 var m = this.isSelected(item) ? 'unselect' : 'select';
12915 _t[m](item, true, false);
12918 if(this.multiSelect || this.singleSelect){
12919 if(this.multiSelect && e.shiftKey && this.lastSelection){
12920 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12922 this.select(item, this.multiSelect && e.ctrlKey);
12923 this.lastSelection = item;
12926 if(!this.tickable){
12927 e.preventDefault();
12935 * Get the number of selected nodes.
12938 getSelectionCount : function(){
12939 return this.selections.length;
12943 * Get the currently selected nodes.
12944 * @return {Array} An array of HTMLElements
12946 getSelectedNodes : function(){
12947 return this.selections;
12951 * Get the indexes of the selected nodes.
12954 getSelectedIndexes : function(){
12955 var indexes = [], s = this.selections;
12956 for(var i = 0, len = s.length; i < len; i++){
12957 indexes.push(s[i].nodeIndex);
12963 * Clear all selections
12964 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12966 clearSelections : function(suppressEvent){
12967 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12968 this.cmp.elements = this.selections;
12969 this.cmp.removeClass(this.selectedClass);
12970 this.selections = [];
12971 if(!suppressEvent){
12972 this.fireEvent("selectionchange", this, this.selections);
12978 * Returns true if the passed node is selected
12979 * @param {HTMLElement/Number} node The node or node index
12980 * @return {Boolean}
12982 isSelected : function(node){
12983 var s = this.selections;
12987 node = this.getNode(node);
12988 return s.indexOf(node) !== -1;
12993 * @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
12994 * @param {Boolean} keepExisting (optional) true to keep existing selections
12995 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12997 select : function(nodeInfo, keepExisting, suppressEvent){
12998 if(nodeInfo instanceof Array){
13000 this.clearSelections(true);
13002 for(var i = 0, len = nodeInfo.length; i < len; i++){
13003 this.select(nodeInfo[i], true, true);
13007 var node = this.getNode(nodeInfo);
13008 if(!node || this.isSelected(node)){
13009 return; // already selected.
13012 this.clearSelections(true);
13015 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13016 Roo.fly(node).addClass(this.selectedClass);
13017 this.selections.push(node);
13018 if(!suppressEvent){
13019 this.fireEvent("selectionchange", this, this.selections);
13027 * @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
13028 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13029 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13031 unselect : function(nodeInfo, keepExisting, suppressEvent)
13033 if(nodeInfo instanceof Array){
13034 Roo.each(this.selections, function(s) {
13035 this.unselect(s, nodeInfo);
13039 var node = this.getNode(nodeInfo);
13040 if(!node || !this.isSelected(node)){
13041 //Roo.log("not selected");
13042 return; // not selected.
13046 Roo.each(this.selections, function(s) {
13048 Roo.fly(node).removeClass(this.selectedClass);
13055 this.selections= ns;
13056 this.fireEvent("selectionchange", this, this.selections);
13060 * Gets a template node.
13061 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13062 * @return {HTMLElement} The node or null if it wasn't found
13064 getNode : function(nodeInfo){
13065 if(typeof nodeInfo == "string"){
13066 return document.getElementById(nodeInfo);
13067 }else if(typeof nodeInfo == "number"){
13068 return this.nodes[nodeInfo];
13074 * Gets a range template nodes.
13075 * @param {Number} startIndex
13076 * @param {Number} endIndex
13077 * @return {Array} An array of nodes
13079 getNodes : function(start, end){
13080 var ns = this.nodes;
13081 start = start || 0;
13082 end = typeof end == "undefined" ? ns.length - 1 : end;
13085 for(var i = start; i <= end; i++){
13089 for(var i = start; i >= end; i--){
13097 * Finds the index of the passed node
13098 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13099 * @return {Number} The index of the node or -1
13101 indexOf : function(node){
13102 node = this.getNode(node);
13103 if(typeof node.nodeIndex == "number"){
13104 return node.nodeIndex;
13106 var ns = this.nodes;
13107 for(var i = 0, len = ns.length; i < len; i++){
13118 * based on jquery fullcalendar
13122 Roo.bootstrap = Roo.bootstrap || {};
13124 * @class Roo.bootstrap.Calendar
13125 * @extends Roo.bootstrap.Component
13126 * Bootstrap Calendar class
13127 * @cfg {Boolean} loadMask (true|false) default false
13128 * @cfg {Object} header generate the user specific header of the calendar, default false
13131 * Create a new Container
13132 * @param {Object} config The config object
13137 Roo.bootstrap.Calendar = function(config){
13138 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13142 * Fires when a date is selected
13143 * @param {DatePicker} this
13144 * @param {Date} date The selected date
13148 * @event monthchange
13149 * Fires when the displayed month changes
13150 * @param {DatePicker} this
13151 * @param {Date} date The selected month
13153 'monthchange': true,
13155 * @event evententer
13156 * Fires when mouse over an event
13157 * @param {Calendar} this
13158 * @param {event} Event
13160 'evententer': true,
13162 * @event eventleave
13163 * Fires when the mouse leaves an
13164 * @param {Calendar} this
13167 'eventleave': true,
13169 * @event eventclick
13170 * Fires when the mouse click an
13171 * @param {Calendar} this
13180 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13183 * @cfg {Number} startDay
13184 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13192 getAutoCreate : function(){
13195 var fc_button = function(name, corner, style, content ) {
13196 return Roo.apply({},{
13198 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13200 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13203 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13214 style : 'width:100%',
13221 cls : 'fc-header-left',
13223 fc_button('prev', 'left', 'arrow', '‹' ),
13224 fc_button('next', 'right', 'arrow', '›' ),
13225 { tag: 'span', cls: 'fc-header-space' },
13226 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13234 cls : 'fc-header-center',
13238 cls: 'fc-header-title',
13241 html : 'month / year'
13249 cls : 'fc-header-right',
13251 /* fc_button('month', 'left', '', 'month' ),
13252 fc_button('week', '', '', 'week' ),
13253 fc_button('day', 'right', '', 'day' )
13265 header = this.header;
13268 var cal_heads = function() {
13270 // fixme - handle this.
13272 for (var i =0; i < Date.dayNames.length; i++) {
13273 var d = Date.dayNames[i];
13276 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13277 html : d.substring(0,3)
13281 ret[0].cls += ' fc-first';
13282 ret[6].cls += ' fc-last';
13285 var cal_cell = function(n) {
13288 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13293 cls: 'fc-day-number',
13297 cls: 'fc-day-content',
13301 style: 'position: relative;' // height: 17px;
13313 var cal_rows = function() {
13316 for (var r = 0; r < 6; r++) {
13323 for (var i =0; i < Date.dayNames.length; i++) {
13324 var d = Date.dayNames[i];
13325 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13328 row.cn[0].cls+=' fc-first';
13329 row.cn[0].cn[0].style = 'min-height:90px';
13330 row.cn[6].cls+=' fc-last';
13334 ret[0].cls += ' fc-first';
13335 ret[4].cls += ' fc-prev-last';
13336 ret[5].cls += ' fc-last';
13343 cls: 'fc-border-separate',
13344 style : 'width:100%',
13352 cls : 'fc-first fc-last',
13370 cls : 'fc-content',
13371 style : "position: relative;",
13374 cls : 'fc-view fc-view-month fc-grid',
13375 style : 'position: relative',
13376 unselectable : 'on',
13379 cls : 'fc-event-container',
13380 style : 'position:absolute;z-index:8;top:0;left:0;'
13398 initEvents : function()
13401 throw "can not find store for calendar";
13407 style: "text-align:center",
13411 style: "background-color:white;width:50%;margin:250 auto",
13415 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13426 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13428 var size = this.el.select('.fc-content', true).first().getSize();
13429 this.maskEl.setSize(size.width, size.height);
13430 this.maskEl.enableDisplayMode("block");
13431 if(!this.loadMask){
13432 this.maskEl.hide();
13435 this.store = Roo.factory(this.store, Roo.data);
13436 this.store.on('load', this.onLoad, this);
13437 this.store.on('beforeload', this.onBeforeLoad, this);
13441 this.cells = this.el.select('.fc-day',true);
13442 //Roo.log(this.cells);
13443 this.textNodes = this.el.query('.fc-day-number');
13444 this.cells.addClassOnOver('fc-state-hover');
13446 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13447 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13448 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13449 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13451 this.on('monthchange', this.onMonthChange, this);
13453 this.update(new Date().clearTime());
13456 resize : function() {
13457 var sz = this.el.getSize();
13459 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13460 this.el.select('.fc-day-content div',true).setHeight(34);
13465 showPrevMonth : function(e){
13466 this.update(this.activeDate.add("mo", -1));
13468 showToday : function(e){
13469 this.update(new Date().clearTime());
13472 showNextMonth : function(e){
13473 this.update(this.activeDate.add("mo", 1));
13477 showPrevYear : function(){
13478 this.update(this.activeDate.add("y", -1));
13482 showNextYear : function(){
13483 this.update(this.activeDate.add("y", 1));
13488 update : function(date)
13490 var vd = this.activeDate;
13491 this.activeDate = date;
13492 // if(vd && this.el){
13493 // var t = date.getTime();
13494 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13495 // Roo.log('using add remove');
13497 // this.fireEvent('monthchange', this, date);
13499 // this.cells.removeClass("fc-state-highlight");
13500 // this.cells.each(function(c){
13501 // if(c.dateValue == t){
13502 // c.addClass("fc-state-highlight");
13503 // setTimeout(function(){
13504 // try{c.dom.firstChild.focus();}catch(e){}
13514 var days = date.getDaysInMonth();
13516 var firstOfMonth = date.getFirstDateOfMonth();
13517 var startingPos = firstOfMonth.getDay()-this.startDay;
13519 if(startingPos < this.startDay){
13523 var pm = date.add(Date.MONTH, -1);
13524 var prevStart = pm.getDaysInMonth()-startingPos;
13526 this.cells = this.el.select('.fc-day',true);
13527 this.textNodes = this.el.query('.fc-day-number');
13528 this.cells.addClassOnOver('fc-state-hover');
13530 var cells = this.cells.elements;
13531 var textEls = this.textNodes;
13533 Roo.each(cells, function(cell){
13534 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13537 days += startingPos;
13539 // convert everything to numbers so it's fast
13540 var day = 86400000;
13541 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13544 //Roo.log(prevStart);
13546 var today = new Date().clearTime().getTime();
13547 var sel = date.clearTime().getTime();
13548 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13549 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13550 var ddMatch = this.disabledDatesRE;
13551 var ddText = this.disabledDatesText;
13552 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13553 var ddaysText = this.disabledDaysText;
13554 var format = this.format;
13556 var setCellClass = function(cal, cell){
13560 //Roo.log('set Cell Class');
13562 var t = d.getTime();
13566 cell.dateValue = t;
13568 cell.className += " fc-today";
13569 cell.className += " fc-state-highlight";
13570 cell.title = cal.todayText;
13573 // disable highlight in other month..
13574 //cell.className += " fc-state-highlight";
13579 cell.className = " fc-state-disabled";
13580 cell.title = cal.minText;
13584 cell.className = " fc-state-disabled";
13585 cell.title = cal.maxText;
13589 if(ddays.indexOf(d.getDay()) != -1){
13590 cell.title = ddaysText;
13591 cell.className = " fc-state-disabled";
13594 if(ddMatch && format){
13595 var fvalue = d.dateFormat(format);
13596 if(ddMatch.test(fvalue)){
13597 cell.title = ddText.replace("%0", fvalue);
13598 cell.className = " fc-state-disabled";
13602 if (!cell.initialClassName) {
13603 cell.initialClassName = cell.dom.className;
13606 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13611 for(; i < startingPos; i++) {
13612 textEls[i].innerHTML = (++prevStart);
13613 d.setDate(d.getDate()+1);
13615 cells[i].className = "fc-past fc-other-month";
13616 setCellClass(this, cells[i]);
13621 for(; i < days; i++){
13622 intDay = i - startingPos + 1;
13623 textEls[i].innerHTML = (intDay);
13624 d.setDate(d.getDate()+1);
13626 cells[i].className = ''; // "x-date-active";
13627 setCellClass(this, cells[i]);
13631 for(; i < 42; i++) {
13632 textEls[i].innerHTML = (++extraDays);
13633 d.setDate(d.getDate()+1);
13635 cells[i].className = "fc-future fc-other-month";
13636 setCellClass(this, cells[i]);
13639 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13641 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13643 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13644 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13646 if(totalRows != 6){
13647 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13648 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13651 this.fireEvent('monthchange', this, date);
13655 if(!this.internalRender){
13656 var main = this.el.dom.firstChild;
13657 var w = main.offsetWidth;
13658 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13659 Roo.fly(main).setWidth(w);
13660 this.internalRender = true;
13661 // opera does not respect the auto grow header center column
13662 // then, after it gets a width opera refuses to recalculate
13663 // without a second pass
13664 if(Roo.isOpera && !this.secondPass){
13665 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13666 this.secondPass = true;
13667 this.update.defer(10, this, [date]);
13674 findCell : function(dt) {
13675 dt = dt.clearTime().getTime();
13677 this.cells.each(function(c){
13678 //Roo.log("check " +c.dateValue + '?=' + dt);
13679 if(c.dateValue == dt){
13689 findCells : function(ev) {
13690 var s = ev.start.clone().clearTime().getTime();
13692 var e= ev.end.clone().clearTime().getTime();
13695 this.cells.each(function(c){
13696 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13698 if(c.dateValue > e){
13701 if(c.dateValue < s){
13710 // findBestRow: function(cells)
13714 // for (var i =0 ; i < cells.length;i++) {
13715 // ret = Math.max(cells[i].rows || 0,ret);
13722 addItem : function(ev)
13724 // look for vertical location slot in
13725 var cells = this.findCells(ev);
13727 // ev.row = this.findBestRow(cells);
13729 // work out the location.
13733 for(var i =0; i < cells.length; i++) {
13735 cells[i].row = cells[0].row;
13738 cells[i].row = cells[i].row + 1;
13748 if (crow.start.getY() == cells[i].getY()) {
13750 crow.end = cells[i];
13767 cells[0].events.push(ev);
13769 this.calevents.push(ev);
13772 clearEvents: function() {
13774 if(!this.calevents){
13778 Roo.each(this.cells.elements, function(c){
13784 Roo.each(this.calevents, function(e) {
13785 Roo.each(e.els, function(el) {
13786 el.un('mouseenter' ,this.onEventEnter, this);
13787 el.un('mouseleave' ,this.onEventLeave, this);
13792 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13798 renderEvents: function()
13802 this.cells.each(function(c) {
13811 if(c.row != c.events.length){
13812 r = 4 - (4 - (c.row - c.events.length));
13815 c.events = ev.slice(0, r);
13816 c.more = ev.slice(r);
13818 if(c.more.length && c.more.length == 1){
13819 c.events.push(c.more.pop());
13822 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13826 this.cells.each(function(c) {
13828 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13831 for (var e = 0; e < c.events.length; e++){
13832 var ev = c.events[e];
13833 var rows = ev.rows;
13835 for(var i = 0; i < rows.length; i++) {
13837 // how many rows should it span..
13840 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13841 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13843 unselectable : "on",
13846 cls: 'fc-event-inner',
13850 // cls: 'fc-event-time',
13851 // html : cells.length > 1 ? '' : ev.time
13855 cls: 'fc-event-title',
13856 html : String.format('{0}', ev.title)
13863 cls: 'ui-resizable-handle ui-resizable-e',
13864 html : '  '
13871 cfg.cls += ' fc-event-start';
13873 if ((i+1) == rows.length) {
13874 cfg.cls += ' fc-event-end';
13877 var ctr = _this.el.select('.fc-event-container',true).first();
13878 var cg = ctr.createChild(cfg);
13880 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13881 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13883 var r = (c.more.length) ? 1 : 0;
13884 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13885 cg.setWidth(ebox.right - sbox.x -2);
13887 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13888 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13889 cg.on('click', _this.onEventClick, _this, ev);
13900 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13901 style : 'position: absolute',
13902 unselectable : "on",
13905 cls: 'fc-event-inner',
13909 cls: 'fc-event-title',
13917 cls: 'ui-resizable-handle ui-resizable-e',
13918 html : '  '
13924 var ctr = _this.el.select('.fc-event-container',true).first();
13925 var cg = ctr.createChild(cfg);
13927 var sbox = c.select('.fc-day-content',true).first().getBox();
13928 var ebox = c.select('.fc-day-content',true).first().getBox();
13930 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13931 cg.setWidth(ebox.right - sbox.x -2);
13933 cg.on('click', _this.onMoreEventClick, _this, c.more);
13943 onEventEnter: function (e, el,event,d) {
13944 this.fireEvent('evententer', this, el, event);
13947 onEventLeave: function (e, el,event,d) {
13948 this.fireEvent('eventleave', this, el, event);
13951 onEventClick: function (e, el,event,d) {
13952 this.fireEvent('eventclick', this, el, event);
13955 onMonthChange: function () {
13959 onMoreEventClick: function(e, el, more)
13963 this.calpopover.placement = 'right';
13964 this.calpopover.setTitle('More');
13966 this.calpopover.setContent('');
13968 var ctr = this.calpopover.el.select('.popover-content', true).first();
13970 Roo.each(more, function(m){
13972 cls : 'fc-event-hori fc-event-draggable',
13975 var cg = ctr.createChild(cfg);
13977 cg.on('click', _this.onEventClick, _this, m);
13980 this.calpopover.show(el);
13985 onLoad: function ()
13987 this.calevents = [];
13990 if(this.store.getCount() > 0){
13991 this.store.data.each(function(d){
13994 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13995 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13996 time : d.data.start_time,
13997 title : d.data.title,
13998 description : d.data.description,
13999 venue : d.data.venue
14004 this.renderEvents();
14006 if(this.calevents.length && this.loadMask){
14007 this.maskEl.hide();
14011 onBeforeLoad: function()
14013 this.clearEvents();
14015 this.maskEl.show();
14029 * @class Roo.bootstrap.Popover
14030 * @extends Roo.bootstrap.Component
14031 * Bootstrap Popover class
14032 * @cfg {String} html contents of the popover (or false to use children..)
14033 * @cfg {String} title of popover (or false to hide)
14034 * @cfg {String} placement how it is placed
14035 * @cfg {String} trigger click || hover (or false to trigger manually)
14036 * @cfg {String} over what (parent or false to trigger manually.)
14037 * @cfg {Number} delay - delay before showing
14040 * Create a new Popover
14041 * @param {Object} config The config object
14044 Roo.bootstrap.Popover = function(config){
14045 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14048 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14050 title: 'Fill in a title',
14053 placement : 'right',
14054 trigger : 'hover', // hover
14060 can_build_overlaid : false,
14062 getChildContainer : function()
14064 return this.el.select('.popover-content',true).first();
14067 getAutoCreate : function(){
14068 Roo.log('make popover?');
14070 cls : 'popover roo-dynamic',
14071 style: 'display:block',
14077 cls : 'popover-inner',
14081 cls: 'popover-title',
14085 cls : 'popover-content',
14096 setTitle: function(str)
14098 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14100 setContent: function(str)
14102 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14104 // as it get's added to the bottom of the page.
14105 onRender : function(ct, position)
14107 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14109 var cfg = Roo.apply({}, this.getAutoCreate());
14113 cfg.cls += ' ' + this.cls;
14116 cfg.style = this.style;
14118 Roo.log("adding to ")
14119 this.el = Roo.get(document.body).createChild(cfg, position);
14125 initEvents : function()
14127 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14128 this.el.enableDisplayMode('block');
14130 if (this.over === false) {
14133 if (this.triggers === false) {
14136 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14137 var triggers = this.trigger ? this.trigger.split(' ') : [];
14138 Roo.each(triggers, function(trigger) {
14140 if (trigger == 'click') {
14141 on_el.on('click', this.toggle, this);
14142 } else if (trigger != 'manual') {
14143 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14144 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14146 on_el.on(eventIn ,this.enter, this);
14147 on_el.on(eventOut, this.leave, this);
14158 toggle : function () {
14159 this.hoverState == 'in' ? this.leave() : this.enter();
14162 enter : function () {
14165 clearTimeout(this.timeout);
14167 this.hoverState = 'in';
14169 if (!this.delay || !this.delay.show) {
14174 this.timeout = setTimeout(function () {
14175 if (_t.hoverState == 'in') {
14178 }, this.delay.show)
14180 leave : function() {
14181 clearTimeout(this.timeout);
14183 this.hoverState = 'out';
14185 if (!this.delay || !this.delay.hide) {
14190 this.timeout = setTimeout(function () {
14191 if (_t.hoverState == 'out') {
14194 }, this.delay.hide)
14197 show : function (on_el)
14200 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14203 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14204 if (this.html !== false) {
14205 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14207 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14208 if (!this.title.length) {
14209 this.el.select('.popover-title',true).hide();
14212 var placement = typeof this.placement == 'function' ?
14213 this.placement.call(this, this.el, on_el) :
14216 var autoToken = /\s?auto?\s?/i;
14217 var autoPlace = autoToken.test(placement);
14219 placement = placement.replace(autoToken, '') || 'top';
14223 //this.el.setXY([0,0]);
14225 this.el.dom.style.display='block';
14226 this.el.addClass(placement);
14228 //this.el.appendTo(on_el);
14230 var p = this.getPosition();
14231 var box = this.el.getBox();
14236 var align = Roo.bootstrap.Popover.alignment[placement];
14237 this.el.alignTo(on_el, align[0],align[1]);
14238 //var arrow = this.el.select('.arrow',true).first();
14239 //arrow.set(align[2],
14241 this.el.addClass('in');
14242 this.hoverState = null;
14244 if (this.el.hasClass('fade')) {
14251 this.el.setXY([0,0]);
14252 this.el.removeClass('in');
14259 Roo.bootstrap.Popover.alignment = {
14260 'left' : ['r-l', [-10,0], 'right'],
14261 'right' : ['l-r', [10,0], 'left'],
14262 'bottom' : ['t-b', [0,10], 'top'],
14263 'top' : [ 'b-t', [0,-10], 'bottom']
14274 * @class Roo.bootstrap.Progress
14275 * @extends Roo.bootstrap.Component
14276 * Bootstrap Progress class
14277 * @cfg {Boolean} striped striped of the progress bar
14278 * @cfg {Boolean} active animated of the progress bar
14282 * Create a new Progress
14283 * @param {Object} config The config object
14286 Roo.bootstrap.Progress = function(config){
14287 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14290 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14295 getAutoCreate : function(){
14303 cfg.cls += ' progress-striped';
14307 cfg.cls += ' active';
14326 * @class Roo.bootstrap.ProgressBar
14327 * @extends Roo.bootstrap.Component
14328 * Bootstrap ProgressBar class
14329 * @cfg {Number} aria_valuenow aria-value now
14330 * @cfg {Number} aria_valuemin aria-value min
14331 * @cfg {Number} aria_valuemax aria-value max
14332 * @cfg {String} label label for the progress bar
14333 * @cfg {String} panel (success | info | warning | danger )
14334 * @cfg {String} role role of the progress bar
14335 * @cfg {String} sr_only text
14339 * Create a new ProgressBar
14340 * @param {Object} config The config object
14343 Roo.bootstrap.ProgressBar = function(config){
14344 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14347 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14351 aria_valuemax : 100,
14357 getAutoCreate : function()
14362 cls: 'progress-bar',
14363 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14375 cfg.role = this.role;
14378 if(this.aria_valuenow){
14379 cfg['aria-valuenow'] = this.aria_valuenow;
14382 if(this.aria_valuemin){
14383 cfg['aria-valuemin'] = this.aria_valuemin;
14386 if(this.aria_valuemax){
14387 cfg['aria-valuemax'] = this.aria_valuemax;
14390 if(this.label && !this.sr_only){
14391 cfg.html = this.label;
14395 cfg.cls += ' progress-bar-' + this.panel;
14401 update : function(aria_valuenow)
14403 this.aria_valuenow = aria_valuenow;
14405 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14420 * @class Roo.bootstrap.TabGroup
14421 * @extends Roo.bootstrap.Column
14422 * Bootstrap Column class
14423 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14424 * @cfg {Boolean} carousel true to make the group behave like a carousel
14427 * Create a new TabGroup
14428 * @param {Object} config The config object
14431 Roo.bootstrap.TabGroup = function(config){
14432 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14434 this.navId = Roo.id();
14437 Roo.bootstrap.TabGroup.register(this);
14441 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14444 transition : false,
14446 getAutoCreate : function()
14448 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14450 cfg.cls += ' tab-content';
14452 if (this.carousel) {
14453 cfg.cls += ' carousel slide';
14455 cls : 'carousel-inner'
14462 getChildContainer : function()
14464 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14468 * register a Navigation item
14469 * @param {Roo.bootstrap.NavItem} the navitem to add
14471 register : function(item)
14473 this.tabs.push( item);
14474 item.navId = this.navId; // not really needed..
14478 getActivePanel : function()
14481 Roo.each(this.tabs, function(t) {
14491 getPanelByName : function(n)
14494 Roo.each(this.tabs, function(t) {
14495 if (t.tabId == n) {
14503 indexOfPanel : function(p)
14506 Roo.each(this.tabs, function(t,i) {
14507 if (t.tabId == p.tabId) {
14516 * show a specific panel
14517 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14518 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14520 showPanel : function (pan)
14523 if (typeof(pan) == 'number') {
14524 pan = this.tabs[pan];
14526 if (typeof(pan) == 'string') {
14527 pan = this.getPanelByName(pan);
14529 if (pan.tabId == this.getActivePanel().tabId) {
14532 var cur = this.getActivePanel();
14534 if (false === cur.fireEvent('beforedeactivate')) {
14538 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14540 this.transition = true;
14541 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14542 var lr = dir == 'next' ? 'left' : 'right';
14543 pan.el.addClass(dir); // or prev
14544 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14545 cur.el.addClass(lr); // or right
14546 pan.el.addClass(lr);
14549 cur.el.on('transitionend', function() {
14550 Roo.log("trans end?");
14552 pan.el.removeClass([lr,dir]);
14553 pan.setActive(true);
14555 cur.el.removeClass([lr]);
14556 cur.setActive(false);
14558 _this.transition = false;
14560 }, this, { single: true } );
14564 cur.setActive(false);
14565 pan.setActive(true);
14569 showPanelNext : function()
14571 var i = this.indexOfPanel(this.getActivePanel());
14572 if (i > this.tabs.length) {
14575 this.showPanel(this.tabs[i+1]);
14577 showPanelPrev : function()
14579 var i = this.indexOfPanel(this.getActivePanel());
14583 this.showPanel(this.tabs[i-1]);
14594 Roo.apply(Roo.bootstrap.TabGroup, {
14598 * register a Navigation Group
14599 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14601 register : function(navgrp)
14603 this.groups[navgrp.navId] = navgrp;
14607 * fetch a Navigation Group based on the navigation ID
14608 * if one does not exist , it will get created.
14609 * @param {string} the navgroup to add
14610 * @returns {Roo.bootstrap.NavGroup} the navgroup
14612 get: function(navId) {
14613 if (typeof(this.groups[navId]) == 'undefined') {
14614 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14616 return this.groups[navId] ;
14631 * @class Roo.bootstrap.TabPanel
14632 * @extends Roo.bootstrap.Component
14633 * Bootstrap TabPanel class
14634 * @cfg {Boolean} active panel active
14635 * @cfg {String} html panel content
14636 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14637 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14641 * Create a new TabPanel
14642 * @param {Object} config The config object
14645 Roo.bootstrap.TabPanel = function(config){
14646 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14650 * Fires when the active status changes
14651 * @param {Roo.bootstrap.TabPanel} this
14652 * @param {Boolean} state the new state
14657 * @event beforedeactivate
14658 * Fires before a tab is de-activated - can be used to do validation on a form.
14659 * @param {Roo.bootstrap.TabPanel} this
14660 * @return {Boolean} false if there is an error
14663 'beforedeactivate': true
14666 this.tabId = this.tabId || Roo.id();
14670 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14677 getAutoCreate : function(){
14680 // item is needed for carousel - not sure if it has any effect otherwise
14681 cls: 'tab-pane item',
14682 html: this.html || ''
14686 cfg.cls += ' active';
14690 cfg.tabId = this.tabId;
14697 initEvents: function()
14699 Roo.log('-------- init events on tab panel ---------');
14701 var p = this.parent();
14702 this.navId = this.navId || p.navId;
14704 if (typeof(this.navId) != 'undefined') {
14705 // not really needed.. but just in case.. parent should be a NavGroup.
14706 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14707 Roo.log(['register', tg, this]);
14713 onRender : function(ct, position)
14715 // Roo.log("Call onRender: " + this.xtype);
14717 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14725 setActive: function(state)
14727 Roo.log("panel - set active " + this.tabId + "=" + state);
14729 this.active = state;
14731 this.el.removeClass('active');
14733 } else if (!this.el.hasClass('active')) {
14734 this.el.addClass('active');
14736 this.fireEvent('changed', this, state);
14753 * @class Roo.bootstrap.DateField
14754 * @extends Roo.bootstrap.Input
14755 * Bootstrap DateField class
14756 * @cfg {Number} weekStart default 0
14757 * @cfg {String} viewMode default empty, (months|years)
14758 * @cfg {String} minViewMode default empty, (months|years)
14759 * @cfg {Number} startDate default -Infinity
14760 * @cfg {Number} endDate default Infinity
14761 * @cfg {Boolean} todayHighlight default false
14762 * @cfg {Boolean} todayBtn default false
14763 * @cfg {Boolean} calendarWeeks default false
14764 * @cfg {Object} daysOfWeekDisabled default empty
14765 * @cfg {Boolean} singleMode default false (true | false)
14767 * @cfg {Boolean} keyboardNavigation default true
14768 * @cfg {String} language default en
14771 * Create a new DateField
14772 * @param {Object} config The config object
14775 Roo.bootstrap.DateField = function(config){
14776 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14780 * Fires when this field show.
14781 * @param {Roo.bootstrap.DateField} this
14782 * @param {Mixed} date The date value
14787 * Fires when this field hide.
14788 * @param {Roo.bootstrap.DateField} this
14789 * @param {Mixed} date The date value
14794 * Fires when select a date.
14795 * @param {Roo.bootstrap.DateField} this
14796 * @param {Mixed} date The date value
14802 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14805 * @cfg {String} format
14806 * The default date format string which can be overriden for localization support. The format must be
14807 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14811 * @cfg {String} altFormats
14812 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14813 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14815 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14823 todayHighlight : false,
14829 keyboardNavigation: true,
14831 calendarWeeks: false,
14833 startDate: -Infinity,
14837 daysOfWeekDisabled: [],
14841 singleMode : false,
14843 UTCDate: function()
14845 return new Date(Date.UTC.apply(Date, arguments));
14848 UTCToday: function()
14850 var today = new Date();
14851 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14854 getDate: function() {
14855 var d = this.getUTCDate();
14856 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14859 getUTCDate: function() {
14863 setDate: function(d) {
14864 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14867 setUTCDate: function(d) {
14869 this.setValue(this.formatDate(this.date));
14872 onRender: function(ct, position)
14875 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14877 this.language = this.language || 'en';
14878 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14879 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14881 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14882 this.format = this.format || 'm/d/y';
14883 this.isInline = false;
14884 this.isInput = true;
14885 this.component = this.el.select('.add-on', true).first() || false;
14886 this.component = (this.component && this.component.length === 0) ? false : this.component;
14887 this.hasInput = this.component && this.inputEL().length;
14889 if (typeof(this.minViewMode === 'string')) {
14890 switch (this.minViewMode) {
14892 this.minViewMode = 1;
14895 this.minViewMode = 2;
14898 this.minViewMode = 0;
14903 if (typeof(this.viewMode === 'string')) {
14904 switch (this.viewMode) {
14917 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14919 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14921 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14923 this.picker().on('mousedown', this.onMousedown, this);
14924 this.picker().on('click', this.onClick, this);
14926 this.picker().addClass('datepicker-dropdown');
14928 this.startViewMode = this.viewMode;
14930 if(this.singleMode){
14931 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14932 v.setVisibilityMode(Roo.Element.DISPLAY)
14936 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14937 v.setStyle('width', '189px');
14941 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14942 if(!this.calendarWeeks){
14947 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14948 v.attr('colspan', function(i, val){
14949 return parseInt(val) + 1;
14954 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14956 this.setStartDate(this.startDate);
14957 this.setEndDate(this.endDate);
14959 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14966 if(this.isInline) {
14971 picker : function()
14973 return this.pickerEl;
14974 // return this.el.select('.datepicker', true).first();
14977 fillDow: function()
14979 var dowCnt = this.weekStart;
14988 if(this.calendarWeeks){
14996 while (dowCnt < this.weekStart + 7) {
15000 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15004 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15007 fillMonths: function()
15010 var months = this.picker().select('>.datepicker-months td', true).first();
15012 months.dom.innerHTML = '';
15018 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15021 months.createChild(month);
15028 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;
15030 if (this.date < this.startDate) {
15031 this.viewDate = new Date(this.startDate);
15032 } else if (this.date > this.endDate) {
15033 this.viewDate = new Date(this.endDate);
15035 this.viewDate = new Date(this.date);
15043 var d = new Date(this.viewDate),
15044 year = d.getUTCFullYear(),
15045 month = d.getUTCMonth(),
15046 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15047 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15048 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15049 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15050 currentDate = this.date && this.date.valueOf(),
15051 today = this.UTCToday();
15053 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15055 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15057 // this.picker.select('>tfoot th.today').
15058 // .text(dates[this.language].today)
15059 // .toggle(this.todayBtn !== false);
15061 this.updateNavArrows();
15064 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15066 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15068 prevMonth.setUTCDate(day);
15070 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15072 var nextMonth = new Date(prevMonth);
15074 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15076 nextMonth = nextMonth.valueOf();
15078 var fillMonths = false;
15080 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15082 while(prevMonth.valueOf() < nextMonth) {
15085 if (prevMonth.getUTCDay() === this.weekStart) {
15087 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15095 if(this.calendarWeeks){
15096 // ISO 8601: First week contains first thursday.
15097 // ISO also states week starts on Monday, but we can be more abstract here.
15099 // Start of current week: based on weekstart/current date
15100 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15101 // Thursday of this week
15102 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15103 // First Thursday of year, year from thursday
15104 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15105 // Calendar week: ms between thursdays, div ms per day, div 7 days
15106 calWeek = (th - yth) / 864e5 / 7 + 1;
15108 fillMonths.cn.push({
15116 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15118 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15121 if (this.todayHighlight &&
15122 prevMonth.getUTCFullYear() == today.getFullYear() &&
15123 prevMonth.getUTCMonth() == today.getMonth() &&
15124 prevMonth.getUTCDate() == today.getDate()) {
15125 clsName += ' today';
15128 if (currentDate && prevMonth.valueOf() === currentDate) {
15129 clsName += ' active';
15132 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15133 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15134 clsName += ' disabled';
15137 fillMonths.cn.push({
15139 cls: 'day ' + clsName,
15140 html: prevMonth.getDate()
15143 prevMonth.setDate(prevMonth.getDate()+1);
15146 var currentYear = this.date && this.date.getUTCFullYear();
15147 var currentMonth = this.date && this.date.getUTCMonth();
15149 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15151 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15152 v.removeClass('active');
15154 if(currentYear === year && k === currentMonth){
15155 v.addClass('active');
15158 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15159 v.addClass('disabled');
15165 year = parseInt(year/10, 10) * 10;
15167 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15169 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15172 for (var i = -1; i < 11; i++) {
15173 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15175 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15183 showMode: function(dir)
15186 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15189 Roo.each(this.picker().select('>div',true).elements, function(v){
15190 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15193 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15198 if(this.isInline) return;
15200 this.picker().removeClass(['bottom', 'top']);
15202 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15204 * place to the top of element!
15208 this.picker().addClass('top');
15209 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15214 this.picker().addClass('bottom');
15216 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15219 parseDate : function(value)
15221 if(!value || value instanceof Date){
15224 var v = Date.parseDate(value, this.format);
15225 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15226 v = Date.parseDate(value, 'Y-m-d');
15228 if(!v && this.altFormats){
15229 if(!this.altFormatsArray){
15230 this.altFormatsArray = this.altFormats.split("|");
15232 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15233 v = Date.parseDate(value, this.altFormatsArray[i]);
15239 formatDate : function(date, fmt)
15241 return (!date || !(date instanceof Date)) ?
15242 date : date.dateFormat(fmt || this.format);
15245 onFocus : function()
15247 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15251 onBlur : function()
15253 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15255 var d = this.inputEl().getValue();
15264 this.picker().show();
15268 this.fireEvent('show', this, this.date);
15273 if(this.isInline) return;
15274 this.picker().hide();
15275 this.viewMode = this.startViewMode;
15278 this.fireEvent('hide', this, this.date);
15282 onMousedown: function(e)
15284 e.stopPropagation();
15285 e.preventDefault();
15290 Roo.bootstrap.DateField.superclass.keyup.call(this);
15294 setValue: function(v)
15297 // v can be a string or a date..
15300 var d = new Date(this.parseDate(v) ).clearTime();
15302 if(isNaN(d.getTime())){
15303 this.date = this.viewDate = '';
15304 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15308 v = this.formatDate(d);
15310 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15312 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15316 this.fireEvent('select', this, this.date);
15320 getValue: function()
15322 return this.formatDate(this.date);
15325 fireKey: function(e)
15327 if (!this.picker().isVisible()){
15328 if (e.keyCode == 27) // allow escape to hide and re-show picker
15333 var dateChanged = false,
15335 newDate, newViewDate;
15340 e.preventDefault();
15344 if (!this.keyboardNavigation) break;
15345 dir = e.keyCode == 37 ? -1 : 1;
15348 newDate = this.moveYear(this.date, dir);
15349 newViewDate = this.moveYear(this.viewDate, dir);
15350 } else if (e.shiftKey){
15351 newDate = this.moveMonth(this.date, dir);
15352 newViewDate = this.moveMonth(this.viewDate, dir);
15354 newDate = new Date(this.date);
15355 newDate.setUTCDate(this.date.getUTCDate() + dir);
15356 newViewDate = new Date(this.viewDate);
15357 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15359 if (this.dateWithinRange(newDate)){
15360 this.date = newDate;
15361 this.viewDate = newViewDate;
15362 this.setValue(this.formatDate(this.date));
15364 e.preventDefault();
15365 dateChanged = true;
15370 if (!this.keyboardNavigation) break;
15371 dir = e.keyCode == 38 ? -1 : 1;
15373 newDate = this.moveYear(this.date, dir);
15374 newViewDate = this.moveYear(this.viewDate, dir);
15375 } else if (e.shiftKey){
15376 newDate = this.moveMonth(this.date, dir);
15377 newViewDate = this.moveMonth(this.viewDate, dir);
15379 newDate = new Date(this.date);
15380 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15381 newViewDate = new Date(this.viewDate);
15382 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15384 if (this.dateWithinRange(newDate)){
15385 this.date = newDate;
15386 this.viewDate = newViewDate;
15387 this.setValue(this.formatDate(this.date));
15389 e.preventDefault();
15390 dateChanged = true;
15394 this.setValue(this.formatDate(this.date));
15396 e.preventDefault();
15399 this.setValue(this.formatDate(this.date));
15413 onClick: function(e)
15415 e.stopPropagation();
15416 e.preventDefault();
15418 var target = e.getTarget();
15420 if(target.nodeName.toLowerCase() === 'i'){
15421 target = Roo.get(target).dom.parentNode;
15424 var nodeName = target.nodeName;
15425 var className = target.className;
15426 var html = target.innerHTML;
15427 //Roo.log(nodeName);
15429 switch(nodeName.toLowerCase()) {
15431 switch(className) {
15437 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15438 switch(this.viewMode){
15440 this.viewDate = this.moveMonth(this.viewDate, dir);
15444 this.viewDate = this.moveYear(this.viewDate, dir);
15450 var date = new Date();
15451 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15453 this.setValue(this.formatDate(this.date));
15460 if (className.indexOf('disabled') < 0) {
15461 this.viewDate.setUTCDate(1);
15462 if (className.indexOf('month') > -1) {
15463 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15465 var year = parseInt(html, 10) || 0;
15466 this.viewDate.setUTCFullYear(year);
15470 if(this.singleMode){
15471 this.setValue(this.formatDate(this.viewDate));
15482 //Roo.log(className);
15483 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15484 var day = parseInt(html, 10) || 1;
15485 var year = this.viewDate.getUTCFullYear(),
15486 month = this.viewDate.getUTCMonth();
15488 if (className.indexOf('old') > -1) {
15495 } else if (className.indexOf('new') > -1) {
15503 //Roo.log([year,month,day]);
15504 this.date = this.UTCDate(year, month, day,0,0,0,0);
15505 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15507 //Roo.log(this.formatDate(this.date));
15508 this.setValue(this.formatDate(this.date));
15515 setStartDate: function(startDate)
15517 this.startDate = startDate || -Infinity;
15518 if (this.startDate !== -Infinity) {
15519 this.startDate = this.parseDate(this.startDate);
15522 this.updateNavArrows();
15525 setEndDate: function(endDate)
15527 this.endDate = endDate || Infinity;
15528 if (this.endDate !== Infinity) {
15529 this.endDate = this.parseDate(this.endDate);
15532 this.updateNavArrows();
15535 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15537 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15538 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15539 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15541 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15542 return parseInt(d, 10);
15545 this.updateNavArrows();
15548 updateNavArrows: function()
15550 if(this.singleMode){
15554 var d = new Date(this.viewDate),
15555 year = d.getUTCFullYear(),
15556 month = d.getUTCMonth();
15558 Roo.each(this.picker().select('.prev', true).elements, function(v){
15560 switch (this.viewMode) {
15563 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15569 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15576 Roo.each(this.picker().select('.next', true).elements, function(v){
15578 switch (this.viewMode) {
15581 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15587 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15595 moveMonth: function(date, dir)
15597 if (!dir) return date;
15598 var new_date = new Date(date.valueOf()),
15599 day = new_date.getUTCDate(),
15600 month = new_date.getUTCMonth(),
15601 mag = Math.abs(dir),
15603 dir = dir > 0 ? 1 : -1;
15606 // If going back one month, make sure month is not current month
15607 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15609 return new_date.getUTCMonth() == month;
15611 // If going forward one month, make sure month is as expected
15612 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15614 return new_date.getUTCMonth() != new_month;
15616 new_month = month + dir;
15617 new_date.setUTCMonth(new_month);
15618 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15619 if (new_month < 0 || new_month > 11)
15620 new_month = (new_month + 12) % 12;
15622 // For magnitudes >1, move one month at a time...
15623 for (var i=0; i<mag; i++)
15624 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15625 new_date = this.moveMonth(new_date, dir);
15626 // ...then reset the day, keeping it in the new month
15627 new_month = new_date.getUTCMonth();
15628 new_date.setUTCDate(day);
15630 return new_month != new_date.getUTCMonth();
15633 // Common date-resetting loop -- if date is beyond end of month, make it
15636 new_date.setUTCDate(--day);
15637 new_date.setUTCMonth(new_month);
15642 moveYear: function(date, dir)
15644 return this.moveMonth(date, dir*12);
15647 dateWithinRange: function(date)
15649 return date >= this.startDate && date <= this.endDate;
15655 this.picker().remove();
15660 Roo.apply(Roo.bootstrap.DateField, {
15671 html: '<i class="fa fa-arrow-left"/>'
15681 html: '<i class="fa fa-arrow-right"/>'
15723 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15724 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15725 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15726 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15727 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15740 navFnc: 'FullYear',
15745 navFnc: 'FullYear',
15750 Roo.apply(Roo.bootstrap.DateField, {
15754 cls: 'datepicker dropdown-menu roo-dynamic',
15758 cls: 'datepicker-days',
15762 cls: 'table-condensed',
15764 Roo.bootstrap.DateField.head,
15768 Roo.bootstrap.DateField.footer
15775 cls: 'datepicker-months',
15779 cls: 'table-condensed',
15781 Roo.bootstrap.DateField.head,
15782 Roo.bootstrap.DateField.content,
15783 Roo.bootstrap.DateField.footer
15790 cls: 'datepicker-years',
15794 cls: 'table-condensed',
15796 Roo.bootstrap.DateField.head,
15797 Roo.bootstrap.DateField.content,
15798 Roo.bootstrap.DateField.footer
15817 * @class Roo.bootstrap.TimeField
15818 * @extends Roo.bootstrap.Input
15819 * Bootstrap DateField class
15823 * Create a new TimeField
15824 * @param {Object} config The config object
15827 Roo.bootstrap.TimeField = function(config){
15828 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15832 * Fires when this field show.
15833 * @param {Roo.bootstrap.DateField} thisthis
15834 * @param {Mixed} date The date value
15839 * Fires when this field hide.
15840 * @param {Roo.bootstrap.DateField} this
15841 * @param {Mixed} date The date value
15846 * Fires when select a date.
15847 * @param {Roo.bootstrap.DateField} this
15848 * @param {Mixed} date The date value
15854 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15857 * @cfg {String} format
15858 * The default time format string which can be overriden for localization support. The format must be
15859 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15863 onRender: function(ct, position)
15866 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15868 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15870 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15872 this.pop = this.picker().select('>.datepicker-time',true).first();
15873 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15875 this.picker().on('mousedown', this.onMousedown, this);
15876 this.picker().on('click', this.onClick, this);
15878 this.picker().addClass('datepicker-dropdown');
15883 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15884 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15885 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15886 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15887 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15888 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15892 fireKey: function(e){
15893 if (!this.picker().isVisible()){
15894 if (e.keyCode == 27) { // allow escape to hide and re-show picker
15900 e.preventDefault();
15908 this.onTogglePeriod();
15911 this.onIncrementMinutes();
15914 this.onDecrementMinutes();
15923 onClick: function(e) {
15924 e.stopPropagation();
15925 e.preventDefault();
15928 picker : function()
15930 return this.el.select('.datepicker', true).first();
15933 fillTime: function()
15935 var time = this.pop.select('tbody', true).first();
15937 time.dom.innerHTML = '';
15952 cls: 'hours-up glyphicon glyphicon-chevron-up'
15972 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15993 cls: 'timepicker-hour',
16008 cls: 'timepicker-minute',
16023 cls: 'btn btn-primary period',
16045 cls: 'hours-down glyphicon glyphicon-chevron-down'
16065 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16083 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16090 var hours = this.time.getHours();
16091 var minutes = this.time.getMinutes();
16104 hours = hours - 12;
16108 hours = '0' + hours;
16112 minutes = '0' + minutes;
16115 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16116 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16117 this.pop.select('button', true).first().dom.innerHTML = period;
16123 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16125 var cls = ['bottom'];
16127 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16134 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16139 this.picker().addClass(cls.join('-'));
16143 Roo.each(cls, function(c){
16145 _this.picker().setTop(_this.inputEl().getHeight());
16149 _this.picker().setTop(0 - _this.picker().getHeight());
16154 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16158 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16165 onFocus : function()
16167 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16171 onBlur : function()
16173 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16179 this.picker().show();
16184 this.fireEvent('show', this, this.date);
16189 this.picker().hide();
16192 this.fireEvent('hide', this, this.date);
16195 setTime : function()
16198 this.setValue(this.time.format(this.format));
16200 this.fireEvent('select', this, this.date);
16205 onMousedown: function(e){
16206 e.stopPropagation();
16207 e.preventDefault();
16210 onIncrementHours: function()
16212 Roo.log('onIncrementHours');
16213 this.time = this.time.add(Date.HOUR, 1);
16218 onDecrementHours: function()
16220 Roo.log('onDecrementHours');
16221 this.time = this.time.add(Date.HOUR, -1);
16225 onIncrementMinutes: function()
16227 Roo.log('onIncrementMinutes');
16228 this.time = this.time.add(Date.MINUTE, 1);
16232 onDecrementMinutes: function()
16234 Roo.log('onDecrementMinutes');
16235 this.time = this.time.add(Date.MINUTE, -1);
16239 onTogglePeriod: function()
16241 Roo.log('onTogglePeriod');
16242 this.time = this.time.add(Date.HOUR, 12);
16249 Roo.apply(Roo.bootstrap.TimeField, {
16279 cls: 'btn btn-info ok',
16291 Roo.apply(Roo.bootstrap.TimeField, {
16295 cls: 'datepicker dropdown-menu',
16299 cls: 'datepicker-time',
16303 cls: 'table-condensed',
16305 Roo.bootstrap.TimeField.content,
16306 Roo.bootstrap.TimeField.footer
16325 * @class Roo.bootstrap.MonthField
16326 * @extends Roo.bootstrap.Input
16327 * Bootstrap MonthField class
16329 * @cfg {String} language default en
16332 * Create a new MonthField
16333 * @param {Object} config The config object
16336 Roo.bootstrap.MonthField = function(config){
16337 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16342 * Fires when this field show.
16343 * @param {Roo.bootstrap.MonthField} this
16344 * @param {Mixed} date The date value
16349 * Fires when this field hide.
16350 * @param {Roo.bootstrap.MonthField} this
16351 * @param {Mixed} date The date value
16356 * Fires when select a date.
16357 * @param {Roo.bootstrap.MonthField} this
16358 * @param {String} oldvalue The old value
16359 * @param {String} newvalue The new value
16365 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16367 onRender: function(ct, position)
16370 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16372 this.language = this.language || 'en';
16373 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16374 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16376 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16377 this.isInline = false;
16378 this.isInput = true;
16379 this.component = this.el.select('.add-on', true).first() || false;
16380 this.component = (this.component && this.component.length === 0) ? false : this.component;
16381 this.hasInput = this.component && this.inputEL().length;
16383 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16385 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16387 this.picker().on('mousedown', this.onMousedown, this);
16388 this.picker().on('click', this.onClick, this);
16390 this.picker().addClass('datepicker-dropdown');
16392 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16393 v.setStyle('width', '189px');
16400 if(this.isInline) {
16406 setValue: function(v, suppressEvent)
16408 var o = this.getValue();
16410 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16414 if(suppressEvent !== true){
16415 this.fireEvent('select', this, o, v);
16420 getValue: function()
16425 onClick: function(e)
16427 e.stopPropagation();
16428 e.preventDefault();
16430 var target = e.getTarget();
16432 if(target.nodeName.toLowerCase() === 'i'){
16433 target = Roo.get(target).dom.parentNode;
16436 var nodeName = target.nodeName;
16437 var className = target.className;
16438 var html = target.innerHTML;
16440 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16444 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16446 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16452 picker : function()
16454 return this.pickerEl;
16457 fillMonths: function()
16460 var months = this.picker().select('>.datepicker-months td', true).first();
16462 months.dom.innerHTML = '';
16468 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16471 months.createChild(month);
16480 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16481 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16484 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16485 e.removeClass('active');
16487 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16488 e.addClass('active');
16495 if(this.isInline) return;
16497 this.picker().removeClass(['bottom', 'top']);
16499 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16501 * place to the top of element!
16505 this.picker().addClass('top');
16506 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16511 this.picker().addClass('bottom');
16513 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16516 onFocus : function()
16518 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16522 onBlur : function()
16524 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16526 var d = this.inputEl().getValue();
16535 this.picker().show();
16536 this.picker().select('>.datepicker-months', true).first().show();
16540 this.fireEvent('show', this, this.date);
16545 if(this.isInline) return;
16546 this.picker().hide();
16547 this.fireEvent('hide', this, this.date);
16551 onMousedown: function(e)
16553 e.stopPropagation();
16554 e.preventDefault();
16559 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16563 fireKey: function(e)
16565 if (!this.picker().isVisible()){
16566 if (e.keyCode == 27) // allow escape to hide and re-show picker
16576 e.preventDefault();
16580 dir = e.keyCode == 37 ? -1 : 1;
16582 this.vIndex = this.vIndex + dir;
16584 if(this.vIndex < 0){
16588 if(this.vIndex > 11){
16592 if(isNaN(this.vIndex)){
16596 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16602 dir = e.keyCode == 38 ? -1 : 1;
16604 this.vIndex = this.vIndex + dir * 4;
16606 if(this.vIndex < 0){
16610 if(this.vIndex > 11){
16614 if(isNaN(this.vIndex)){
16618 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16623 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16624 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16628 e.preventDefault();
16631 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16632 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16648 this.picker().remove();
16653 Roo.apply(Roo.bootstrap.MonthField, {
16672 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16673 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16678 Roo.apply(Roo.bootstrap.MonthField, {
16682 cls: 'datepicker dropdown-menu roo-dynamic',
16686 cls: 'datepicker-months',
16690 cls: 'table-condensed',
16692 Roo.bootstrap.DateField.content
16712 * @class Roo.bootstrap.CheckBox
16713 * @extends Roo.bootstrap.Input
16714 * Bootstrap CheckBox class
16716 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16717 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16718 * @cfg {String} boxLabel The text that appears beside the checkbox
16719 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16720 * @cfg {Boolean} checked initnal the element
16721 * @cfg {Boolean} inline inline the element (default false)
16722 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16725 * Create a new CheckBox
16726 * @param {Object} config The config object
16729 Roo.bootstrap.CheckBox = function(config){
16730 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16735 * Fires when the element is checked or unchecked.
16736 * @param {Roo.bootstrap.CheckBox} this This input
16737 * @param {Boolean} checked The new checked value
16744 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16746 inputType: 'checkbox',
16754 getAutoCreate : function()
16756 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16762 cfg.cls = 'form-group ' + this.inputType; //input-group
16765 cfg.cls += ' ' + this.inputType + '-inline';
16771 type : this.inputType,
16772 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16773 cls : 'roo-' + this.inputType, //'form-box',
16774 placeholder : this.placeholder || ''
16778 if (this.weight) { // Validity check?
16779 cfg.cls += " " + this.inputType + "-" + this.weight;
16782 if (this.disabled) {
16783 input.disabled=true;
16787 input.checked = this.checked;
16791 input.name = this.name;
16795 input.cls += ' input-' + this.size;
16800 ['xs','sm','md','lg'].map(function(size){
16801 if (settings[size]) {
16802 cfg.cls += ' col-' + size + '-' + settings[size];
16806 var inputblock = input;
16808 if (this.before || this.after) {
16811 cls : 'input-group',
16816 inputblock.cn.push({
16818 cls : 'input-group-addon',
16823 inputblock.cn.push(input);
16826 inputblock.cn.push({
16828 cls : 'input-group-addon',
16835 if (align ==='left' && this.fieldLabel.length) {
16836 Roo.log("left and has label");
16842 cls : 'control-label col-md-' + this.labelWidth,
16843 html : this.fieldLabel
16847 cls : "col-md-" + (12 - this.labelWidth),
16854 } else if ( this.fieldLabel.length) {
16859 tag: this.boxLabel ? 'span' : 'label',
16861 cls: 'control-label box-input-label',
16862 //cls : 'input-group-addon',
16863 html : this.fieldLabel
16873 Roo.log(" no label && no align");
16874 cfg.cn = [ inputblock ] ;
16879 var boxLabelCfg = {
16881 //'for': id, // box label is handled by onclick - so no for...
16883 html: this.boxLabel
16887 boxLabelCfg.tooltip = this.tooltip;
16890 cfg.cn.push(boxLabelCfg);
16900 * return the real input element.
16902 inputEl: function ()
16904 return this.el.select('input.roo-' + this.inputType,true).first();
16907 labelEl: function()
16909 return this.el.select('label.control-label',true).first();
16911 /* depricated... */
16915 return this.labelEl();
16918 initEvents : function()
16920 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16922 this.inputEl().on('click', this.onClick, this);
16924 if (this.boxLabel) {
16925 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16928 this.startValue = this.getValue();
16931 Roo.bootstrap.CheckBox.register(this);
16935 onClick : function()
16937 this.setChecked(!this.checked);
16940 setChecked : function(state,suppressEvent)
16942 this.startValue = this.getValue();
16944 if(this.inputType == 'radio'){
16946 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16947 e.dom.checked = false;
16950 this.inputEl().dom.checked = true;
16952 this.inputEl().dom.value = this.inputValue;
16954 if(suppressEvent !== true){
16955 this.fireEvent('check', this, true);
16963 this.checked = state;
16965 this.inputEl().dom.checked = state;
16967 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16969 if(suppressEvent !== true){
16970 this.fireEvent('check', this, state);
16976 getValue : function()
16978 if(this.inputType == 'radio'){
16979 return this.getGroupValue();
16982 return this.inputEl().getValue();
16986 getGroupValue : function()
16988 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16992 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16995 setValue : function(v,suppressEvent)
16997 if(this.inputType == 'radio'){
16998 this.setGroupValue(v, suppressEvent);
17002 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17007 setGroupValue : function(v, suppressEvent)
17009 this.startValue = this.getValue();
17011 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17012 e.dom.checked = false;
17014 if(e.dom.value == v){
17015 e.dom.checked = true;
17019 if(suppressEvent !== true){
17020 this.fireEvent('check', this, true);
17028 validate : function()
17032 (this.inputType == 'radio' && this.validateRadio()) ||
17033 (this.inputType == 'checkbox' && this.validateCheckbox())
17039 this.markInvalid();
17043 validateRadio : function()
17047 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17048 if(!e.dom.checked){
17060 validateCheckbox : function()
17063 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17066 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17074 for(var i in group){
17079 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17086 * Mark this field as valid
17088 markValid : function()
17090 if(this.allowBlank){
17096 this.fireEvent('valid', this);
17098 if(this.inputType == 'radio'){
17099 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17100 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17101 e.findParent('.form-group', false, true).addClass(_this.validClass);
17108 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17109 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17113 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17119 for(var i in group){
17120 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17121 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17126 * Mark this field as invalid
17127 * @param {String} msg The validation message
17129 markInvalid : function(msg)
17131 if(this.allowBlank){
17137 this.fireEvent('invalid', this, msg);
17139 if(this.inputType == 'radio'){
17140 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17141 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17142 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17149 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17150 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17154 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17160 for(var i in group){
17161 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17162 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17169 Roo.apply(Roo.bootstrap.CheckBox, {
17174 * register a CheckBox Group
17175 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17177 register : function(checkbox)
17179 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17180 this.groups[checkbox.groupId] = {};
17183 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17187 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17191 * fetch a CheckBox Group based on the group ID
17192 * @param {string} the group ID
17193 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17195 get: function(groupId) {
17196 if (typeof(this.groups[groupId]) == 'undefined') {
17200 return this.groups[groupId] ;
17212 *<div class="radio">
17214 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17215 Option one is this and that—be sure to include why it's great
17222 *<label class="radio-inline">fieldLabel</label>
17223 *<label class="radio-inline">
17224 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17232 * @class Roo.bootstrap.Radio
17233 * @extends Roo.bootstrap.CheckBox
17234 * Bootstrap Radio class
17237 * Create a new Radio
17238 * @param {Object} config The config object
17241 Roo.bootstrap.Radio = function(config){
17242 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17246 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17248 inputType: 'radio',
17252 getAutoCreate : function()
17254 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17255 align = align || 'left'; // default...
17262 tag : this.inline ? 'span' : 'div',
17267 var inline = this.inline ? ' radio-inline' : '';
17271 // does not need for, as we wrap the input with it..
17273 cls : 'control-label box-label' + inline,
17276 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17280 //cls : 'control-label' + inline,
17281 html : this.fieldLabel,
17282 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17291 type : this.inputType,
17292 //value : (!this.checked) ? this.valueOff : this.inputValue,
17293 value : this.inputValue,
17295 placeholder : this.placeholder || '' // ?? needed????
17298 if (this.weight) { // Validity check?
17299 input.cls += " radio-" + this.weight;
17301 if (this.disabled) {
17302 input.disabled=true;
17306 input.checked = this.checked;
17310 input.name = this.name;
17314 input.cls += ' input-' + this.size;
17317 //?? can span's inline have a width??
17320 ['xs','sm','md','lg'].map(function(size){
17321 if (settings[size]) {
17322 cfg.cls += ' col-' + size + '-' + settings[size];
17326 var inputblock = input;
17328 if (this.before || this.after) {
17331 cls : 'input-group',
17336 inputblock.cn.push({
17338 cls : 'input-group-addon',
17342 inputblock.cn.push(input);
17344 inputblock.cn.push({
17346 cls : 'input-group-addon',
17354 if (this.fieldLabel && this.fieldLabel.length) {
17355 cfg.cn.push(fieldLabel);
17358 // normal bootstrap puts the input inside the label.
17359 // however with our styled version - it has to go after the input.
17361 //lbl.cn.push(inputblock);
17365 cls: 'radio' + inline,
17372 cfg.cn.push( lblwrap);
17377 html: this.boxLabel
17386 initEvents : function()
17388 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17390 this.inputEl().on('click', this.onClick, this);
17391 if (this.boxLabel) {
17392 Roo.log('find label')
17393 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17398 inputEl: function ()
17400 return this.el.select('input.roo-radio',true).first();
17402 onClick : function()
17405 this.setChecked(true);
17408 setChecked : function(state,suppressEvent)
17411 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17412 v.dom.checked = false;
17415 Roo.log(this.inputEl().dom);
17416 this.checked = state;
17417 this.inputEl().dom.checked = state;
17419 if(suppressEvent !== true){
17420 this.fireEvent('check', this, state);
17423 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17427 getGroupValue : function()
17430 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17431 if(v.dom.checked == true){
17432 value = v.dom.value;
17440 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17441 * @return {Mixed} value The field value
17443 getValue : function(){
17444 return this.getGroupValue();
17450 //<script type="text/javascript">
17453 * Based Ext JS Library 1.1.1
17454 * Copyright(c) 2006-2007, Ext JS, LLC.
17460 * @class Roo.HtmlEditorCore
17461 * @extends Roo.Component
17462 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17464 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17467 Roo.HtmlEditorCore = function(config){
17470 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17475 * @event initialize
17476 * Fires when the editor is fully initialized (including the iframe)
17477 * @param {Roo.HtmlEditorCore} this
17482 * Fires when the editor is first receives the focus. Any insertion must wait
17483 * until after this event.
17484 * @param {Roo.HtmlEditorCore} this
17488 * @event beforesync
17489 * Fires before the textarea is updated with content from the editor iframe. Return false
17490 * to cancel the sync.
17491 * @param {Roo.HtmlEditorCore} this
17492 * @param {String} html
17496 * @event beforepush
17497 * Fires before the iframe editor is updated with content from the textarea. Return false
17498 * to cancel the push.
17499 * @param {Roo.HtmlEditorCore} this
17500 * @param {String} html
17505 * Fires when the textarea is updated with content from the editor iframe.
17506 * @param {Roo.HtmlEditorCore} this
17507 * @param {String} html
17512 * Fires when the iframe editor is updated with content from the textarea.
17513 * @param {Roo.HtmlEditorCore} this
17514 * @param {String} html
17519 * @event editorevent
17520 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17521 * @param {Roo.HtmlEditorCore} this
17527 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17529 // defaults : white / black...
17530 this.applyBlacklists();
17537 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17541 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17547 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17552 * @cfg {Number} height (in pixels)
17556 * @cfg {Number} width (in pixels)
17561 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17564 stylesheets: false,
17569 // private properties
17570 validationEvent : false,
17572 initialized : false,
17574 sourceEditMode : false,
17575 onFocus : Roo.emptyFn,
17577 hideMode:'offsets',
17581 // blacklist + whitelisted elements..
17588 * Protected method that will not generally be called directly. It
17589 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17590 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17592 getDocMarkup : function(){
17596 // inherit styels from page...??
17597 if (this.stylesheets === false) {
17599 Roo.get(document.head).select('style').each(function(node) {
17600 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17603 Roo.get(document.head).select('link').each(function(node) {
17604 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17607 } else if (!this.stylesheets.length) {
17609 st = '<style type="text/css">' +
17610 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17616 st += '<style type="text/css">' +
17617 'IMG { cursor: pointer } ' +
17621 return '<html><head>' + st +
17622 //<style type="text/css">' +
17623 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17625 ' </head><body class="roo-htmleditor-body"></body></html>';
17629 onRender : function(ct, position)
17632 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17633 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17636 this.el.dom.style.border = '0 none';
17637 this.el.dom.setAttribute('tabIndex', -1);
17638 this.el.addClass('x-hidden hide');
17642 if(Roo.isIE){ // fix IE 1px bogus margin
17643 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17647 this.frameId = Roo.id();
17651 var iframe = this.owner.wrap.createChild({
17653 cls: 'form-control', // bootstrap..
17655 name: this.frameId,
17656 frameBorder : 'no',
17657 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17662 this.iframe = iframe.dom;
17664 this.assignDocWin();
17666 this.doc.designMode = 'on';
17669 this.doc.write(this.getDocMarkup());
17673 var task = { // must defer to wait for browser to be ready
17675 //console.log("run task?" + this.doc.readyState);
17676 this.assignDocWin();
17677 if(this.doc.body || this.doc.readyState == 'complete'){
17679 this.doc.designMode="on";
17683 Roo.TaskMgr.stop(task);
17684 this.initEditor.defer(10, this);
17691 Roo.TaskMgr.start(task);
17696 onResize : function(w, h)
17698 Roo.log('resize: ' +w + ',' + h );
17699 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17703 if(typeof w == 'number'){
17705 this.iframe.style.width = w + 'px';
17707 if(typeof h == 'number'){
17709 this.iframe.style.height = h + 'px';
17711 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17718 * Toggles the editor between standard and source edit mode.
17719 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17721 toggleSourceEdit : function(sourceEditMode){
17723 this.sourceEditMode = sourceEditMode === true;
17725 if(this.sourceEditMode){
17727 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17730 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17731 //this.iframe.className = '';
17734 //this.setSize(this.owner.wrap.getSize());
17735 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17742 * Protected method that will not generally be called directly. If you need/want
17743 * custom HTML cleanup, this is the method you should override.
17744 * @param {String} html The HTML to be cleaned
17745 * return {String} The cleaned HTML
17747 cleanHtml : function(html){
17748 html = String(html);
17749 if(html.length > 5){
17750 if(Roo.isSafari){ // strip safari nonsense
17751 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17754 if(html == ' '){
17761 * HTML Editor -> Textarea
17762 * Protected method that will not generally be called directly. Syncs the contents
17763 * of the editor iframe with the textarea.
17765 syncValue : function(){
17766 if(this.initialized){
17767 var bd = (this.doc.body || this.doc.documentElement);
17768 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17769 var html = bd.innerHTML;
17771 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17772 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17774 html = '<div style="'+m[0]+'">' + html + '</div>';
17777 html = this.cleanHtml(html);
17778 // fix up the special chars.. normaly like back quotes in word...
17779 // however we do not want to do this with chinese..
17780 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17781 var cc = b.charCodeAt();
17783 (cc >= 0x4E00 && cc < 0xA000 ) ||
17784 (cc >= 0x3400 && cc < 0x4E00 ) ||
17785 (cc >= 0xf900 && cc < 0xfb00 )
17791 if(this.owner.fireEvent('beforesync', this, html) !== false){
17792 this.el.dom.value = html;
17793 this.owner.fireEvent('sync', this, html);
17799 * Protected method that will not generally be called directly. Pushes the value of the textarea
17800 * into the iframe editor.
17802 pushValue : function(){
17803 if(this.initialized){
17804 var v = this.el.dom.value.trim();
17806 // if(v.length < 1){
17810 if(this.owner.fireEvent('beforepush', this, v) !== false){
17811 var d = (this.doc.body || this.doc.documentElement);
17813 this.cleanUpPaste();
17814 this.el.dom.value = d.innerHTML;
17815 this.owner.fireEvent('push', this, v);
17821 deferFocus : function(){
17822 this.focus.defer(10, this);
17826 focus : function(){
17827 if(this.win && !this.sourceEditMode){
17834 assignDocWin: function()
17836 var iframe = this.iframe;
17839 this.doc = iframe.contentWindow.document;
17840 this.win = iframe.contentWindow;
17842 // if (!Roo.get(this.frameId)) {
17845 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17846 // this.win = Roo.get(this.frameId).dom.contentWindow;
17848 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17852 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17853 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17858 initEditor : function(){
17859 //console.log("INIT EDITOR");
17860 this.assignDocWin();
17864 this.doc.designMode="on";
17866 this.doc.write(this.getDocMarkup());
17869 var dbody = (this.doc.body || this.doc.documentElement);
17870 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17871 // this copies styles from the containing element into thsi one..
17872 // not sure why we need all of this..
17873 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17875 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17876 //ss['background-attachment'] = 'fixed'; // w3c
17877 dbody.bgProperties = 'fixed'; // ie
17878 //Roo.DomHelper.applyStyles(dbody, ss);
17879 Roo.EventManager.on(this.doc, {
17880 //'mousedown': this.onEditorEvent,
17881 'mouseup': this.onEditorEvent,
17882 'dblclick': this.onEditorEvent,
17883 'click': this.onEditorEvent,
17884 'keyup': this.onEditorEvent,
17889 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17891 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17892 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17894 this.initialized = true;
17896 this.owner.fireEvent('initialize', this);
17901 onDestroy : function(){
17907 //for (var i =0; i < this.toolbars.length;i++) {
17908 // // fixme - ask toolbars for heights?
17909 // this.toolbars[i].onDestroy();
17912 //this.wrap.dom.innerHTML = '';
17913 //this.wrap.remove();
17918 onFirstFocus : function(){
17920 this.assignDocWin();
17923 this.activated = true;
17926 if(Roo.isGecko){ // prevent silly gecko errors
17928 var s = this.win.getSelection();
17929 if(!s.focusNode || s.focusNode.nodeType != 3){
17930 var r = s.getRangeAt(0);
17931 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17936 this.execCmd('useCSS', true);
17937 this.execCmd('styleWithCSS', false);
17940 this.owner.fireEvent('activate', this);
17944 adjustFont: function(btn){
17945 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17946 //if(Roo.isSafari){ // safari
17949 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17950 if(Roo.isSafari){ // safari
17951 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17952 v = (v < 10) ? 10 : v;
17953 v = (v > 48) ? 48 : v;
17954 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17959 v = Math.max(1, v+adjust);
17961 this.execCmd('FontSize', v );
17964 onEditorEvent : function(e){
17965 this.owner.fireEvent('editorevent', this, e);
17966 // this.updateToolbar();
17967 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17970 insertTag : function(tg)
17972 // could be a bit smarter... -> wrap the current selected tRoo..
17973 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17975 range = this.createRange(this.getSelection());
17976 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17977 wrappingNode.appendChild(range.extractContents());
17978 range.insertNode(wrappingNode);
17985 this.execCmd("formatblock", tg);
17989 insertText : function(txt)
17993 var range = this.createRange();
17994 range.deleteContents();
17995 //alert(Sender.getAttribute('label'));
17997 range.insertNode(this.doc.createTextNode(txt));
18003 * Executes a Midas editor command on the editor document and performs necessary focus and
18004 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18005 * @param {String} cmd The Midas command
18006 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18008 relayCmd : function(cmd, value){
18010 this.execCmd(cmd, value);
18011 this.owner.fireEvent('editorevent', this);
18012 //this.updateToolbar();
18013 this.owner.deferFocus();
18017 * Executes a Midas editor command directly on the editor document.
18018 * For visual commands, you should use {@link #relayCmd} instead.
18019 * <b>This should only be called after the editor is initialized.</b>
18020 * @param {String} cmd The Midas command
18021 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18023 execCmd : function(cmd, value){
18024 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18031 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18033 * @param {String} text | dom node..
18035 insertAtCursor : function(text)
18040 if(!this.activated){
18046 var r = this.doc.selection.createRange();
18057 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18061 // from jquery ui (MIT licenced)
18063 var win = this.win;
18065 if (win.getSelection && win.getSelection().getRangeAt) {
18066 range = win.getSelection().getRangeAt(0);
18067 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18068 range.insertNode(node);
18069 } else if (win.document.selection && win.document.selection.createRange) {
18070 // no firefox support
18071 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18072 win.document.selection.createRange().pasteHTML(txt);
18074 // no firefox support
18075 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18076 this.execCmd('InsertHTML', txt);
18085 mozKeyPress : function(e){
18087 var c = e.getCharCode(), cmd;
18090 c = String.fromCharCode(c).toLowerCase();
18104 this.cleanUpPaste.defer(100, this);
18112 e.preventDefault();
18120 fixKeys : function(){ // load time branching for fastest keydown performance
18122 return function(e){
18123 var k = e.getKey(), r;
18126 r = this.doc.selection.createRange();
18129 r.pasteHTML('    ');
18136 r = this.doc.selection.createRange();
18138 var target = r.parentElement();
18139 if(!target || target.tagName.toLowerCase() != 'li'){
18141 r.pasteHTML('<br />');
18147 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18148 this.cleanUpPaste.defer(100, this);
18154 }else if(Roo.isOpera){
18155 return function(e){
18156 var k = e.getKey();
18160 this.execCmd('InsertHTML','    ');
18163 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18164 this.cleanUpPaste.defer(100, this);
18169 }else if(Roo.isSafari){
18170 return function(e){
18171 var k = e.getKey();
18175 this.execCmd('InsertText','\t');
18179 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18180 this.cleanUpPaste.defer(100, this);
18188 getAllAncestors: function()
18190 var p = this.getSelectedNode();
18193 a.push(p); // push blank onto stack..
18194 p = this.getParentElement();
18198 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18202 a.push(this.doc.body);
18206 lastSelNode : false,
18209 getSelection : function()
18211 this.assignDocWin();
18212 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18215 getSelectedNode: function()
18217 // this may only work on Gecko!!!
18219 // should we cache this!!!!
18224 var range = this.createRange(this.getSelection()).cloneRange();
18227 var parent = range.parentElement();
18229 var testRange = range.duplicate();
18230 testRange.moveToElementText(parent);
18231 if (testRange.inRange(range)) {
18234 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18237 parent = parent.parentElement;
18242 // is ancestor a text element.
18243 var ac = range.commonAncestorContainer;
18244 if (ac.nodeType == 3) {
18245 ac = ac.parentNode;
18248 var ar = ac.childNodes;
18251 var other_nodes = [];
18252 var has_other_nodes = false;
18253 for (var i=0;i<ar.length;i++) {
18254 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18257 // fullly contained node.
18259 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18264 // probably selected..
18265 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18266 other_nodes.push(ar[i]);
18270 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18275 has_other_nodes = true;
18277 if (!nodes.length && other_nodes.length) {
18278 nodes= other_nodes;
18280 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18286 createRange: function(sel)
18288 // this has strange effects when using with
18289 // top toolbar - not sure if it's a great idea.
18290 //this.editor.contentWindow.focus();
18291 if (typeof sel != "undefined") {
18293 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18295 return this.doc.createRange();
18298 return this.doc.createRange();
18301 getParentElement: function()
18304 this.assignDocWin();
18305 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18307 var range = this.createRange(sel);
18310 var p = range.commonAncestorContainer;
18311 while (p.nodeType == 3) { // text node
18322 * Range intersection.. the hard stuff...
18326 * [ -- selected range --- ]
18330 * if end is before start or hits it. fail.
18331 * if start is after end or hits it fail.
18333 * if either hits (but other is outside. - then it's not
18339 // @see http://www.thismuchiknow.co.uk/?p=64.
18340 rangeIntersectsNode : function(range, node)
18342 var nodeRange = node.ownerDocument.createRange();
18344 nodeRange.selectNode(node);
18346 nodeRange.selectNodeContents(node);
18349 var rangeStartRange = range.cloneRange();
18350 rangeStartRange.collapse(true);
18352 var rangeEndRange = range.cloneRange();
18353 rangeEndRange.collapse(false);
18355 var nodeStartRange = nodeRange.cloneRange();
18356 nodeStartRange.collapse(true);
18358 var nodeEndRange = nodeRange.cloneRange();
18359 nodeEndRange.collapse(false);
18361 return rangeStartRange.compareBoundaryPoints(
18362 Range.START_TO_START, nodeEndRange) == -1 &&
18363 rangeEndRange.compareBoundaryPoints(
18364 Range.START_TO_START, nodeStartRange) == 1;
18368 rangeCompareNode : function(range, node)
18370 var nodeRange = node.ownerDocument.createRange();
18372 nodeRange.selectNode(node);
18374 nodeRange.selectNodeContents(node);
18378 range.collapse(true);
18380 nodeRange.collapse(true);
18382 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18383 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18385 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18387 var nodeIsBefore = ss == 1;
18388 var nodeIsAfter = ee == -1;
18390 if (nodeIsBefore && nodeIsAfter)
18392 if (!nodeIsBefore && nodeIsAfter)
18393 return 1; //right trailed.
18395 if (nodeIsBefore && !nodeIsAfter)
18396 return 2; // left trailed.
18401 // private? - in a new class?
18402 cleanUpPaste : function()
18404 // cleans up the whole document..
18405 Roo.log('cleanuppaste');
18407 this.cleanUpChildren(this.doc.body);
18408 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18409 if (clean != this.doc.body.innerHTML) {
18410 this.doc.body.innerHTML = clean;
18415 cleanWordChars : function(input) {// change the chars to hex code
18416 var he = Roo.HtmlEditorCore;
18418 var output = input;
18419 Roo.each(he.swapCodes, function(sw) {
18420 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18422 output = output.replace(swapper, sw[1]);
18429 cleanUpChildren : function (n)
18431 if (!n.childNodes.length) {
18434 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18435 this.cleanUpChild(n.childNodes[i]);
18442 cleanUpChild : function (node)
18445 //console.log(node);
18446 if (node.nodeName == "#text") {
18447 // clean up silly Windows -- stuff?
18450 if (node.nodeName == "#comment") {
18451 node.parentNode.removeChild(node);
18452 // clean up silly Windows -- stuff?
18455 var lcname = node.tagName.toLowerCase();
18456 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18457 // whitelist of tags..
18459 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18461 node.parentNode.removeChild(node);
18466 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18468 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18469 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18471 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18472 // remove_keep_children = true;
18475 if (remove_keep_children) {
18476 this.cleanUpChildren(node);
18477 // inserts everything just before this node...
18478 while (node.childNodes.length) {
18479 var cn = node.childNodes[0];
18480 node.removeChild(cn);
18481 node.parentNode.insertBefore(cn, node);
18483 node.parentNode.removeChild(node);
18487 if (!node.attributes || !node.attributes.length) {
18488 this.cleanUpChildren(node);
18492 function cleanAttr(n,v)
18495 if (v.match(/^\./) || v.match(/^\//)) {
18498 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18501 if (v.match(/^#/)) {
18504 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18505 node.removeAttribute(n);
18509 var cwhite = this.cwhite;
18510 var cblack = this.cblack;
18512 function cleanStyle(n,v)
18514 if (v.match(/expression/)) { //XSS?? should we even bother..
18515 node.removeAttribute(n);
18519 var parts = v.split(/;/);
18522 Roo.each(parts, function(p) {
18523 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18527 var l = p.split(':').shift().replace(/\s+/g,'');
18528 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18530 if ( cwhite.length && cblack.indexOf(l) > -1) {
18531 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18532 //node.removeAttribute(n);
18536 // only allow 'c whitelisted system attributes'
18537 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18538 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18539 //node.removeAttribute(n);
18549 if (clean.length) {
18550 node.setAttribute(n, clean.join(';'));
18552 node.removeAttribute(n);
18558 for (var i = node.attributes.length-1; i > -1 ; i--) {
18559 var a = node.attributes[i];
18562 if (a.name.toLowerCase().substr(0,2)=='on') {
18563 node.removeAttribute(a.name);
18566 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18567 node.removeAttribute(a.name);
18570 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18571 cleanAttr(a.name,a.value); // fixme..
18574 if (a.name == 'style') {
18575 cleanStyle(a.name,a.value);
18578 /// clean up MS crap..
18579 // tecnically this should be a list of valid class'es..
18582 if (a.name == 'class') {
18583 if (a.value.match(/^Mso/)) {
18584 node.className = '';
18587 if (a.value.match(/body/)) {
18588 node.className = '';
18599 this.cleanUpChildren(node);
18604 * Clean up MS wordisms...
18606 cleanWord : function(node)
18609 var cleanWordChildren = function()
18611 if (!node.childNodes.length) {
18614 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18615 _t.cleanWord(node.childNodes[i]);
18621 this.cleanWord(this.doc.body);
18624 if (node.nodeName == "#text") {
18625 // clean up silly Windows -- stuff?
18628 if (node.nodeName == "#comment") {
18629 node.parentNode.removeChild(node);
18630 // clean up silly Windows -- stuff?
18634 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18635 node.parentNode.removeChild(node);
18639 // remove - but keep children..
18640 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18641 while (node.childNodes.length) {
18642 var cn = node.childNodes[0];
18643 node.removeChild(cn);
18644 node.parentNode.insertBefore(cn, node);
18646 node.parentNode.removeChild(node);
18647 cleanWordChildren();
18651 if (node.className.length) {
18653 var cn = node.className.split(/\W+/);
18655 Roo.each(cn, function(cls) {
18656 if (cls.match(/Mso[a-zA-Z]+/)) {
18661 node.className = cna.length ? cna.join(' ') : '';
18663 node.removeAttribute("class");
18667 if (node.hasAttribute("lang")) {
18668 node.removeAttribute("lang");
18671 if (node.hasAttribute("style")) {
18673 var styles = node.getAttribute("style").split(";");
18675 Roo.each(styles, function(s) {
18676 if (!s.match(/:/)) {
18679 var kv = s.split(":");
18680 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18683 // what ever is left... we allow.
18686 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18687 if (!nstyle.length) {
18688 node.removeAttribute('style');
18692 cleanWordChildren();
18696 domToHTML : function(currentElement, depth, nopadtext) {
18698 depth = depth || 0;
18699 nopadtext = nopadtext || false;
18701 if (!currentElement) {
18702 return this.domToHTML(this.doc.body);
18705 //Roo.log(currentElement);
18707 var allText = false;
18708 var nodeName = currentElement.nodeName;
18709 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18711 if (nodeName == '#text') {
18713 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18718 if (nodeName != 'BODY') {
18721 // Prints the node tagName, such as <A>, <IMG>, etc
18724 for(i = 0; i < currentElement.attributes.length;i++) {
18726 var aname = currentElement.attributes.item(i).name;
18727 if (!currentElement.attributes.item(i).value.length) {
18730 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18733 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18742 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18745 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18750 // Traverse the tree
18752 var currentElementChild = currentElement.childNodes.item(i);
18753 var allText = true;
18754 var innerHTML = '';
18756 while (currentElementChild) {
18757 // Formatting code (indent the tree so it looks nice on the screen)
18758 var nopad = nopadtext;
18759 if (lastnode == 'SPAN') {
18763 if (currentElementChild.nodeName == '#text') {
18764 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18765 toadd = nopadtext ? toadd : toadd.trim();
18766 if (!nopad && toadd.length > 80) {
18767 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18769 innerHTML += toadd;
18772 currentElementChild = currentElement.childNodes.item(i);
18778 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18780 // Recursively traverse the tree structure of the child node
18781 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18782 lastnode = currentElementChild.nodeName;
18784 currentElementChild=currentElement.childNodes.item(i);
18790 // The remaining code is mostly for formatting the tree
18791 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18796 ret+= "</"+tagName+">";
18802 applyBlacklists : function()
18804 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18805 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18809 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18810 if (b.indexOf(tag) > -1) {
18813 this.white.push(tag);
18817 Roo.each(w, function(tag) {
18818 if (b.indexOf(tag) > -1) {
18821 if (this.white.indexOf(tag) > -1) {
18824 this.white.push(tag);
18829 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18830 if (w.indexOf(tag) > -1) {
18833 this.black.push(tag);
18837 Roo.each(b, function(tag) {
18838 if (w.indexOf(tag) > -1) {
18841 if (this.black.indexOf(tag) > -1) {
18844 this.black.push(tag);
18849 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18850 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18854 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18855 if (b.indexOf(tag) > -1) {
18858 this.cwhite.push(tag);
18862 Roo.each(w, function(tag) {
18863 if (b.indexOf(tag) > -1) {
18866 if (this.cwhite.indexOf(tag) > -1) {
18869 this.cwhite.push(tag);
18874 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18875 if (w.indexOf(tag) > -1) {
18878 this.cblack.push(tag);
18882 Roo.each(b, function(tag) {
18883 if (w.indexOf(tag) > -1) {
18886 if (this.cblack.indexOf(tag) > -1) {
18889 this.cblack.push(tag);
18894 setStylesheets : function(stylesheets)
18896 if(typeof(stylesheets) == 'string'){
18897 Roo.get(this.iframe.contentDocument.head).createChild({
18899 rel : 'stylesheet',
18908 Roo.each(stylesheets, function(s) {
18913 Roo.get(_this.iframe.contentDocument.head).createChild({
18915 rel : 'stylesheet',
18924 removeStylesheets : function()
18928 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18933 // hide stuff that is not compatible
18947 * @event specialkey
18951 * @cfg {String} fieldClass @hide
18954 * @cfg {String} focusClass @hide
18957 * @cfg {String} autoCreate @hide
18960 * @cfg {String} inputType @hide
18963 * @cfg {String} invalidClass @hide
18966 * @cfg {String} invalidText @hide
18969 * @cfg {String} msgFx @hide
18972 * @cfg {String} validateOnBlur @hide
18976 Roo.HtmlEditorCore.white = [
18977 'area', 'br', 'img', 'input', 'hr', 'wbr',
18979 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18980 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18981 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18982 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18983 'table', 'ul', 'xmp',
18985 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18988 'dir', 'menu', 'ol', 'ul', 'dl',
18994 Roo.HtmlEditorCore.black = [
18995 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18997 'base', 'basefont', 'bgsound', 'blink', 'body',
18998 'frame', 'frameset', 'head', 'html', 'ilayer',
18999 'iframe', 'layer', 'link', 'meta', 'object',
19000 'script', 'style' ,'title', 'xml' // clean later..
19002 Roo.HtmlEditorCore.clean = [
19003 'script', 'style', 'title', 'xml'
19005 Roo.HtmlEditorCore.remove = [
19010 Roo.HtmlEditorCore.ablack = [
19014 Roo.HtmlEditorCore.aclean = [
19015 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19019 Roo.HtmlEditorCore.pwhite= [
19020 'http', 'https', 'mailto'
19023 // white listed style attributes.
19024 Roo.HtmlEditorCore.cwhite= [
19025 // 'text-align', /// default is to allow most things..
19031 // black listed style attributes.
19032 Roo.HtmlEditorCore.cblack= [
19033 // 'font-size' -- this can be set by the project
19037 Roo.HtmlEditorCore.swapCodes =[
19056 * @class Roo.bootstrap.HtmlEditor
19057 * @extends Roo.bootstrap.TextArea
19058 * Bootstrap HtmlEditor class
19061 * Create a new HtmlEditor
19062 * @param {Object} config The config object
19065 Roo.bootstrap.HtmlEditor = function(config){
19066 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19067 if (!this.toolbars) {
19068 this.toolbars = [];
19070 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19073 * @event initialize
19074 * Fires when the editor is fully initialized (including the iframe)
19075 * @param {HtmlEditor} this
19080 * Fires when the editor is first receives the focus. Any insertion must wait
19081 * until after this event.
19082 * @param {HtmlEditor} this
19086 * @event beforesync
19087 * Fires before the textarea is updated with content from the editor iframe. Return false
19088 * to cancel the sync.
19089 * @param {HtmlEditor} this
19090 * @param {String} html
19094 * @event beforepush
19095 * Fires before the iframe editor is updated with content from the textarea. Return false
19096 * to cancel the push.
19097 * @param {HtmlEditor} this
19098 * @param {String} html
19103 * Fires when the textarea is updated with content from the editor iframe.
19104 * @param {HtmlEditor} this
19105 * @param {String} html
19110 * Fires when the iframe editor is updated with content from the textarea.
19111 * @param {HtmlEditor} this
19112 * @param {String} html
19116 * @event editmodechange
19117 * Fires when the editor switches edit modes
19118 * @param {HtmlEditor} this
19119 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19121 editmodechange: true,
19123 * @event editorevent
19124 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19125 * @param {HtmlEditor} this
19129 * @event firstfocus
19130 * Fires when on first focus - needed by toolbars..
19131 * @param {HtmlEditor} this
19136 * Auto save the htmlEditor value as a file into Events
19137 * @param {HtmlEditor} this
19141 * @event savedpreview
19142 * preview the saved version of htmlEditor
19143 * @param {HtmlEditor} this
19150 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19154 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19159 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19164 * @cfg {Number} height (in pixels)
19168 * @cfg {Number} width (in pixels)
19173 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19176 stylesheets: false,
19181 // private properties
19182 validationEvent : false,
19184 initialized : false,
19187 onFocus : Roo.emptyFn,
19189 hideMode:'offsets',
19192 tbContainer : false,
19194 toolbarContainer :function() {
19195 return this.wrap.select('.x-html-editor-tb',true).first();
19199 * Protected method that will not generally be called directly. It
19200 * is called when the editor creates its toolbar. Override this method if you need to
19201 * add custom toolbar buttons.
19202 * @param {HtmlEditor} editor
19204 createToolbar : function(){
19206 Roo.log("create toolbars");
19208 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19209 this.toolbars[0].render(this.toolbarContainer());
19213 // if (!editor.toolbars || !editor.toolbars.length) {
19214 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19217 // for (var i =0 ; i < editor.toolbars.length;i++) {
19218 // editor.toolbars[i] = Roo.factory(
19219 // typeof(editor.toolbars[i]) == 'string' ?
19220 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19221 // Roo.bootstrap.HtmlEditor);
19222 // editor.toolbars[i].init(editor);
19228 onRender : function(ct, position)
19230 // Roo.log("Call onRender: " + this.xtype);
19232 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19234 this.wrap = this.inputEl().wrap({
19235 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19238 this.editorcore.onRender(ct, position);
19240 if (this.resizable) {
19241 this.resizeEl = new Roo.Resizable(this.wrap, {
19245 minHeight : this.height,
19246 height: this.height,
19247 handles : this.resizable,
19250 resize : function(r, w, h) {
19251 _t.onResize(w,h); // -something
19257 this.createToolbar(this);
19260 if(!this.width && this.resizable){
19261 this.setSize(this.wrap.getSize());
19263 if (this.resizeEl) {
19264 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19265 // should trigger onReize..
19271 onResize : function(w, h)
19273 Roo.log('resize: ' +w + ',' + h );
19274 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19278 if(this.inputEl() ){
19279 if(typeof w == 'number'){
19280 var aw = w - this.wrap.getFrameWidth('lr');
19281 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19284 if(typeof h == 'number'){
19285 var tbh = -11; // fixme it needs to tool bar size!
19286 for (var i =0; i < this.toolbars.length;i++) {
19287 // fixme - ask toolbars for heights?
19288 tbh += this.toolbars[i].el.getHeight();
19289 //if (this.toolbars[i].footer) {
19290 // tbh += this.toolbars[i].footer.el.getHeight();
19298 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19299 ah -= 5; // knock a few pixes off for look..
19300 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19304 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19305 this.editorcore.onResize(ew,eh);
19310 * Toggles the editor between standard and source edit mode.
19311 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19313 toggleSourceEdit : function(sourceEditMode)
19315 this.editorcore.toggleSourceEdit(sourceEditMode);
19317 if(this.editorcore.sourceEditMode){
19318 Roo.log('editor - showing textarea');
19321 // Roo.log(this.syncValue());
19323 this.inputEl().removeClass(['hide', 'x-hidden']);
19324 this.inputEl().dom.removeAttribute('tabIndex');
19325 this.inputEl().focus();
19327 Roo.log('editor - hiding textarea');
19329 // Roo.log(this.pushValue());
19332 this.inputEl().addClass(['hide', 'x-hidden']);
19333 this.inputEl().dom.setAttribute('tabIndex', -1);
19334 //this.deferFocus();
19337 if(this.resizable){
19338 this.setSize(this.wrap.getSize());
19341 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19344 // private (for BoxComponent)
19345 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19347 // private (for BoxComponent)
19348 getResizeEl : function(){
19352 // private (for BoxComponent)
19353 getPositionEl : function(){
19358 initEvents : function(){
19359 this.originalValue = this.getValue();
19363 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19366 // markInvalid : Roo.emptyFn,
19368 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19371 // clearInvalid : Roo.emptyFn,
19373 setValue : function(v){
19374 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19375 this.editorcore.pushValue();
19380 deferFocus : function(){
19381 this.focus.defer(10, this);
19385 focus : function(){
19386 this.editorcore.focus();
19392 onDestroy : function(){
19398 for (var i =0; i < this.toolbars.length;i++) {
19399 // fixme - ask toolbars for heights?
19400 this.toolbars[i].onDestroy();
19403 this.wrap.dom.innerHTML = '';
19404 this.wrap.remove();
19409 onFirstFocus : function(){
19410 //Roo.log("onFirstFocus");
19411 this.editorcore.onFirstFocus();
19412 for (var i =0; i < this.toolbars.length;i++) {
19413 this.toolbars[i].onFirstFocus();
19419 syncValue : function()
19421 this.editorcore.syncValue();
19424 pushValue : function()
19426 this.editorcore.pushValue();
19430 // hide stuff that is not compatible
19444 * @event specialkey
19448 * @cfg {String} fieldClass @hide
19451 * @cfg {String} focusClass @hide
19454 * @cfg {String} autoCreate @hide
19457 * @cfg {String} inputType @hide
19460 * @cfg {String} invalidClass @hide
19463 * @cfg {String} invalidText @hide
19466 * @cfg {String} msgFx @hide
19469 * @cfg {String} validateOnBlur @hide
19478 Roo.namespace('Roo.bootstrap.htmleditor');
19480 * @class Roo.bootstrap.HtmlEditorToolbar1
19485 new Roo.bootstrap.HtmlEditor({
19488 new Roo.bootstrap.HtmlEditorToolbar1({
19489 disable : { fonts: 1 , format: 1, ..., ... , ...],
19495 * @cfg {Object} disable List of elements to disable..
19496 * @cfg {Array} btns List of additional buttons.
19500 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19503 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19506 Roo.apply(this, config);
19508 // default disabled, based on 'good practice'..
19509 this.disable = this.disable || {};
19510 Roo.applyIf(this.disable, {
19513 specialElements : true
19515 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19517 this.editor = config.editor;
19518 this.editorcore = config.editor.editorcore;
19520 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19522 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19523 // dont call parent... till later.
19525 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19530 editorcore : false,
19535 "h1","h2","h3","h4","h5","h6",
19537 "abbr", "acronym", "address", "cite", "samp", "var",
19541 onRender : function(ct, position)
19543 // Roo.log("Call onRender: " + this.xtype);
19545 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19547 this.el.dom.style.marginBottom = '0';
19549 var editorcore = this.editorcore;
19550 var editor= this.editor;
19553 var btn = function(id,cmd , toggle, handler){
19555 var event = toggle ? 'toggle' : 'click';
19560 xns: Roo.bootstrap,
19563 enableToggle:toggle !== false,
19565 pressed : toggle ? false : null,
19568 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19569 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19578 xns: Roo.bootstrap,
19579 glyphicon : 'font',
19583 xns: Roo.bootstrap,
19587 Roo.each(this.formats, function(f) {
19588 style.menu.items.push({
19590 xns: Roo.bootstrap,
19591 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19596 editorcore.insertTag(this.tagname);
19603 children.push(style);
19606 btn('bold',false,true);
19607 btn('italic',false,true);
19608 btn('align-left', 'justifyleft',true);
19609 btn('align-center', 'justifycenter',true);
19610 btn('align-right' , 'justifyright',true);
19611 btn('link', false, false, function(btn) {
19612 //Roo.log("create link?");
19613 var url = prompt(this.createLinkText, this.defaultLinkValue);
19614 if(url && url != 'http:/'+'/'){
19615 this.editorcore.relayCmd('createlink', url);
19618 btn('list','insertunorderedlist',true);
19619 btn('pencil', false,true, function(btn){
19622 this.toggleSourceEdit(btn.pressed);
19628 xns: Roo.bootstrap,
19633 xns: Roo.bootstrap,
19638 cog.menu.items.push({
19640 xns: Roo.bootstrap,
19641 html : Clean styles,
19646 editorcore.insertTag(this.tagname);
19655 this.xtype = 'NavSimplebar';
19657 for(var i=0;i< children.length;i++) {
19659 this.buttons.add(this.addxtypeChild(children[i]));
19663 editor.on('editorevent', this.updateToolbar, this);
19665 onBtnClick : function(id)
19667 this.editorcore.relayCmd(id);
19668 this.editorcore.focus();
19672 * Protected method that will not generally be called directly. It triggers
19673 * a toolbar update by reading the markup state of the current selection in the editor.
19675 updateToolbar: function(){
19677 if(!this.editorcore.activated){
19678 this.editor.onFirstFocus(); // is this neeed?
19682 var btns = this.buttons;
19683 var doc = this.editorcore.doc;
19684 btns.get('bold').setActive(doc.queryCommandState('bold'));
19685 btns.get('italic').setActive(doc.queryCommandState('italic'));
19686 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19688 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19689 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19690 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19692 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19693 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19696 var ans = this.editorcore.getAllAncestors();
19697 if (this.formatCombo) {
19700 var store = this.formatCombo.store;
19701 this.formatCombo.setValue("");
19702 for (var i =0; i < ans.length;i++) {
19703 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19705 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19713 // hides menus... - so this cant be on a menu...
19714 Roo.bootstrap.MenuMgr.hideAll();
19716 Roo.bootstrap.MenuMgr.hideAll();
19717 //this.editorsyncValue();
19719 onFirstFocus: function() {
19720 this.buttons.each(function(item){
19724 toggleSourceEdit : function(sourceEditMode){
19727 if(sourceEditMode){
19728 Roo.log("disabling buttons");
19729 this.buttons.each( function(item){
19730 if(item.cmd != 'pencil'){
19736 Roo.log("enabling buttons");
19737 if(this.editorcore.initialized){
19738 this.buttons.each( function(item){
19744 Roo.log("calling toggole on editor");
19745 // tell the editor that it's been pressed..
19746 this.editor.toggleSourceEdit(sourceEditMode);
19756 * @class Roo.bootstrap.Table.AbstractSelectionModel
19757 * @extends Roo.util.Observable
19758 * Abstract base class for grid SelectionModels. It provides the interface that should be
19759 * implemented by descendant classes. This class should not be directly instantiated.
19762 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19763 this.locked = false;
19764 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19768 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19769 /** @ignore Called by the grid automatically. Do not call directly. */
19770 init : function(grid){
19776 * Locks the selections.
19779 this.locked = true;
19783 * Unlocks the selections.
19785 unlock : function(){
19786 this.locked = false;
19790 * Returns true if the selections are locked.
19791 * @return {Boolean}
19793 isLocked : function(){
19794 return this.locked;
19798 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19799 * @class Roo.bootstrap.Table.RowSelectionModel
19800 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19801 * It supports multiple selections and keyboard selection/navigation.
19803 * @param {Object} config
19806 Roo.bootstrap.Table.RowSelectionModel = function(config){
19807 Roo.apply(this, config);
19808 this.selections = new Roo.util.MixedCollection(false, function(o){
19813 this.lastActive = false;
19817 * @event selectionchange
19818 * Fires when the selection changes
19819 * @param {SelectionModel} this
19821 "selectionchange" : true,
19823 * @event afterselectionchange
19824 * Fires after the selection changes (eg. by key press or clicking)
19825 * @param {SelectionModel} this
19827 "afterselectionchange" : true,
19829 * @event beforerowselect
19830 * Fires when a row is selected being selected, return false to cancel.
19831 * @param {SelectionModel} this
19832 * @param {Number} rowIndex The selected index
19833 * @param {Boolean} keepExisting False if other selections will be cleared
19835 "beforerowselect" : true,
19838 * Fires when a row is selected.
19839 * @param {SelectionModel} this
19840 * @param {Number} rowIndex The selected index
19841 * @param {Roo.data.Record} r The record
19843 "rowselect" : true,
19845 * @event rowdeselect
19846 * Fires when a row is deselected.
19847 * @param {SelectionModel} this
19848 * @param {Number} rowIndex The selected index
19850 "rowdeselect" : true
19852 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19853 this.locked = false;
19856 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19858 * @cfg {Boolean} singleSelect
19859 * True to allow selection of only one row at a time (defaults to false)
19861 singleSelect : false,
19864 initEvents : function(){
19866 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19867 this.grid.on("mousedown", this.handleMouseDown, this);
19868 }else{ // allow click to work like normal
19869 this.grid.on("rowclick", this.handleDragableRowClick, this);
19872 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19873 "up" : function(e){
19875 this.selectPrevious(e.shiftKey);
19876 }else if(this.last !== false && this.lastActive !== false){
19877 var last = this.last;
19878 this.selectRange(this.last, this.lastActive-1);
19879 this.grid.getView().focusRow(this.lastActive);
19880 if(last !== false){
19884 this.selectFirstRow();
19886 this.fireEvent("afterselectionchange", this);
19888 "down" : function(e){
19890 this.selectNext(e.shiftKey);
19891 }else if(this.last !== false && this.lastActive !== false){
19892 var last = this.last;
19893 this.selectRange(this.last, this.lastActive+1);
19894 this.grid.getView().focusRow(this.lastActive);
19895 if(last !== false){
19899 this.selectFirstRow();
19901 this.fireEvent("afterselectionchange", this);
19906 var view = this.grid.view;
19907 view.on("refresh", this.onRefresh, this);
19908 view.on("rowupdated", this.onRowUpdated, this);
19909 view.on("rowremoved", this.onRemove, this);
19913 onRefresh : function(){
19914 var ds = this.grid.dataSource, i, v = this.grid.view;
19915 var s = this.selections;
19916 s.each(function(r){
19917 if((i = ds.indexOfId(r.id)) != -1){
19926 onRemove : function(v, index, r){
19927 this.selections.remove(r);
19931 onRowUpdated : function(v, index, r){
19932 if(this.isSelected(r)){
19933 v.onRowSelect(index);
19939 * @param {Array} records The records to select
19940 * @param {Boolean} keepExisting (optional) True to keep existing selections
19942 selectRecords : function(records, keepExisting){
19944 this.clearSelections();
19946 var ds = this.grid.dataSource;
19947 for(var i = 0, len = records.length; i < len; i++){
19948 this.selectRow(ds.indexOf(records[i]), true);
19953 * Gets the number of selected rows.
19956 getCount : function(){
19957 return this.selections.length;
19961 * Selects the first row in the grid.
19963 selectFirstRow : function(){
19968 * Select the last row.
19969 * @param {Boolean} keepExisting (optional) True to keep existing selections
19971 selectLastRow : function(keepExisting){
19972 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19976 * Selects the row immediately following the last selected row.
19977 * @param {Boolean} keepExisting (optional) True to keep existing selections
19979 selectNext : function(keepExisting){
19980 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19981 this.selectRow(this.last+1, keepExisting);
19982 this.grid.getView().focusRow(this.last);
19987 * Selects the row that precedes the last selected row.
19988 * @param {Boolean} keepExisting (optional) True to keep existing selections
19990 selectPrevious : function(keepExisting){
19992 this.selectRow(this.last-1, keepExisting);
19993 this.grid.getView().focusRow(this.last);
19998 * Returns the selected records
19999 * @return {Array} Array of selected records
20001 getSelections : function(){
20002 return [].concat(this.selections.items);
20006 * Returns the first selected record.
20009 getSelected : function(){
20010 return this.selections.itemAt(0);
20015 * Clears all selections.
20017 clearSelections : function(fast){
20018 if(this.locked) return;
20020 var ds = this.grid.dataSource;
20021 var s = this.selections;
20022 s.each(function(r){
20023 this.deselectRow(ds.indexOfId(r.id));
20027 this.selections.clear();
20034 * Selects all rows.
20036 selectAll : function(){
20037 if(this.locked) return;
20038 this.selections.clear();
20039 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20040 this.selectRow(i, true);
20045 * Returns True if there is a selection.
20046 * @return {Boolean}
20048 hasSelection : function(){
20049 return this.selections.length > 0;
20053 * Returns True if the specified row is selected.
20054 * @param {Number/Record} record The record or index of the record to check
20055 * @return {Boolean}
20057 isSelected : function(index){
20058 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20059 return (r && this.selections.key(r.id) ? true : false);
20063 * Returns True if the specified record id is selected.
20064 * @param {String} id The id of record to check
20065 * @return {Boolean}
20067 isIdSelected : function(id){
20068 return (this.selections.key(id) ? true : false);
20072 handleMouseDown : function(e, t){
20073 var view = this.grid.getView(), rowIndex;
20074 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20077 if(e.shiftKey && this.last !== false){
20078 var last = this.last;
20079 this.selectRange(last, rowIndex, e.ctrlKey);
20080 this.last = last; // reset the last
20081 view.focusRow(rowIndex);
20083 var isSelected = this.isSelected(rowIndex);
20084 if(e.button !== 0 && isSelected){
20085 view.focusRow(rowIndex);
20086 }else if(e.ctrlKey && isSelected){
20087 this.deselectRow(rowIndex);
20088 }else if(!isSelected){
20089 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20090 view.focusRow(rowIndex);
20093 this.fireEvent("afterselectionchange", this);
20096 handleDragableRowClick : function(grid, rowIndex, e)
20098 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20099 this.selectRow(rowIndex, false);
20100 grid.view.focusRow(rowIndex);
20101 this.fireEvent("afterselectionchange", this);
20106 * Selects multiple rows.
20107 * @param {Array} rows Array of the indexes of the row to select
20108 * @param {Boolean} keepExisting (optional) True to keep existing selections
20110 selectRows : function(rows, keepExisting){
20112 this.clearSelections();
20114 for(var i = 0, len = rows.length; i < len; i++){
20115 this.selectRow(rows[i], true);
20120 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20121 * @param {Number} startRow The index of the first row in the range
20122 * @param {Number} endRow The index of the last row in the range
20123 * @param {Boolean} keepExisting (optional) True to retain existing selections
20125 selectRange : function(startRow, endRow, keepExisting){
20126 if(this.locked) return;
20128 this.clearSelections();
20130 if(startRow <= endRow){
20131 for(var i = startRow; i <= endRow; i++){
20132 this.selectRow(i, true);
20135 for(var i = startRow; i >= endRow; i--){
20136 this.selectRow(i, true);
20142 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20143 * @param {Number} startRow The index of the first row in the range
20144 * @param {Number} endRow The index of the last row in the range
20146 deselectRange : function(startRow, endRow, preventViewNotify){
20147 if(this.locked) return;
20148 for(var i = startRow; i <= endRow; i++){
20149 this.deselectRow(i, preventViewNotify);
20155 * @param {Number} row The index of the row to select
20156 * @param {Boolean} keepExisting (optional) True to keep existing selections
20158 selectRow : function(index, keepExisting, preventViewNotify){
20159 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20160 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20161 if(!keepExisting || this.singleSelect){
20162 this.clearSelections();
20164 var r = this.grid.dataSource.getAt(index);
20165 this.selections.add(r);
20166 this.last = this.lastActive = index;
20167 if(!preventViewNotify){
20168 this.grid.getView().onRowSelect(index);
20170 this.fireEvent("rowselect", this, index, r);
20171 this.fireEvent("selectionchange", this);
20177 * @param {Number} row The index of the row to deselect
20179 deselectRow : function(index, preventViewNotify){
20180 if(this.locked) return;
20181 if(this.last == index){
20184 if(this.lastActive == index){
20185 this.lastActive = false;
20187 var r = this.grid.dataSource.getAt(index);
20188 this.selections.remove(r);
20189 if(!preventViewNotify){
20190 this.grid.getView().onRowDeselect(index);
20192 this.fireEvent("rowdeselect", this, index);
20193 this.fireEvent("selectionchange", this);
20197 restoreLast : function(){
20199 this.last = this._last;
20204 acceptsNav : function(row, col, cm){
20205 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20209 onEditorKey : function(field, e){
20210 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20215 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20217 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20219 }else if(k == e.ENTER && !e.ctrlKey){
20223 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20225 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20227 }else if(k == e.ESC){
20231 g.startEditing(newCell[0], newCell[1]);
20236 * Ext JS Library 1.1.1
20237 * Copyright(c) 2006-2007, Ext JS, LLC.
20239 * Originally Released Under LGPL - original licence link has changed is not relivant.
20242 * <script type="text/javascript">
20246 * @class Roo.bootstrap.PagingToolbar
20248 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20250 * Create a new PagingToolbar
20251 * @param {Object} config The config object
20253 Roo.bootstrap.PagingToolbar = function(config)
20255 // old args format still supported... - xtype is prefered..
20256 // created from xtype...
20257 var ds = config.dataSource;
20258 this.toolbarItems = [];
20259 if (config.items) {
20260 this.toolbarItems = config.items;
20261 // config.items = [];
20264 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20271 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20275 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20277 * @cfg {Roo.data.Store} dataSource
20278 * The underlying data store providing the paged data
20281 * @cfg {String/HTMLElement/Element} container
20282 * container The id or element that will contain the toolbar
20285 * @cfg {Boolean} displayInfo
20286 * True to display the displayMsg (defaults to false)
20289 * @cfg {Number} pageSize
20290 * The number of records to display per page (defaults to 20)
20294 * @cfg {String} displayMsg
20295 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20297 displayMsg : 'Displaying {0} - {1} of {2}',
20299 * @cfg {String} emptyMsg
20300 * The message to display when no records are found (defaults to "No data to display")
20302 emptyMsg : 'No data to display',
20304 * Customizable piece of the default paging text (defaults to "Page")
20307 beforePageText : "Page",
20309 * Customizable piece of the default paging text (defaults to "of %0")
20312 afterPageText : "of {0}",
20314 * Customizable piece of the default paging text (defaults to "First Page")
20317 firstText : "First Page",
20319 * Customizable piece of the default paging text (defaults to "Previous Page")
20322 prevText : "Previous Page",
20324 * Customizable piece of the default paging text (defaults to "Next Page")
20327 nextText : "Next Page",
20329 * Customizable piece of the default paging text (defaults to "Last Page")
20332 lastText : "Last Page",
20334 * Customizable piece of the default paging text (defaults to "Refresh")
20337 refreshText : "Refresh",
20341 onRender : function(ct, position)
20343 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20344 this.navgroup.parentId = this.id;
20345 this.navgroup.onRender(this.el, null);
20346 // add the buttons to the navgroup
20348 if(this.displayInfo){
20349 Roo.log(this.el.select('ul.navbar-nav',true).first());
20350 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20351 this.displayEl = this.el.select('.x-paging-info', true).first();
20352 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20353 // this.displayEl = navel.el.select('span',true).first();
20359 Roo.each(_this.buttons, function(e){
20360 Roo.factory(e).onRender(_this.el, null);
20364 Roo.each(_this.toolbarItems, function(e) {
20365 _this.navgroup.addItem(e);
20369 this.first = this.navgroup.addItem({
20370 tooltip: this.firstText,
20372 icon : 'fa fa-backward',
20374 preventDefault: true,
20375 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20378 this.prev = this.navgroup.addItem({
20379 tooltip: this.prevText,
20381 icon : 'fa fa-step-backward',
20383 preventDefault: true,
20384 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20386 //this.addSeparator();
20389 var field = this.navgroup.addItem( {
20391 cls : 'x-paging-position',
20393 html : this.beforePageText +
20394 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20395 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20398 this.field = field.el.select('input', true).first();
20399 this.field.on("keydown", this.onPagingKeydown, this);
20400 this.field.on("focus", function(){this.dom.select();});
20403 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20404 //this.field.setHeight(18);
20405 //this.addSeparator();
20406 this.next = this.navgroup.addItem({
20407 tooltip: this.nextText,
20409 html : ' <i class="fa fa-step-forward">',
20411 preventDefault: true,
20412 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20414 this.last = this.navgroup.addItem({
20415 tooltip: this.lastText,
20416 icon : 'fa fa-forward',
20419 preventDefault: true,
20420 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20422 //this.addSeparator();
20423 this.loading = this.navgroup.addItem({
20424 tooltip: this.refreshText,
20425 icon: 'fa fa-refresh',
20426 preventDefault: true,
20427 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20433 updateInfo : function(){
20434 if(this.displayEl){
20435 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20436 var msg = count == 0 ?
20440 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20442 this.displayEl.update(msg);
20447 onLoad : function(ds, r, o){
20448 this.cursor = o.params ? o.params.start : 0;
20449 var d = this.getPageData(),
20453 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20454 this.field.dom.value = ap;
20455 this.first.setDisabled(ap == 1);
20456 this.prev.setDisabled(ap == 1);
20457 this.next.setDisabled(ap == ps);
20458 this.last.setDisabled(ap == ps);
20459 this.loading.enable();
20464 getPageData : function(){
20465 var total = this.ds.getTotalCount();
20468 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20469 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20474 onLoadError : function(){
20475 this.loading.enable();
20479 onPagingKeydown : function(e){
20480 var k = e.getKey();
20481 var d = this.getPageData();
20483 var v = this.field.dom.value, pageNum;
20484 if(!v || isNaN(pageNum = parseInt(v, 10))){
20485 this.field.dom.value = d.activePage;
20488 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20489 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20492 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))
20494 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20495 this.field.dom.value = pageNum;
20496 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20499 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20501 var v = this.field.dom.value, pageNum;
20502 var increment = (e.shiftKey) ? 10 : 1;
20503 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20505 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20506 this.field.dom.value = d.activePage;
20509 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20511 this.field.dom.value = parseInt(v, 10) + increment;
20512 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20513 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20520 beforeLoad : function(){
20522 this.loading.disable();
20527 onClick : function(which){
20536 ds.load({params:{start: 0, limit: this.pageSize}});
20539 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20542 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20545 var total = ds.getTotalCount();
20546 var extra = total % this.pageSize;
20547 var lastStart = extra ? (total - extra) : total-this.pageSize;
20548 ds.load({params:{start: lastStart, limit: this.pageSize}});
20551 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20557 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20558 * @param {Roo.data.Store} store The data store to unbind
20560 unbind : function(ds){
20561 ds.un("beforeload", this.beforeLoad, this);
20562 ds.un("load", this.onLoad, this);
20563 ds.un("loadexception", this.onLoadError, this);
20564 ds.un("remove", this.updateInfo, this);
20565 ds.un("add", this.updateInfo, this);
20566 this.ds = undefined;
20570 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20571 * @param {Roo.data.Store} store The data store to bind
20573 bind : function(ds){
20574 ds.on("beforeload", this.beforeLoad, this);
20575 ds.on("load", this.onLoad, this);
20576 ds.on("loadexception", this.onLoadError, this);
20577 ds.on("remove", this.updateInfo, this);
20578 ds.on("add", this.updateInfo, this);
20589 * @class Roo.bootstrap.MessageBar
20590 * @extends Roo.bootstrap.Component
20591 * Bootstrap MessageBar class
20592 * @cfg {String} html contents of the MessageBar
20593 * @cfg {String} weight (info | success | warning | danger) default info
20594 * @cfg {String} beforeClass insert the bar before the given class
20595 * @cfg {Boolean} closable (true | false) default false
20596 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20599 * Create a new Element
20600 * @param {Object} config The config object
20603 Roo.bootstrap.MessageBar = function(config){
20604 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20607 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20613 beforeClass: 'bootstrap-sticky-wrap',
20615 getAutoCreate : function(){
20619 cls: 'alert alert-dismissable alert-' + this.weight,
20624 html: this.html || ''
20630 cfg.cls += ' alert-messages-fixed';
20644 onRender : function(ct, position)
20646 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20649 var cfg = Roo.apply({}, this.getAutoCreate());
20653 cfg.cls += ' ' + this.cls;
20656 cfg.style = this.style;
20658 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20660 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20663 this.el.select('>button.close').on('click', this.hide, this);
20669 if (!this.rendered) {
20675 this.fireEvent('show', this);
20681 if (!this.rendered) {
20687 this.fireEvent('hide', this);
20690 update : function()
20692 // var e = this.el.dom.firstChild;
20694 // if(this.closable){
20695 // e = e.nextSibling;
20698 // e.data = this.html || '';
20700 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20716 * @class Roo.bootstrap.Graph
20717 * @extends Roo.bootstrap.Component
20718 * Bootstrap Graph class
20722 @cfg {String} graphtype bar | vbar | pie
20723 @cfg {number} g_x coodinator | centre x (pie)
20724 @cfg {number} g_y coodinator | centre y (pie)
20725 @cfg {number} g_r radius (pie)
20726 @cfg {number} g_height height of the chart (respected by all elements in the set)
20727 @cfg {number} g_width width of the chart (respected by all elements in the set)
20728 @cfg {Object} title The title of the chart
20731 -opts (object) options for the chart
20733 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20734 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20736 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.
20737 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20739 o stretch (boolean)
20741 -opts (object) options for the pie
20744 o startAngle (number)
20745 o endAngle (number)
20749 * Create a new Input
20750 * @param {Object} config The config object
20753 Roo.bootstrap.Graph = function(config){
20754 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20760 * The img click event for the img.
20761 * @param {Roo.EventObject} e
20767 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20778 //g_colors: this.colors,
20785 getAutoCreate : function(){
20796 onRender : function(ct,position){
20797 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20798 this.raphael = Raphael(this.el.dom);
20800 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20801 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20802 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20803 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20805 r.text(160, 10, "Single Series Chart").attr(txtattr);
20806 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20807 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20808 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20810 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20811 r.barchart(330, 10, 300, 220, data1);
20812 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20813 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20816 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20817 // r.barchart(30, 30, 560, 250, xdata, {
20818 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20819 // axis : "0 0 1 1",
20820 // axisxlabels : xdata
20821 // //yvalues : cols,
20824 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20826 // this.load(null,xdata,{
20827 // axis : "0 0 1 1",
20828 // axisxlabels : xdata
20833 load : function(graphtype,xdata,opts){
20834 this.raphael.clear();
20836 graphtype = this.graphtype;
20841 var r = this.raphael,
20842 fin = function () {
20843 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20845 fout = function () {
20846 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20848 pfin = function() {
20849 this.sector.stop();
20850 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20853 this.label[0].stop();
20854 this.label[0].attr({ r: 7.5 });
20855 this.label[1].attr({ "font-weight": 800 });
20858 pfout = function() {
20859 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20862 this.label[0].animate({ r: 5 }, 500, "bounce");
20863 this.label[1].attr({ "font-weight": 400 });
20869 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20872 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20875 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20876 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20878 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20885 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20890 setTitle: function(o)
20895 initEvents: function() {
20898 this.el.on('click', this.onClick, this);
20902 onClick : function(e)
20904 Roo.log('img onclick');
20905 this.fireEvent('click', this, e);
20917 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20920 * @class Roo.bootstrap.dash.NumberBox
20921 * @extends Roo.bootstrap.Component
20922 * Bootstrap NumberBox class
20923 * @cfg {String} headline Box headline
20924 * @cfg {String} content Box content
20925 * @cfg {String} icon Box icon
20926 * @cfg {String} footer Footer text
20927 * @cfg {String} fhref Footer href
20930 * Create a new NumberBox
20931 * @param {Object} config The config object
20935 Roo.bootstrap.dash.NumberBox = function(config){
20936 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20940 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20949 getAutoCreate : function(){
20953 cls : 'small-box ',
20961 cls : 'roo-headline',
20962 html : this.headline
20966 cls : 'roo-content',
20967 html : this.content
20981 cls : 'ion ' + this.icon
20990 cls : 'small-box-footer',
20991 href : this.fhref || '#',
20995 cfg.cn.push(footer);
21002 onRender : function(ct,position){
21003 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21010 setHeadline: function (value)
21012 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21015 setFooter: function (value, href)
21017 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21020 this.el.select('a.small-box-footer',true).first().attr('href', href);
21025 setContent: function (value)
21027 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21030 initEvents: function()
21044 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21047 * @class Roo.bootstrap.dash.TabBox
21048 * @extends Roo.bootstrap.Component
21049 * Bootstrap TabBox class
21050 * @cfg {String} title Title of the TabBox
21051 * @cfg {String} icon Icon of the TabBox
21052 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21053 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21056 * Create a new TabBox
21057 * @param {Object} config The config object
21061 Roo.bootstrap.dash.TabBox = function(config){
21062 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21067 * When a pane is added
21068 * @param {Roo.bootstrap.dash.TabPane} pane
21072 * @event activatepane
21073 * When a pane is activated
21074 * @param {Roo.bootstrap.dash.TabPane} pane
21076 "activatepane" : true
21084 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21089 tabScrollable : false,
21091 getChildContainer : function()
21093 return this.el.select('.tab-content', true).first();
21096 getAutoCreate : function(){
21100 cls: 'pull-left header',
21108 cls: 'fa ' + this.icon
21114 cls: 'nav nav-tabs pull-right',
21120 if(this.tabScrollable){
21127 cls: 'nav nav-tabs pull-right',
21138 cls: 'nav-tabs-custom',
21143 cls: 'tab-content no-padding',
21151 initEvents : function()
21153 //Roo.log('add add pane handler');
21154 this.on('addpane', this.onAddPane, this);
21157 * Updates the box title
21158 * @param {String} html to set the title to.
21160 setTitle : function(value)
21162 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21164 onAddPane : function(pane)
21166 this.panes.push(pane);
21167 //Roo.log('addpane');
21169 // tabs are rendere left to right..
21170 if(!this.showtabs){
21174 var ctr = this.el.select('.nav-tabs', true).first();
21177 var existing = ctr.select('.nav-tab',true);
21178 var qty = existing.getCount();;
21181 var tab = ctr.createChild({
21183 cls : 'nav-tab' + (qty ? '' : ' active'),
21191 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21194 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21196 pane.el.addClass('active');
21201 onTabClick : function(ev,un,ob,pane)
21203 //Roo.log('tab - prev default');
21204 ev.preventDefault();
21207 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21208 pane.tab.addClass('active');
21209 //Roo.log(pane.title);
21210 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21211 // technically we should have a deactivate event.. but maybe add later.
21212 // and it should not de-activate the selected tab...
21213 this.fireEvent('activatepane', pane);
21214 pane.el.addClass('active');
21215 pane.fireEvent('activate');
21220 getActivePane : function()
21223 Roo.each(this.panes, function(p) {
21224 if(p.el.hasClass('active')){
21245 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21247 * @class Roo.bootstrap.TabPane
21248 * @extends Roo.bootstrap.Component
21249 * Bootstrap TabPane class
21250 * @cfg {Boolean} active (false | true) Default false
21251 * @cfg {String} title title of panel
21255 * Create a new TabPane
21256 * @param {Object} config The config object
21259 Roo.bootstrap.dash.TabPane = function(config){
21260 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21266 * When a pane is activated
21267 * @param {Roo.bootstrap.dash.TabPane} pane
21274 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21279 // the tabBox that this is attached to.
21282 getAutoCreate : function()
21290 cfg.cls += ' active';
21295 initEvents : function()
21297 //Roo.log('trigger add pane handler');
21298 this.parent().fireEvent('addpane', this)
21302 * Updates the tab title
21303 * @param {String} html to set the title to.
21305 setTitle: function(str)
21311 this.tab.select('a', true).first().dom.innerHTML = str;
21328 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21331 * @class Roo.bootstrap.menu.Menu
21332 * @extends Roo.bootstrap.Component
21333 * Bootstrap Menu class - container for Menu
21334 * @cfg {String} html Text of the menu
21335 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21336 * @cfg {String} icon Font awesome icon
21337 * @cfg {String} pos Menu align to (top | bottom) default bottom
21341 * Create a new Menu
21342 * @param {Object} config The config object
21346 Roo.bootstrap.menu.Menu = function(config){
21347 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21351 * @event beforeshow
21352 * Fires before this menu is displayed
21353 * @param {Roo.bootstrap.menu.Menu} this
21357 * @event beforehide
21358 * Fires before this menu is hidden
21359 * @param {Roo.bootstrap.menu.Menu} this
21364 * Fires after this menu is displayed
21365 * @param {Roo.bootstrap.menu.Menu} this
21370 * Fires after this menu is hidden
21371 * @param {Roo.bootstrap.menu.Menu} this
21376 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21377 * @param {Roo.bootstrap.menu.Menu} this
21378 * @param {Roo.EventObject} e
21385 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21389 weight : 'default',
21394 getChildContainer : function() {
21395 if(this.isSubMenu){
21399 return this.el.select('ul.dropdown-menu', true).first();
21402 getAutoCreate : function()
21407 cls : 'roo-menu-text',
21415 cls : 'fa ' + this.icon
21426 cls : 'dropdown-button btn btn-' + this.weight,
21431 cls : 'dropdown-toggle btn btn-' + this.weight,
21441 cls : 'dropdown-menu'
21447 if(this.pos == 'top'){
21448 cfg.cls += ' dropup';
21451 if(this.isSubMenu){
21454 cls : 'dropdown-menu'
21461 onRender : function(ct, position)
21463 this.isSubMenu = ct.hasClass('dropdown-submenu');
21465 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21468 initEvents : function()
21470 if(this.isSubMenu){
21474 this.hidden = true;
21476 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21477 this.triggerEl.on('click', this.onTriggerPress, this);
21479 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21480 this.buttonEl.on('click', this.onClick, this);
21486 if(this.isSubMenu){
21490 return this.el.select('ul.dropdown-menu', true).first();
21493 onClick : function(e)
21495 this.fireEvent("click", this, e);
21498 onTriggerPress : function(e)
21500 if (this.isVisible()) {
21507 isVisible : function(){
21508 return !this.hidden;
21513 this.fireEvent("beforeshow", this);
21515 this.hidden = false;
21516 this.el.addClass('open');
21518 Roo.get(document).on("mouseup", this.onMouseUp, this);
21520 this.fireEvent("show", this);
21527 this.fireEvent("beforehide", this);
21529 this.hidden = true;
21530 this.el.removeClass('open');
21532 Roo.get(document).un("mouseup", this.onMouseUp);
21534 this.fireEvent("hide", this);
21537 onMouseUp : function()
21551 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21554 * @class Roo.bootstrap.menu.Item
21555 * @extends Roo.bootstrap.Component
21556 * Bootstrap MenuItem class
21557 * @cfg {Boolean} submenu (true | false) default false
21558 * @cfg {String} html text of the item
21559 * @cfg {String} href the link
21560 * @cfg {Boolean} disable (true | false) default false
21561 * @cfg {Boolean} preventDefault (true | false) default true
21562 * @cfg {String} icon Font awesome icon
21563 * @cfg {String} pos Submenu align to (left | right) default right
21567 * Create a new Item
21568 * @param {Object} config The config object
21572 Roo.bootstrap.menu.Item = function(config){
21573 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21577 * Fires when the mouse is hovering over this menu
21578 * @param {Roo.bootstrap.menu.Item} this
21579 * @param {Roo.EventObject} e
21584 * Fires when the mouse exits this menu
21585 * @param {Roo.bootstrap.menu.Item} this
21586 * @param {Roo.EventObject} e
21592 * The raw click event for the entire grid.
21593 * @param {Roo.EventObject} e
21599 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21604 preventDefault: true,
21609 getAutoCreate : function()
21614 cls : 'roo-menu-item-text',
21622 cls : 'fa ' + this.icon
21631 href : this.href || '#',
21638 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21642 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21644 if(this.pos == 'left'){
21645 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21652 initEvents : function()
21654 this.el.on('mouseover', this.onMouseOver, this);
21655 this.el.on('mouseout', this.onMouseOut, this);
21657 this.el.select('a', true).first().on('click', this.onClick, this);
21661 onClick : function(e)
21663 if(this.preventDefault){
21664 e.preventDefault();
21667 this.fireEvent("click", this, e);
21670 onMouseOver : function(e)
21672 if(this.submenu && this.pos == 'left'){
21673 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21676 this.fireEvent("mouseover", this, e);
21679 onMouseOut : function(e)
21681 this.fireEvent("mouseout", this, e);
21693 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21696 * @class Roo.bootstrap.menu.Separator
21697 * @extends Roo.bootstrap.Component
21698 * Bootstrap Separator class
21701 * Create a new Separator
21702 * @param {Object} config The config object
21706 Roo.bootstrap.menu.Separator = function(config){
21707 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21710 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21712 getAutoCreate : function(){
21733 * @class Roo.bootstrap.Tooltip
21734 * Bootstrap Tooltip class
21735 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21736 * to determine which dom element triggers the tooltip.
21738 * It needs to add support for additional attributes like tooltip-position
21741 * Create a new Toolti
21742 * @param {Object} config The config object
21745 Roo.bootstrap.Tooltip = function(config){
21746 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21749 Roo.apply(Roo.bootstrap.Tooltip, {
21751 * @function init initialize tooltip monitoring.
21755 currentTip : false,
21756 currentRegion : false,
21762 Roo.get(document).on('mouseover', this.enter ,this);
21763 Roo.get(document).on('mouseout', this.leave, this);
21766 this.currentTip = new Roo.bootstrap.Tooltip();
21769 enter : function(ev)
21771 var dom = ev.getTarget();
21773 //Roo.log(['enter',dom]);
21774 var el = Roo.fly(dom);
21775 if (this.currentEl) {
21777 //Roo.log(this.currentEl);
21778 //Roo.log(this.currentEl.contains(dom));
21779 if (this.currentEl == el) {
21782 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21790 if (this.currentTip.el) {
21791 this.currentTip.el.hide(); // force hiding...
21796 // you can not look for children, as if el is the body.. then everythign is the child..
21797 if (!el.attr('tooltip')) { //
21798 if (!el.select("[tooltip]").elements.length) {
21801 // is the mouse over this child...?
21802 bindEl = el.select("[tooltip]").first();
21803 var xy = ev.getXY();
21804 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21805 //Roo.log("not in region.");
21808 //Roo.log("child element over..");
21811 this.currentEl = bindEl;
21812 this.currentTip.bind(bindEl);
21813 this.currentRegion = Roo.lib.Region.getRegion(dom);
21814 this.currentTip.enter();
21817 leave : function(ev)
21819 var dom = ev.getTarget();
21820 //Roo.log(['leave',dom]);
21821 if (!this.currentEl) {
21826 if (dom != this.currentEl.dom) {
21829 var xy = ev.getXY();
21830 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21833 // only activate leave if mouse cursor is outside... bounding box..
21838 if (this.currentTip) {
21839 this.currentTip.leave();
21841 //Roo.log('clear currentEl');
21842 this.currentEl = false;
21847 'left' : ['r-l', [-2,0], 'right'],
21848 'right' : ['l-r', [2,0], 'left'],
21849 'bottom' : ['t-b', [0,2], 'top'],
21850 'top' : [ 'b-t', [0,-2], 'bottom']
21856 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21861 delay : null, // can be { show : 300 , hide: 500}
21865 hoverState : null, //???
21867 placement : 'bottom',
21869 getAutoCreate : function(){
21876 cls : 'tooltip-arrow'
21879 cls : 'tooltip-inner'
21886 bind : function(el)
21892 enter : function () {
21894 if (this.timeout != null) {
21895 clearTimeout(this.timeout);
21898 this.hoverState = 'in';
21899 //Roo.log("enter - show");
21900 if (!this.delay || !this.delay.show) {
21905 this.timeout = setTimeout(function () {
21906 if (_t.hoverState == 'in') {
21909 }, this.delay.show);
21913 clearTimeout(this.timeout);
21915 this.hoverState = 'out';
21916 if (!this.delay || !this.delay.hide) {
21922 this.timeout = setTimeout(function () {
21923 //Roo.log("leave - timeout");
21925 if (_t.hoverState == 'out') {
21927 Roo.bootstrap.Tooltip.currentEl = false;
21935 this.render(document.body);
21938 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21940 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
21942 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip
21944 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21946 var placement = typeof this.placement == 'function' ?
21947 this.placement.call(this, this.el, on_el) :
21950 var autoToken = /\s?auto?\s?/i;
21951 var autoPlace = autoToken.test(placement);
21953 placement = placement.replace(autoToken, '') || 'top';
21957 //this.el.setXY([0,0]);
21959 //this.el.dom.style.display='block';
21960 this.el.addClass(placement);
21962 //this.el.appendTo(on_el);
21964 var p = this.getPosition();
21965 var box = this.el.getBox();
21970 var align = Roo.bootstrap.Tooltip.alignment[placement];
21971 this.el.alignTo(this.bindEl, align[0],align[1]);
21972 //var arrow = this.el.select('.arrow',true).first();
21973 //arrow.set(align[2],
21975 this.el.addClass('in fade');
21976 this.hoverState = null;
21978 if (this.el.hasClass('fade')) {
21989 //this.el.setXY([0,0]);
21990 this.el.removeClass('in');
22006 * @class Roo.bootstrap.LocationPicker
22007 * @extends Roo.bootstrap.Component
22008 * Bootstrap LocationPicker class
22009 * @cfg {Number} latitude Position when init default 0
22010 * @cfg {Number} longitude Position when init default 0
22011 * @cfg {Number} zoom default 15
22012 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22013 * @cfg {Boolean} mapTypeControl default false
22014 * @cfg {Boolean} disableDoubleClickZoom default false
22015 * @cfg {Boolean} scrollwheel default true
22016 * @cfg {Boolean} streetViewControl default false
22017 * @cfg {Number} radius default 0
22018 * @cfg {String} locationName
22019 * @cfg {Boolean} draggable default true
22020 * @cfg {Boolean} enableAutocomplete default false
22021 * @cfg {Boolean} enableReverseGeocode default true
22022 * @cfg {String} markerTitle
22025 * Create a new LocationPicker
22026 * @param {Object} config The config object
22030 Roo.bootstrap.LocationPicker = function(config){
22032 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22037 * Fires when the picker initialized.
22038 * @param {Roo.bootstrap.LocationPicker} this
22039 * @param {Google Location} location
22043 * @event positionchanged
22044 * Fires when the picker position changed.
22045 * @param {Roo.bootstrap.LocationPicker} this
22046 * @param {Google Location} location
22048 positionchanged : true,
22051 * Fires when the map resize.
22052 * @param {Roo.bootstrap.LocationPicker} this
22057 * Fires when the map show.
22058 * @param {Roo.bootstrap.LocationPicker} this
22063 * Fires when the map hide.
22064 * @param {Roo.bootstrap.LocationPicker} this
22069 * Fires when click the map.
22070 * @param {Roo.bootstrap.LocationPicker} this
22071 * @param {Map event} e
22075 * @event mapRightClick
22076 * Fires when right click the map.
22077 * @param {Roo.bootstrap.LocationPicker} this
22078 * @param {Map event} e
22080 mapRightClick : true,
22082 * @event markerClick
22083 * Fires when click the marker.
22084 * @param {Roo.bootstrap.LocationPicker} this
22085 * @param {Map event} e
22087 markerClick : true,
22089 * @event markerRightClick
22090 * Fires when right click the marker.
22091 * @param {Roo.bootstrap.LocationPicker} this
22092 * @param {Map event} e
22094 markerRightClick : true,
22096 * @event OverlayViewDraw
22097 * Fires when OverlayView Draw
22098 * @param {Roo.bootstrap.LocationPicker} this
22100 OverlayViewDraw : true,
22102 * @event OverlayViewOnAdd
22103 * Fires when OverlayView Draw
22104 * @param {Roo.bootstrap.LocationPicker} this
22106 OverlayViewOnAdd : true,
22108 * @event OverlayViewOnRemove
22109 * Fires when OverlayView Draw
22110 * @param {Roo.bootstrap.LocationPicker} this
22112 OverlayViewOnRemove : true,
22114 * @event OverlayViewShow
22115 * Fires when OverlayView Draw
22116 * @param {Roo.bootstrap.LocationPicker} this
22117 * @param {Pixel} cpx
22119 OverlayViewShow : true,
22121 * @event OverlayViewHide
22122 * Fires when OverlayView Draw
22123 * @param {Roo.bootstrap.LocationPicker} this
22125 OverlayViewHide : true
22130 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22132 gMapContext: false,
22138 mapTypeControl: false,
22139 disableDoubleClickZoom: false,
22141 streetViewControl: false,
22145 enableAutocomplete: false,
22146 enableReverseGeocode: true,
22149 getAutoCreate: function()
22154 cls: 'roo-location-picker'
22160 initEvents: function(ct, position)
22162 if(!this.el.getWidth() || this.isApplied()){
22166 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22171 initial: function()
22173 if(!this.mapTypeId){
22174 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22177 this.gMapContext = this.GMapContext();
22179 this.initOverlayView();
22181 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22185 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22186 _this.setPosition(_this.gMapContext.marker.position);
22189 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22190 _this.fireEvent('mapClick', this, event);
22194 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22195 _this.fireEvent('mapRightClick', this, event);
22199 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22200 _this.fireEvent('markerClick', this, event);
22204 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22205 _this.fireEvent('markerRightClick', this, event);
22209 this.setPosition(this.gMapContext.location);
22211 this.fireEvent('initial', this, this.gMapContext.location);
22214 initOverlayView: function()
22218 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22222 _this.fireEvent('OverlayViewDraw', _this);
22227 _this.fireEvent('OverlayViewOnAdd', _this);
22230 onRemove: function()
22232 _this.fireEvent('OverlayViewOnRemove', _this);
22235 show: function(cpx)
22237 _this.fireEvent('OverlayViewShow', _this, cpx);
22242 _this.fireEvent('OverlayViewHide', _this);
22248 fromLatLngToContainerPixel: function(event)
22250 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22253 isApplied: function()
22255 return this.getGmapContext() == false ? false : true;
22258 getGmapContext: function()
22260 return this.gMapContext
22263 GMapContext: function()
22265 var position = new google.maps.LatLng(this.latitude, this.longitude);
22267 var _map = new google.maps.Map(this.el.dom, {
22270 mapTypeId: this.mapTypeId,
22271 mapTypeControl: this.mapTypeControl,
22272 disableDoubleClickZoom: this.disableDoubleClickZoom,
22273 scrollwheel: this.scrollwheel,
22274 streetViewControl: this.streetViewControl,
22275 locationName: this.locationName,
22276 draggable: this.draggable,
22277 enableAutocomplete: this.enableAutocomplete,
22278 enableReverseGeocode: this.enableReverseGeocode
22281 var _marker = new google.maps.Marker({
22282 position: position,
22284 title: this.markerTitle,
22285 draggable: this.draggable
22292 location: position,
22293 radius: this.radius,
22294 locationName: this.locationName,
22295 addressComponents: {
22296 formatted_address: null,
22297 addressLine1: null,
22298 addressLine2: null,
22300 streetNumber: null,
22304 stateOrProvince: null
22307 domContainer: this.el.dom,
22308 geodecoder: new google.maps.Geocoder()
22312 drawCircle: function(center, radius, options)
22314 if (this.gMapContext.circle != null) {
22315 this.gMapContext.circle.setMap(null);
22319 options = Roo.apply({}, options, {
22320 strokeColor: "#0000FF",
22321 strokeOpacity: .35,
22323 fillColor: "#0000FF",
22327 options.map = this.gMapContext.map;
22328 options.radius = radius;
22329 options.center = center;
22330 this.gMapContext.circle = new google.maps.Circle(options);
22331 return this.gMapContext.circle;
22337 setPosition: function(location)
22339 this.gMapContext.location = location;
22340 this.gMapContext.marker.setPosition(location);
22341 this.gMapContext.map.panTo(location);
22342 this.drawCircle(location, this.gMapContext.radius, {});
22346 if (this.gMapContext.settings.enableReverseGeocode) {
22347 this.gMapContext.geodecoder.geocode({
22348 latLng: this.gMapContext.location
22349 }, function(results, status) {
22351 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22352 _this.gMapContext.locationName = results[0].formatted_address;
22353 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22355 _this.fireEvent('positionchanged', this, location);
22362 this.fireEvent('positionchanged', this, location);
22367 google.maps.event.trigger(this.gMapContext.map, "resize");
22369 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22371 this.fireEvent('resize', this);
22374 setPositionByLatLng: function(latitude, longitude)
22376 this.setPosition(new google.maps.LatLng(latitude, longitude));
22379 getCurrentPosition: function()
22382 latitude: this.gMapContext.location.lat(),
22383 longitude: this.gMapContext.location.lng()
22387 getAddressName: function()
22389 return this.gMapContext.locationName;
22392 getAddressComponents: function()
22394 return this.gMapContext.addressComponents;
22397 address_component_from_google_geocode: function(address_components)
22401 for (var i = 0; i < address_components.length; i++) {
22402 var component = address_components[i];
22403 if (component.types.indexOf("postal_code") >= 0) {
22404 result.postalCode = component.short_name;
22405 } else if (component.types.indexOf("street_number") >= 0) {
22406 result.streetNumber = component.short_name;
22407 } else if (component.types.indexOf("route") >= 0) {
22408 result.streetName = component.short_name;
22409 } else if (component.types.indexOf("neighborhood") >= 0) {
22410 result.city = component.short_name;
22411 } else if (component.types.indexOf("locality") >= 0) {
22412 result.city = component.short_name;
22413 } else if (component.types.indexOf("sublocality") >= 0) {
22414 result.district = component.short_name;
22415 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22416 result.stateOrProvince = component.short_name;
22417 } else if (component.types.indexOf("country") >= 0) {
22418 result.country = component.short_name;
22422 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22423 result.addressLine2 = "";
22427 setZoomLevel: function(zoom)
22429 this.gMapContext.map.setZoom(zoom);
22442 this.fireEvent('show', this);
22453 this.fireEvent('hide', this);
22458 Roo.apply(Roo.bootstrap.LocationPicker, {
22460 OverlayView : function(map, options)
22462 options = options || {};
22476 * @class Roo.bootstrap.Alert
22477 * @extends Roo.bootstrap.Component
22478 * Bootstrap Alert class
22479 * @cfg {String} title The title of alert
22480 * @cfg {String} html The content of alert
22481 * @cfg {String} weight ( success | info | warning | danger )
22482 * @cfg {String} faicon font-awesomeicon
22485 * Create a new alert
22486 * @param {Object} config The config object
22490 Roo.bootstrap.Alert = function(config){
22491 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22495 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22502 getAutoCreate : function()
22511 cls : 'roo-alert-icon'
22516 cls : 'roo-alert-title',
22521 cls : 'roo-alert-text',
22528 cfg.cn[0].cls += ' fa ' + this.faicon;
22532 cfg.cls += ' alert-' + this.weight;
22538 initEvents: function()
22540 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22543 setTitle : function(str)
22545 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22548 setText : function(str)
22550 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22553 setWeight : function(weight)
22556 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22559 this.weight = weight;
22561 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22564 setIcon : function(icon)
22567 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22572 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);