4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
33 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
36 allowDomMove : false, // to stop relocations in parent onRender...
46 * Initialize Events for the element
48 initEvents : function() { },
54 can_build_overlaid : true,
56 container_method : false,
63 // returns the parent component..
64 return Roo.ComponentMgr.get(this.parentId)
70 onRender : function(ct, position)
72 // Roo.log("Call onRender: " + this.xtype);
74 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
77 if (this.el.attr('xtype')) {
78 this.el.attr('xtypex', this.el.attr('xtype'));
79 this.el.dom.removeAttribute('xtype');
89 var cfg = Roo.apply({}, this.getAutoCreate());
92 // fill in the extra attributes
93 if (this.xattr && typeof(this.xattr) =='object') {
94 for (var i in this.xattr) {
95 cfg[i] = this.xattr[i];
100 cfg.dataId = this.dataId;
104 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
107 if (this.style) { // fixme needs to support more complex style data.
108 cfg.style = this.style;
112 cfg.name = this.name;
117 this.el = ct.createChild(cfg, position);
120 this.tooltipEl().attr('tooltip', this.tooltip);
123 if(this.tabIndex !== undefined){
124 this.el.dom.setAttribute('tabIndex', this.tabIndex);
131 * Fetch the element to add children to
132 * @return {Roo.Element} defaults to this.el
134 getChildContainer : function()
139 * Fetch the element to display the tooltip on.
140 * @return {Roo.Element} defaults to this.el
142 tooltipEl : function()
147 addxtype : function(tree,cntr)
151 cn = Roo.factory(tree);
153 cn.parentType = this.xtype; //??
154 cn.parentId = this.id;
156 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
157 if (typeof(cn.container_method) == 'string') {
158 cntr = cn.container_method;
162 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
164 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
166 var build_from_html = Roo.XComponent.build_from_html;
168 var is_body = (tree.xtype == 'Body') ;
170 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
172 var self_cntr_el = Roo.get(this[cntr](false));
174 // do not try and build conditional elements
175 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
179 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
180 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
181 return this.addxtypeChild(tree,cntr);
184 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
187 return this.addxtypeChild(Roo.apply({}, tree),cntr);
190 Roo.log('skipping render');
198 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
204 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
208 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
213 addxtypeChild : function (tree, cntr)
215 Roo.debug && Roo.log('addxtypeChild:' + cntr);
217 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
220 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
221 (typeof(tree['flexy:foreach']) != 'undefined');
225 skip_children = false;
226 // render the element if it's not BODY.
227 if (tree.xtype != 'Body') {
229 cn = Roo.factory(tree);
231 cn.parentType = this.xtype; //??
232 cn.parentId = this.id;
234 var build_from_html = Roo.XComponent.build_from_html;
237 // does the container contain child eleemnts with 'xtype' attributes.
238 // that match this xtype..
239 // note - when we render we create these as well..
240 // so we should check to see if body has xtype set.
241 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
243 var self_cntr_el = Roo.get(this[cntr](false));
244 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
247 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
248 // and are not displayed -this causes this to use up the wrong element when matching.
249 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
252 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
253 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
259 //echild.dom.removeAttribute('xtype');
261 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
262 Roo.debug && Roo.log(self_cntr_el);
263 Roo.debug && Roo.log(echild);
264 Roo.debug && Roo.log(cn);
270 // if object has flexy:if - then it may or may not be rendered.
271 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
272 // skip a flexy if element.
273 Roo.debug && Roo.log('skipping render');
274 Roo.debug && Roo.log(tree);
276 Roo.debug && Roo.log('skipping all children');
277 skip_children = true;
282 // actually if flexy:foreach is found, we really want to create
283 // multiple copies here...
285 //Roo.log(this[cntr]());
286 cn.render(this[cntr](true));
288 // then add the element..
296 if (typeof (tree.menu) != 'undefined') {
297 tree.menu.parentType = cn.xtype;
298 tree.menu.triggerEl = cn.el;
299 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
303 if (!tree.items || !tree.items.length) {
307 var items = tree.items;
310 //Roo.log(items.length);
312 if (!skip_children) {
313 for(var i =0;i < items.length;i++) {
314 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
336 * @class Roo.bootstrap.Body
337 * @extends Roo.bootstrap.Component
338 * Bootstrap Body class
342 * @param {Object} config The config object
345 Roo.bootstrap.Body = function(config){
346 Roo.bootstrap.Body.superclass.constructor.call(this, config);
347 this.el = Roo.get(document.body);
348 if (this.cls && this.cls.length) {
349 Roo.get(document.body).addClass(this.cls);
353 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
358 onRender : function(ct, position)
360 /* Roo.log("Roo.bootstrap.Body - onRender");
361 if (this.cls && this.cls.length) {
362 Roo.get(document.body).addClass(this.cls);
382 * @class Roo.bootstrap.ButtonGroup
383 * @extends Roo.bootstrap.Component
384 * Bootstrap ButtonGroup class
385 * @cfg {String} size lg | sm | xs (default empty normal)
386 * @cfg {String} align vertical | justified (default none)
387 * @cfg {String} direction up | down (default down)
388 * @cfg {Boolean} toolbar false | true
389 * @cfg {Boolean} btn true | false
394 * @param {Object} config The config object
397 Roo.bootstrap.ButtonGroup = function(config){
398 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
401 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
409 getAutoCreate : function(){
415 cfg.html = this.html || cfg.html;
426 if (['vertical','justified'].indexOf(this.align)!==-1) {
427 cfg.cls = 'btn-group-' + this.align;
429 if (this.align == 'justified') {
430 console.log(this.items);
434 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
435 cfg.cls += ' btn-group-' + this.size;
438 if (this.direction == 'up') {
439 cfg.cls += ' dropup' ;
455 * @class Roo.bootstrap.Button
456 * @extends Roo.bootstrap.Component
457 * Bootstrap Button class
458 * @cfg {String} html The button content
459 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
460 * @cfg {String} size ( lg | sm | xs)
461 * @cfg {String} tag ( a | input | submit)
462 * @cfg {String} href empty or href
463 * @cfg {Boolean} disabled default false;
464 * @cfg {Boolean} isClose default false;
465 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
466 * @cfg {String} badge text for badge
467 * @cfg {String} theme default
468 * @cfg {Boolean} inverse
469 * @cfg {Boolean} toggle
470 * @cfg {String} ontext text for on toggle state
471 * @cfg {String} offtext text for off toggle state
472 * @cfg {Boolean} defaulton
473 * @cfg {Boolean} preventDefault default true
474 * @cfg {Boolean} removeClass remove the standard class..
475 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
478 * Create a new button
479 * @param {Object} config The config object
483 Roo.bootstrap.Button = function(config){
484 Roo.bootstrap.Button.superclass.constructor.call(this, config);
489 * When a butotn is pressed
490 * @param {Roo.EventObject} e
495 * After the button has been toggles
496 * @param {Roo.EventObject} e
497 * @param {boolean} pressed (also available as button.pressed)
503 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
521 preventDefault: true,
530 getAutoCreate : function(){
538 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
539 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
544 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
546 if (this.toggle == true) {
549 cls: 'slider-frame roo-button',
554 'data-off-text':'OFF',
555 cls: 'slider-button',
561 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
562 cfg.cls += ' '+this.weight;
571 cfg["aria-hidden"] = true;
573 cfg.html = "×";
579 if (this.theme==='default') {
580 cfg.cls = 'btn roo-button';
582 //if (this.parentType != 'Navbar') {
583 this.weight = this.weight.length ? this.weight : 'default';
585 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
587 cfg.cls += ' btn-' + this.weight;
589 } else if (this.theme==='glow') {
592 cfg.cls = 'btn-glow roo-button';
594 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
596 cfg.cls += ' ' + this.weight;
602 this.cls += ' inverse';
607 cfg.cls += ' active';
611 cfg.disabled = 'disabled';
615 Roo.log('changing to ul' );
617 this.glyphicon = 'caret';
620 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
622 //gsRoo.log(this.parentType);
623 if (this.parentType === 'Navbar' && !this.parent().bar) {
624 Roo.log('changing to li?');
633 href : this.href || '#'
636 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
637 cfg.cls += ' dropdown';
644 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
646 if (this.glyphicon) {
647 cfg.html = ' ' + cfg.html;
652 cls: 'glyphicon glyphicon-' + this.glyphicon
662 // cfg.cls='btn roo-button';
666 var value = cfg.html;
671 cls: 'glyphicon glyphicon-' + this.glyphicon,
690 cfg.cls += ' dropdown';
691 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
694 if (cfg.tag !== 'a' && this.href !== '') {
695 throw "Tag must be a to set href.";
696 } else if (this.href.length > 0) {
697 cfg.href = this.href;
700 if(this.removeClass){
705 cfg.target = this.target;
710 initEvents: function() {
711 // Roo.log('init events?');
712 // Roo.log(this.el.dom);
715 if (typeof (this.menu) != 'undefined') {
716 this.menu.parentType = this.xtype;
717 this.menu.triggerEl = this.el;
718 this.addxtype(Roo.apply({}, this.menu));
722 if (this.el.hasClass('roo-button')) {
723 this.el.on('click', this.onClick, this);
725 this.el.select('.roo-button').on('click', this.onClick, this);
728 if(this.removeClass){
729 this.el.on('click', this.onClick, this);
732 this.el.enableDisplayMode();
735 onClick : function(e)
742 Roo.log('button on click ');
743 if(this.preventDefault){
746 if (this.pressed === true || this.pressed === false) {
747 this.pressed = !this.pressed;
748 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
749 this.fireEvent('toggle', this, e, this.pressed);
753 this.fireEvent('click', this, e);
757 * Enables this button
761 this.disabled = false;
762 this.el.removeClass('disabled');
766 * Disable this button
770 this.disabled = true;
771 this.el.addClass('disabled');
774 * sets the active state on/off,
775 * @param {Boolean} state (optional) Force a particular state
777 setActive : function(v) {
779 this.el[v ? 'addClass' : 'removeClass']('active');
782 * toggles the current active state
784 toggleActive : function()
786 var active = this.el.hasClass('active');
787 this.setActive(!active);
791 setText : function(str)
793 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
797 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
820 * @class Roo.bootstrap.Column
821 * @extends Roo.bootstrap.Component
822 * Bootstrap Column class
823 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
824 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
825 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
826 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
827 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
828 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
829 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
830 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
833 * @cfg {Boolean} hidden (true|false) hide the element
834 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
835 * @cfg {String} fa (ban|check|...) font awesome icon
836 * @cfg {Number} fasize (1|2|....) font awsome size
838 * @cfg {String} icon (info-sign|check|...) glyphicon name
840 * @cfg {String} html content of column.
843 * Create a new Column
844 * @param {Object} config The config object
847 Roo.bootstrap.Column = function(config){
848 Roo.bootstrap.Column.superclass.constructor.call(this, config);
851 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
869 getAutoCreate : function(){
870 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
878 ['xs','sm','md','lg'].map(function(size){
879 //Roo.log( size + ':' + settings[size]);
881 if (settings[size+'off'] !== false) {
882 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
885 if (settings[size] === false) {
888 Roo.log(settings[size]);
889 if (!settings[size]) { // 0 = hidden
890 cfg.cls += ' hidden-' + size;
893 cfg.cls += ' col-' + size + '-' + settings[size];
898 cfg.cls += ' hidden';
901 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
902 cfg.cls +=' alert alert-' + this.alert;
906 if (this.html.length) {
907 cfg.html = this.html;
911 if (this.fasize > 1) {
912 fasize = ' fa-' + this.fasize + 'x';
914 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
919 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
938 * @class Roo.bootstrap.Container
939 * @extends Roo.bootstrap.Component
940 * Bootstrap Container class
941 * @cfg {Boolean} jumbotron is it a jumbotron element
942 * @cfg {String} html content of element
943 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
944 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
945 * @cfg {String} header content of header (for panel)
946 * @cfg {String} footer content of footer (for panel)
947 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
948 * @cfg {String} tag (header|aside|section) type of HTML tag.
949 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
950 * @cfg {String} fa (ban|check|...) font awesome icon
951 * @cfg {String} icon (info-sign|check|...) glyphicon name
952 * @cfg {Boolean} hidden (true|false) hide the element
956 * Create a new Container
957 * @param {Object} config The config object
960 Roo.bootstrap.Container = function(config){
961 Roo.bootstrap.Container.superclass.constructor.call(this, config);
964 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
978 getChildContainer : function() {
984 if (this.panel.length) {
985 return this.el.select('.panel-body',true).first();
992 getAutoCreate : function(){
995 tag : this.tag || 'div',
999 if (this.jumbotron) {
1000 cfg.cls = 'jumbotron';
1005 // - this is applied by the parent..
1007 // cfg.cls = this.cls + '';
1010 if (this.sticky.length) {
1012 var bd = Roo.get(document.body);
1013 if (!bd.hasClass('bootstrap-sticky')) {
1014 bd.addClass('bootstrap-sticky');
1015 Roo.select('html',true).setStyle('height', '100%');
1018 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1022 if (this.well.length) {
1023 switch (this.well) {
1026 cfg.cls +=' well well-' +this.well;
1035 cfg.cls += ' hidden';
1039 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1040 cfg.cls +=' alert alert-' + this.alert;
1045 if (this.panel.length) {
1046 cfg.cls += ' panel panel-' + this.panel;
1048 if (this.header.length) {
1051 cls : 'panel-heading',
1054 cls : 'panel-title',
1067 if (this.footer.length) {
1069 cls : 'panel-footer',
1078 body.html = this.html || cfg.html;
1079 // prefix with the icons..
1081 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1084 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1089 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1090 cfg.cls = 'container';
1096 titleEl : function()
1098 if(!this.el || !this.panel.length || !this.header.length){
1102 return this.el.select('.panel-title',true).first();
1105 setTitle : function(v)
1107 var titleEl = this.titleEl();
1113 titleEl.dom.innerHTML = v;
1116 getTitle : function()
1119 var titleEl = this.titleEl();
1125 return titleEl.dom.innerHTML;
1139 * @class Roo.bootstrap.Img
1140 * @extends Roo.bootstrap.Component
1141 * Bootstrap Img class
1142 * @cfg {Boolean} imgResponsive false | true
1143 * @cfg {String} border rounded | circle | thumbnail
1144 * @cfg {String} src image source
1145 * @cfg {String} alt image alternative text
1146 * @cfg {String} href a tag href
1147 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1150 * Create a new Input
1151 * @param {Object} config The config object
1154 Roo.bootstrap.Img = function(config){
1155 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1161 * The img click event for the img.
1162 * @param {Roo.EventObject} e
1168 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1170 imgResponsive: true,
1176 getAutoCreate : function(){
1180 cls: (this.imgResponsive) ? 'img-responsive' : '',
1184 cfg.html = this.html || cfg.html;
1186 cfg.src = this.src || cfg.src;
1188 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1189 cfg.cls += ' img-' + this.border;
1206 a.target = this.target;
1212 return (this.href) ? a : cfg;
1215 initEvents: function() {
1218 this.el.on('click', this.onClick, this);
1222 onClick : function(e)
1224 Roo.log('img onclick');
1225 this.fireEvent('click', this, e);
1239 * @class Roo.bootstrap.Link
1240 * @extends Roo.bootstrap.Component
1241 * Bootstrap Link Class
1242 * @cfg {String} alt image alternative text
1243 * @cfg {String} href a tag href
1244 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1245 * @cfg {String} html the content of the link.
1246 * @cfg {String} anchor name for the anchor link
1248 * @cfg {Boolean} preventDefault (true | false) default false
1252 * Create a new Input
1253 * @param {Object} config The config object
1256 Roo.bootstrap.Link = function(config){
1257 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1263 * The img click event for the img.
1264 * @param {Roo.EventObject} e
1270 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1274 preventDefault: false,
1278 getAutoCreate : function()
1284 // anchor's do not require html/href...
1285 if (this.anchor === false) {
1286 cfg.html = this.html || 'html-missing';
1287 cfg.href = this.href || '#';
1289 cfg.name = this.anchor;
1290 if (this.html !== false) {
1291 cfg.html = this.html;
1293 if (this.href !== false) {
1294 cfg.href = this.href;
1298 if(this.alt !== false){
1303 if(this.target !== false) {
1304 cfg.target = this.target;
1310 initEvents: function() {
1312 if(!this.href || this.preventDefault){
1313 this.el.on('click', this.onClick, this);
1317 onClick : function(e)
1319 if(this.preventDefault){
1322 //Roo.log('img onclick');
1323 this.fireEvent('click', this, e);
1336 * @class Roo.bootstrap.Header
1337 * @extends Roo.bootstrap.Component
1338 * Bootstrap Header class
1339 * @cfg {String} html content of header
1340 * @cfg {Number} level (1|2|3|4|5|6) default 1
1343 * Create a new Header
1344 * @param {Object} config The config object
1348 Roo.bootstrap.Header = function(config){
1349 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1352 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1360 getAutoCreate : function(){
1363 tag: 'h' + (1 *this.level),
1364 html: this.html || 'fill in html'
1376 * Ext JS Library 1.1.1
1377 * Copyright(c) 2006-2007, Ext JS, LLC.
1379 * Originally Released Under LGPL - original licence link has changed is not relivant.
1382 * <script type="text/javascript">
1386 * @class Roo.bootstrap.MenuMgr
1387 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1390 Roo.bootstrap.MenuMgr = function(){
1391 var menus, active, groups = {}, attached = false, lastShow = new Date();
1393 // private - called when first menu is created
1396 active = new Roo.util.MixedCollection();
1397 Roo.get(document).addKeyListener(27, function(){
1398 if(active.length > 0){
1406 if(active && active.length > 0){
1407 var c = active.clone();
1417 if(active.length < 1){
1418 Roo.get(document).un("mouseup", onMouseDown);
1426 var last = active.last();
1427 lastShow = new Date();
1430 Roo.get(document).on("mouseup", onMouseDown);
1435 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1436 m.parentMenu.activeChild = m;
1437 }else if(last && last.isVisible()){
1438 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1443 function onBeforeHide(m){
1445 m.activeChild.hide();
1447 if(m.autoHideTimer){
1448 clearTimeout(m.autoHideTimer);
1449 delete m.autoHideTimer;
1454 function onBeforeShow(m){
1455 var pm = m.parentMenu;
1456 if(!pm && !m.allowOtherMenus){
1458 }else if(pm && pm.activeChild && active != m){
1459 pm.activeChild.hide();
1464 function onMouseDown(e){
1465 Roo.log("on MouseDown");
1466 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1474 function onBeforeCheck(mi, state){
1476 var g = groups[mi.group];
1477 for(var i = 0, l = g.length; i < l; i++){
1479 g[i].setChecked(false);
1488 * Hides all menus that are currently visible
1490 hideAll : function(){
1495 register : function(menu){
1499 menus[menu.id] = menu;
1500 menu.on("beforehide", onBeforeHide);
1501 menu.on("hide", onHide);
1502 menu.on("beforeshow", onBeforeShow);
1503 menu.on("show", onShow);
1505 if(g && menu.events["checkchange"]){
1509 groups[g].push(menu);
1510 menu.on("checkchange", onCheck);
1515 * Returns a {@link Roo.menu.Menu} object
1516 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1517 * be used to generate and return a new Menu instance.
1519 get : function(menu){
1520 if(typeof menu == "string"){ // menu id
1522 }else if(menu.events){ // menu instance
1525 /*else if(typeof menu.length == 'number'){ // array of menu items?
1526 return new Roo.bootstrap.Menu({items:menu});
1527 }else{ // otherwise, must be a config
1528 return new Roo.bootstrap.Menu(menu);
1535 unregister : function(menu){
1536 delete menus[menu.id];
1537 menu.un("beforehide", onBeforeHide);
1538 menu.un("hide", onHide);
1539 menu.un("beforeshow", onBeforeShow);
1540 menu.un("show", onShow);
1542 if(g && menu.events["checkchange"]){
1543 groups[g].remove(menu);
1544 menu.un("checkchange", onCheck);
1549 registerCheckable : function(menuItem){
1550 var g = menuItem.group;
1555 groups[g].push(menuItem);
1556 menuItem.on("beforecheckchange", onBeforeCheck);
1561 unregisterCheckable : function(menuItem){
1562 var g = menuItem.group;
1564 groups[g].remove(menuItem);
1565 menuItem.un("beforecheckchange", onBeforeCheck);
1577 * @class Roo.bootstrap.Menu
1578 * @extends Roo.bootstrap.Component
1579 * Bootstrap Menu class - container for MenuItems
1580 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1584 * @param {Object} config The config object
1588 Roo.bootstrap.Menu = function(config){
1589 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1590 if (this.registerMenu) {
1591 Roo.bootstrap.MenuMgr.register(this);
1596 * Fires before this menu is displayed
1597 * @param {Roo.menu.Menu} this
1602 * Fires before this menu is hidden
1603 * @param {Roo.menu.Menu} this
1608 * Fires after this menu is displayed
1609 * @param {Roo.menu.Menu} this
1614 * Fires after this menu is hidden
1615 * @param {Roo.menu.Menu} this
1620 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1621 * @param {Roo.menu.Menu} this
1622 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1623 * @param {Roo.EventObject} e
1628 * Fires when the mouse is hovering over this menu
1629 * @param {Roo.menu.Menu} this
1630 * @param {Roo.EventObject} e
1631 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1636 * Fires when the mouse exits this menu
1637 * @param {Roo.menu.Menu} this
1638 * @param {Roo.EventObject} e
1639 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1644 * Fires when a menu item contained in this menu is clicked
1645 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1646 * @param {Roo.EventObject} e
1650 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1653 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1657 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1660 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1662 registerMenu : true,
1664 menuItems :false, // stores the menu items..
1670 getChildContainer : function() {
1674 getAutoCreate : function(){
1676 //if (['right'].indexOf(this.align)!==-1) {
1677 // cfg.cn[1].cls += ' pull-right'
1683 cls : 'dropdown-menu' ,
1684 style : 'z-index:1000'
1688 if (this.type === 'submenu') {
1689 cfg.cls = 'submenu active';
1691 if (this.type === 'treeview') {
1692 cfg.cls = 'treeview-menu';
1697 initEvents : function() {
1699 // Roo.log("ADD event");
1700 // Roo.log(this.triggerEl.dom);
1701 this.triggerEl.on('click', this.onTriggerPress, this);
1702 this.triggerEl.addClass('dropdown-toggle');
1703 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1705 this.el.on("mouseover", this.onMouseOver, this);
1706 this.el.on("mouseout", this.onMouseOut, this);
1710 findTargetItem : function(e){
1711 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1715 //Roo.log(t); Roo.log(t.id);
1717 //Roo.log(this.menuitems);
1718 return this.menuitems.get(t.id);
1720 //return this.items.get(t.menuItemId);
1725 onClick : function(e){
1726 Roo.log("menu.onClick");
1727 var t = this.findTargetItem(e);
1728 if(!t || t.isContainer){
1733 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1734 if(t == this.activeItem && t.shouldDeactivate(e)){
1735 this.activeItem.deactivate();
1736 delete this.activeItem;
1740 this.setActiveItem(t, true);
1748 Roo.log('pass click event');
1752 this.fireEvent("click", this, t, e);
1756 onMouseOver : function(e){
1757 var t = this.findTargetItem(e);
1760 // if(t.canActivate && !t.disabled){
1761 // this.setActiveItem(t, true);
1765 this.fireEvent("mouseover", this, e, t);
1767 isVisible : function(){
1768 return !this.hidden;
1770 onMouseOut : function(e){
1771 var t = this.findTargetItem(e);
1774 // if(t == this.activeItem && t.shouldDeactivate(e)){
1775 // this.activeItem.deactivate();
1776 // delete this.activeItem;
1779 this.fireEvent("mouseout", this, e, t);
1784 * Displays this menu relative to another element
1785 * @param {String/HTMLElement/Roo.Element} element The element to align to
1786 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1787 * the element (defaults to this.defaultAlign)
1788 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1790 show : function(el, pos, parentMenu){
1791 this.parentMenu = parentMenu;
1795 this.fireEvent("beforeshow", this);
1796 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1799 * Displays this menu at a specific xy position
1800 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1801 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1803 showAt : function(xy, parentMenu, /* private: */_e){
1804 this.parentMenu = parentMenu;
1809 this.fireEvent("beforeshow", this);
1811 //xy = this.el.adjustForConstraints(xy);
1813 //this.el.setXY(xy);
1815 this.hideMenuItems();
1816 this.hidden = false;
1817 this.triggerEl.addClass('open');
1819 this.fireEvent("show", this);
1825 this.doFocus.defer(50, this);
1829 doFocus : function(){
1831 this.focusEl.focus();
1836 * Hides this menu and optionally all parent menus
1837 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1839 hide : function(deep){
1841 this.hideMenuItems();
1842 if(this.el && this.isVisible()){
1843 this.fireEvent("beforehide", this);
1844 if(this.activeItem){
1845 this.activeItem.deactivate();
1846 this.activeItem = null;
1848 this.triggerEl.removeClass('open');;
1850 this.fireEvent("hide", this);
1852 if(deep === true && this.parentMenu){
1853 this.parentMenu.hide(true);
1857 onTriggerPress : function(e)
1860 Roo.log('trigger press');
1861 //Roo.log(e.getTarget());
1862 // Roo.log(this.triggerEl.dom);
1863 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1866 if (this.isVisible()) {
1870 this.show(this.triggerEl, false, false);
1879 hideMenuItems : function()
1881 //$(backdrop).remove()
1882 Roo.select('.open',true).each(function(aa) {
1884 aa.removeClass('open');
1885 //var parent = getParent($(this))
1886 //var relatedTarget = { relatedTarget: this }
1888 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1889 //if (e.isDefaultPrevented()) return
1890 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1893 addxtypeChild : function (tree, cntr) {
1894 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1896 this.menuitems.add(comp);
1917 * @class Roo.bootstrap.MenuItem
1918 * @extends Roo.bootstrap.Component
1919 * Bootstrap MenuItem class
1920 * @cfg {String} html the menu label
1921 * @cfg {String} href the link
1922 * @cfg {Boolean} preventDefault (true | false) default true
1923 * @cfg {Boolean} isContainer (true | false) default false
1927 * Create a new MenuItem
1928 * @param {Object} config The config object
1932 Roo.bootstrap.MenuItem = function(config){
1933 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1938 * The raw click event for the entire grid.
1939 * @param {Roo.EventObject} e
1945 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1949 preventDefault: true,
1950 isContainer : false,
1952 getAutoCreate : function(){
1954 if(this.isContainer){
1957 cls: 'dropdown-menu-item'
1963 cls: 'dropdown-menu-item',
1972 if (this.parent().type == 'treeview') {
1973 cfg.cls = 'treeview-menu';
1976 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1977 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1981 initEvents: function() {
1983 //this.el.select('a').on('click', this.onClick, this);
1986 onClick : function(e)
1988 Roo.log('item on click ');
1989 //if(this.preventDefault){
1990 // e.preventDefault();
1992 //this.parent().hideMenuItems();
1994 this.fireEvent('click', this, e);
2013 * @class Roo.bootstrap.MenuSeparator
2014 * @extends Roo.bootstrap.Component
2015 * Bootstrap MenuSeparator class
2018 * Create a new MenuItem
2019 * @param {Object} config The config object
2023 Roo.bootstrap.MenuSeparator = function(config){
2024 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2027 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2029 getAutoCreate : function(){
2044 <div class="modal fade">
2045 <div class="modal-dialog">
2046 <div class="modal-content">
2047 <div class="modal-header">
2048 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
2049 <h4 class="modal-title">Modal title</h4>
2051 <div class="modal-body">
2052 <p>One fine body…</p>
2054 <div class="modal-footer">
2055 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2056 <button type="button" class="btn btn-primary">Save changes</button>
2058 </div><!-- /.modal-content -->
2059 </div><!-- /.modal-dialog -->
2060 </div><!-- /.modal -->
2070 * @class Roo.bootstrap.Modal
2071 * @extends Roo.bootstrap.Component
2072 * Bootstrap Modal class
2073 * @cfg {String} title Title of dialog
2074 * @cfg {Boolean} specificTitle default false
2075 * @cfg {Array} buttons Array of buttons or standard button set..
2076 * @cfg {String} buttonPosition (left|right|center) default right
2077 * @cfg {Boolean} animate default true
2078 * @cfg {Boolean} allow_close default true
2081 * Create a new Modal Dialog
2082 * @param {Object} config The config object
2085 Roo.bootstrap.Modal = function(config){
2086 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2091 * The raw btnclick event for the button
2092 * @param {Roo.EventObject} e
2096 this.buttons = this.buttons || [];
2099 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2101 title : 'test dialog',
2108 specificTitle: false,
2110 buttonPosition: 'right',
2116 onRender : function(ct, position)
2118 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2121 var cfg = Roo.apply({}, this.getAutoCreate());
2124 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2126 //if (!cfg.name.length) {
2130 cfg.cls += ' ' + this.cls;
2133 cfg.style = this.style;
2135 this.el = Roo.get(document.body).createChild(cfg, position);
2137 //var type = this.el.dom.type;
2139 if(this.tabIndex !== undefined){
2140 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2145 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2146 this.maskEl.enableDisplayMode("block");
2148 //this.el.addClass("x-dlg-modal");
2150 if (this.buttons.length) {
2151 Roo.each(this.buttons, function(bb) {
2152 b = Roo.apply({}, bb);
2153 b.xns = b.xns || Roo.bootstrap;
2154 b.xtype = b.xtype || 'Button';
2155 if (typeof(b.listeners) == 'undefined') {
2156 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2159 var btn = Roo.factory(b);
2161 btn.onRender(this.el.select('.modal-footer div').first());
2165 // render the children.
2168 if(typeof(this.items) != 'undefined'){
2169 var items = this.items;
2172 for(var i =0;i < items.length;i++) {
2173 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2177 this.items = nitems;
2179 this.body = this.el.select('.modal-body',true).first();
2180 this.close = this.el.select('.modal-header .close', true).first();
2181 this.footer = this.el.select('.modal-footer',true).first();
2183 //this.el.addClass([this.fieldClass, this.cls]);
2186 getAutoCreate : function(){
2191 html : this.html || ''
2196 cls : 'modal-title',
2200 if(this.specificTitle){
2206 if (this.allow_close) {
2217 style : 'display: none',
2220 cls: "modal-dialog",
2223 cls : "modal-content",
2226 cls : 'modal-header',
2231 cls : 'modal-footer',
2235 cls: 'btn-' + this.buttonPosition
2252 modal.cls += ' fade';
2258 getChildContainer : function() {
2260 return this.el.select('.modal-body',true).first();
2263 getButtonContainer : function() {
2264 return this.el.select('.modal-footer div',true).first();
2267 initEvents : function()
2269 this.el.select('.modal-header .close').on('click', this.hide, this);
2271 // this.addxtype(this);
2275 if (!this.rendered) {
2279 this.el.setStyle('display', 'block');
2283 (function(){ _this.el.addClass('in'); }).defer(50);
2285 this.el.addClass('in');
2288 Roo.get(document.body).addClass("x-body-masked");
2289 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2291 this.el.setStyle('zIndex', '10001');
2293 this.fireEvent('show', this);
2300 Roo.get(document.body).removeClass("x-body-masked");
2301 this.el.removeClass('in');
2305 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2307 this.el.setStyle('display', 'none');
2310 this.fireEvent('hide', this);
2313 addButton : function(str, cb)
2317 var b = Roo.apply({}, { html : str } );
2318 b.xns = b.xns || Roo.bootstrap;
2319 b.xtype = b.xtype || 'Button';
2320 if (typeof(b.listeners) == 'undefined') {
2321 b.listeners = { click : cb.createDelegate(this) };
2324 var btn = Roo.factory(b);
2326 btn.onRender(this.el.select('.modal-footer div').first());
2332 setDefaultButton : function(btn)
2334 //this.el.select('.modal-footer').()
2336 resizeTo: function(w,h)
2340 setContentSize : function(w, h)
2344 onButtonClick: function(btn,e)
2347 this.fireEvent('btnclick', btn.name, e);
2349 setTitle: function(str) {
2350 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2356 Roo.apply(Roo.bootstrap.Modal, {
2358 * Button config that displays a single OK button
2367 * Button config that displays Yes and No buttons
2383 * Button config that displays OK and Cancel buttons
2398 * Button config that displays Yes, No and Cancel buttons
2420 * messagebox - can be used as a replace
2424 * @class Roo.MessageBox
2425 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2429 Roo.Msg.alert('Status', 'Changes saved successfully.');
2431 // Prompt for user data:
2432 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2434 // process text value...
2438 // Show a dialog using config options:
2440 title:'Save Changes?',
2441 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2442 buttons: Roo.Msg.YESNOCANCEL,
2449 Roo.bootstrap.MessageBox = function(){
2450 var dlg, opt, mask, waitTimer;
2451 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2452 var buttons, activeTextEl, bwidth;
2456 var handleButton = function(button){
2458 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2462 var handleHide = function(){
2464 dlg.el.removeClass(opt.cls);
2467 // Roo.TaskMgr.stop(waitTimer);
2468 // waitTimer = null;
2473 var updateButtons = function(b){
2476 buttons["ok"].hide();
2477 buttons["cancel"].hide();
2478 buttons["yes"].hide();
2479 buttons["no"].hide();
2480 //dlg.footer.dom.style.display = 'none';
2483 dlg.footer.dom.style.display = '';
2484 for(var k in buttons){
2485 if(typeof buttons[k] != "function"){
2488 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2489 width += buttons[k].el.getWidth()+15;
2499 var handleEsc = function(d, k, e){
2500 if(opt && opt.closable !== false){
2510 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2511 * @return {Roo.BasicDialog} The BasicDialog element
2513 getDialog : function(){
2515 dlg = new Roo.bootstrap.Modal( {
2518 //constraintoviewport:false,
2520 //collapsible : false,
2525 //buttonAlign:"center",
2526 closeClick : function(){
2527 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2530 handleButton("cancel");
2535 dlg.on("hide", handleHide);
2537 //dlg.addKeyListener(27, handleEsc);
2539 this.buttons = buttons;
2540 var bt = this.buttonText;
2541 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2542 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2543 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2544 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2546 bodyEl = dlg.body.createChild({
2548 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2549 '<textarea class="roo-mb-textarea"></textarea>' +
2550 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2552 msgEl = bodyEl.dom.firstChild;
2553 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2554 textboxEl.enableDisplayMode();
2555 textboxEl.addKeyListener([10,13], function(){
2556 if(dlg.isVisible() && opt && opt.buttons){
2559 }else if(opt.buttons.yes){
2560 handleButton("yes");
2564 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2565 textareaEl.enableDisplayMode();
2566 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2567 progressEl.enableDisplayMode();
2568 var pf = progressEl.dom.firstChild;
2570 pp = Roo.get(pf.firstChild);
2571 pp.setHeight(pf.offsetHeight);
2579 * Updates the message box body text
2580 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2581 * the XHTML-compliant non-breaking space character '&#160;')
2582 * @return {Roo.MessageBox} This message box
2584 updateText : function(text){
2585 if(!dlg.isVisible() && !opt.width){
2586 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2588 msgEl.innerHTML = text || ' ';
2590 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2591 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2593 Math.min(opt.width || cw , this.maxWidth),
2594 Math.max(opt.minWidth || this.minWidth, bwidth)
2597 activeTextEl.setWidth(w);
2599 if(dlg.isVisible()){
2600 dlg.fixedcenter = false;
2602 // to big, make it scroll. = But as usual stupid IE does not support
2605 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2606 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2607 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2609 bodyEl.dom.style.height = '';
2610 bodyEl.dom.style.overflowY = '';
2613 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2615 bodyEl.dom.style.overflowX = '';
2618 dlg.setContentSize(w, bodyEl.getHeight());
2619 if(dlg.isVisible()){
2620 dlg.fixedcenter = true;
2626 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2627 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2628 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2629 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2630 * @return {Roo.MessageBox} This message box
2632 updateProgress : function(value, text){
2634 this.updateText(text);
2636 if (pp) { // weird bug on my firefox - for some reason this is not defined
2637 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2643 * Returns true if the message box is currently displayed
2644 * @return {Boolean} True if the message box is visible, else false
2646 isVisible : function(){
2647 return dlg && dlg.isVisible();
2651 * Hides the message box if it is displayed
2654 if(this.isVisible()){
2660 * Displays a new message box, or reinitializes an existing message box, based on the config options
2661 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2662 * The following config object properties are supported:
2664 Property Type Description
2665 ---------- --------------- ------------------------------------------------------------------------------------
2666 animEl String/Element An id or Element from which the message box should animate as it opens and
2667 closes (defaults to undefined)
2668 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2669 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2670 closable Boolean False to hide the top-right close button (defaults to true). Note that
2671 progress and wait dialogs will ignore this property and always hide the
2672 close button as they can only be closed programmatically.
2673 cls String A custom CSS class to apply to the message box element
2674 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2675 displayed (defaults to 75)
2676 fn Function A callback function to execute after closing the dialog. The arguments to the
2677 function will be btn (the name of the button that was clicked, if applicable,
2678 e.g. "ok"), and text (the value of the active text field, if applicable).
2679 Progress and wait dialogs will ignore this option since they do not respond to
2680 user actions and can only be closed programmatically, so any required function
2681 should be called by the same code after it closes the dialog.
2682 icon String A CSS class that provides a background image to be used as an icon for
2683 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2684 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2685 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2686 modal Boolean False to allow user interaction with the page while the message box is
2687 displayed (defaults to true)
2688 msg String A string that will replace the existing message box body text (defaults
2689 to the XHTML-compliant non-breaking space character ' ')
2690 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2691 progress Boolean True to display a progress bar (defaults to false)
2692 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2693 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2694 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2695 title String The title text
2696 value String The string value to set into the active textbox element if displayed
2697 wait Boolean True to display a progress bar (defaults to false)
2698 width Number The width of the dialog in pixels
2705 msg: 'Please enter your address:',
2707 buttons: Roo.MessageBox.OKCANCEL,
2710 animEl: 'addAddressBtn'
2713 * @param {Object} config Configuration options
2714 * @return {Roo.MessageBox} This message box
2716 show : function(options)
2719 // this causes nightmares if you show one dialog after another
2720 // especially on callbacks..
2722 if(this.isVisible()){
2725 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2726 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2727 Roo.log("New Dialog Message:" + options.msg )
2728 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2729 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2732 var d = this.getDialog();
2734 d.setTitle(opt.title || " ");
2735 d.close.setDisplayed(opt.closable !== false);
2736 activeTextEl = textboxEl;
2737 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2742 textareaEl.setHeight(typeof opt.multiline == "number" ?
2743 opt.multiline : this.defaultTextHeight);
2744 activeTextEl = textareaEl;
2753 progressEl.setDisplayed(opt.progress === true);
2754 this.updateProgress(0);
2755 activeTextEl.dom.value = opt.value || "";
2757 dlg.setDefaultButton(activeTextEl);
2759 var bs = opt.buttons;
2763 }else if(bs && bs.yes){
2764 db = buttons["yes"];
2766 dlg.setDefaultButton(db);
2768 bwidth = updateButtons(opt.buttons);
2769 this.updateText(opt.msg);
2771 d.el.addClass(opt.cls);
2773 d.proxyDrag = opt.proxyDrag === true;
2774 d.modal = opt.modal !== false;
2775 d.mask = opt.modal !== false ? mask : false;
2777 // force it to the end of the z-index stack so it gets a cursor in FF
2778 document.body.appendChild(dlg.el.dom);
2779 d.animateTarget = null;
2780 d.show(options.animEl);
2786 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2787 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2788 * and closing the message box when the process is complete.
2789 * @param {String} title The title bar text
2790 * @param {String} msg The message box body text
2791 * @return {Roo.MessageBox} This message box
2793 progress : function(title, msg){
2800 minWidth: this.minProgressWidth,
2807 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2808 * If a callback function is passed it will be called after the user clicks the button, and the
2809 * id of the button that was clicked will be passed as the only parameter to the callback
2810 * (could also be the top-right close button).
2811 * @param {String} title The title bar text
2812 * @param {String} msg The message box body text
2813 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2814 * @param {Object} scope (optional) The scope of the callback function
2815 * @return {Roo.MessageBox} This message box
2817 alert : function(title, msg, fn, scope){
2830 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2831 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2832 * You are responsible for closing the message box when the process is complete.
2833 * @param {String} msg The message box body text
2834 * @param {String} title (optional) The title bar text
2835 * @return {Roo.MessageBox} This message box
2837 wait : function(msg, title){
2848 waitTimer = Roo.TaskMgr.start({
2850 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2858 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2859 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2860 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2861 * @param {String} title The title bar text
2862 * @param {String} msg The message box body text
2863 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2864 * @param {Object} scope (optional) The scope of the callback function
2865 * @return {Roo.MessageBox} This message box
2867 confirm : function(title, msg, fn, scope){
2871 buttons: this.YESNO,
2880 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2881 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2882 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2883 * (could also be the top-right close button) and the text that was entered will be passed as the two
2884 * parameters to the callback.
2885 * @param {String} title The title bar text
2886 * @param {String} msg The message box body text
2887 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2888 * @param {Object} scope (optional) The scope of the callback function
2889 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2890 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2891 * @return {Roo.MessageBox} This message box
2893 prompt : function(title, msg, fn, scope, multiline){
2897 buttons: this.OKCANCEL,
2902 multiline: multiline,
2909 * Button config that displays a single OK button
2914 * Button config that displays Yes and No buttons
2917 YESNO : {yes:true, no:true},
2919 * Button config that displays OK and Cancel buttons
2922 OKCANCEL : {ok:true, cancel:true},
2924 * Button config that displays Yes, No and Cancel buttons
2927 YESNOCANCEL : {yes:true, no:true, cancel:true},
2930 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2933 defaultTextHeight : 75,
2935 * The maximum width in pixels of the message box (defaults to 600)
2940 * The minimum width in pixels of the message box (defaults to 100)
2945 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2946 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2949 minProgressWidth : 250,
2951 * An object containing the default button text strings that can be overriden for localized language support.
2952 * Supported properties are: ok, cancel, yes and no.
2953 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2966 * Shorthand for {@link Roo.MessageBox}
2968 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2969 Roo.Msg = Roo.Msg || Roo.MessageBox;
2978 * @class Roo.bootstrap.Navbar
2979 * @extends Roo.bootstrap.Component
2980 * Bootstrap Navbar class
2983 * Create a new Navbar
2984 * @param {Object} config The config object
2988 Roo.bootstrap.Navbar = function(config){
2989 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2993 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3002 getAutoCreate : function(){
3005 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3009 initEvents :function ()
3011 //Roo.log(this.el.select('.navbar-toggle',true));
3012 this.el.select('.navbar-toggle',true).on('click', function() {
3013 // Roo.log('click');
3014 this.el.select('.navbar-collapse',true).toggleClass('in');
3022 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3024 var size = this.el.getSize();
3025 this.maskEl.setSize(size.width, size.height);
3026 this.maskEl.enableDisplayMode("block");
3035 getChildContainer : function()
3037 if (this.el.select('.collapse').getCount()) {
3038 return this.el.select('.collapse',true).first();
3071 * @class Roo.bootstrap.NavSimplebar
3072 * @extends Roo.bootstrap.Navbar
3073 * Bootstrap Sidebar class
3075 * @cfg {Boolean} inverse is inverted color
3077 * @cfg {String} type (nav | pills | tabs)
3078 * @cfg {Boolean} arrangement stacked | justified
3079 * @cfg {String} align (left | right) alignment
3081 * @cfg {Boolean} main (true|false) main nav bar? default false
3082 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3084 * @cfg {String} tag (header|footer|nav|div) default is nav
3090 * Create a new Sidebar
3091 * @param {Object} config The config object
3095 Roo.bootstrap.NavSimplebar = function(config){
3096 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3099 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3115 getAutoCreate : function(){
3119 tag : this.tag || 'div',
3132 this.type = this.type || 'nav';
3133 if (['tabs','pills'].indexOf(this.type)!==-1) {
3134 cfg.cn[0].cls += ' nav-' + this.type
3138 if (this.type!=='nav') {
3139 Roo.log('nav type must be nav/tabs/pills')
3141 cfg.cn[0].cls += ' navbar-nav'
3147 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3148 cfg.cn[0].cls += ' nav-' + this.arrangement;
3152 if (this.align === 'right') {
3153 cfg.cn[0].cls += ' navbar-right';
3157 cfg.cls += ' navbar-inverse';
3184 * @class Roo.bootstrap.NavHeaderbar
3185 * @extends Roo.bootstrap.NavSimplebar
3186 * Bootstrap Sidebar class
3188 * @cfg {String} brand what is brand
3189 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3190 * @cfg {String} brand_href href of the brand
3191 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3192 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3193 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3194 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3197 * Create a new Sidebar
3198 * @param {Object} config The config object
3202 Roo.bootstrap.NavHeaderbar = function(config){
3203 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3207 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3214 desktopCenter : false,
3217 getAutoCreate : function(){
3220 tag: this.nav || 'nav',
3227 if (this.desktopCenter) {
3228 cn.push({cls : 'container', cn : []});
3235 cls: 'navbar-header',
3240 cls: 'navbar-toggle',
3241 'data-toggle': 'collapse',
3246 html: 'Toggle navigation'
3268 cls: 'collapse navbar-collapse',
3272 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3274 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3275 cfg.cls += ' navbar-' + this.position;
3277 // tag can override this..
3279 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3282 if (this.brand !== '') {
3285 href: this.brand_href ? this.brand_href : '#',
3286 cls: 'navbar-brand',
3294 cfg.cls += ' main-nav';
3302 getHeaderChildContainer : function()
3304 if (this.el.select('.navbar-header').getCount()) {
3305 return this.el.select('.navbar-header',true).first();
3308 return this.getChildContainer();
3312 initEvents : function()
3314 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3316 if (this.autohide) {
3321 Roo.get(document).on('scroll',function(e) {
3322 var ns = Roo.get(document).getScroll().top;
3323 var os = prevScroll;
3327 ft.removeClass('slideDown');
3328 ft.addClass('slideUp');
3331 ft.removeClass('slideUp');
3332 ft.addClass('slideDown');
3356 * @class Roo.bootstrap.NavSidebar
3357 * @extends Roo.bootstrap.Navbar
3358 * Bootstrap Sidebar class
3361 * Create a new Sidebar
3362 * @param {Object} config The config object
3366 Roo.bootstrap.NavSidebar = function(config){
3367 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3370 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3372 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3374 getAutoCreate : function(){
3379 cls: 'sidebar sidebar-nav'
3401 * @class Roo.bootstrap.NavGroup
3402 * @extends Roo.bootstrap.Component
3403 * Bootstrap NavGroup class
3404 * @cfg {String} align left | right
3405 * @cfg {Boolean} inverse false | true
3406 * @cfg {String} type (nav|pills|tab) default nav
3407 * @cfg {String} navId - reference Id for navbar.
3411 * Create a new nav group
3412 * @param {Object} config The config object
3415 Roo.bootstrap.NavGroup = function(config){
3416 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3419 Roo.bootstrap.NavGroup.register(this);
3423 * Fires when the active item changes
3424 * @param {Roo.bootstrap.NavGroup} this
3425 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3426 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3433 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3444 getAutoCreate : function()
3446 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3453 if (['tabs','pills'].indexOf(this.type)!==-1) {
3454 cfg.cls += ' nav-' + this.type
3456 if (this.type!=='nav') {
3457 Roo.log('nav type must be nav/tabs/pills')
3459 cfg.cls += ' navbar-nav'
3462 if (this.parent().sidebar) {
3465 cls: 'dashboard-menu sidebar-menu'
3471 if (this.form === true) {
3477 if (this.align === 'right') {
3478 cfg.cls += ' navbar-right';
3480 cfg.cls += ' navbar-left';
3484 if (this.align === 'right') {
3485 cfg.cls += ' navbar-right';
3489 cfg.cls += ' navbar-inverse';
3497 * sets the active Navigation item
3498 * @param {Roo.bootstrap.NavItem} the new current navitem
3500 setActiveItem : function(item)
3503 Roo.each(this.navItems, function(v){
3508 v.setActive(false, true);
3515 item.setActive(true, true);
3516 this.fireEvent('changed', this, item, prev);
3521 * gets the active Navigation item
3522 * @return {Roo.bootstrap.NavItem} the current navitem
3524 getActive : function()
3528 Roo.each(this.navItems, function(v){
3539 indexOfNav : function()
3543 Roo.each(this.navItems, function(v,i){
3554 * adds a Navigation item
3555 * @param {Roo.bootstrap.NavItem} the navitem to add
3557 addItem : function(cfg)
3559 var cn = new Roo.bootstrap.NavItem(cfg);
3561 cn.parentId = this.id;
3562 cn.onRender(this.el, null);
3566 * register a Navigation item
3567 * @param {Roo.bootstrap.NavItem} the navitem to add
3569 register : function(item)
3571 this.navItems.push( item);
3572 item.navId = this.navId;
3577 * clear all the Navigation item
3580 clearAll : function()
3583 this.el.dom.innerHTML = '';
3586 getNavItem: function(tabId)
3589 Roo.each(this.navItems, function(e) {
3590 if (e.tabId == tabId) {
3600 setActiveNext : function()
3602 var i = this.indexOfNav(this.getActive());
3603 if (i > this.navItems.length) {
3606 this.setActiveItem(this.navItems[i+1]);
3608 setActivePrev : function()
3610 var i = this.indexOfNav(this.getActive());
3614 this.setActiveItem(this.navItems[i-1]);
3616 clearWasActive : function(except) {
3617 Roo.each(this.navItems, function(e) {
3618 if (e.tabId != except.tabId && e.was_active) {
3619 e.was_active = false;
3626 getWasActive : function ()
3629 Roo.each(this.navItems, function(e) {
3644 Roo.apply(Roo.bootstrap.NavGroup, {
3648 * register a Navigation Group
3649 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3651 register : function(navgrp)
3653 this.groups[navgrp.navId] = navgrp;
3657 * fetch a Navigation Group based on the navigation ID
3658 * @param {string} the navgroup to add
3659 * @returns {Roo.bootstrap.NavGroup} the navgroup
3661 get: function(navId) {
3662 if (typeof(this.groups[navId]) == 'undefined') {
3664 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3666 return this.groups[navId] ;
3681 * @class Roo.bootstrap.NavItem
3682 * @extends Roo.bootstrap.Component
3683 * Bootstrap Navbar.NavItem class
3684 * @cfg {String} href link to
3685 * @cfg {String} html content of button
3686 * @cfg {String} badge text inside badge
3687 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3688 * @cfg {String} glyphicon name of glyphicon
3689 * @cfg {String} icon name of font awesome icon
3690 * @cfg {Boolean} active Is item active
3691 * @cfg {Boolean} disabled Is item disabled
3693 * @cfg {Boolean} preventDefault (true | false) default false
3694 * @cfg {String} tabId the tab that this item activates.
3695 * @cfg {String} tagtype (a|span) render as a href or span?
3698 * Create a new Navbar Item
3699 * @param {Object} config The config object
3701 Roo.bootstrap.NavItem = function(config){
3702 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3707 * The raw click event for the entire grid.
3708 * @param {Roo.EventObject} e
3713 * Fires when the active item active state changes
3714 * @param {Roo.bootstrap.NavItem} this
3715 * @param {boolean} state the new state
3723 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3731 preventDefault : false,
3738 getAutoCreate : function(){
3746 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3748 if (this.disabled) {
3749 cfg.cls += ' disabled';
3752 if (this.href || this.html || this.glyphicon || this.icon) {
3756 href : this.href || "#",
3757 html: this.html || ''
3762 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3765 if(this.glyphicon) {
3766 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3771 cfg.cn[0].html += " <span class='caret'></span>";
3775 if (this.badge !== '') {
3777 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3785 initEvents: function()
3787 if (typeof (this.menu) != 'undefined') {
3788 this.menu.parentType = this.xtype;
3789 this.menu.triggerEl = this.el;
3790 this.menu = this.addxtype(Roo.apply({}, this.menu));
3793 this.el.select('a',true).on('click', this.onClick, this);
3795 if(this.tagtype == 'span'){
3796 this.el.select('span',true).on('click', this.onClick, this);
3799 // at this point parent should be available..
3800 this.parent().register(this);
3803 onClick : function(e)
3806 if(this.preventDefault){
3809 if (this.disabled) {
3813 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3814 if (tg && tg.transition) {
3815 Roo.log("waiting for the transitionend");
3819 Roo.log("fire event clicked");
3820 if(this.fireEvent('click', this, e) === false){
3824 if(this.tagtype == 'span'){
3828 var p = this.parent();
3829 if (['tabs','pills'].indexOf(p.type)!==-1) {
3830 if (typeof(p.setActiveItem) !== 'undefined') {
3831 p.setActiveItem(this);
3834 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3835 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3836 // remove the collapsed menu expand...
3837 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3842 isActive: function () {
3845 setActive : function(state, fire, is_was_active)
3847 if (this.active && !state & this.navId) {
3848 this.was_active = true;
3849 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3851 nv.clearWasActive(this);
3855 this.active = state;
3858 this.el.removeClass('active');
3859 } else if (!this.el.hasClass('active')) {
3860 this.el.addClass('active');
3863 this.fireEvent('changed', this, state);
3866 // show a panel if it's registered and related..
3868 if (!this.navId || !this.tabId || !state || is_was_active) {
3872 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3876 var pan = tg.getPanelByName(this.tabId);
3880 // if we can not flip to new panel - go back to old nav highlight..
3881 if (false == tg.showPanel(pan)) {
3882 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3884 var onav = nv.getWasActive();
3886 onav.setActive(true, false, true);
3895 // this should not be here...
3896 setDisabled : function(state)
3898 this.disabled = state;
3900 this.el.removeClass('disabled');
3901 } else if (!this.el.hasClass('disabled')) {
3902 this.el.addClass('disabled');
3908 * Fetch the element to display the tooltip on.
3909 * @return {Roo.Element} defaults to this.el
3911 tooltipEl : function()
3913 return this.el.select('' + this.tagtype + '', true).first();
3924 * <span> icon </span>
3925 * <span> text </span>
3926 * <span>badge </span>
3930 * @class Roo.bootstrap.NavSidebarItem
3931 * @extends Roo.bootstrap.NavItem
3932 * Bootstrap Navbar.NavSidebarItem class
3934 * Create a new Navbar Button
3935 * @param {Object} config The config object
3937 Roo.bootstrap.NavSidebarItem = function(config){
3938 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3943 * The raw click event for the entire grid.
3944 * @param {Roo.EventObject} e
3949 * Fires when the active item active state changes
3950 * @param {Roo.bootstrap.NavSidebarItem} this
3951 * @param {boolean} state the new state
3959 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3962 getAutoCreate : function(){
3967 href : this.href || '#',
3979 html : this.html || ''
3984 cfg.cls += ' active';
3988 if (this.glyphicon || this.icon) {
3989 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3990 a.cn.push({ tag : 'i', cls : c }) ;
3995 if (this.badge !== '') {
3996 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4000 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4001 a.cls += 'dropdown-toggle treeview' ;
4025 * @class Roo.bootstrap.Row
4026 * @extends Roo.bootstrap.Component
4027 * Bootstrap Row class (contains columns...)
4031 * @param {Object} config The config object
4034 Roo.bootstrap.Row = function(config){
4035 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4038 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4040 getAutoCreate : function(){
4059 * @class Roo.bootstrap.Element
4060 * @extends Roo.bootstrap.Component
4061 * Bootstrap Element class
4062 * @cfg {String} html contents of the element
4063 * @cfg {String} tag tag of the element
4064 * @cfg {String} cls class of the element
4067 * Create a new Element
4068 * @param {Object} config The config object
4071 Roo.bootstrap.Element = function(config){
4072 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4075 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4082 getAutoCreate : function(){
4107 * @class Roo.bootstrap.Pagination
4108 * @extends Roo.bootstrap.Component
4109 * Bootstrap Pagination class
4110 * @cfg {String} size xs | sm | md | lg
4111 * @cfg {Boolean} inverse false | true
4114 * Create a new Pagination
4115 * @param {Object} config The config object
4118 Roo.bootstrap.Pagination = function(config){
4119 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4122 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4128 getAutoCreate : function(){
4134 cfg.cls += ' inverse';
4140 cfg.cls += " " + this.cls;
4158 * @class Roo.bootstrap.PaginationItem
4159 * @extends Roo.bootstrap.Component
4160 * Bootstrap PaginationItem class
4161 * @cfg {String} html text
4162 * @cfg {String} href the link
4163 * @cfg {Boolean} preventDefault (true | false) default true
4164 * @cfg {Boolean} active (true | false) default false
4168 * Create a new PaginationItem
4169 * @param {Object} config The config object
4173 Roo.bootstrap.PaginationItem = function(config){
4174 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4179 * The raw click event for the entire grid.
4180 * @param {Roo.EventObject} e
4186 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4190 preventDefault: true,
4194 getAutoCreate : function(){
4200 href : this.href ? this.href : '#',
4201 html : this.html ? this.html : ''
4211 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4217 initEvents: function() {
4219 this.el.on('click', this.onClick, this);
4222 onClick : function(e)
4224 Roo.log('PaginationItem on click ');
4225 if(this.preventDefault){
4229 this.fireEvent('click', this, e);
4245 * @class Roo.bootstrap.Slider
4246 * @extends Roo.bootstrap.Component
4247 * Bootstrap Slider class
4250 * Create a new Slider
4251 * @param {Object} config The config object
4254 Roo.bootstrap.Slider = function(config){
4255 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4258 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4260 getAutoCreate : function(){
4264 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4268 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4280 * Ext JS Library 1.1.1
4281 * Copyright(c) 2006-2007, Ext JS, LLC.
4283 * Originally Released Under LGPL - original licence link has changed is not relivant.
4286 * <script type="text/javascript">
4291 * @class Roo.grid.ColumnModel
4292 * @extends Roo.util.Observable
4293 * This is the default implementation of a ColumnModel used by the Grid. It defines
4294 * the columns in the grid.
4297 var colModel = new Roo.grid.ColumnModel([
4298 {header: "Ticker", width: 60, sortable: true, locked: true},
4299 {header: "Company Name", width: 150, sortable: true},
4300 {header: "Market Cap.", width: 100, sortable: true},
4301 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4302 {header: "Employees", width: 100, sortable: true, resizable: false}
4307 * The config options listed for this class are options which may appear in each
4308 * individual column definition.
4309 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4311 * @param {Object} config An Array of column config objects. See this class's
4312 * config objects for details.
4314 Roo.grid.ColumnModel = function(config){
4316 * The config passed into the constructor
4318 this.config = config;
4321 // if no id, create one
4322 // if the column does not have a dataIndex mapping,
4323 // map it to the order it is in the config
4324 for(var i = 0, len = config.length; i < len; i++){
4326 if(typeof c.dataIndex == "undefined"){
4329 if(typeof c.renderer == "string"){
4330 c.renderer = Roo.util.Format[c.renderer];
4332 if(typeof c.id == "undefined"){
4335 if(c.editor && c.editor.xtype){
4336 c.editor = Roo.factory(c.editor, Roo.grid);
4338 if(c.editor && c.editor.isFormField){
4339 c.editor = new Roo.grid.GridEditor(c.editor);
4341 this.lookup[c.id] = c;
4345 * The width of columns which have no width specified (defaults to 100)
4348 this.defaultWidth = 100;
4351 * Default sortable of columns which have no sortable specified (defaults to false)
4354 this.defaultSortable = false;
4358 * @event widthchange
4359 * Fires when the width of a column changes.
4360 * @param {ColumnModel} this
4361 * @param {Number} columnIndex The column index
4362 * @param {Number} newWidth The new width
4364 "widthchange": true,
4366 * @event headerchange
4367 * Fires when the text of a header changes.
4368 * @param {ColumnModel} this
4369 * @param {Number} columnIndex The column index
4370 * @param {Number} newText The new header text
4372 "headerchange": true,
4374 * @event hiddenchange
4375 * Fires when a column is hidden or "unhidden".
4376 * @param {ColumnModel} this
4377 * @param {Number} columnIndex The column index
4378 * @param {Boolean} hidden true if hidden, false otherwise
4380 "hiddenchange": true,
4382 * @event columnmoved
4383 * Fires when a column is moved.
4384 * @param {ColumnModel} this
4385 * @param {Number} oldIndex
4386 * @param {Number} newIndex
4388 "columnmoved" : true,
4390 * @event columlockchange
4391 * Fires when a column's locked state is changed
4392 * @param {ColumnModel} this
4393 * @param {Number} colIndex
4394 * @param {Boolean} locked true if locked
4396 "columnlockchange" : true
4398 Roo.grid.ColumnModel.superclass.constructor.call(this);
4400 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4402 * @cfg {String} header The header text to display in the Grid view.
4405 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4406 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4407 * specified, the column's index is used as an index into the Record's data Array.
4410 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4411 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4414 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4415 * Defaults to the value of the {@link #defaultSortable} property.
4416 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4419 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4422 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4425 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4428 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4431 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4432 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4433 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4434 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4437 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4440 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4443 * @cfg {String} cursor (Optional)
4446 * Returns the id of the column at the specified index.
4447 * @param {Number} index The column index
4448 * @return {String} the id
4450 getColumnId : function(index){
4451 return this.config[index].id;
4455 * Returns the column for a specified id.
4456 * @param {String} id The column id
4457 * @return {Object} the column
4459 getColumnById : function(id){
4460 return this.lookup[id];
4465 * Returns the column for a specified dataIndex.
4466 * @param {String} dataIndex The column dataIndex
4467 * @return {Object|Boolean} the column or false if not found
4469 getColumnByDataIndex: function(dataIndex){
4470 var index = this.findColumnIndex(dataIndex);
4471 return index > -1 ? this.config[index] : false;
4475 * Returns the index for a specified column id.
4476 * @param {String} id The column id
4477 * @return {Number} the index, or -1 if not found
4479 getIndexById : function(id){
4480 for(var i = 0, len = this.config.length; i < len; i++){
4481 if(this.config[i].id == id){
4489 * Returns the index for a specified column dataIndex.
4490 * @param {String} dataIndex The column dataIndex
4491 * @return {Number} the index, or -1 if not found
4494 findColumnIndex : function(dataIndex){
4495 for(var i = 0, len = this.config.length; i < len; i++){
4496 if(this.config[i].dataIndex == dataIndex){
4504 moveColumn : function(oldIndex, newIndex){
4505 var c = this.config[oldIndex];
4506 this.config.splice(oldIndex, 1);
4507 this.config.splice(newIndex, 0, c);
4508 this.dataMap = null;
4509 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4512 isLocked : function(colIndex){
4513 return this.config[colIndex].locked === true;
4516 setLocked : function(colIndex, value, suppressEvent){
4517 if(this.isLocked(colIndex) == value){
4520 this.config[colIndex].locked = value;
4522 this.fireEvent("columnlockchange", this, colIndex, value);
4526 getTotalLockedWidth : function(){
4528 for(var i = 0; i < this.config.length; i++){
4529 if(this.isLocked(i) && !this.isHidden(i)){
4530 this.totalWidth += this.getColumnWidth(i);
4536 getLockedCount : function(){
4537 for(var i = 0, len = this.config.length; i < len; i++){
4538 if(!this.isLocked(i)){
4545 * Returns the number of columns.
4548 getColumnCount : function(visibleOnly){
4549 if(visibleOnly === true){
4551 for(var i = 0, len = this.config.length; i < len; i++){
4552 if(!this.isHidden(i)){
4558 return this.config.length;
4562 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4563 * @param {Function} fn
4564 * @param {Object} scope (optional)
4565 * @return {Array} result
4567 getColumnsBy : function(fn, scope){
4569 for(var i = 0, len = this.config.length; i < len; i++){
4570 var c = this.config[i];
4571 if(fn.call(scope||this, c, i) === true){
4579 * Returns true if the specified column is sortable.
4580 * @param {Number} col The column index
4583 isSortable : function(col){
4584 if(typeof this.config[col].sortable == "undefined"){
4585 return this.defaultSortable;
4587 return this.config[col].sortable;
4591 * Returns the rendering (formatting) function defined for the column.
4592 * @param {Number} col The column index.
4593 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4595 getRenderer : function(col){
4596 if(!this.config[col].renderer){
4597 return Roo.grid.ColumnModel.defaultRenderer;
4599 return this.config[col].renderer;
4603 * Sets the rendering (formatting) function for a column.
4604 * @param {Number} col The column index
4605 * @param {Function} fn The function to use to process the cell's raw data
4606 * to return HTML markup for the grid view. The render function is called with
4607 * the following parameters:<ul>
4608 * <li>Data value.</li>
4609 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4610 * <li>css A CSS style string to apply to the table cell.</li>
4611 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4612 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4613 * <li>Row index</li>
4614 * <li>Column index</li>
4615 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4617 setRenderer : function(col, fn){
4618 this.config[col].renderer = fn;
4622 * Returns the width for the specified column.
4623 * @param {Number} col The column index
4626 getColumnWidth : function(col){
4627 return this.config[col].width * 1 || this.defaultWidth;
4631 * Sets the width for a column.
4632 * @param {Number} col The column index
4633 * @param {Number} width The new width
4635 setColumnWidth : function(col, width, suppressEvent){
4636 this.config[col].width = width;
4637 this.totalWidth = null;
4639 this.fireEvent("widthchange", this, col, width);
4644 * Returns the total width of all columns.
4645 * @param {Boolean} includeHidden True to include hidden column widths
4648 getTotalWidth : function(includeHidden){
4649 if(!this.totalWidth){
4650 this.totalWidth = 0;
4651 for(var i = 0, len = this.config.length; i < len; i++){
4652 if(includeHidden || !this.isHidden(i)){
4653 this.totalWidth += this.getColumnWidth(i);
4657 return this.totalWidth;
4661 * Returns the header for the specified column.
4662 * @param {Number} col The column index
4665 getColumnHeader : function(col){
4666 return this.config[col].header;
4670 * Sets the header for a column.
4671 * @param {Number} col The column index
4672 * @param {String} header The new header
4674 setColumnHeader : function(col, header){
4675 this.config[col].header = header;
4676 this.fireEvent("headerchange", this, col, header);
4680 * Returns the tooltip for the specified column.
4681 * @param {Number} col The column index
4684 getColumnTooltip : function(col){
4685 return this.config[col].tooltip;
4688 * Sets the tooltip for a column.
4689 * @param {Number} col The column index
4690 * @param {String} tooltip The new tooltip
4692 setColumnTooltip : function(col, tooltip){
4693 this.config[col].tooltip = tooltip;
4697 * Returns the dataIndex for the specified column.
4698 * @param {Number} col The column index
4701 getDataIndex : function(col){
4702 return this.config[col].dataIndex;
4706 * Sets the dataIndex for a column.
4707 * @param {Number} col The column index
4708 * @param {Number} dataIndex The new dataIndex
4710 setDataIndex : function(col, dataIndex){
4711 this.config[col].dataIndex = dataIndex;
4717 * Returns true if the cell is editable.
4718 * @param {Number} colIndex The column index
4719 * @param {Number} rowIndex The row index
4722 isCellEditable : function(colIndex, rowIndex){
4723 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4727 * Returns the editor defined for the cell/column.
4728 * return false or null to disable editing.
4729 * @param {Number} colIndex The column index
4730 * @param {Number} rowIndex The row index
4733 getCellEditor : function(colIndex, rowIndex){
4734 return this.config[colIndex].editor;
4738 * Sets if a column is editable.
4739 * @param {Number} col The column index
4740 * @param {Boolean} editable True if the column is editable
4742 setEditable : function(col, editable){
4743 this.config[col].editable = editable;
4748 * Returns true if the column is hidden.
4749 * @param {Number} colIndex The column index
4752 isHidden : function(colIndex){
4753 return this.config[colIndex].hidden;
4758 * Returns true if the column width cannot be changed
4760 isFixed : function(colIndex){
4761 return this.config[colIndex].fixed;
4765 * Returns true if the column can be resized
4768 isResizable : function(colIndex){
4769 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4772 * Sets if a column is hidden.
4773 * @param {Number} colIndex The column index
4774 * @param {Boolean} hidden True if the column is hidden
4776 setHidden : function(colIndex, hidden){
4777 this.config[colIndex].hidden = hidden;
4778 this.totalWidth = null;
4779 this.fireEvent("hiddenchange", this, colIndex, hidden);
4783 * Sets the editor for a column.
4784 * @param {Number} col The column index
4785 * @param {Object} editor The editor object
4787 setEditor : function(col, editor){
4788 this.config[col].editor = editor;
4792 Roo.grid.ColumnModel.defaultRenderer = function(value){
4793 if(typeof value == "string" && value.length < 1){
4799 // Alias for backwards compatibility
4800 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4803 * Ext JS Library 1.1.1
4804 * Copyright(c) 2006-2007, Ext JS, LLC.
4806 * Originally Released Under LGPL - original licence link has changed is not relivant.
4809 * <script type="text/javascript">
4813 * @class Roo.LoadMask
4814 * A simple utility class for generically masking elements while loading data. If the element being masked has
4815 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4816 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4817 * element's UpdateManager load indicator and will be destroyed after the initial load.
4819 * Create a new LoadMask
4820 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4821 * @param {Object} config The config object
4823 Roo.LoadMask = function(el, config){
4824 this.el = Roo.get(el);
4825 Roo.apply(this, config);
4827 this.store.on('beforeload', this.onBeforeLoad, this);
4828 this.store.on('load', this.onLoad, this);
4829 this.store.on('loadexception', this.onLoadException, this);
4830 this.removeMask = false;
4832 var um = this.el.getUpdateManager();
4833 um.showLoadIndicator = false; // disable the default indicator
4834 um.on('beforeupdate', this.onBeforeLoad, this);
4835 um.on('update', this.onLoad, this);
4836 um.on('failure', this.onLoad, this);
4837 this.removeMask = true;
4841 Roo.LoadMask.prototype = {
4843 * @cfg {Boolean} removeMask
4844 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4845 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4849 * The text to display in a centered loading message box (defaults to 'Loading...')
4853 * @cfg {String} msgCls
4854 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4856 msgCls : 'x-mask-loading',
4859 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4865 * Disables the mask to prevent it from being displayed
4867 disable : function(){
4868 this.disabled = true;
4872 * Enables the mask so that it can be displayed
4874 enable : function(){
4875 this.disabled = false;
4878 onLoadException : function()
4882 if (typeof(arguments[3]) != 'undefined') {
4883 Roo.MessageBox.alert("Error loading",arguments[3]);
4887 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4888 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4897 this.el.unmask(this.removeMask);
4902 this.el.unmask(this.removeMask);
4906 onBeforeLoad : function(){
4908 this.el.mask(this.msg, this.msgCls);
4913 destroy : function(){
4915 this.store.un('beforeload', this.onBeforeLoad, this);
4916 this.store.un('load', this.onLoad, this);
4917 this.store.un('loadexception', this.onLoadException, this);
4919 var um = this.el.getUpdateManager();
4920 um.un('beforeupdate', this.onBeforeLoad, this);
4921 um.un('update', this.onLoad, this);
4922 um.un('failure', this.onLoad, this);
4933 * @class Roo.bootstrap.Table
4934 * @extends Roo.bootstrap.Component
4935 * Bootstrap Table class
4936 * @cfg {String} cls table class
4937 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4938 * @cfg {String} bgcolor Specifies the background color for a table
4939 * @cfg {Number} border Specifies whether the table cells should have borders or not
4940 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4941 * @cfg {Number} cellspacing Specifies the space between cells
4942 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4943 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4944 * @cfg {String} sortable Specifies that the table should be sortable
4945 * @cfg {String} summary Specifies a summary of the content of a table
4946 * @cfg {Number} width Specifies the width of a table
4947 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4949 * @cfg {boolean} striped Should the rows be alternative striped
4950 * @cfg {boolean} bordered Add borders to the table
4951 * @cfg {boolean} hover Add hover highlighting
4952 * @cfg {boolean} condensed Format condensed
4953 * @cfg {boolean} responsive Format condensed
4954 * @cfg {Boolean} loadMask (true|false) default false
4955 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4956 * @cfg {Boolean} thead (true|false) generate thead, default true
4957 * @cfg {Boolean} RowSelection (true|false) default false
4958 * @cfg {Boolean} CellSelection (true|false) default false
4959 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4963 * Create a new Table
4964 * @param {Object} config The config object
4967 Roo.bootstrap.Table = function(config){
4968 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4971 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4972 this.sm = this.selModel;
4973 this.sm.xmodule = this.xmodule || false;
4975 if (this.cm && typeof(this.cm.config) == 'undefined') {
4976 this.colModel = new Roo.grid.ColumnModel(this.cm);
4977 this.cm = this.colModel;
4978 this.cm.xmodule = this.xmodule || false;
4981 this.store= Roo.factory(this.store, Roo.data);
4982 this.ds = this.store;
4983 this.ds.xmodule = this.xmodule || false;
4986 if (this.footer && this.store) {
4987 this.footer.dataSource = this.ds;
4988 this.footer = Roo.factory(this.footer);
4995 * Fires when a cell is clicked
4996 * @param {Roo.bootstrap.Table} this
4997 * @param {Roo.Element} el
4998 * @param {Number} rowIndex
4999 * @param {Number} columnIndex
5000 * @param {Roo.EventObject} e
5004 * @event celldblclick
5005 * Fires when a cell is double clicked
5006 * @param {Roo.bootstrap.Table} this
5007 * @param {Roo.Element} el
5008 * @param {Number} rowIndex
5009 * @param {Number} columnIndex
5010 * @param {Roo.EventObject} e
5012 "celldblclick" : true,
5015 * Fires when a row is clicked
5016 * @param {Roo.bootstrap.Table} this
5017 * @param {Roo.Element} el
5018 * @param {Number} rowIndex
5019 * @param {Roo.EventObject} e
5023 * @event rowdblclick
5024 * Fires when a row is double clicked
5025 * @param {Roo.bootstrap.Table} this
5026 * @param {Roo.Element} el
5027 * @param {Number} rowIndex
5028 * @param {Roo.EventObject} e
5030 "rowdblclick" : true,
5033 * Fires when a mouseover occur
5034 * @param {Roo.bootstrap.Table} this
5035 * @param {Roo.Element} el
5036 * @param {Number} rowIndex
5037 * @param {Number} columnIndex
5038 * @param {Roo.EventObject} e
5043 * Fires when a mouseout occur
5044 * @param {Roo.bootstrap.Table} this
5045 * @param {Roo.Element} el
5046 * @param {Number} rowIndex
5047 * @param {Number} columnIndex
5048 * @param {Roo.EventObject} e
5053 * Fires when a row is rendered, so you can change add a style to it.
5054 * @param {Roo.bootstrap.Table} this
5055 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5062 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5086 RowSelection : false,
5087 CellSelection : false,
5090 // Roo.Element - the tbody
5093 getAutoCreate : function(){
5094 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5103 cfg.cls += ' table-striped';
5107 cfg.cls += ' table-hover';
5109 if (this.bordered) {
5110 cfg.cls += ' table-bordered';
5112 if (this.condensed) {
5113 cfg.cls += ' table-condensed';
5115 if (this.responsive) {
5116 cfg.cls += ' table-responsive';
5120 cfg.cls+= ' ' +this.cls;
5123 // this lot should be simplifed...
5126 cfg.align=this.align;
5129 cfg.bgcolor=this.bgcolor;
5132 cfg.border=this.border;
5134 if (this.cellpadding) {
5135 cfg.cellpadding=this.cellpadding;
5137 if (this.cellspacing) {
5138 cfg.cellspacing=this.cellspacing;
5141 cfg.frame=this.frame;
5144 cfg.rules=this.rules;
5146 if (this.sortable) {
5147 cfg.sortable=this.sortable;
5150 cfg.summary=this.summary;
5153 cfg.width=this.width;
5156 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5159 if(this.store || this.cm){
5161 cfg.cn.push(this.renderHeader());
5164 cfg.cn.push(this.renderBody());
5167 cfg.cn.push(this.renderFooter());
5170 cfg.cls+= ' TableGrid';
5173 return { cn : [ cfg ] };
5176 initEvents : function()
5178 if(!this.store || !this.cm){
5182 //Roo.log('initEvents with ds!!!!');
5184 this.mainBody = this.el.select('tbody', true).first();
5189 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5190 e.on('click', _this.sort, _this);
5193 this.el.on("click", this.onClick, this);
5194 this.el.on("dblclick", this.onDblClick, this);
5196 // why is this done????? = it breaks dialogs??
5197 //this.parent().el.setStyle('position', 'relative');
5201 this.footer.parentId = this.id;
5202 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5205 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5207 this.store.on('load', this.onLoad, this);
5208 this.store.on('beforeload', this.onBeforeLoad, this);
5209 this.store.on('update', this.onUpdate, this);
5210 this.store.on('add', this.onAdd, this);
5214 onMouseover : function(e, el)
5216 var cell = Roo.get(el);
5222 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5223 cell = cell.findParent('td', false, true);
5226 var row = cell.findParent('tr', false, true);
5227 var cellIndex = cell.dom.cellIndex;
5228 var rowIndex = row.dom.rowIndex - 1; // start from 0
5230 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5234 onMouseout : function(e, el)
5236 var cell = Roo.get(el);
5242 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5243 cell = cell.findParent('td', false, true);
5246 var row = cell.findParent('tr', false, true);
5247 var cellIndex = cell.dom.cellIndex;
5248 var rowIndex = row.dom.rowIndex - 1; // start from 0
5250 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5254 onClick : function(e, el)
5256 var cell = Roo.get(el);
5258 if(!cell || (!this.CellSelection && !this.RowSelection)){
5263 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5264 cell = cell.findParent('td', false, true);
5267 var row = cell.findParent('tr', false, true);
5268 var cellIndex = cell.dom.cellIndex;
5269 var rowIndex = row.dom.rowIndex - 1;
5271 if(this.CellSelection){
5272 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5275 if(this.RowSelection){
5276 this.fireEvent('rowclick', this, row, rowIndex, e);
5282 onDblClick : function(e,el)
5284 var cell = Roo.get(el);
5286 if(!cell || (!this.CellSelection && !this.RowSelection)){
5290 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5291 cell = cell.findParent('td', false, true);
5294 var row = cell.findParent('tr', false, true);
5295 var cellIndex = cell.dom.cellIndex;
5296 var rowIndex = row.dom.rowIndex - 1;
5298 if(this.CellSelection){
5299 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5302 if(this.RowSelection){
5303 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5307 sort : function(e,el)
5309 var col = Roo.get(el)
5311 if(!col.hasClass('sortable')){
5315 var sort = col.attr('sort');
5318 if(col.hasClass('glyphicon-arrow-up')){
5322 this.store.sortInfo = {field : sort, direction : dir};
5325 Roo.log("calling footer first");
5326 this.footer.onClick('first');
5329 this.store.load({ params : { start : 0 } });
5333 renderHeader : function()
5342 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5344 var config = cm.config[i];
5349 html: cm.getColumnHeader(i)
5352 if(typeof(config.hidden) != 'undefined' && config.hidden){
5353 c.style += ' display:none;';
5356 if(typeof(config.dataIndex) != 'undefined'){
5357 c.sort = config.dataIndex;
5360 if(typeof(config.sortable) != 'undefined' && config.sortable){
5364 if(typeof(config.align) != 'undefined' && config.align.length){
5365 c.style += ' text-align:' + config.align + ';';
5368 if(typeof(config.width) != 'undefined'){
5369 c.style += ' width:' + config.width + 'px;';
5378 renderBody : function()
5388 colspan : this.cm.getColumnCount()
5398 renderFooter : function()
5408 colspan : this.cm.getColumnCount()
5422 Roo.log('ds onload');
5427 var ds = this.store;
5429 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5430 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5432 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5433 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5436 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5437 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5441 var tbody = this.mainBody;
5443 if(ds.getCount() > 0){
5444 ds.data.each(function(d,rowIndex){
5445 var row = this.renderRow(cm, ds, rowIndex);
5447 tbody.createChild(row);
5451 if(row.cellObjects.length){
5452 Roo.each(row.cellObjects, function(r){
5453 _this.renderCellObject(r);
5460 Roo.each(this.el.select('tbody td', true).elements, function(e){
5461 e.on('mouseover', _this.onMouseover, _this);
5464 Roo.each(this.el.select('tbody td', true).elements, function(e){
5465 e.on('mouseout', _this.onMouseout, _this);
5468 //if(this.loadMask){
5469 // this.maskEl.hide();
5474 onUpdate : function(ds,record)
5476 this.refreshRow(record);
5478 onRemove : function(ds, record, index, isUpdate){
5479 if(isUpdate !== true){
5480 this.fireEvent("beforerowremoved", this, index, record);
5482 var bt = this.mainBody.dom;
5484 bt.removeChild(bt.rows[index]);
5487 if(isUpdate !== true){
5488 //this.stripeRows(index);
5489 //this.syncRowHeights(index, index);
5491 this.fireEvent("rowremoved", this, index, record);
5495 onAdd : function(ds, records, rowIndex)
5497 //Roo.log('on Add called');
5498 // - note this does not handle multiple adding very well..
5499 var bt = this.mainBody.dom;
5500 for (var i =0 ; i < records.length;i++) {
5501 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5502 //Roo.log(records[i]);
5503 //Roo.log(this.store.getAt(rowIndex+i));
5504 this.insertRow(this.store, rowIndex + i, false);
5511 refreshRow : function(record){
5512 var ds = this.store, index;
5513 if(typeof record == 'number'){
5515 record = ds.getAt(index);
5517 index = ds.indexOf(record);
5519 this.insertRow(ds, index, true);
5520 this.onRemove(ds, record, index+1, true);
5521 //this.syncRowHeights(index, index);
5523 this.fireEvent("rowupdated", this, index, record);
5526 insertRow : function(dm, rowIndex, isUpdate){
5529 this.fireEvent("beforerowsinserted", this, rowIndex);
5531 //var s = this.getScrollState();
5532 var row = this.renderRow(this.cm, this.store, rowIndex);
5533 // insert before rowIndex..
5534 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5538 if(row.cellObjects.length){
5539 Roo.each(row.cellObjects, function(r){
5540 _this.renderCellObject(r);
5545 this.fireEvent("rowsinserted", this, rowIndex);
5546 //this.syncRowHeights(firstRow, lastRow);
5547 //this.stripeRows(firstRow);
5554 getRowDom : function(rowIndex)
5556 // not sure if I need to check this.. but let's do it anyway..
5557 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5558 this.mainBody.dom.rows[rowIndex] : false
5560 // returns the object tree for a tr..
5563 renderRow : function(cm, ds, rowIndex) {
5565 var d = ds.getAt(rowIndex);
5572 var cellObjects = [];
5574 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5575 var config = cm.config[i];
5577 var renderer = cm.getRenderer(i);
5581 if(typeof(renderer) !== 'undefined'){
5582 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5584 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5585 // and are rendered into the cells after the row is rendered - using the id for the element.
5587 if(typeof(value) === 'object'){
5597 rowIndex : rowIndex,
5602 this.fireEvent('rowclass', this, rowcfg);
5606 cls : rowcfg.rowClass,
5608 html: (typeof(value) === 'object') ? '' : value
5615 if(typeof(config.hidden) != 'undefined' && config.hidden){
5616 td.style += ' display:none;';
5619 if(typeof(config.align) != 'undefined' && config.align.length){
5620 td.style += ' text-align:' + config.align + ';';
5623 if(typeof(config.width) != 'undefined'){
5624 td.style += ' width:' + config.width + 'px;';
5627 if(typeof(config.cursor) != 'undefined'){
5628 td.style += ' cursor:' + config.cursor + ';';
5635 row.cellObjects = cellObjects;
5643 onBeforeLoad : function()
5645 //Roo.log('ds onBeforeLoad');
5649 //if(this.loadMask){
5650 // this.maskEl.show();
5658 this.el.select('tbody', true).first().dom.innerHTML = '';
5661 * Show or hide a row.
5662 * @param {Number} rowIndex to show or hide
5663 * @param {Boolean} state hide
5665 setRowVisibility : function(rowIndex, state)
5667 var bt = this.mainBody.dom;
5668 if(typeof(bt.rows[rowIndex]) == 'undefined'){
5671 bt.rows[rowIndex].style.display = state ? '' : 'none';
5675 getSelectionModel : function(){
5677 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5679 return this.selModel;
5682 * Render the Roo.bootstrap object from renderder
5684 renderCellObject : function(r)
5688 var t = r.cfg.render(r.container);
5691 Roo.each(r.cfg.cn, function(c){
5693 container: t.getChildContainer(),
5696 _this.renderCellObject(child);
5713 * @class Roo.bootstrap.TableCell
5714 * @extends Roo.bootstrap.Component
5715 * Bootstrap TableCell class
5716 * @cfg {String} html cell contain text
5717 * @cfg {String} cls cell class
5718 * @cfg {String} tag cell tag (td|th) default td
5719 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5720 * @cfg {String} align Aligns the content in a cell
5721 * @cfg {String} axis Categorizes cells
5722 * @cfg {String} bgcolor Specifies the background color of a cell
5723 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5724 * @cfg {Number} colspan Specifies the number of columns a cell should span
5725 * @cfg {String} headers Specifies one or more header cells a cell is related to
5726 * @cfg {Number} height Sets the height of a cell
5727 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5728 * @cfg {Number} rowspan Sets the number of rows a cell should span
5729 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5730 * @cfg {String} valign Vertical aligns the content in a cell
5731 * @cfg {Number} width Specifies the width of a cell
5734 * Create a new TableCell
5735 * @param {Object} config The config object
5738 Roo.bootstrap.TableCell = function(config){
5739 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5742 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5762 getAutoCreate : function(){
5763 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5783 cfg.align=this.align
5789 cfg.bgcolor=this.bgcolor
5792 cfg.charoff=this.charoff
5795 cfg.colspan=this.colspan
5798 cfg.headers=this.headers
5801 cfg.height=this.height
5804 cfg.nowrap=this.nowrap
5807 cfg.rowspan=this.rowspan
5810 cfg.scope=this.scope
5813 cfg.valign=this.valign
5816 cfg.width=this.width
5835 * @class Roo.bootstrap.TableRow
5836 * @extends Roo.bootstrap.Component
5837 * Bootstrap TableRow class
5838 * @cfg {String} cls row class
5839 * @cfg {String} align Aligns the content in a table row
5840 * @cfg {String} bgcolor Specifies a background color for a table row
5841 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5842 * @cfg {String} valign Vertical aligns the content in a table row
5845 * Create a new TableRow
5846 * @param {Object} config The config object
5849 Roo.bootstrap.TableRow = function(config){
5850 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5853 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5861 getAutoCreate : function(){
5862 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5872 cfg.align = this.align;
5875 cfg.bgcolor = this.bgcolor;
5878 cfg.charoff = this.charoff;
5881 cfg.valign = this.valign;
5899 * @class Roo.bootstrap.TableBody
5900 * @extends Roo.bootstrap.Component
5901 * Bootstrap TableBody class
5902 * @cfg {String} cls element class
5903 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5904 * @cfg {String} align Aligns the content inside the element
5905 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5906 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5909 * Create a new TableBody
5910 * @param {Object} config The config object
5913 Roo.bootstrap.TableBody = function(config){
5914 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5917 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5925 getAutoCreate : function(){
5926 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5940 cfg.align = this.align;
5943 cfg.charoff = this.charoff;
5946 cfg.valign = this.valign;
5953 // initEvents : function()
5960 // this.store = Roo.factory(this.store, Roo.data);
5961 // this.store.on('load', this.onLoad, this);
5963 // this.store.load();
5967 // onLoad: function ()
5969 // this.fireEvent('load', this);
5979 * Ext JS Library 1.1.1
5980 * Copyright(c) 2006-2007, Ext JS, LLC.
5982 * Originally Released Under LGPL - original licence link has changed is not relivant.
5985 * <script type="text/javascript">
5988 // as we use this in bootstrap.
5989 Roo.namespace('Roo.form');
5991 * @class Roo.form.Action
5992 * Internal Class used to handle form actions
5994 * @param {Roo.form.BasicForm} el The form element or its id
5995 * @param {Object} config Configuration options
6000 // define the action interface
6001 Roo.form.Action = function(form, options){
6003 this.options = options || {};
6006 * Client Validation Failed
6009 Roo.form.Action.CLIENT_INVALID = 'client';
6011 * Server Validation Failed
6014 Roo.form.Action.SERVER_INVALID = 'server';
6016 * Connect to Server Failed
6019 Roo.form.Action.CONNECT_FAILURE = 'connect';
6021 * Reading Data from Server Failed
6024 Roo.form.Action.LOAD_FAILURE = 'load';
6026 Roo.form.Action.prototype = {
6028 failureType : undefined,
6029 response : undefined,
6033 run : function(options){
6038 success : function(response){
6043 handleResponse : function(response){
6047 // default connection failure
6048 failure : function(response){
6050 this.response = response;
6051 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6052 this.form.afterAction(this, false);
6055 processResponse : function(response){
6056 this.response = response;
6057 if(!response.responseText){
6060 this.result = this.handleResponse(response);
6064 // utility functions used internally
6065 getUrl : function(appendParams){
6066 var url = this.options.url || this.form.url || this.form.el.dom.action;
6068 var p = this.getParams();
6070 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6076 getMethod : function(){
6077 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6080 getParams : function(){
6081 var bp = this.form.baseParams;
6082 var p = this.options.params;
6084 if(typeof p == "object"){
6085 p = Roo.urlEncode(Roo.applyIf(p, bp));
6086 }else if(typeof p == 'string' && bp){
6087 p += '&' + Roo.urlEncode(bp);
6090 p = Roo.urlEncode(bp);
6095 createCallback : function(){
6097 success: this.success,
6098 failure: this.failure,
6100 timeout: (this.form.timeout*1000),
6101 upload: this.form.fileUpload ? this.success : undefined
6106 Roo.form.Action.Submit = function(form, options){
6107 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6110 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6113 haveProgress : false,
6114 uploadComplete : false,
6116 // uploadProgress indicator.
6117 uploadProgress : function()
6119 if (!this.form.progressUrl) {
6123 if (!this.haveProgress) {
6124 Roo.MessageBox.progress("Uploading", "Uploading");
6126 if (this.uploadComplete) {
6127 Roo.MessageBox.hide();
6131 this.haveProgress = true;
6133 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6135 var c = new Roo.data.Connection();
6137 url : this.form.progressUrl,
6142 success : function(req){
6143 //console.log(data);
6147 rdata = Roo.decode(req.responseText)
6149 Roo.log("Invalid data from server..");
6153 if (!rdata || !rdata.success) {
6155 Roo.MessageBox.alert(Roo.encode(rdata));
6158 var data = rdata.data;
6160 if (this.uploadComplete) {
6161 Roo.MessageBox.hide();
6166 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6167 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6170 this.uploadProgress.defer(2000,this);
6173 failure: function(data) {
6174 Roo.log('progress url failed ');
6185 // run get Values on the form, so it syncs any secondary forms.
6186 this.form.getValues();
6188 var o = this.options;
6189 var method = this.getMethod();
6190 var isPost = method == 'POST';
6191 if(o.clientValidation === false || this.form.isValid()){
6193 if (this.form.progressUrl) {
6194 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6195 (new Date() * 1) + '' + Math.random());
6200 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6201 form:this.form.el.dom,
6202 url:this.getUrl(!isPost),
6204 params:isPost ? this.getParams() : null,
6205 isUpload: this.form.fileUpload
6208 this.uploadProgress();
6210 }else if (o.clientValidation !== false){ // client validation failed
6211 this.failureType = Roo.form.Action.CLIENT_INVALID;
6212 this.form.afterAction(this, false);
6216 success : function(response)
6218 this.uploadComplete= true;
6219 if (this.haveProgress) {
6220 Roo.MessageBox.hide();
6224 var result = this.processResponse(response);
6225 if(result === true || result.success){
6226 this.form.afterAction(this, true);
6230 this.form.markInvalid(result.errors);
6231 this.failureType = Roo.form.Action.SERVER_INVALID;
6233 this.form.afterAction(this, false);
6235 failure : function(response)
6237 this.uploadComplete= true;
6238 if (this.haveProgress) {
6239 Roo.MessageBox.hide();
6242 this.response = response;
6243 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6244 this.form.afterAction(this, false);
6247 handleResponse : function(response){
6248 if(this.form.errorReader){
6249 var rs = this.form.errorReader.read(response);
6252 for(var i = 0, len = rs.records.length; i < len; i++) {
6253 var r = rs.records[i];
6257 if(errors.length < 1){
6261 success : rs.success,
6267 ret = Roo.decode(response.responseText);
6271 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6281 Roo.form.Action.Load = function(form, options){
6282 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6283 this.reader = this.form.reader;
6286 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6291 Roo.Ajax.request(Roo.apply(
6292 this.createCallback(), {
6293 method:this.getMethod(),
6294 url:this.getUrl(false),
6295 params:this.getParams()
6299 success : function(response){
6301 var result = this.processResponse(response);
6302 if(result === true || !result.success || !result.data){
6303 this.failureType = Roo.form.Action.LOAD_FAILURE;
6304 this.form.afterAction(this, false);
6307 this.form.clearInvalid();
6308 this.form.setValues(result.data);
6309 this.form.afterAction(this, true);
6312 handleResponse : function(response){
6313 if(this.form.reader){
6314 var rs = this.form.reader.read(response);
6315 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6317 success : rs.success,
6321 return Roo.decode(response.responseText);
6325 Roo.form.Action.ACTION_TYPES = {
6326 'load' : Roo.form.Action.Load,
6327 'submit' : Roo.form.Action.Submit
6336 * @class Roo.bootstrap.Form
6337 * @extends Roo.bootstrap.Component
6338 * Bootstrap Form class
6339 * @cfg {String} method GET | POST (default POST)
6340 * @cfg {String} labelAlign top | left (default top)
6341 * @cfg {String} align left | right - for navbars
6342 * @cfg {Boolean} loadMask load mask when submit (default true)
6347 * @param {Object} config The config object
6351 Roo.bootstrap.Form = function(config){
6352 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6355 * @event clientvalidation
6356 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6357 * @param {Form} this
6358 * @param {Boolean} valid true if the form has passed client-side validation
6360 clientvalidation: true,
6362 * @event beforeaction
6363 * Fires before any action is performed. Return false to cancel the action.
6364 * @param {Form} this
6365 * @param {Action} action The action to be performed
6369 * @event actionfailed
6370 * Fires when an action fails.
6371 * @param {Form} this
6372 * @param {Action} action The action that failed
6374 actionfailed : true,
6376 * @event actioncomplete
6377 * Fires when an action is completed.
6378 * @param {Form} this
6379 * @param {Action} action The action that completed
6381 actioncomplete : true
6386 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6389 * @cfg {String} method
6390 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6395 * The URL to use for form actions if one isn't supplied in the action options.
6398 * @cfg {Boolean} fileUpload
6399 * Set to true if this form is a file upload.
6403 * @cfg {Object} baseParams
6404 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6408 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6412 * @cfg {Sting} align (left|right) for navbar forms
6417 activeAction : null,
6420 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6421 * element by passing it or its id or mask the form itself by passing in true.
6424 waitMsgTarget : false,
6428 getAutoCreate : function(){
6432 method : this.method || 'POST',
6433 id : this.id || Roo.id(),
6436 if (this.parent().xtype.match(/^Nav/)) {
6437 cfg.cls = 'navbar-form navbar-' + this.align;
6441 if (this.labelAlign == 'left' ) {
6442 cfg.cls += ' form-horizontal';
6448 initEvents : function()
6450 this.el.on('submit', this.onSubmit, this);
6451 // this was added as random key presses on the form where triggering form submit.
6452 this.el.on('keypress', function(e) {
6453 if (e.getCharCode() != 13) {
6456 // we might need to allow it for textareas.. and some other items.
6457 // check e.getTarget().
6459 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6463 Roo.log("keypress blocked");
6471 onSubmit : function(e){
6476 * Returns true if client-side validation on the form is successful.
6479 isValid : function(){
6480 var items = this.getItems();
6482 items.each(function(f){
6491 * Returns true if any fields in this form have changed since their original load.
6494 isDirty : function(){
6496 var items = this.getItems();
6497 items.each(function(f){
6507 * Performs a predefined action (submit or load) or custom actions you define on this form.
6508 * @param {String} actionName The name of the action type
6509 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6510 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6511 * accept other config options):
6513 Property Type Description
6514 ---------------- --------------- ----------------------------------------------------------------------------------
6515 url String The url for the action (defaults to the form's url)
6516 method String The form method to use (defaults to the form's method, or POST if not defined)
6517 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6518 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6519 validate the form on the client (defaults to false)
6521 * @return {BasicForm} this
6523 doAction : function(action, options){
6524 if(typeof action == 'string'){
6525 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6527 if(this.fireEvent('beforeaction', this, action) !== false){
6528 this.beforeAction(action);
6529 action.run.defer(100, action);
6535 beforeAction : function(action){
6536 var o = action.options;
6539 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6541 // not really supported yet.. ??
6543 //if(this.waitMsgTarget === true){
6544 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6545 //}else if(this.waitMsgTarget){
6546 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6547 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6549 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6555 afterAction : function(action, success){
6556 this.activeAction = null;
6557 var o = action.options;
6559 //if(this.waitMsgTarget === true){
6561 //}else if(this.waitMsgTarget){
6562 // this.waitMsgTarget.unmask();
6564 // Roo.MessageBox.updateProgress(1);
6565 // Roo.MessageBox.hide();
6572 Roo.callback(o.success, o.scope, [this, action]);
6573 this.fireEvent('actioncomplete', this, action);
6577 // failure condition..
6578 // we have a scenario where updates need confirming.
6579 // eg. if a locking scenario exists..
6580 // we look for { errors : { needs_confirm : true }} in the response.
6582 (typeof(action.result) != 'undefined') &&
6583 (typeof(action.result.errors) != 'undefined') &&
6584 (typeof(action.result.errors.needs_confirm) != 'undefined')
6587 Roo.log("not supported yet");
6590 Roo.MessageBox.confirm(
6591 "Change requires confirmation",
6592 action.result.errorMsg,
6597 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6607 Roo.callback(o.failure, o.scope, [this, action]);
6608 // show an error message if no failed handler is set..
6609 if (!this.hasListener('actionfailed')) {
6610 Roo.log("need to add dialog support");
6612 Roo.MessageBox.alert("Error",
6613 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6614 action.result.errorMsg :
6615 "Saving Failed, please check your entries or try again"
6620 this.fireEvent('actionfailed', this, action);
6625 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6626 * @param {String} id The value to search for
6629 findField : function(id){
6630 var items = this.getItems();
6631 var field = items.get(id);
6633 items.each(function(f){
6634 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6641 return field || null;
6644 * Mark fields in this form invalid in bulk.
6645 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6646 * @return {BasicForm} this
6648 markInvalid : function(errors){
6649 if(errors instanceof Array){
6650 for(var i = 0, len = errors.length; i < len; i++){
6651 var fieldError = errors[i];
6652 var f = this.findField(fieldError.id);
6654 f.markInvalid(fieldError.msg);
6660 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6661 field.markInvalid(errors[id]);
6665 //Roo.each(this.childForms || [], function (f) {
6666 // f.markInvalid(errors);
6673 * Set values for fields in this form in bulk.
6674 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6675 * @return {BasicForm} this
6677 setValues : function(values){
6678 if(values instanceof Array){ // array of objects
6679 for(var i = 0, len = values.length; i < len; i++){
6681 var f = this.findField(v.id);
6683 f.setValue(v.value);
6684 if(this.trackResetOnLoad){
6685 f.originalValue = f.getValue();
6689 }else{ // object hash
6692 if(typeof values[id] != 'function' && (field = this.findField(id))){
6694 if (field.setFromData &&
6696 field.displayField &&
6697 // combos' with local stores can
6698 // be queried via setValue()
6699 // to set their value..
6700 (field.store && !field.store.isLocal)
6704 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6705 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6706 field.setFromData(sd);
6709 field.setValue(values[id]);
6713 if(this.trackResetOnLoad){
6714 field.originalValue = field.getValue();
6720 //Roo.each(this.childForms || [], function (f) {
6721 // f.setValues(values);
6728 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6729 * they are returned as an array.
6730 * @param {Boolean} asString
6733 getValues : function(asString){
6734 //if (this.childForms) {
6735 // copy values from the child forms
6736 // Roo.each(this.childForms, function (f) {
6737 // this.setValues(f.getValues());
6743 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6744 if(asString === true){
6747 return Roo.urlDecode(fs);
6751 * Returns the fields in this form as an object with key/value pairs.
6752 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6755 getFieldValues : function(with_hidden)
6757 var items = this.getItems();
6759 items.each(function(f){
6763 var v = f.getValue();
6764 if (f.inputType =='radio') {
6765 if (typeof(ret[f.getName()]) == 'undefined') {
6766 ret[f.getName()] = ''; // empty..
6769 if (!f.el.dom.checked) {
6777 // not sure if this supported any more..
6778 if ((typeof(v) == 'object') && f.getRawValue) {
6779 v = f.getRawValue() ; // dates..
6781 // combo boxes where name != hiddenName...
6782 if (f.name != f.getName()) {
6783 ret[f.name] = f.getRawValue();
6785 ret[f.getName()] = v;
6792 * Clears all invalid messages in this form.
6793 * @return {BasicForm} this
6795 clearInvalid : function(){
6796 var items = this.getItems();
6798 items.each(function(f){
6809 * @return {BasicForm} this
6812 var items = this.getItems();
6813 items.each(function(f){
6817 Roo.each(this.childForms || [], function (f) {
6824 getItems : function()
6826 var r=new Roo.util.MixedCollection(false, function(o){
6827 return o.id || (o.id = Roo.id());
6829 var iter = function(el) {
6836 Roo.each(el.items,function(e) {
6855 * Ext JS Library 1.1.1
6856 * Copyright(c) 2006-2007, Ext JS, LLC.
6858 * Originally Released Under LGPL - original licence link has changed is not relivant.
6861 * <script type="text/javascript">
6864 * @class Roo.form.VTypes
6865 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6868 Roo.form.VTypes = function(){
6869 // closure these in so they are only created once.
6870 var alpha = /^[a-zA-Z_]+$/;
6871 var alphanum = /^[a-zA-Z0-9_]+$/;
6872 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6873 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6875 // All these messages and functions are configurable
6878 * The function used to validate email addresses
6879 * @param {String} value The email address
6881 'email' : function(v){
6882 return email.test(v);
6885 * The error text to display when the email validation function returns false
6888 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6890 * The keystroke filter mask to be applied on email input
6893 'emailMask' : /[a-z0-9_\.\-@]/i,
6896 * The function used to validate URLs
6897 * @param {String} value The URL
6899 'url' : function(v){
6903 * The error text to display when the url validation function returns false
6906 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6909 * The function used to validate alpha values
6910 * @param {String} value The value
6912 'alpha' : function(v){
6913 return alpha.test(v);
6916 * The error text to display when the alpha validation function returns false
6919 'alphaText' : 'This field should only contain letters and _',
6921 * The keystroke filter mask to be applied on alpha input
6924 'alphaMask' : /[a-z_]/i,
6927 * The function used to validate alphanumeric values
6928 * @param {String} value The value
6930 'alphanum' : function(v){
6931 return alphanum.test(v);
6934 * The error text to display when the alphanumeric validation function returns false
6937 'alphanumText' : 'This field should only contain letters, numbers and _',
6939 * The keystroke filter mask to be applied on alphanumeric input
6942 'alphanumMask' : /[a-z0-9_]/i
6952 * @class Roo.bootstrap.Input
6953 * @extends Roo.bootstrap.Component
6954 * Bootstrap Input class
6955 * @cfg {Boolean} disabled is it disabled
6956 * @cfg {String} fieldLabel - the label associated
6957 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6958 * @cfg {String} name name of the input
6959 * @cfg {string} fieldLabel - the label associated
6960 * @cfg {string} inputType - input / file submit ...
6961 * @cfg {string} placeholder - placeholder to put in text.
6962 * @cfg {string} before - input group add on before
6963 * @cfg {string} after - input group add on after
6964 * @cfg {string} size - (lg|sm) or leave empty..
6965 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6966 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6967 * @cfg {Number} md colspan out of 12 for computer-sized screens
6968 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6969 * @cfg {string} value default value of the input
6970 * @cfg {Number} labelWidth set the width of label (0-12)
6971 * @cfg {String} labelAlign (top|left)
6972 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6973 * @cfg {String} align (left|center|right) Default left
6977 * Create a new Input
6978 * @param {Object} config The config object
6981 Roo.bootstrap.Input = function(config){
6982 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6987 * Fires when this field receives input focus.
6988 * @param {Roo.form.Field} this
6993 * Fires when this field loses input focus.
6994 * @param {Roo.form.Field} this
6999 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7000 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7001 * @param {Roo.form.Field} this
7002 * @param {Roo.EventObject} e The event object
7007 * Fires just before the field blurs if the field value has changed.
7008 * @param {Roo.form.Field} this
7009 * @param {Mixed} newValue The new value
7010 * @param {Mixed} oldValue The original value
7015 * Fires after the field has been marked as invalid.
7016 * @param {Roo.form.Field} this
7017 * @param {String} msg The validation message
7022 * Fires after the field has been validated with no errors.
7023 * @param {Roo.form.Field} this
7028 * Fires after the key up
7029 * @param {Roo.form.Field} this
7030 * @param {Roo.EventObject} e The event Object
7036 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7038 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7039 automatic validation (defaults to "keyup").
7041 validationEvent : "keyup",
7043 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7045 validateOnBlur : true,
7047 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7049 validationDelay : 250,
7051 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7053 focusClass : "x-form-focus", // not needed???
7057 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7059 invalidClass : "has-error",
7062 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7064 selectOnFocus : false,
7067 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7071 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7076 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7078 disableKeyFilter : false,
7081 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7085 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7089 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7091 blankText : "This field is required",
7094 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7098 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7100 maxLength : Number.MAX_VALUE,
7102 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7104 minLengthText : "The minimum length for this field is {0}",
7106 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7108 maxLengthText : "The maximum length for this field is {0}",
7112 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7113 * If available, this function will be called only after the basic validators all return true, and will be passed the
7114 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7118 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7119 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7120 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7124 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7147 formatedValue : false,
7149 parentLabelAlign : function()
7152 while (parent.parent()) {
7153 parent = parent.parent();
7154 if (typeof(parent.labelAlign) !='undefined') {
7155 return parent.labelAlign;
7162 getAutoCreate : function(){
7164 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7170 if(this.inputType != 'hidden'){
7171 cfg.cls = 'form-group' //input-group
7177 type : this.inputType,
7179 cls : 'form-control',
7180 placeholder : this.placeholder || ''
7185 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7188 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7189 input.maxLength = this.maxLength;
7192 if (this.disabled) {
7193 input.disabled=true;
7196 if (this.readOnly) {
7197 input.readonly=true;
7201 input.name = this.name;
7204 input.cls += ' input-' + this.size;
7207 ['xs','sm','md','lg'].map(function(size){
7208 if (settings[size]) {
7209 cfg.cls += ' col-' + size + '-' + settings[size];
7213 var inputblock = input;
7215 if (this.before || this.after) {
7218 cls : 'input-group',
7221 if (this.before && typeof(this.before) == 'string') {
7223 inputblock.cn.push({
7225 cls : 'roo-input-before input-group-addon',
7229 if (this.before && typeof(this.before) == 'object') {
7230 this.before = Roo.factory(this.before);
7231 Roo.log(this.before);
7232 inputblock.cn.push({
7234 cls : 'roo-input-before input-group-' +
7235 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7239 inputblock.cn.push(input);
7241 if (this.after && typeof(this.after) == 'string') {
7242 inputblock.cn.push({
7244 cls : 'roo-input-after input-group-addon',
7248 if (this.after && typeof(this.after) == 'object') {
7249 this.after = Roo.factory(this.after);
7250 Roo.log(this.after);
7251 inputblock.cn.push({
7253 cls : 'roo-input-after input-group-' +
7254 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7259 if (align ==='left' && this.fieldLabel.length) {
7260 Roo.log("left and has label");
7266 cls : 'control-label col-sm-' + this.labelWidth,
7267 html : this.fieldLabel
7271 cls : "col-sm-" + (12 - this.labelWidth),
7278 } else if ( this.fieldLabel.length) {
7284 //cls : 'input-group-addon',
7285 html : this.fieldLabel
7295 Roo.log(" no label && no align");
7304 Roo.log('input-parentType: ' + this.parentType);
7306 if (this.parentType === 'Navbar' && this.parent().bar) {
7307 cfg.cls += ' navbar-form';
7315 * return the real input element.
7317 inputEl: function ()
7319 return this.el.select('input.form-control',true).first();
7322 tooltipEl : function()
7324 return this.inputEl();
7327 setDisabled : function(v)
7329 var i = this.inputEl().dom;
7331 i.removeAttribute('disabled');
7335 i.setAttribute('disabled','true');
7337 initEvents : function()
7340 this.inputEl().on("keydown" , this.fireKey, this);
7341 this.inputEl().on("focus", this.onFocus, this);
7342 this.inputEl().on("blur", this.onBlur, this);
7344 this.inputEl().relayEvent('keyup', this);
7346 // reference to original value for reset
7347 this.originalValue = this.getValue();
7348 //Roo.form.TextField.superclass.initEvents.call(this);
7349 if(this.validationEvent == 'keyup'){
7350 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7351 this.inputEl().on('keyup', this.filterValidation, this);
7353 else if(this.validationEvent !== false){
7354 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7357 if(this.selectOnFocus){
7358 this.on("focus", this.preFocus, this);
7361 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7362 this.inputEl().on("keypress", this.filterKeys, this);
7365 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7366 this.el.on("click", this.autoSize, this);
7369 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7370 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7373 if (typeof(this.before) == 'object') {
7374 this.before.render(this.el.select('.roo-input-before',true).first());
7376 if (typeof(this.after) == 'object') {
7377 this.after.render(this.el.select('.roo-input-after',true).first());
7382 filterValidation : function(e){
7383 if(!e.isNavKeyPress()){
7384 this.validationTask.delay(this.validationDelay);
7388 * Validates the field value
7389 * @return {Boolean} True if the value is valid, else false
7391 validate : function(){
7392 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7393 if(this.disabled || this.validateValue(this.getRawValue())){
7394 this.clearInvalid();
7402 * Validates a value according to the field's validation rules and marks the field as invalid
7403 * if the validation fails
7404 * @param {Mixed} value The value to validate
7405 * @return {Boolean} True if the value is valid, else false
7407 validateValue : function(value){
7408 if(value.length < 1) { // if it's blank
7409 if(this.allowBlank){
7410 this.clearInvalid();
7413 this.markInvalid(this.blankText);
7417 if(value.length < this.minLength){
7418 this.markInvalid(String.format(this.minLengthText, this.minLength));
7421 if(value.length > this.maxLength){
7422 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7426 var vt = Roo.form.VTypes;
7427 if(!vt[this.vtype](value, this)){
7428 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7432 if(typeof this.validator == "function"){
7433 var msg = this.validator(value);
7435 this.markInvalid(msg);
7439 if(this.regex && !this.regex.test(value)){
7440 this.markInvalid(this.regexText);
7449 fireKey : function(e){
7450 //Roo.log('field ' + e.getKey());
7451 if(e.isNavKeyPress()){
7452 this.fireEvent("specialkey", this, e);
7455 focus : function (selectText){
7457 this.inputEl().focus();
7458 if(selectText === true){
7459 this.inputEl().dom.select();
7465 onFocus : function(){
7466 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7467 // this.el.addClass(this.focusClass);
7470 this.hasFocus = true;
7471 this.startValue = this.getValue();
7472 this.fireEvent("focus", this);
7476 beforeBlur : Roo.emptyFn,
7480 onBlur : function(){
7482 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7483 //this.el.removeClass(this.focusClass);
7485 this.hasFocus = false;
7486 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7489 var v = this.getValue();
7490 if(String(v) !== String(this.startValue)){
7491 this.fireEvent('change', this, v, this.startValue);
7493 this.fireEvent("blur", this);
7497 * Resets the current field value to the originally loaded value and clears any validation messages
7500 this.setValue(this.originalValue);
7501 this.clearInvalid();
7504 * Returns the name of the field
7505 * @return {Mixed} name The name field
7507 getName: function(){
7511 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7512 * @return {Mixed} value The field value
7514 getValue : function(){
7516 var v = this.inputEl().getValue();
7521 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7522 * @return {Mixed} value The field value
7524 getRawValue : function(){
7525 var v = this.inputEl().getValue();
7531 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7532 * @param {Mixed} value The value to set
7534 setRawValue : function(v){
7535 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7538 selectText : function(start, end){
7539 var v = this.getRawValue();
7541 start = start === undefined ? 0 : start;
7542 end = end === undefined ? v.length : end;
7543 var d = this.inputEl().dom;
7544 if(d.setSelectionRange){
7545 d.setSelectionRange(start, end);
7546 }else if(d.createTextRange){
7547 var range = d.createTextRange();
7548 range.moveStart("character", start);
7549 range.moveEnd("character", v.length-end);
7556 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7557 * @param {Mixed} value The value to set
7559 setValue : function(v){
7562 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7568 processValue : function(value){
7569 if(this.stripCharsRe){
7570 var newValue = value.replace(this.stripCharsRe, '');
7571 if(newValue !== value){
7572 this.setRawValue(newValue);
7579 preFocus : function(){
7581 if(this.selectOnFocus){
7582 this.inputEl().dom.select();
7585 filterKeys : function(e){
7587 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7590 var c = e.getCharCode(), cc = String.fromCharCode(c);
7591 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7594 if(!this.maskRe.test(cc)){
7599 * Clear any invalid styles/messages for this field
7601 clearInvalid : function(){
7603 if(!this.el || this.preventMark){ // not rendered
7606 this.el.removeClass(this.invalidClass);
7608 switch(this.msgTarget){
7610 this.el.dom.qtip = '';
7613 this.el.dom.title = '';
7617 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7622 this.errorIcon.dom.qtip = '';
7623 this.errorIcon.hide();
7624 this.un('resize', this.alignErrorIcon, this);
7628 var t = Roo.getDom(this.msgTarget);
7630 t.style.display = 'none';
7634 this.fireEvent('valid', this);
7637 * Mark this field as invalid
7638 * @param {String} msg The validation message
7640 markInvalid : function(msg){
7641 if(!this.el || this.preventMark){ // not rendered
7644 this.el.addClass(this.invalidClass);
7646 msg = msg || this.invalidText;
7647 switch(this.msgTarget){
7649 this.el.dom.qtip = msg;
7650 this.el.dom.qclass = 'x-form-invalid-tip';
7651 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7652 Roo.QuickTips.enable();
7656 this.el.dom.title = msg;
7660 var elp = this.el.findParent('.x-form-element', 5, true);
7661 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7662 this.errorEl.setWidth(elp.getWidth(true)-20);
7664 this.errorEl.update(msg);
7665 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7668 if(!this.errorIcon){
7669 var elp = this.el.findParent('.x-form-element', 5, true);
7670 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7672 this.alignErrorIcon();
7673 this.errorIcon.dom.qtip = msg;
7674 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7675 this.errorIcon.show();
7676 this.on('resize', this.alignErrorIcon, this);
7679 var t = Roo.getDom(this.msgTarget);
7681 t.style.display = this.msgDisplay;
7685 this.fireEvent('invalid', this, msg);
7688 SafariOnKeyDown : function(event)
7690 // this is a workaround for a password hang bug on chrome/ webkit.
7692 var isSelectAll = false;
7694 if(this.inputEl().dom.selectionEnd > 0){
7695 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7697 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7698 event.preventDefault();
7703 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7705 event.preventDefault();
7706 // this is very hacky as keydown always get's upper case.
7708 var cc = String.fromCharCode(event.getCharCode());
7709 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7713 adjustWidth : function(tag, w){
7714 tag = tag.toLowerCase();
7715 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7716 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7720 if(tag == 'textarea'){
7723 }else if(Roo.isOpera){
7727 if(tag == 'textarea'){
7746 * @class Roo.bootstrap.TextArea
7747 * @extends Roo.bootstrap.Input
7748 * Bootstrap TextArea class
7749 * @cfg {Number} cols Specifies the visible width of a text area
7750 * @cfg {Number} rows Specifies the visible number of lines in a text area
7751 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7752 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7753 * @cfg {string} html text
7756 * Create a new TextArea
7757 * @param {Object} config The config object
7760 Roo.bootstrap.TextArea = function(config){
7761 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7765 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7775 getAutoCreate : function(){
7777 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7788 value : this.value || '',
7789 html: this.html || '',
7790 cls : 'form-control',
7791 placeholder : this.placeholder || ''
7795 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7796 input.maxLength = this.maxLength;
7800 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7804 input.cols = this.cols;
7807 if (this.readOnly) {
7808 input.readonly = true;
7812 input.name = this.name;
7816 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7820 ['xs','sm','md','lg'].map(function(size){
7821 if (settings[size]) {
7822 cfg.cls += ' col-' + size + '-' + settings[size];
7826 var inputblock = input;
7828 if (this.before || this.after) {
7831 cls : 'input-group',
7835 inputblock.cn.push({
7837 cls : 'input-group-addon',
7841 inputblock.cn.push(input);
7843 inputblock.cn.push({
7845 cls : 'input-group-addon',
7852 if (align ==='left' && this.fieldLabel.length) {
7853 Roo.log("left and has label");
7859 cls : 'control-label col-sm-' + this.labelWidth,
7860 html : this.fieldLabel
7864 cls : "col-sm-" + (12 - this.labelWidth),
7871 } else if ( this.fieldLabel.length) {
7877 //cls : 'input-group-addon',
7878 html : this.fieldLabel
7888 Roo.log(" no label && no align");
7898 if (this.disabled) {
7899 input.disabled=true;
7906 * return the real textarea element.
7908 inputEl: function ()
7910 return this.el.select('textarea.form-control',true).first();
7918 * trigger field - base class for combo..
7923 * @class Roo.bootstrap.TriggerField
7924 * @extends Roo.bootstrap.Input
7925 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7926 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7927 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7928 * for which you can provide a custom implementation. For example:
7930 var trigger = new Roo.bootstrap.TriggerField();
7931 trigger.onTriggerClick = myTriggerFn;
7932 trigger.applyTo('my-field');
7935 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7936 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7937 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7938 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7939 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
7942 * Create a new TriggerField.
7943 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7944 * to the base TextField)
7946 Roo.bootstrap.TriggerField = function(config){
7947 this.mimicing = false;
7948 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7951 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7953 * @cfg {String} triggerClass A CSS class to apply to the trigger
7956 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7960 /** @cfg {Boolean} grow @hide */
7961 /** @cfg {Number} growMin @hide */
7962 /** @cfg {Number} growMax @hide */
7968 autoSize: Roo.emptyFn,
7975 actionMode : 'wrap',
7980 getAutoCreate : function(){
7982 var align = this.labelAlign || this.parentLabelAlign();
7987 cls: 'form-group' //input-group
7994 type : this.inputType,
7995 cls : 'form-control',
7996 autocomplete: 'false',
7997 placeholder : this.placeholder || ''
8001 input.name = this.name;
8004 input.cls += ' input-' + this.size;
8007 if (this.disabled) {
8008 input.disabled=true;
8011 var inputblock = input;
8013 if (this.before || this.after) {
8016 cls : 'input-group',
8020 inputblock.cn.push({
8022 cls : 'input-group-addon',
8026 inputblock.cn.push(input);
8028 inputblock.cn.push({
8030 cls : 'input-group-addon',
8043 cls: 'form-hidden-field'
8051 Roo.log('multiple');
8059 cls: 'form-hidden-field'
8063 cls: 'select2-choices',
8067 cls: 'select2-search-field',
8080 cls: 'select2-container input-group',
8085 // cls: 'typeahead typeahead-long dropdown-menu',
8086 // style: 'display:none'
8091 if(!this.multiple && this.showToggleBtn){
8097 if (this.caret != false) {
8100 cls: 'fa fa-' + this.caret
8107 cls : 'input-group-addon btn dropdown-toggle',
8112 cls: 'combobox-clear',
8126 combobox.cls += ' select2-container-multi';
8129 if (align ==='left' && this.fieldLabel.length) {
8131 Roo.log("left and has label");
8137 cls : 'control-label col-sm-' + this.labelWidth,
8138 html : this.fieldLabel
8142 cls : "col-sm-" + (12 - this.labelWidth),
8149 } else if ( this.fieldLabel.length) {
8155 //cls : 'input-group-addon',
8156 html : this.fieldLabel
8166 Roo.log(" no label && no align");
8173 ['xs','sm','md','lg'].map(function(size){
8174 if (settings[size]) {
8175 cfg.cls += ' col-' + size + '-' + settings[size];
8186 onResize : function(w, h){
8187 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8188 // if(typeof w == 'number'){
8189 // var x = w - this.trigger.getWidth();
8190 // this.inputEl().setWidth(this.adjustWidth('input', x));
8191 // this.trigger.setStyle('left', x+'px');
8196 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8199 getResizeEl : function(){
8200 return this.inputEl();
8204 getPositionEl : function(){
8205 return this.inputEl();
8209 alignErrorIcon : function(){
8210 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8214 initEvents : function(){
8218 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8219 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8220 if(!this.multiple && this.showToggleBtn){
8221 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8222 if(this.hideTrigger){
8223 this.trigger.setDisplayed(false);
8225 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8229 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8232 //this.trigger.addClassOnOver('x-form-trigger-over');
8233 //this.trigger.addClassOnClick('x-form-trigger-click');
8236 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8240 createList : function()
8242 this.list = Roo.get(document.body).createChild({
8244 cls: 'typeahead typeahead-long dropdown-menu',
8245 style: 'display:none'
8248 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8253 initTrigger : function(){
8258 onDestroy : function(){
8260 this.trigger.removeAllListeners();
8261 // this.trigger.remove();
8264 // this.wrap.remove();
8266 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8270 onFocus : function(){
8271 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8274 this.wrap.addClass('x-trigger-wrap-focus');
8275 this.mimicing = true;
8276 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8277 if(this.monitorTab){
8278 this.el.on("keydown", this.checkTab, this);
8285 checkTab : function(e){
8286 if(e.getKey() == e.TAB){
8292 onBlur : function(){
8297 mimicBlur : function(e, t){
8299 if(!this.wrap.contains(t) && this.validateBlur()){
8306 triggerBlur : function(){
8307 this.mimicing = false;
8308 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8309 if(this.monitorTab){
8310 this.el.un("keydown", this.checkTab, this);
8312 //this.wrap.removeClass('x-trigger-wrap-focus');
8313 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8317 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8318 validateBlur : function(e, t){
8323 onDisable : function(){
8324 this.inputEl().dom.disabled = true;
8325 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8327 // this.wrap.addClass('x-item-disabled');
8332 onEnable : function(){
8333 this.inputEl().dom.disabled = false;
8334 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8336 // this.el.removeClass('x-item-disabled');
8341 onShow : function(){
8342 var ae = this.getActionEl();
8345 ae.dom.style.display = '';
8346 ae.dom.style.visibility = 'visible';
8352 onHide : function(){
8353 var ae = this.getActionEl();
8354 ae.dom.style.display = 'none';
8358 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8359 * by an implementing function.
8361 * @param {EventObject} e
8363 onTriggerClick : Roo.emptyFn
8367 * Ext JS Library 1.1.1
8368 * Copyright(c) 2006-2007, Ext JS, LLC.
8370 * Originally Released Under LGPL - original licence link has changed is not relivant.
8373 * <script type="text/javascript">
8378 * @class Roo.data.SortTypes
8380 * Defines the default sorting (casting?) comparison functions used when sorting data.
8382 Roo.data.SortTypes = {
8384 * Default sort that does nothing
8385 * @param {Mixed} s The value being converted
8386 * @return {Mixed} The comparison value
8393 * The regular expression used to strip tags
8397 stripTagsRE : /<\/?[^>]+>/gi,
8400 * Strips all HTML tags to sort on text only
8401 * @param {Mixed} s The value being converted
8402 * @return {String} The comparison value
8404 asText : function(s){
8405 return String(s).replace(this.stripTagsRE, "");
8409 * Strips all HTML tags to sort on text only - Case insensitive
8410 * @param {Mixed} s The value being converted
8411 * @return {String} The comparison value
8413 asUCText : function(s){
8414 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8418 * Case insensitive string
8419 * @param {Mixed} s The value being converted
8420 * @return {String} The comparison value
8422 asUCString : function(s) {
8423 return String(s).toUpperCase();
8428 * @param {Mixed} s The value being converted
8429 * @return {Number} The comparison value
8431 asDate : function(s) {
8435 if(s instanceof Date){
8438 return Date.parse(String(s));
8443 * @param {Mixed} s The value being converted
8444 * @return {Float} The comparison value
8446 asFloat : function(s) {
8447 var val = parseFloat(String(s).replace(/,/g, ""));
8448 if(isNaN(val)) val = 0;
8454 * @param {Mixed} s The value being converted
8455 * @return {Number} The comparison value
8457 asInt : function(s) {
8458 var val = parseInt(String(s).replace(/,/g, ""));
8459 if(isNaN(val)) val = 0;
8464 * Ext JS Library 1.1.1
8465 * Copyright(c) 2006-2007, Ext JS, LLC.
8467 * Originally Released Under LGPL - original licence link has changed is not relivant.
8470 * <script type="text/javascript">
8474 * @class Roo.data.Record
8475 * Instances of this class encapsulate both record <em>definition</em> information, and record
8476 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8477 * to access Records cached in an {@link Roo.data.Store} object.<br>
8479 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8480 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8483 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8485 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8486 * {@link #create}. The parameters are the same.
8487 * @param {Array} data An associative Array of data values keyed by the field name.
8488 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8489 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8490 * not specified an integer id is generated.
8492 Roo.data.Record = function(data, id){
8493 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8498 * Generate a constructor for a specific record layout.
8499 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8500 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8501 * Each field definition object may contain the following properties: <ul>
8502 * <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,
8503 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8504 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8505 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8506 * is being used, then this is a string containing the javascript expression to reference the data relative to
8507 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8508 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8509 * this may be omitted.</p></li>
8510 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8511 * <ul><li>auto (Default, implies no conversion)</li>
8516 * <li>date</li></ul></p></li>
8517 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8518 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8519 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8520 * by the Reader into an object that will be stored in the Record. It is passed the
8521 * following parameters:<ul>
8522 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8524 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8526 * <br>usage:<br><pre><code>
8527 var TopicRecord = Roo.data.Record.create(
8528 {name: 'title', mapping: 'topic_title'},
8529 {name: 'author', mapping: 'username'},
8530 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8531 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8532 {name: 'lastPoster', mapping: 'user2'},
8533 {name: 'excerpt', mapping: 'post_text'}
8536 var myNewRecord = new TopicRecord({
8537 title: 'Do my job please',
8540 lastPost: new Date(),
8541 lastPoster: 'Animal',
8542 excerpt: 'No way dude!'
8544 myStore.add(myNewRecord);
8549 Roo.data.Record.create = function(o){
8551 f.superclass.constructor.apply(this, arguments);
8553 Roo.extend(f, Roo.data.Record);
8554 var p = f.prototype;
8555 p.fields = new Roo.util.MixedCollection(false, function(field){
8558 for(var i = 0, len = o.length; i < len; i++){
8559 p.fields.add(new Roo.data.Field(o[i]));
8561 f.getField = function(name){
8562 return p.fields.get(name);
8567 Roo.data.Record.AUTO_ID = 1000;
8568 Roo.data.Record.EDIT = 'edit';
8569 Roo.data.Record.REJECT = 'reject';
8570 Roo.data.Record.COMMIT = 'commit';
8572 Roo.data.Record.prototype = {
8574 * Readonly flag - true if this record has been modified.
8583 join : function(store){
8588 * Set the named field to the specified value.
8589 * @param {String} name The name of the field to set.
8590 * @param {Object} value The value to set the field to.
8592 set : function(name, value){
8593 if(this.data[name] == value){
8600 if(typeof this.modified[name] == 'undefined'){
8601 this.modified[name] = this.data[name];
8603 this.data[name] = value;
8604 if(!this.editing && this.store){
8605 this.store.afterEdit(this);
8610 * Get the value of the named field.
8611 * @param {String} name The name of the field to get the value of.
8612 * @return {Object} The value of the field.
8614 get : function(name){
8615 return this.data[name];
8619 beginEdit : function(){
8620 this.editing = true;
8625 cancelEdit : function(){
8626 this.editing = false;
8627 delete this.modified;
8631 endEdit : function(){
8632 this.editing = false;
8633 if(this.dirty && this.store){
8634 this.store.afterEdit(this);
8639 * Usually called by the {@link Roo.data.Store} which owns the Record.
8640 * Rejects all changes made to the Record since either creation, or the last commit operation.
8641 * Modified fields are reverted to their original values.
8643 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8644 * of reject operations.
8646 reject : function(){
8647 var m = this.modified;
8649 if(typeof m[n] != "function"){
8650 this.data[n] = m[n];
8654 delete this.modified;
8655 this.editing = false;
8657 this.store.afterReject(this);
8662 * Usually called by the {@link Roo.data.Store} which owns the Record.
8663 * Commits all changes made to the Record since either creation, or the last commit operation.
8665 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8666 * of commit operations.
8668 commit : function(){
8670 delete this.modified;
8671 this.editing = false;
8673 this.store.afterCommit(this);
8678 hasError : function(){
8679 return this.error != null;
8683 clearError : function(){
8688 * Creates a copy of this record.
8689 * @param {String} id (optional) A new record id if you don't want to use this record's id
8692 copy : function(newId) {
8693 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8697 * Ext JS Library 1.1.1
8698 * Copyright(c) 2006-2007, Ext JS, LLC.
8700 * Originally Released Under LGPL - original licence link has changed is not relivant.
8703 * <script type="text/javascript">
8709 * @class Roo.data.Store
8710 * @extends Roo.util.Observable
8711 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8712 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8714 * 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
8715 * has no knowledge of the format of the data returned by the Proxy.<br>
8717 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8718 * instances from the data object. These records are cached and made available through accessor functions.
8720 * Creates a new Store.
8721 * @param {Object} config A config object containing the objects needed for the Store to access data,
8722 * and read the data into Records.
8724 Roo.data.Store = function(config){
8725 this.data = new Roo.util.MixedCollection(false);
8726 this.data.getKey = function(o){
8729 this.baseParams = {};
8736 "multisort" : "_multisort"
8739 if(config && config.data){
8740 this.inlineData = config.data;
8744 Roo.apply(this, config);
8746 if(this.reader){ // reader passed
8747 this.reader = Roo.factory(this.reader, Roo.data);
8748 this.reader.xmodule = this.xmodule || false;
8749 if(!this.recordType){
8750 this.recordType = this.reader.recordType;
8752 if(this.reader.onMetaChange){
8753 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8757 if(this.recordType){
8758 this.fields = this.recordType.prototype.fields;
8764 * @event datachanged
8765 * Fires when the data cache has changed, and a widget which is using this Store
8766 * as a Record cache should refresh its view.
8767 * @param {Store} this
8772 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8773 * @param {Store} this
8774 * @param {Object} meta The JSON metadata
8779 * Fires when Records have been added to the Store
8780 * @param {Store} this
8781 * @param {Roo.data.Record[]} records The array of Records added
8782 * @param {Number} index The index at which the record(s) were added
8787 * Fires when a Record has been removed from the Store
8788 * @param {Store} this
8789 * @param {Roo.data.Record} record The Record that was removed
8790 * @param {Number} index The index at which the record was removed
8795 * Fires when a Record has been updated
8796 * @param {Store} this
8797 * @param {Roo.data.Record} record The Record that was updated
8798 * @param {String} operation The update operation being performed. Value may be one of:
8800 Roo.data.Record.EDIT
8801 Roo.data.Record.REJECT
8802 Roo.data.Record.COMMIT
8808 * Fires when the data cache has been cleared.
8809 * @param {Store} this
8814 * Fires before a request is made for a new data object. If the beforeload handler returns false
8815 * the load action will be canceled.
8816 * @param {Store} this
8817 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8821 * @event beforeloadadd
8822 * Fires after a new set of Records has been loaded.
8823 * @param {Store} this
8824 * @param {Roo.data.Record[]} records The Records that were loaded
8825 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8827 beforeloadadd : true,
8830 * Fires after a new set of Records has been loaded, before they are added to the store.
8831 * @param {Store} this
8832 * @param {Roo.data.Record[]} records The Records that were loaded
8833 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8834 * @params {Object} return from reader
8838 * @event loadexception
8839 * Fires if an exception occurs in the Proxy during loading.
8840 * Called with the signature of the Proxy's "loadexception" event.
8841 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8844 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8845 * @param {Object} load options
8846 * @param {Object} jsonData from your request (normally this contains the Exception)
8848 loadexception : true
8852 this.proxy = Roo.factory(this.proxy, Roo.data);
8853 this.proxy.xmodule = this.xmodule || false;
8854 this.relayEvents(this.proxy, ["loadexception"]);
8856 this.sortToggle = {};
8857 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8859 Roo.data.Store.superclass.constructor.call(this);
8861 if(this.inlineData){
8862 this.loadData(this.inlineData);
8863 delete this.inlineData;
8867 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8869 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8870 * without a remote query - used by combo/forms at present.
8874 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8877 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8880 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8881 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8884 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8885 * on any HTTP request
8888 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8891 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8895 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8896 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8901 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8902 * loaded or when a record is removed. (defaults to false).
8904 pruneModifiedRecords : false,
8910 * Add Records to the Store and fires the add event.
8911 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8913 add : function(records){
8914 records = [].concat(records);
8915 for(var i = 0, len = records.length; i < len; i++){
8916 records[i].join(this);
8918 var index = this.data.length;
8919 this.data.addAll(records);
8920 this.fireEvent("add", this, records, index);
8924 * Remove a Record from the Store and fires the remove event.
8925 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8927 remove : function(record){
8928 var index = this.data.indexOf(record);
8929 this.data.removeAt(index);
8930 if(this.pruneModifiedRecords){
8931 this.modified.remove(record);
8933 this.fireEvent("remove", this, record, index);
8937 * Remove all Records from the Store and fires the clear event.
8939 removeAll : function(){
8941 if(this.pruneModifiedRecords){
8944 this.fireEvent("clear", this);
8948 * Inserts Records to the Store at the given index and fires the add event.
8949 * @param {Number} index The start index at which to insert the passed Records.
8950 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8952 insert : function(index, records){
8953 records = [].concat(records);
8954 for(var i = 0, len = records.length; i < len; i++){
8955 this.data.insert(index, records[i]);
8956 records[i].join(this);
8958 this.fireEvent("add", this, records, index);
8962 * Get the index within the cache of the passed Record.
8963 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8964 * @return {Number} The index of the passed Record. Returns -1 if not found.
8966 indexOf : function(record){
8967 return this.data.indexOf(record);
8971 * Get the index within the cache of the Record with the passed id.
8972 * @param {String} id The id of the Record to find.
8973 * @return {Number} The index of the Record. Returns -1 if not found.
8975 indexOfId : function(id){
8976 return this.data.indexOfKey(id);
8980 * Get the Record with the specified id.
8981 * @param {String} id The id of the Record to find.
8982 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8984 getById : function(id){
8985 return this.data.key(id);
8989 * Get the Record at the specified index.
8990 * @param {Number} index The index of the Record to find.
8991 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8993 getAt : function(index){
8994 return this.data.itemAt(index);
8998 * Returns a range of Records between specified indices.
8999 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9000 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9001 * @return {Roo.data.Record[]} An array of Records
9003 getRange : function(start, end){
9004 return this.data.getRange(start, end);
9008 storeOptions : function(o){
9009 o = Roo.apply({}, o);
9012 this.lastOptions = o;
9016 * Loads the Record cache from the configured Proxy using the configured Reader.
9018 * If using remote paging, then the first load call must specify the <em>start</em>
9019 * and <em>limit</em> properties in the options.params property to establish the initial
9020 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9022 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9023 * and this call will return before the new data has been loaded. Perform any post-processing
9024 * in a callback function, or in a "load" event handler.</strong>
9026 * @param {Object} options An object containing properties which control loading options:<ul>
9027 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9028 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9029 * passed the following arguments:<ul>
9030 * <li>r : Roo.data.Record[]</li>
9031 * <li>options: Options object from the load call</li>
9032 * <li>success: Boolean success indicator</li></ul></li>
9033 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9034 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9037 load : function(options){
9038 options = options || {};
9039 if(this.fireEvent("beforeload", this, options) !== false){
9040 this.storeOptions(options);
9041 var p = Roo.apply(options.params || {}, this.baseParams);
9042 // if meta was not loaded from remote source.. try requesting it.
9043 if (!this.reader.metaFromRemote) {
9046 if(this.sortInfo && this.remoteSort){
9047 var pn = this.paramNames;
9048 p[pn["sort"]] = this.sortInfo.field;
9049 p[pn["dir"]] = this.sortInfo.direction;
9051 if (this.multiSort) {
9052 var pn = this.paramNames;
9053 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9056 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9061 * Reloads the Record cache from the configured Proxy using the configured Reader and
9062 * the options from the last load operation performed.
9063 * @param {Object} options (optional) An object containing properties which may override the options
9064 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9065 * the most recently used options are reused).
9067 reload : function(options){
9068 this.load(Roo.applyIf(options||{}, this.lastOptions));
9072 // Called as a callback by the Reader during a load operation.
9073 loadRecords : function(o, options, success){
9074 if(!o || success === false){
9075 if(success !== false){
9076 this.fireEvent("load", this, [], options, o);
9078 if(options.callback){
9079 options.callback.call(options.scope || this, [], options, false);
9083 // if data returned failure - throw an exception.
9084 if (o.success === false) {
9085 // show a message if no listener is registered.
9086 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9087 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9089 // loadmask wil be hooked into this..
9090 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9093 var r = o.records, t = o.totalRecords || r.length;
9095 this.fireEvent("beforeloadadd", this, r, options, o);
9097 if(!options || options.add !== true){
9098 if(this.pruneModifiedRecords){
9101 for(var i = 0, len = r.length; i < len; i++){
9105 this.data = this.snapshot;
9106 delete this.snapshot;
9109 this.data.addAll(r);
9110 this.totalLength = t;
9112 this.fireEvent("datachanged", this);
9114 this.totalLength = Math.max(t, this.data.length+r.length);
9117 this.fireEvent("load", this, r, options, o);
9118 if(options.callback){
9119 options.callback.call(options.scope || this, r, options, true);
9125 * Loads data from a passed data block. A Reader which understands the format of the data
9126 * must have been configured in the constructor.
9127 * @param {Object} data The data block from which to read the Records. The format of the data expected
9128 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9129 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9131 loadData : function(o, append){
9132 var r = this.reader.readRecords(o);
9133 this.loadRecords(r, {add: append}, true);
9137 * Gets the number of cached records.
9139 * <em>If using paging, this may not be the total size of the dataset. If the data object
9140 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9141 * the data set size</em>
9143 getCount : function(){
9144 return this.data.length || 0;
9148 * Gets the total number of records in the dataset as returned by the server.
9150 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9151 * the dataset size</em>
9153 getTotalCount : function(){
9154 return this.totalLength || 0;
9158 * Returns the sort state of the Store as an object with two properties:
9160 field {String} The name of the field by which the Records are sorted
9161 direction {String} The sort order, "ASC" or "DESC"
9164 getSortState : function(){
9165 return this.sortInfo;
9169 applySort : function(){
9170 if(this.sortInfo && !this.remoteSort){
9171 var s = this.sortInfo, f = s.field;
9172 var st = this.fields.get(f).sortType;
9173 var fn = function(r1, r2){
9174 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9175 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9177 this.data.sort(s.direction, fn);
9178 if(this.snapshot && this.snapshot != this.data){
9179 this.snapshot.sort(s.direction, fn);
9185 * Sets the default sort column and order to be used by the next load operation.
9186 * @param {String} fieldName The name of the field to sort by.
9187 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9189 setDefaultSort : function(field, dir){
9190 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9195 * If remote sorting is used, the sort is performed on the server, and the cache is
9196 * reloaded. If local sorting is used, the cache is sorted internally.
9197 * @param {String} fieldName The name of the field to sort by.
9198 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9200 sort : function(fieldName, dir){
9201 var f = this.fields.get(fieldName);
9203 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9205 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9206 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9211 this.sortToggle[f.name] = dir;
9212 this.sortInfo = {field: f.name, direction: dir};
9213 if(!this.remoteSort){
9215 this.fireEvent("datachanged", this);
9217 this.load(this.lastOptions);
9222 * Calls the specified function for each of the Records in the cache.
9223 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9224 * Returning <em>false</em> aborts and exits the iteration.
9225 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9227 each : function(fn, scope){
9228 this.data.each(fn, scope);
9232 * Gets all records modified since the last commit. Modified records are persisted across load operations
9233 * (e.g., during paging).
9234 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9236 getModifiedRecords : function(){
9237 return this.modified;
9241 createFilterFn : function(property, value, anyMatch){
9242 if(!value.exec){ // not a regex
9243 value = String(value);
9244 if(value.length == 0){
9247 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9250 return value.test(r.data[property]);
9255 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9256 * @param {String} property A field on your records
9257 * @param {Number} start The record index to start at (defaults to 0)
9258 * @param {Number} end The last record index to include (defaults to length - 1)
9259 * @return {Number} The sum
9261 sum : function(property, start, end){
9262 var rs = this.data.items, v = 0;
9264 end = (end || end === 0) ? end : rs.length-1;
9266 for(var i = start; i <= end; i++){
9267 v += (rs[i].data[property] || 0);
9273 * Filter the records by a specified property.
9274 * @param {String} field A field on your records
9275 * @param {String/RegExp} value Either a string that the field
9276 * should start with or a RegExp to test against the field
9277 * @param {Boolean} anyMatch True to match any part not just the beginning
9279 filter : function(property, value, anyMatch){
9280 var fn = this.createFilterFn(property, value, anyMatch);
9281 return fn ? this.filterBy(fn) : this.clearFilter();
9285 * Filter by a function. The specified function will be called with each
9286 * record in this data source. If the function returns true the record is included,
9287 * otherwise it is filtered.
9288 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9289 * @param {Object} scope (optional) The scope of the function (defaults to this)
9291 filterBy : function(fn, scope){
9292 this.snapshot = this.snapshot || this.data;
9293 this.data = this.queryBy(fn, scope||this);
9294 this.fireEvent("datachanged", this);
9298 * Query the records by a specified property.
9299 * @param {String} field A field on your records
9300 * @param {String/RegExp} value Either a string that the field
9301 * should start with or a RegExp to test against the field
9302 * @param {Boolean} anyMatch True to match any part not just the beginning
9303 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9305 query : function(property, value, anyMatch){
9306 var fn = this.createFilterFn(property, value, anyMatch);
9307 return fn ? this.queryBy(fn) : this.data.clone();
9311 * Query by a function. The specified function will be called with each
9312 * record in this data source. If the function returns true the record is included
9314 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9315 * @param {Object} scope (optional) The scope of the function (defaults to this)
9316 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9318 queryBy : function(fn, scope){
9319 var data = this.snapshot || this.data;
9320 return data.filterBy(fn, scope||this);
9324 * Collects unique values for a particular dataIndex from this store.
9325 * @param {String} dataIndex The property to collect
9326 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9327 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9328 * @return {Array} An array of the unique values
9330 collect : function(dataIndex, allowNull, bypassFilter){
9331 var d = (bypassFilter === true && this.snapshot) ?
9332 this.snapshot.items : this.data.items;
9333 var v, sv, r = [], l = {};
9334 for(var i = 0, len = d.length; i < len; i++){
9335 v = d[i].data[dataIndex];
9337 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9346 * Revert to a view of the Record cache with no filtering applied.
9347 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9349 clearFilter : function(suppressEvent){
9350 if(this.snapshot && this.snapshot != this.data){
9351 this.data = this.snapshot;
9352 delete this.snapshot;
9353 if(suppressEvent !== true){
9354 this.fireEvent("datachanged", this);
9360 afterEdit : function(record){
9361 if(this.modified.indexOf(record) == -1){
9362 this.modified.push(record);
9364 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9368 afterReject : function(record){
9369 this.modified.remove(record);
9370 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9374 afterCommit : function(record){
9375 this.modified.remove(record);
9376 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9380 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9381 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9383 commitChanges : function(){
9384 var m = this.modified.slice(0);
9386 for(var i = 0, len = m.length; i < len; i++){
9392 * Cancel outstanding changes on all changed records.
9394 rejectChanges : function(){
9395 var m = this.modified.slice(0);
9397 for(var i = 0, len = m.length; i < len; i++){
9402 onMetaChange : function(meta, rtype, o){
9403 this.recordType = rtype;
9404 this.fields = rtype.prototype.fields;
9405 delete this.snapshot;
9406 this.sortInfo = meta.sortInfo || this.sortInfo;
9408 this.fireEvent('metachange', this, this.reader.meta);
9411 moveIndex : function(data, type)
9413 var index = this.indexOf(data);
9415 var newIndex = index + type;
9419 this.insert(newIndex, data);
9424 * Ext JS Library 1.1.1
9425 * Copyright(c) 2006-2007, Ext JS, LLC.
9427 * Originally Released Under LGPL - original licence link has changed is not relivant.
9430 * <script type="text/javascript">
9434 * @class Roo.data.SimpleStore
9435 * @extends Roo.data.Store
9436 * Small helper class to make creating Stores from Array data easier.
9437 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9438 * @cfg {Array} fields An array of field definition objects, or field name strings.
9439 * @cfg {Array} data The multi-dimensional array of data
9441 * @param {Object} config
9443 Roo.data.SimpleStore = function(config){
9444 Roo.data.SimpleStore.superclass.constructor.call(this, {
9446 reader: new Roo.data.ArrayReader({
9449 Roo.data.Record.create(config.fields)
9451 proxy : new Roo.data.MemoryProxy(config.data)
9455 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9457 * Ext JS Library 1.1.1
9458 * Copyright(c) 2006-2007, Ext JS, LLC.
9460 * Originally Released Under LGPL - original licence link has changed is not relivant.
9463 * <script type="text/javascript">
9468 * @extends Roo.data.Store
9469 * @class Roo.data.JsonStore
9470 * Small helper class to make creating Stores for JSON data easier. <br/>
9472 var store = new Roo.data.JsonStore({
9473 url: 'get-images.php',
9475 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9478 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9479 * JsonReader and HttpProxy (unless inline data is provided).</b>
9480 * @cfg {Array} fields An array of field definition objects, or field name strings.
9482 * @param {Object} config
9484 Roo.data.JsonStore = function(c){
9485 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9486 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9487 reader: new Roo.data.JsonReader(c, c.fields)
9490 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9492 * Ext JS Library 1.1.1
9493 * Copyright(c) 2006-2007, Ext JS, LLC.
9495 * Originally Released Under LGPL - original licence link has changed is not relivant.
9498 * <script type="text/javascript">
9502 Roo.data.Field = function(config){
9503 if(typeof config == "string"){
9504 config = {name: config};
9506 Roo.apply(this, config);
9512 var st = Roo.data.SortTypes;
9513 // named sortTypes are supported, here we look them up
9514 if(typeof this.sortType == "string"){
9515 this.sortType = st[this.sortType];
9518 // set default sortType for strings and dates
9522 this.sortType = st.asUCString;
9525 this.sortType = st.asDate;
9528 this.sortType = st.none;
9533 var stripRe = /[\$,%]/g;
9535 // prebuilt conversion function for this field, instead of
9536 // switching every time we're reading a value
9538 var cv, dateFormat = this.dateFormat;
9543 cv = function(v){ return v; };
9546 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9550 return v !== undefined && v !== null && v !== '' ?
9551 parseInt(String(v).replace(stripRe, ""), 10) : '';
9556 return v !== undefined && v !== null && v !== '' ?
9557 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9562 cv = function(v){ return v === true || v === "true" || v == 1; };
9569 if(v instanceof Date){
9573 if(dateFormat == "timestamp"){
9574 return new Date(v*1000);
9576 return Date.parseDate(v, dateFormat);
9578 var parsed = Date.parse(v);
9579 return parsed ? new Date(parsed) : null;
9588 Roo.data.Field.prototype = {
9596 * Ext JS Library 1.1.1
9597 * Copyright(c) 2006-2007, Ext JS, LLC.
9599 * Originally Released Under LGPL - original licence link has changed is not relivant.
9602 * <script type="text/javascript">
9605 // Base class for reading structured data from a data source. This class is intended to be
9606 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9609 * @class Roo.data.DataReader
9610 * Base class for reading structured data from a data source. This class is intended to be
9611 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9614 Roo.data.DataReader = function(meta, recordType){
9618 this.recordType = recordType instanceof Array ?
9619 Roo.data.Record.create(recordType) : recordType;
9622 Roo.data.DataReader.prototype = {
9624 * Create an empty record
9625 * @param {Object} data (optional) - overlay some values
9626 * @return {Roo.data.Record} record created.
9628 newRow : function(d) {
9630 this.recordType.prototype.fields.each(function(c) {
9632 case 'int' : da[c.name] = 0; break;
9633 case 'date' : da[c.name] = new Date(); break;
9634 case 'float' : da[c.name] = 0.0; break;
9635 case 'boolean' : da[c.name] = false; break;
9636 default : da[c.name] = ""; break;
9640 return new this.recordType(Roo.apply(da, d));
9645 * Ext JS Library 1.1.1
9646 * Copyright(c) 2006-2007, Ext JS, LLC.
9648 * Originally Released Under LGPL - original licence link has changed is not relivant.
9651 * <script type="text/javascript">
9655 * @class Roo.data.DataProxy
9656 * @extends Roo.data.Observable
9657 * This class is an abstract base class for implementations which provide retrieval of
9658 * unformatted data objects.<br>
9660 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9661 * (of the appropriate type which knows how to parse the data object) to provide a block of
9662 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9664 * Custom implementations must implement the load method as described in
9665 * {@link Roo.data.HttpProxy#load}.
9667 Roo.data.DataProxy = function(){
9671 * Fires before a network request is made to retrieve a data object.
9672 * @param {Object} This DataProxy object.
9673 * @param {Object} params The params parameter to the load function.
9678 * Fires before the load method's callback is called.
9679 * @param {Object} This DataProxy object.
9680 * @param {Object} o The data object.
9681 * @param {Object} arg The callback argument object passed to the load function.
9685 * @event loadexception
9686 * Fires if an Exception occurs during data retrieval.
9687 * @param {Object} This DataProxy object.
9688 * @param {Object} o The data object.
9689 * @param {Object} arg The callback argument object passed to the load function.
9690 * @param {Object} e The Exception.
9692 loadexception : true
9694 Roo.data.DataProxy.superclass.constructor.call(this);
9697 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9700 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9704 * Ext JS Library 1.1.1
9705 * Copyright(c) 2006-2007, Ext JS, LLC.
9707 * Originally Released Under LGPL - original licence link has changed is not relivant.
9710 * <script type="text/javascript">
9713 * @class Roo.data.MemoryProxy
9714 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9715 * to the Reader when its load method is called.
9717 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9719 Roo.data.MemoryProxy = function(data){
9723 Roo.data.MemoryProxy.superclass.constructor.call(this);
9727 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9729 * Load data from the requested source (in this case an in-memory
9730 * data object passed to the constructor), read the data object into
9731 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9732 * process that block using the passed callback.
9733 * @param {Object} params This parameter is not used by the MemoryProxy class.
9734 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9735 * object into a block of Roo.data.Records.
9736 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9737 * The function must be passed <ul>
9738 * <li>The Record block object</li>
9739 * <li>The "arg" argument from the load function</li>
9740 * <li>A boolean success indicator</li>
9742 * @param {Object} scope The scope in which to call the callback
9743 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9745 load : function(params, reader, callback, scope, arg){
9746 params = params || {};
9749 result = reader.readRecords(this.data);
9751 this.fireEvent("loadexception", this, arg, null, e);
9752 callback.call(scope, null, arg, false);
9755 callback.call(scope, result, arg, true);
9759 update : function(params, records){
9764 * Ext JS Library 1.1.1
9765 * Copyright(c) 2006-2007, Ext JS, LLC.
9767 * Originally Released Under LGPL - original licence link has changed is not relivant.
9770 * <script type="text/javascript">
9773 * @class Roo.data.HttpProxy
9774 * @extends Roo.data.DataProxy
9775 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9776 * configured to reference a certain URL.<br><br>
9778 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9779 * from which the running page was served.<br><br>
9781 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9783 * Be aware that to enable the browser to parse an XML document, the server must set
9784 * the Content-Type header in the HTTP response to "text/xml".
9786 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9787 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9788 * will be used to make the request.
9790 Roo.data.HttpProxy = function(conn){
9791 Roo.data.HttpProxy.superclass.constructor.call(this);
9792 // is conn a conn config or a real conn?
9794 this.useAjax = !conn || !conn.events;
9798 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9799 // thse are take from connection...
9802 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9805 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9806 * extra parameters to each request made by this object. (defaults to undefined)
9809 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9810 * to each request made by this object. (defaults to undefined)
9813 * @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)
9816 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9819 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9825 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9829 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9830 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9831 * a finer-grained basis than the DataProxy events.
9833 getConnection : function(){
9834 return this.useAjax ? Roo.Ajax : this.conn;
9838 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9839 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9840 * process that block using the passed callback.
9841 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9842 * for the request to the remote server.
9843 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9844 * object into a block of Roo.data.Records.
9845 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9846 * The function must be passed <ul>
9847 * <li>The Record block object</li>
9848 * <li>The "arg" argument from the load function</li>
9849 * <li>A boolean success indicator</li>
9851 * @param {Object} scope The scope in which to call the callback
9852 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9854 load : function(params, reader, callback, scope, arg){
9855 if(this.fireEvent("beforeload", this, params) !== false){
9857 params : params || {},
9859 callback : callback,
9864 callback : this.loadResponse,
9868 Roo.applyIf(o, this.conn);
9869 if(this.activeRequest){
9870 Roo.Ajax.abort(this.activeRequest);
9872 this.activeRequest = Roo.Ajax.request(o);
9874 this.conn.request(o);
9877 callback.call(scope||this, null, arg, false);
9882 loadResponse : function(o, success, response){
9883 delete this.activeRequest;
9885 this.fireEvent("loadexception", this, o, response);
9886 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9891 result = o.reader.read(response);
9893 this.fireEvent("loadexception", this, o, response, e);
9894 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9898 this.fireEvent("load", this, o, o.request.arg);
9899 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9903 update : function(dataSet){
9908 updateResponse : function(dataSet){
9913 * Ext JS Library 1.1.1
9914 * Copyright(c) 2006-2007, Ext JS, LLC.
9916 * Originally Released Under LGPL - original licence link has changed is not relivant.
9919 * <script type="text/javascript">
9923 * @class Roo.data.ScriptTagProxy
9924 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9925 * other than the originating domain of the running page.<br><br>
9927 * <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
9928 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9930 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9931 * source code that is used as the source inside a <script> tag.<br><br>
9933 * In order for the browser to process the returned data, the server must wrap the data object
9934 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9935 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9936 * depending on whether the callback name was passed:
9939 boolean scriptTag = false;
9940 String cb = request.getParameter("callback");
9943 response.setContentType("text/javascript");
9945 response.setContentType("application/x-json");
9947 Writer out = response.getWriter();
9949 out.write(cb + "(");
9951 out.print(dataBlock.toJsonString());
9958 * @param {Object} config A configuration object.
9960 Roo.data.ScriptTagProxy = function(config){
9961 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9962 Roo.apply(this, config);
9963 this.head = document.getElementsByTagName("head")[0];
9966 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9968 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9970 * @cfg {String} url The URL from which to request the data object.
9973 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9977 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9978 * the server the name of the callback function set up by the load call to process the returned data object.
9979 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9980 * javascript output which calls this named function passing the data object as its only parameter.
9982 callbackParam : "callback",
9984 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9985 * name to the request.
9990 * Load data from the configured URL, read the data object into
9991 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9992 * process that block using the passed callback.
9993 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9994 * for the request to the remote server.
9995 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9996 * object into a block of Roo.data.Records.
9997 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9998 * The function must be passed <ul>
9999 * <li>The Record block object</li>
10000 * <li>The "arg" argument from the load function</li>
10001 * <li>A boolean success indicator</li>
10003 * @param {Object} scope The scope in which to call the callback
10004 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10006 load : function(params, reader, callback, scope, arg){
10007 if(this.fireEvent("beforeload", this, params) !== false){
10009 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10011 var url = this.url;
10012 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10014 url += "&_dc=" + (new Date().getTime());
10016 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10019 cb : "stcCallback"+transId,
10020 scriptId : "stcScript"+transId,
10024 callback : callback,
10030 window[trans.cb] = function(o){
10031 conn.handleResponse(o, trans);
10034 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10036 if(this.autoAbort !== false){
10040 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10042 var script = document.createElement("script");
10043 script.setAttribute("src", url);
10044 script.setAttribute("type", "text/javascript");
10045 script.setAttribute("id", trans.scriptId);
10046 this.head.appendChild(script);
10048 this.trans = trans;
10050 callback.call(scope||this, null, arg, false);
10055 isLoading : function(){
10056 return this.trans ? true : false;
10060 * Abort the current server request.
10062 abort : function(){
10063 if(this.isLoading()){
10064 this.destroyTrans(this.trans);
10069 destroyTrans : function(trans, isLoaded){
10070 this.head.removeChild(document.getElementById(trans.scriptId));
10071 clearTimeout(trans.timeoutId);
10073 window[trans.cb] = undefined;
10075 delete window[trans.cb];
10078 // if hasn't been loaded, wait for load to remove it to prevent script error
10079 window[trans.cb] = function(){
10080 window[trans.cb] = undefined;
10082 delete window[trans.cb];
10089 handleResponse : function(o, trans){
10090 this.trans = false;
10091 this.destroyTrans(trans, true);
10094 result = trans.reader.readRecords(o);
10096 this.fireEvent("loadexception", this, o, trans.arg, e);
10097 trans.callback.call(trans.scope||window, null, trans.arg, false);
10100 this.fireEvent("load", this, o, trans.arg);
10101 trans.callback.call(trans.scope||window, result, trans.arg, true);
10105 handleFailure : function(trans){
10106 this.trans = false;
10107 this.destroyTrans(trans, false);
10108 this.fireEvent("loadexception", this, null, trans.arg);
10109 trans.callback.call(trans.scope||window, null, trans.arg, false);
10113 * Ext JS Library 1.1.1
10114 * Copyright(c) 2006-2007, Ext JS, LLC.
10116 * Originally Released Under LGPL - original licence link has changed is not relivant.
10119 * <script type="text/javascript">
10123 * @class Roo.data.JsonReader
10124 * @extends Roo.data.DataReader
10125 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10126 * based on mappings in a provided Roo.data.Record constructor.
10128 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10129 * in the reply previously.
10134 var RecordDef = Roo.data.Record.create([
10135 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10136 {name: 'occupation'} // This field will use "occupation" as the mapping.
10138 var myReader = new Roo.data.JsonReader({
10139 totalProperty: "results", // The property which contains the total dataset size (optional)
10140 root: "rows", // The property which contains an Array of row objects
10141 id: "id" // The property within each row object that provides an ID for the record (optional)
10145 * This would consume a JSON file like this:
10147 { 'results': 2, 'rows': [
10148 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10149 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10152 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10153 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10154 * paged from the remote server.
10155 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10156 * @cfg {String} root name of the property which contains the Array of row objects.
10157 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10159 * Create a new JsonReader
10160 * @param {Object} meta Metadata configuration options
10161 * @param {Object} recordType Either an Array of field definition objects,
10162 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10164 Roo.data.JsonReader = function(meta, recordType){
10167 // set some defaults:
10168 Roo.applyIf(meta, {
10169 totalProperty: 'total',
10170 successProperty : 'success',
10175 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10177 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10180 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10181 * Used by Store query builder to append _requestMeta to params.
10184 metaFromRemote : false,
10186 * This method is only used by a DataProxy which has retrieved data from a remote server.
10187 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10188 * @return {Object} data A data block which is used by an Roo.data.Store object as
10189 * a cache of Roo.data.Records.
10191 read : function(response){
10192 var json = response.responseText;
10194 var o = /* eval:var:o */ eval("("+json+")");
10196 throw {message: "JsonReader.read: Json object not found"};
10202 this.metaFromRemote = true;
10203 this.meta = o.metaData;
10204 this.recordType = Roo.data.Record.create(o.metaData.fields);
10205 this.onMetaChange(this.meta, this.recordType, o);
10207 return this.readRecords(o);
10210 // private function a store will implement
10211 onMetaChange : function(meta, recordType, o){
10218 simpleAccess: function(obj, subsc) {
10225 getJsonAccessor: function(){
10227 return function(expr) {
10229 return(re.test(expr))
10230 ? new Function("obj", "return obj." + expr)
10235 return Roo.emptyFn;
10240 * Create a data block containing Roo.data.Records from an XML document.
10241 * @param {Object} o An object which contains an Array of row objects in the property specified
10242 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10243 * which contains the total size of the dataset.
10244 * @return {Object} data A data block which is used by an Roo.data.Store object as
10245 * a cache of Roo.data.Records.
10247 readRecords : function(o){
10249 * After any data loads, the raw JSON data is available for further custom processing.
10253 var s = this.meta, Record = this.recordType,
10254 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10256 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10258 if(s.totalProperty) {
10259 this.getTotal = this.getJsonAccessor(s.totalProperty);
10261 if(s.successProperty) {
10262 this.getSuccess = this.getJsonAccessor(s.successProperty);
10264 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10266 var g = this.getJsonAccessor(s.id);
10267 this.getId = function(rec) {
10269 return (r === undefined || r === "") ? null : r;
10272 this.getId = function(){return null;};
10275 for(var jj = 0; jj < fl; jj++){
10277 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10278 this.ef[jj] = this.getJsonAccessor(map);
10282 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10283 if(s.totalProperty){
10284 var vt = parseInt(this.getTotal(o), 10);
10289 if(s.successProperty){
10290 var vs = this.getSuccess(o);
10291 if(vs === false || vs === 'false'){
10296 for(var i = 0; i < c; i++){
10299 var id = this.getId(n);
10300 for(var j = 0; j < fl; j++){
10302 var v = this.ef[j](n);
10304 Roo.log('missing convert for ' + f.name);
10308 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10310 var record = new Record(values, id);
10312 records[i] = record;
10318 totalRecords : totalRecords
10323 * Ext JS Library 1.1.1
10324 * Copyright(c) 2006-2007, Ext JS, LLC.
10326 * Originally Released Under LGPL - original licence link has changed is not relivant.
10329 * <script type="text/javascript">
10333 * @class Roo.data.ArrayReader
10334 * @extends Roo.data.DataReader
10335 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10336 * Each element of that Array represents a row of data fields. The
10337 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10338 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10342 var RecordDef = Roo.data.Record.create([
10343 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10344 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10346 var myReader = new Roo.data.ArrayReader({
10347 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10351 * This would consume an Array like this:
10353 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10355 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10357 * Create a new JsonReader
10358 * @param {Object} meta Metadata configuration options.
10359 * @param {Object} recordType Either an Array of field definition objects
10360 * as specified to {@link Roo.data.Record#create},
10361 * or an {@link Roo.data.Record} object
10362 * created using {@link Roo.data.Record#create}.
10364 Roo.data.ArrayReader = function(meta, recordType){
10365 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10368 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10370 * Create a data block containing Roo.data.Records from an XML document.
10371 * @param {Object} o An Array of row objects which represents the dataset.
10372 * @return {Object} data A data block which is used by an Roo.data.Store object as
10373 * a cache of Roo.data.Records.
10375 readRecords : function(o){
10376 var sid = this.meta ? this.meta.id : null;
10377 var recordType = this.recordType, fields = recordType.prototype.fields;
10380 for(var i = 0; i < root.length; i++){
10383 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10384 for(var j = 0, jlen = fields.length; j < jlen; j++){
10385 var f = fields.items[j];
10386 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10387 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10389 values[f.name] = v;
10391 var record = new recordType(values, id);
10393 records[records.length] = record;
10397 totalRecords : records.length
10406 * @class Roo.bootstrap.ComboBox
10407 * @extends Roo.bootstrap.TriggerField
10408 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10409 * @cfg {Boolean} append (true|false) default false
10410 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10411 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10412 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10413 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10414 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10416 * Create a new ComboBox.
10417 * @param {Object} config Configuration options
10419 Roo.bootstrap.ComboBox = function(config){
10420 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10424 * Fires when the dropdown list is expanded
10425 * @param {Roo.bootstrap.ComboBox} combo This combo box
10430 * Fires when the dropdown list is collapsed
10431 * @param {Roo.bootstrap.ComboBox} combo This combo box
10435 * @event beforeselect
10436 * Fires before a list item is selected. Return false to cancel the selection.
10437 * @param {Roo.bootstrap.ComboBox} combo This combo box
10438 * @param {Roo.data.Record} record The data record returned from the underlying store
10439 * @param {Number} index The index of the selected item in the dropdown list
10441 'beforeselect' : true,
10444 * Fires when a list item is selected
10445 * @param {Roo.bootstrap.ComboBox} combo This combo box
10446 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10447 * @param {Number} index The index of the selected item in the dropdown list
10451 * @event beforequery
10452 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10453 * The event object passed has these properties:
10454 * @param {Roo.bootstrap.ComboBox} combo This combo box
10455 * @param {String} query The query
10456 * @param {Boolean} forceAll true to force "all" query
10457 * @param {Boolean} cancel true to cancel the query
10458 * @param {Object} e The query event object
10460 'beforequery': true,
10463 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10464 * @param {Roo.bootstrap.ComboBox} combo This combo box
10469 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10470 * @param {Roo.bootstrap.ComboBox} combo This combo box
10471 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10476 * Fires when the remove value from the combobox array
10477 * @param {Roo.bootstrap.ComboBox} combo This combo box
10484 this.tickItems = [];
10486 this.selectedIndex = -1;
10487 if(this.mode == 'local'){
10488 if(config.queryDelay === undefined){
10489 this.queryDelay = 10;
10491 if(config.minChars === undefined){
10497 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10500 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10501 * rendering into an Roo.Editor, defaults to false)
10504 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10505 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10508 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10511 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10512 * the dropdown list (defaults to undefined, with no header element)
10516 * @cfg {String/Roo.Template} tpl The template to use to render the output
10520 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10522 listWidth: undefined,
10524 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10525 * mode = 'remote' or 'text' if mode = 'local')
10527 displayField: undefined,
10529 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10530 * mode = 'remote' or 'value' if mode = 'local').
10531 * Note: use of a valueField requires the user make a selection
10532 * in order for a value to be mapped.
10534 valueField: undefined,
10538 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10539 * field's data value (defaults to the underlying DOM element's name)
10541 hiddenName: undefined,
10543 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10547 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10549 selectedClass: 'active',
10552 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10556 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10557 * anchor positions (defaults to 'tl-bl')
10559 listAlign: 'tl-bl?',
10561 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10565 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10566 * query specified by the allQuery config option (defaults to 'query')
10568 triggerAction: 'query',
10570 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10571 * (defaults to 4, does not apply if editable = false)
10575 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10576 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10580 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10581 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10585 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10586 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10590 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10591 * when editable = true (defaults to false)
10593 selectOnFocus:false,
10595 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10597 queryParam: 'query',
10599 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10600 * when mode = 'remote' (defaults to 'Loading...')
10602 loadingText: 'Loading...',
10604 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10608 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10612 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10613 * traditional select (defaults to true)
10617 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10621 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10625 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10626 * listWidth has a higher value)
10630 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10631 * allow the user to set arbitrary text into the field (defaults to false)
10633 forceSelection:false,
10635 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10636 * if typeAhead = true (defaults to 250)
10638 typeAheadDelay : 250,
10640 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10641 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10643 valueNotFoundText : undefined,
10645 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10647 blockFocus : false,
10650 * @cfg {Boolean} disableClear Disable showing of clear button.
10652 disableClear : false,
10654 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10656 alwaysQuery : false,
10659 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10673 btnPosition : 'right',
10674 triggerList : true,
10675 showToggleBtn : true,
10676 // element that contains real text value.. (when hidden is used..)
10678 getAutoCreate : function()
10685 if(!this.tickable){
10686 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10691 * ComboBox with tickable selections
10694 var align = this.labelAlign || this.parentLabelAlign();
10697 cls : 'form-group roo-combobox-tickable' //input-group
10703 cls : 'tickable-buttons',
10708 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10715 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10722 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10729 Roo.each(buttons.cn, function(c){
10731 c.cls += ' btn-' + _this.size;
10734 if (_this.disabled) {
10745 cls: 'form-hidden-field'
10749 cls: 'select2-choices',
10753 cls: 'select2-search-field',
10765 cls: 'select2-container input-group select2-container-multi',
10770 // cls: 'typeahead typeahead-long dropdown-menu',
10771 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10776 if (align ==='left' && this.fieldLabel.length) {
10778 Roo.log("left and has label");
10784 cls : 'control-label col-sm-' + this.labelWidth,
10785 html : this.fieldLabel
10789 cls : "col-sm-" + (12 - this.labelWidth),
10796 } else if ( this.fieldLabel.length) {
10802 //cls : 'input-group-addon',
10803 html : this.fieldLabel
10813 Roo.log(" no label && no align");
10820 ['xs','sm','md','lg'].map(function(size){
10821 if (settings[size]) {
10822 cfg.cls += ' col-' + size + '-' + settings[size];
10831 initEvents: function()
10835 throw "can not find store for combo";
10837 this.store = Roo.factory(this.store, Roo.data);
10840 this.initTickableEvents();
10844 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10846 if(this.hiddenName){
10848 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10850 this.hiddenField.dom.value =
10851 this.hiddenValue !== undefined ? this.hiddenValue :
10852 this.value !== undefined ? this.value : '';
10854 // prevent input submission
10855 this.el.dom.removeAttribute('name');
10856 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10861 // this.el.dom.setAttribute('autocomplete', 'off');
10864 var cls = 'x-combo-list';
10866 //this.list = new Roo.Layer({
10867 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10873 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10874 _this.list.setWidth(lw);
10877 this.list.on('mouseover', this.onViewOver, this);
10878 this.list.on('mousemove', this.onViewMove, this);
10880 this.list.on('scroll', this.onViewScroll, this);
10883 this.list.swallowEvent('mousewheel');
10884 this.assetHeight = 0;
10887 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10888 this.assetHeight += this.header.getHeight();
10891 this.innerList = this.list.createChild({cls:cls+'-inner'});
10892 this.innerList.on('mouseover', this.onViewOver, this);
10893 this.innerList.on('mousemove', this.onViewMove, this);
10894 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10896 if(this.allowBlank && !this.pageSize && !this.disableClear){
10897 this.footer = this.list.createChild({cls:cls+'-ft'});
10898 this.pageTb = new Roo.Toolbar(this.footer);
10902 this.footer = this.list.createChild({cls:cls+'-ft'});
10903 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10904 {pageSize: this.pageSize});
10908 if (this.pageTb && this.allowBlank && !this.disableClear) {
10910 this.pageTb.add(new Roo.Toolbar.Fill(), {
10911 cls: 'x-btn-icon x-btn-clear',
10913 handler: function()
10916 _this.clearValue();
10917 _this.onSelect(false, -1);
10922 this.assetHeight += this.footer.getHeight();
10927 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10930 this.view = new Roo.View(this.list, this.tpl, {
10931 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10933 //this.view.wrapEl.setDisplayed(false);
10934 this.view.on('click', this.onViewClick, this);
10938 this.store.on('beforeload', this.onBeforeLoad, this);
10939 this.store.on('load', this.onLoad, this);
10940 this.store.on('loadexception', this.onLoadException, this);
10942 if(this.resizable){
10943 this.resizer = new Roo.Resizable(this.list, {
10944 pinned:true, handles:'se'
10946 this.resizer.on('resize', function(r, w, h){
10947 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10948 this.listWidth = w;
10949 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10950 this.restrictHeight();
10952 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10955 if(!this.editable){
10956 this.editable = true;
10957 this.setEditable(false);
10962 if (typeof(this.events.add.listeners) != 'undefined') {
10964 this.addicon = this.wrap.createChild(
10965 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10967 this.addicon.on('click', function(e) {
10968 this.fireEvent('add', this);
10971 if (typeof(this.events.edit.listeners) != 'undefined') {
10973 this.editicon = this.wrap.createChild(
10974 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10975 if (this.addicon) {
10976 this.editicon.setStyle('margin-left', '40px');
10978 this.editicon.on('click', function(e) {
10980 // we fire even if inothing is selected..
10981 this.fireEvent('edit', this, this.lastData );
10987 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10988 "up" : function(e){
10989 this.inKeyMode = true;
10993 "down" : function(e){
10994 if(!this.isExpanded()){
10995 this.onTriggerClick();
10997 this.inKeyMode = true;
11002 "enter" : function(e){
11003 // this.onViewClick();
11007 if(this.fireEvent("specialkey", this, e)){
11008 this.onViewClick(false);
11014 "esc" : function(e){
11018 "tab" : function(e){
11021 if(this.fireEvent("specialkey", this, e)){
11022 this.onViewClick(false);
11030 doRelay : function(foo, bar, hname){
11031 if(hname == 'down' || this.scope.isExpanded()){
11032 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11041 this.queryDelay = Math.max(this.queryDelay || 10,
11042 this.mode == 'local' ? 10 : 250);
11045 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11047 if(this.typeAhead){
11048 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11050 if(this.editable !== false){
11051 this.inputEl().on("keyup", this.onKeyUp, this);
11053 if(this.forceSelection){
11054 this.inputEl().on('blur', this.doForce, this);
11058 this.choices = this.el.select('ul.select2-choices', true).first();
11059 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11063 initTickableEvents: function()
11067 if(this.hiddenName){
11069 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11071 this.hiddenField.dom.value =
11072 this.hiddenValue !== undefined ? this.hiddenValue :
11073 this.value !== undefined ? this.value : '';
11075 // prevent input submission
11076 this.el.dom.removeAttribute('name');
11077 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11082 // this.list = this.el.select('ul.dropdown-menu',true).first();
11084 this.choices = this.el.select('ul.select2-choices', true).first();
11085 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11086 if(this.triggerList){
11087 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11090 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11091 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11093 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11094 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11096 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11097 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11099 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11100 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11101 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11104 this.cancelBtn.hide();
11109 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11110 _this.list.setWidth(lw);
11113 this.list.on('mouseover', this.onViewOver, this);
11114 this.list.on('mousemove', this.onViewMove, this);
11116 this.list.on('scroll', this.onViewScroll, this);
11119 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>';
11122 this.view = new Roo.View(this.list, this.tpl, {
11123 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11126 //this.view.wrapEl.setDisplayed(false);
11127 this.view.on('click', this.onViewClick, this);
11131 this.store.on('beforeload', this.onBeforeLoad, this);
11132 this.store.on('load', this.onLoad, this);
11133 this.store.on('loadexception', this.onLoadException, this);
11135 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11136 // "up" : function(e){
11137 // this.inKeyMode = true;
11138 // this.selectPrev();
11141 // "down" : function(e){
11142 // if(!this.isExpanded()){
11143 // this.onTriggerClick();
11145 // this.inKeyMode = true;
11146 // this.selectNext();
11150 // "enter" : function(e){
11151 //// this.onViewClick();
11153 // this.collapse();
11155 // if(this.fireEvent("specialkey", this, e)){
11156 // this.onViewClick(false);
11162 // "esc" : function(e){
11163 // this.collapse();
11166 // "tab" : function(e){
11167 // this.collapse();
11169 // if(this.fireEvent("specialkey", this, e)){
11170 // this.onViewClick(false);
11178 // doRelay : function(foo, bar, hname){
11179 // if(hname == 'down' || this.scope.isExpanded()){
11180 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11185 // forceKeyDown: true
11189 this.queryDelay = Math.max(this.queryDelay || 10,
11190 this.mode == 'local' ? 10 : 250);
11193 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11195 if(this.typeAhead){
11196 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11200 onDestroy : function(){
11202 this.view.setStore(null);
11203 this.view.el.removeAllListeners();
11204 this.view.el.remove();
11205 this.view.purgeListeners();
11208 this.list.dom.innerHTML = '';
11212 this.store.un('beforeload', this.onBeforeLoad, this);
11213 this.store.un('load', this.onLoad, this);
11214 this.store.un('loadexception', this.onLoadException, this);
11216 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11220 fireKey : function(e){
11221 if(e.isNavKeyPress() && !this.list.isVisible()){
11222 this.fireEvent("specialkey", this, e);
11227 onResize: function(w, h){
11228 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11230 // if(typeof w != 'number'){
11231 // // we do not handle it!?!?
11234 // var tw = this.trigger.getWidth();
11235 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11236 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11238 // this.inputEl().setWidth( this.adjustWidth('input', x));
11240 // //this.trigger.setStyle('left', x+'px');
11242 // if(this.list && this.listWidth === undefined){
11243 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11244 // this.list.setWidth(lw);
11245 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11253 * Allow or prevent the user from directly editing the field text. If false is passed,
11254 * the user will only be able to select from the items defined in the dropdown list. This method
11255 * is the runtime equivalent of setting the 'editable' config option at config time.
11256 * @param {Boolean} value True to allow the user to directly edit the field text
11258 setEditable : function(value){
11259 if(value == this.editable){
11262 this.editable = value;
11264 this.inputEl().dom.setAttribute('readOnly', true);
11265 this.inputEl().on('mousedown', this.onTriggerClick, this);
11266 this.inputEl().addClass('x-combo-noedit');
11268 this.inputEl().dom.setAttribute('readOnly', false);
11269 this.inputEl().un('mousedown', this.onTriggerClick, this);
11270 this.inputEl().removeClass('x-combo-noedit');
11276 onBeforeLoad : function(combo,opts){
11277 if(!this.hasFocus){
11281 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11283 this.restrictHeight();
11284 this.selectedIndex = -1;
11288 onLoad : function(){
11290 this.hasQuery = false;
11292 if(!this.hasFocus){
11296 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11297 this.loading.hide();
11300 if(this.store.getCount() > 0){
11302 // this.restrictHeight();
11303 if(this.lastQuery == this.allQuery){
11304 if(this.editable && !this.tickable){
11305 this.inputEl().dom.select();
11309 !this.selectByValue(this.value, true) &&
11310 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11311 this.store.lastOptions.add != true)
11313 this.select(0, true);
11316 if(this.autoFocus){
11319 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11320 this.taTask.delay(this.typeAheadDelay);
11324 this.onEmptyResults();
11330 onLoadException : function()
11332 this.hasQuery = false;
11334 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11335 this.loading.hide();
11339 Roo.log(this.store.reader.jsonData);
11340 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11342 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11348 onTypeAhead : function(){
11349 if(this.store.getCount() > 0){
11350 var r = this.store.getAt(0);
11351 var newValue = r.data[this.displayField];
11352 var len = newValue.length;
11353 var selStart = this.getRawValue().length;
11355 if(selStart != len){
11356 this.setRawValue(newValue);
11357 this.selectText(selStart, newValue.length);
11363 onSelect : function(record, index){
11365 if(this.fireEvent('beforeselect', this, record, index) !== false){
11367 this.setFromData(index > -1 ? record.data : false);
11370 this.fireEvent('select', this, record, index);
11375 * Returns the currently selected field value or empty string if no value is set.
11376 * @return {String} value The selected value
11378 getValue : function(){
11381 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11384 if(this.valueField){
11385 return typeof this.value != 'undefined' ? this.value : '';
11387 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11392 * Clears any text/value currently set in the field
11394 clearValue : function(){
11395 if(this.hiddenField){
11396 this.hiddenField.dom.value = '';
11399 this.setRawValue('');
11400 this.lastSelectionText = '';
11405 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11406 * will be displayed in the field. If the value does not match the data value of an existing item,
11407 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11408 * Otherwise the field will be blank (although the value will still be set).
11409 * @param {String} value The value to match
11411 setValue : function(v){
11418 if(this.valueField){
11419 var r = this.findRecord(this.valueField, v);
11421 text = r.data[this.displayField];
11422 }else if(this.valueNotFoundText !== undefined){
11423 text = this.valueNotFoundText;
11426 this.lastSelectionText = text;
11427 if(this.hiddenField){
11428 this.hiddenField.dom.value = v;
11430 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11434 * @property {Object} the last set data for the element
11439 * Sets the value of the field based on a object which is related to the record format for the store.
11440 * @param {Object} value the value to set as. or false on reset?
11442 setFromData : function(o){
11449 var dv = ''; // display value
11450 var vv = ''; // value value..
11452 if (this.displayField) {
11453 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11455 // this is an error condition!!!
11456 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11459 if(this.valueField){
11460 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11463 if(this.hiddenField){
11464 this.hiddenField.dom.value = vv;
11466 this.lastSelectionText = dv;
11467 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11471 // no hidden field.. - we store the value in 'value', but still display
11472 // display field!!!!
11473 this.lastSelectionText = dv;
11474 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11480 reset : function(){
11481 // overridden so that last data is reset..
11482 this.setValue(this.originalValue);
11483 this.clearInvalid();
11484 this.lastData = false;
11486 this.view.clearSelections();
11490 findRecord : function(prop, value){
11492 if(this.store.getCount() > 0){
11493 this.store.each(function(r){
11494 if(r.data[prop] == value){
11504 getName: function()
11506 // returns hidden if it's set..
11507 if (!this.rendered) {return ''};
11508 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11512 onViewMove : function(e, t){
11513 this.inKeyMode = false;
11517 onViewOver : function(e, t){
11518 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11521 var item = this.view.findItemFromChild(t);
11524 var index = this.view.indexOf(item);
11525 this.select(index, false);
11530 onViewClick : function(view, doFocus, el, e)
11532 var index = this.view.getSelectedIndexes()[0];
11534 var r = this.store.getAt(index);
11538 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11545 Roo.each(this.tickItems, function(v,k){
11547 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11548 _this.tickItems.splice(k, 1);
11558 this.tickItems.push(r.data);
11563 this.onSelect(r, index);
11565 if(doFocus !== false && !this.blockFocus){
11566 this.inputEl().focus();
11571 restrictHeight : function(){
11572 //this.innerList.dom.style.height = '';
11573 //var inner = this.innerList.dom;
11574 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11575 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11576 //this.list.beginUpdate();
11577 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11578 this.list.alignTo(this.inputEl(), this.listAlign);
11579 this.list.alignTo(this.inputEl(), this.listAlign);
11580 //this.list.endUpdate();
11584 onEmptyResults : function(){
11589 * Returns true if the dropdown list is expanded, else false.
11591 isExpanded : function(){
11592 return this.list.isVisible();
11596 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11597 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11598 * @param {String} value The data value of the item to select
11599 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11600 * selected item if it is not currently in view (defaults to true)
11601 * @return {Boolean} True if the value matched an item in the list, else false
11603 selectByValue : function(v, scrollIntoView){
11604 if(v !== undefined && v !== null){
11605 var r = this.findRecord(this.valueField || this.displayField, v);
11607 this.select(this.store.indexOf(r), scrollIntoView);
11615 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11616 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11617 * @param {Number} index The zero-based index of the list item to select
11618 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11619 * selected item if it is not currently in view (defaults to true)
11621 select : function(index, scrollIntoView){
11622 this.selectedIndex = index;
11623 this.view.select(index);
11624 if(scrollIntoView !== false){
11625 var el = this.view.getNode(index);
11626 if(el && !this.multiple && !this.tickable){
11627 this.list.scrollChildIntoView(el, false);
11633 selectNext : function(){
11634 var ct = this.store.getCount();
11636 if(this.selectedIndex == -1){
11638 }else if(this.selectedIndex < ct-1){
11639 this.select(this.selectedIndex+1);
11645 selectPrev : function(){
11646 var ct = this.store.getCount();
11648 if(this.selectedIndex == -1){
11650 }else if(this.selectedIndex != 0){
11651 this.select(this.selectedIndex-1);
11657 onKeyUp : function(e){
11658 if(this.editable !== false && !e.isSpecialKey()){
11659 this.lastKey = e.getKey();
11660 this.dqTask.delay(this.queryDelay);
11665 validateBlur : function(){
11666 return !this.list || !this.list.isVisible();
11670 initQuery : function(){
11671 this.doQuery(this.getRawValue());
11675 doForce : function(){
11676 if(this.inputEl().dom.value.length > 0){
11677 this.inputEl().dom.value =
11678 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11684 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11685 * query allowing the query action to be canceled if needed.
11686 * @param {String} query The SQL query to execute
11687 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11688 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11689 * saved in the current store (defaults to false)
11691 doQuery : function(q, forceAll){
11693 if(q === undefined || q === null){
11698 forceAll: forceAll,
11702 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11707 forceAll = qe.forceAll;
11708 if(forceAll === true || (q.length >= this.minChars)){
11710 this.hasQuery = true;
11712 if(this.lastQuery != q || this.alwaysQuery){
11713 this.lastQuery = q;
11714 if(this.mode == 'local'){
11715 this.selectedIndex = -1;
11717 this.store.clearFilter();
11719 this.store.filter(this.displayField, q);
11723 this.store.baseParams[this.queryParam] = q;
11725 var options = {params : this.getParams(q)};
11728 options.add = true;
11729 options.params.start = this.page * this.pageSize;
11732 this.store.load(options);
11734 * this code will make the page width larger, at the beginning, the list not align correctly,
11735 * we should expand the list on onLoad
11736 * so command out it
11741 this.selectedIndex = -1;
11746 this.loadNext = false;
11750 getParams : function(q){
11752 //p[this.queryParam] = q;
11756 p.limit = this.pageSize;
11762 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11764 collapse : function(){
11765 if(!this.isExpanded()){
11773 this.cancelBtn.hide();
11774 this.trigger.show();
11777 Roo.get(document).un('mousedown', this.collapseIf, this);
11778 Roo.get(document).un('mousewheel', this.collapseIf, this);
11779 if (!this.editable) {
11780 Roo.get(document).un('keydown', this.listKeyPress, this);
11782 this.fireEvent('collapse', this);
11786 collapseIf : function(e){
11787 var in_combo = e.within(this.el);
11788 var in_list = e.within(this.list);
11789 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11791 if (in_combo || in_list || is_list) {
11792 //e.stopPropagation();
11797 this.onTickableFooterButtonClick(e, false, false);
11805 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11807 expand : function(){
11809 if(this.isExpanded() || !this.hasFocus){
11813 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11814 this.list.setWidth(lw);
11821 this.restrictHeight();
11825 this.tickItems = Roo.apply([], this.item);
11828 this.cancelBtn.show();
11829 this.trigger.hide();
11833 Roo.get(document).on('mousedown', this.collapseIf, this);
11834 Roo.get(document).on('mousewheel', this.collapseIf, this);
11835 if (!this.editable) {
11836 Roo.get(document).on('keydown', this.listKeyPress, this);
11839 this.fireEvent('expand', this);
11843 // Implements the default empty TriggerField.onTriggerClick function
11844 onTriggerClick : function(e)
11846 Roo.log('trigger click');
11848 if(this.disabled || !this.triggerList){
11853 this.loadNext = false;
11855 if(this.isExpanded()){
11857 if (!this.blockFocus) {
11858 this.inputEl().focus();
11862 this.hasFocus = true;
11863 if(this.triggerAction == 'all') {
11864 this.doQuery(this.allQuery, true);
11866 this.doQuery(this.getRawValue());
11868 if (!this.blockFocus) {
11869 this.inputEl().focus();
11874 onTickableTriggerClick : function(e)
11881 this.loadNext = false;
11882 this.hasFocus = true;
11884 if(this.triggerAction == 'all') {
11885 this.doQuery(this.allQuery, true);
11887 this.doQuery(this.getRawValue());
11891 onSearchFieldClick : function(e)
11893 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11898 this.loadNext = false;
11899 this.hasFocus = true;
11901 if(this.triggerAction == 'all') {
11902 this.doQuery(this.allQuery, true);
11904 this.doQuery(this.getRawValue());
11908 listKeyPress : function(e)
11910 //Roo.log('listkeypress');
11911 // scroll to first matching element based on key pres..
11912 if (e.isSpecialKey()) {
11915 var k = String.fromCharCode(e.getKey()).toUpperCase();
11918 var csel = this.view.getSelectedNodes();
11919 var cselitem = false;
11921 var ix = this.view.indexOf(csel[0]);
11922 cselitem = this.store.getAt(ix);
11923 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11929 this.store.each(function(v) {
11931 // start at existing selection.
11932 if (cselitem.id == v.id) {
11938 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11939 match = this.store.indexOf(v);
11945 if (match === false) {
11946 return true; // no more action?
11949 this.view.select(match);
11950 var sn = Roo.get(this.view.getSelectedNodes()[0])
11951 sn.scrollIntoView(sn.dom.parentNode, false);
11954 onViewScroll : function(e, t){
11956 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){
11960 this.hasQuery = true;
11962 this.loading = this.list.select('.loading', true).first();
11964 if(this.loading === null){
11965 this.list.createChild({
11967 cls: 'loading select2-more-results select2-active',
11968 html: 'Loading more results...'
11971 this.loading = this.list.select('.loading', true).first();
11973 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11975 this.loading.hide();
11978 this.loading.show();
11983 this.loadNext = true;
11985 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11990 addItem : function(o)
11992 var dv = ''; // display value
11994 if (this.displayField) {
11995 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11997 // this is an error condition!!!
11998 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12005 var choice = this.choices.createChild({
12007 cls: 'select2-search-choice',
12016 cls: 'select2-search-choice-close',
12021 }, this.searchField);
12023 var close = choice.select('a.select2-search-choice-close', true).first()
12025 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12033 this.inputEl().dom.value = '';
12037 onRemoveItem : function(e, _self, o)
12039 e.preventDefault();
12040 var index = this.item.indexOf(o.data) * 1;
12043 Roo.log('not this item?!');
12047 this.item.splice(index, 1);
12052 this.fireEvent('remove', this, e);
12056 syncValue : function()
12058 if(!this.item.length){
12065 Roo.each(this.item, function(i){
12066 if(_this.valueField){
12067 value.push(i[_this.valueField]);
12074 this.value = value.join(',');
12076 if(this.hiddenField){
12077 this.hiddenField.dom.value = this.value;
12081 clearItem : function()
12083 if(!this.multiple){
12089 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12096 inputEl: function ()
12099 return this.searchField;
12101 return this.el.select('input.form-control',true).first();
12105 onTickableFooterButtonClick : function(e, btn, el)
12107 e.preventDefault();
12109 if(btn && btn.name == 'cancel'){
12110 this.tickItems = Roo.apply([], this.item);
12119 Roo.each(this.tickItems, function(o){
12127 validate : function()
12129 var v = this.getRawValue();
12132 v = this.getValue();
12135 if(this.disabled || this.validateValue(v)){
12136 this.clearInvalid();
12145 * @cfg {Boolean} grow
12149 * @cfg {Number} growMin
12153 * @cfg {Number} growMax
12163 * Ext JS Library 1.1.1
12164 * Copyright(c) 2006-2007, Ext JS, LLC.
12166 * Originally Released Under LGPL - original licence link has changed is not relivant.
12169 * <script type="text/javascript">
12174 * @extends Roo.util.Observable
12175 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12176 * This class also supports single and multi selection modes. <br>
12177 * Create a data model bound view:
12179 var store = new Roo.data.Store(...);
12181 var view = new Roo.View({
12183 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12185 singleSelect: true,
12186 selectedClass: "ydataview-selected",
12190 // listen for node click?
12191 view.on("click", function(vw, index, node, e){
12192 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12196 dataModel.load("foobar.xml");
12198 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12200 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12201 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12203 * Note: old style constructor is still suported (container, template, config)
12206 * Create a new View
12207 * @param {Object} config The config object
12210 Roo.View = function(config, depreciated_tpl, depreciated_config){
12212 this.parent = false;
12214 if (typeof(depreciated_tpl) == 'undefined') {
12215 // new way.. - universal constructor.
12216 Roo.apply(this, config);
12217 this.el = Roo.get(this.el);
12220 this.el = Roo.get(config);
12221 this.tpl = depreciated_tpl;
12222 Roo.apply(this, depreciated_config);
12224 this.wrapEl = this.el.wrap().wrap();
12225 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12228 if(typeof(this.tpl) == "string"){
12229 this.tpl = new Roo.Template(this.tpl);
12231 // support xtype ctors..
12232 this.tpl = new Roo.factory(this.tpl, Roo);
12236 this.tpl.compile();
12241 * @event beforeclick
12242 * Fires before a click is processed. Returns false to cancel the default action.
12243 * @param {Roo.View} this
12244 * @param {Number} index The index of the target node
12245 * @param {HTMLElement} node The target node
12246 * @param {Roo.EventObject} e The raw event object
12248 "beforeclick" : true,
12251 * Fires when a template node is clicked.
12252 * @param {Roo.View} this
12253 * @param {Number} index The index of the target node
12254 * @param {HTMLElement} node The target node
12255 * @param {Roo.EventObject} e The raw event object
12260 * Fires when a template node is double clicked.
12261 * @param {Roo.View} this
12262 * @param {Number} index The index of the target node
12263 * @param {HTMLElement} node The target node
12264 * @param {Roo.EventObject} e The raw event object
12268 * @event contextmenu
12269 * Fires when a template node is right clicked.
12270 * @param {Roo.View} this
12271 * @param {Number} index The index of the target node
12272 * @param {HTMLElement} node The target node
12273 * @param {Roo.EventObject} e The raw event object
12275 "contextmenu" : true,
12277 * @event selectionchange
12278 * Fires when the selected nodes change.
12279 * @param {Roo.View} this
12280 * @param {Array} selections Array of the selected nodes
12282 "selectionchange" : true,
12285 * @event beforeselect
12286 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12287 * @param {Roo.View} this
12288 * @param {HTMLElement} node The node to be selected
12289 * @param {Array} selections Array of currently selected nodes
12291 "beforeselect" : true,
12293 * @event preparedata
12294 * Fires on every row to render, to allow you to change the data.
12295 * @param {Roo.View} this
12296 * @param {Object} data to be rendered (change this)
12298 "preparedata" : true
12306 "click": this.onClick,
12307 "dblclick": this.onDblClick,
12308 "contextmenu": this.onContextMenu,
12312 this.selections = [];
12314 this.cmp = new Roo.CompositeElementLite([]);
12316 this.store = Roo.factory(this.store, Roo.data);
12317 this.setStore(this.store, true);
12320 if ( this.footer && this.footer.xtype) {
12322 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12324 this.footer.dataSource = this.store
12325 this.footer.container = fctr;
12326 this.footer = Roo.factory(this.footer, Roo);
12327 fctr.insertFirst(this.el);
12329 // this is a bit insane - as the paging toolbar seems to detach the el..
12330 // dom.parentNode.parentNode.parentNode
12331 // they get detached?
12335 Roo.View.superclass.constructor.call(this);
12340 Roo.extend(Roo.View, Roo.util.Observable, {
12343 * @cfg {Roo.data.Store} store Data store to load data from.
12348 * @cfg {String|Roo.Element} el The container element.
12353 * @cfg {String|Roo.Template} tpl The template used by this View
12357 * @cfg {String} dataName the named area of the template to use as the data area
12358 * Works with domtemplates roo-name="name"
12362 * @cfg {String} selectedClass The css class to add to selected nodes
12364 selectedClass : "x-view-selected",
12366 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12371 * @cfg {String} text to display on mask (default Loading)
12375 * @cfg {Boolean} multiSelect Allow multiple selection
12377 multiSelect : false,
12379 * @cfg {Boolean} singleSelect Allow single selection
12381 singleSelect: false,
12384 * @cfg {Boolean} toggleSelect - selecting
12386 toggleSelect : false,
12389 * @cfg {Boolean} tickable - selecting
12394 * Returns the element this view is bound to.
12395 * @return {Roo.Element}
12397 getEl : function(){
12398 return this.wrapEl;
12404 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12406 refresh : function(){
12407 Roo.log('refresh');
12410 // if we are using something like 'domtemplate', then
12411 // the what gets used is:
12412 // t.applySubtemplate(NAME, data, wrapping data..)
12413 // the outer template then get' applied with
12414 // the store 'extra data'
12415 // and the body get's added to the
12416 // roo-name="data" node?
12417 // <span class='roo-tpl-{name}'></span> ?????
12421 this.clearSelections();
12422 this.el.update("");
12424 var records = this.store.getRange();
12425 if(records.length < 1) {
12427 // is this valid?? = should it render a template??
12429 this.el.update(this.emptyText);
12433 if (this.dataName) {
12434 this.el.update(t.apply(this.store.meta)); //????
12435 el = this.el.child('.roo-tpl-' + this.dataName);
12438 for(var i = 0, len = records.length; i < len; i++){
12439 var data = this.prepareData(records[i].data, i, records[i]);
12440 this.fireEvent("preparedata", this, data, i, records[i]);
12442 var d = Roo.apply({}, data);
12445 Roo.apply(d, {'roo-id' : Roo.id()});
12449 Roo.each(this.parent.item, function(item){
12450 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12453 Roo.apply(d, {'roo-data-checked' : 'checked'});
12457 html[html.length] = Roo.util.Format.trim(
12459 t.applySubtemplate(this.dataName, d, this.store.meta) :
12466 el.update(html.join(""));
12467 this.nodes = el.dom.childNodes;
12468 this.updateIndexes(0);
12473 * Function to override to reformat the data that is sent to
12474 * the template for each node.
12475 * DEPRICATED - use the preparedata event handler.
12476 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12477 * a JSON object for an UpdateManager bound view).
12479 prepareData : function(data, index, record)
12481 this.fireEvent("preparedata", this, data, index, record);
12485 onUpdate : function(ds, record){
12486 Roo.log('on update');
12487 this.clearSelections();
12488 var index = this.store.indexOf(record);
12489 var n = this.nodes[index];
12490 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12491 n.parentNode.removeChild(n);
12492 this.updateIndexes(index, index);
12498 onAdd : function(ds, records, index)
12500 Roo.log(['on Add', ds, records, index] );
12501 this.clearSelections();
12502 if(this.nodes.length == 0){
12506 var n = this.nodes[index];
12507 for(var i = 0, len = records.length; i < len; i++){
12508 var d = this.prepareData(records[i].data, i, records[i]);
12510 this.tpl.insertBefore(n, d);
12513 this.tpl.append(this.el, d);
12516 this.updateIndexes(index);
12519 onRemove : function(ds, record, index){
12520 Roo.log('onRemove');
12521 this.clearSelections();
12522 var el = this.dataName ?
12523 this.el.child('.roo-tpl-' + this.dataName) :
12526 el.dom.removeChild(this.nodes[index]);
12527 this.updateIndexes(index);
12531 * Refresh an individual node.
12532 * @param {Number} index
12534 refreshNode : function(index){
12535 this.onUpdate(this.store, this.store.getAt(index));
12538 updateIndexes : function(startIndex, endIndex){
12539 var ns = this.nodes;
12540 startIndex = startIndex || 0;
12541 endIndex = endIndex || ns.length - 1;
12542 for(var i = startIndex; i <= endIndex; i++){
12543 ns[i].nodeIndex = i;
12548 * Changes the data store this view uses and refresh the view.
12549 * @param {Store} store
12551 setStore : function(store, initial){
12552 if(!initial && this.store){
12553 this.store.un("datachanged", this.refresh);
12554 this.store.un("add", this.onAdd);
12555 this.store.un("remove", this.onRemove);
12556 this.store.un("update", this.onUpdate);
12557 this.store.un("clear", this.refresh);
12558 this.store.un("beforeload", this.onBeforeLoad);
12559 this.store.un("load", this.onLoad);
12560 this.store.un("loadexception", this.onLoad);
12564 store.on("datachanged", this.refresh, this);
12565 store.on("add", this.onAdd, this);
12566 store.on("remove", this.onRemove, this);
12567 store.on("update", this.onUpdate, this);
12568 store.on("clear", this.refresh, this);
12569 store.on("beforeload", this.onBeforeLoad, this);
12570 store.on("load", this.onLoad, this);
12571 store.on("loadexception", this.onLoad, this);
12579 * onbeforeLoad - masks the loading area.
12582 onBeforeLoad : function(store,opts)
12584 Roo.log('onBeforeLoad');
12586 this.el.update("");
12588 this.el.mask(this.mask ? this.mask : "Loading" );
12590 onLoad : function ()
12597 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12598 * @param {HTMLElement} node
12599 * @return {HTMLElement} The template node
12601 findItemFromChild : function(node){
12602 var el = this.dataName ?
12603 this.el.child('.roo-tpl-' + this.dataName,true) :
12606 if(!node || node.parentNode == el){
12609 var p = node.parentNode;
12610 while(p && p != el){
12611 if(p.parentNode == el){
12620 onClick : function(e){
12621 var item = this.findItemFromChild(e.getTarget());
12623 var index = this.indexOf(item);
12624 if(this.onItemClick(item, index, e) !== false){
12625 this.fireEvent("click", this, index, item, e);
12628 this.clearSelections();
12633 onContextMenu : function(e){
12634 var item = this.findItemFromChild(e.getTarget());
12636 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12641 onDblClick : function(e){
12642 var item = this.findItemFromChild(e.getTarget());
12644 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12648 onItemClick : function(item, index, e)
12650 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12653 if (this.toggleSelect) {
12654 var m = this.isSelected(item) ? 'unselect' : 'select';
12657 _t[m](item, true, false);
12660 if(this.multiSelect || this.singleSelect){
12661 if(this.multiSelect && e.shiftKey && this.lastSelection){
12662 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12664 this.select(item, this.multiSelect && e.ctrlKey);
12665 this.lastSelection = item;
12668 if(!this.tickable){
12669 e.preventDefault();
12677 * Get the number of selected nodes.
12680 getSelectionCount : function(){
12681 return this.selections.length;
12685 * Get the currently selected nodes.
12686 * @return {Array} An array of HTMLElements
12688 getSelectedNodes : function(){
12689 return this.selections;
12693 * Get the indexes of the selected nodes.
12696 getSelectedIndexes : function(){
12697 var indexes = [], s = this.selections;
12698 for(var i = 0, len = s.length; i < len; i++){
12699 indexes.push(s[i].nodeIndex);
12705 * Clear all selections
12706 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12708 clearSelections : function(suppressEvent){
12709 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12710 this.cmp.elements = this.selections;
12711 this.cmp.removeClass(this.selectedClass);
12712 this.selections = [];
12713 if(!suppressEvent){
12714 this.fireEvent("selectionchange", this, this.selections);
12720 * Returns true if the passed node is selected
12721 * @param {HTMLElement/Number} node The node or node index
12722 * @return {Boolean}
12724 isSelected : function(node){
12725 var s = this.selections;
12729 node = this.getNode(node);
12730 return s.indexOf(node) !== -1;
12735 * @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
12736 * @param {Boolean} keepExisting (optional) true to keep existing selections
12737 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12739 select : function(nodeInfo, keepExisting, suppressEvent){
12740 if(nodeInfo instanceof Array){
12742 this.clearSelections(true);
12744 for(var i = 0, len = nodeInfo.length; i < len; i++){
12745 this.select(nodeInfo[i], true, true);
12749 var node = this.getNode(nodeInfo);
12750 if(!node || this.isSelected(node)){
12751 return; // already selected.
12754 this.clearSelections(true);
12757 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12758 Roo.fly(node).addClass(this.selectedClass);
12759 this.selections.push(node);
12760 if(!suppressEvent){
12761 this.fireEvent("selectionchange", this, this.selections);
12769 * @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
12770 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12771 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12773 unselect : function(nodeInfo, keepExisting, suppressEvent)
12775 if(nodeInfo instanceof Array){
12776 Roo.each(this.selections, function(s) {
12777 this.unselect(s, nodeInfo);
12781 var node = this.getNode(nodeInfo);
12782 if(!node || !this.isSelected(node)){
12783 Roo.log("not selected");
12784 return; // not selected.
12788 Roo.each(this.selections, function(s) {
12790 Roo.fly(node).removeClass(this.selectedClass);
12797 this.selections= ns;
12798 this.fireEvent("selectionchange", this, this.selections);
12802 * Gets a template node.
12803 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12804 * @return {HTMLElement} The node or null if it wasn't found
12806 getNode : function(nodeInfo){
12807 if(typeof nodeInfo == "string"){
12808 return document.getElementById(nodeInfo);
12809 }else if(typeof nodeInfo == "number"){
12810 return this.nodes[nodeInfo];
12816 * Gets a range template nodes.
12817 * @param {Number} startIndex
12818 * @param {Number} endIndex
12819 * @return {Array} An array of nodes
12821 getNodes : function(start, end){
12822 var ns = this.nodes;
12823 start = start || 0;
12824 end = typeof end == "undefined" ? ns.length - 1 : end;
12827 for(var i = start; i <= end; i++){
12831 for(var i = start; i >= end; i--){
12839 * Finds the index of the passed node
12840 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12841 * @return {Number} The index of the node or -1
12843 indexOf : function(node){
12844 node = this.getNode(node);
12845 if(typeof node.nodeIndex == "number"){
12846 return node.nodeIndex;
12848 var ns = this.nodes;
12849 for(var i = 0, len = ns.length; i < len; i++){
12860 * based on jquery fullcalendar
12864 Roo.bootstrap = Roo.bootstrap || {};
12866 * @class Roo.bootstrap.Calendar
12867 * @extends Roo.bootstrap.Component
12868 * Bootstrap Calendar class
12869 * @cfg {Boolean} loadMask (true|false) default false
12870 * @cfg {Object} header generate the user specific header of the calendar, default false
12873 * Create a new Container
12874 * @param {Object} config The config object
12879 Roo.bootstrap.Calendar = function(config){
12880 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12884 * Fires when a date is selected
12885 * @param {DatePicker} this
12886 * @param {Date} date The selected date
12890 * @event monthchange
12891 * Fires when the displayed month changes
12892 * @param {DatePicker} this
12893 * @param {Date} date The selected month
12895 'monthchange': true,
12897 * @event evententer
12898 * Fires when mouse over an event
12899 * @param {Calendar} this
12900 * @param {event} Event
12902 'evententer': true,
12904 * @event eventleave
12905 * Fires when the mouse leaves an
12906 * @param {Calendar} this
12909 'eventleave': true,
12911 * @event eventclick
12912 * Fires when the mouse click an
12913 * @param {Calendar} this
12922 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12925 * @cfg {Number} startDay
12926 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12934 getAutoCreate : function(){
12937 var fc_button = function(name, corner, style, content ) {
12938 return Roo.apply({},{
12940 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12942 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12945 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12956 style : 'width:100%',
12963 cls : 'fc-header-left',
12965 fc_button('prev', 'left', 'arrow', '‹' ),
12966 fc_button('next', 'right', 'arrow', '›' ),
12967 { tag: 'span', cls: 'fc-header-space' },
12968 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12976 cls : 'fc-header-center',
12980 cls: 'fc-header-title',
12983 html : 'month / year'
12991 cls : 'fc-header-right',
12993 /* fc_button('month', 'left', '', 'month' ),
12994 fc_button('week', '', '', 'week' ),
12995 fc_button('day', 'right', '', 'day' )
13007 header = this.header;
13010 var cal_heads = function() {
13012 // fixme - handle this.
13014 for (var i =0; i < Date.dayNames.length; i++) {
13015 var d = Date.dayNames[i];
13018 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13019 html : d.substring(0,3)
13023 ret[0].cls += ' fc-first';
13024 ret[6].cls += ' fc-last';
13027 var cal_cell = function(n) {
13030 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13035 cls: 'fc-day-number',
13039 cls: 'fc-day-content',
13043 style: 'position: relative;' // height: 17px;
13055 var cal_rows = function() {
13058 for (var r = 0; r < 6; r++) {
13065 for (var i =0; i < Date.dayNames.length; i++) {
13066 var d = Date.dayNames[i];
13067 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13070 row.cn[0].cls+=' fc-first';
13071 row.cn[0].cn[0].style = 'min-height:90px';
13072 row.cn[6].cls+=' fc-last';
13076 ret[0].cls += ' fc-first';
13077 ret[4].cls += ' fc-prev-last';
13078 ret[5].cls += ' fc-last';
13085 cls: 'fc-border-separate',
13086 style : 'width:100%',
13094 cls : 'fc-first fc-last',
13112 cls : 'fc-content',
13113 style : "position: relative;",
13116 cls : 'fc-view fc-view-month fc-grid',
13117 style : 'position: relative',
13118 unselectable : 'on',
13121 cls : 'fc-event-container',
13122 style : 'position:absolute;z-index:8;top:0;left:0;'
13140 initEvents : function()
13143 throw "can not find store for calendar";
13149 style: "text-align:center",
13153 style: "background-color:white;width:50%;margin:250 auto",
13157 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13168 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13170 var size = this.el.select('.fc-content', true).first().getSize();
13171 this.maskEl.setSize(size.width, size.height);
13172 this.maskEl.enableDisplayMode("block");
13173 if(!this.loadMask){
13174 this.maskEl.hide();
13177 this.store = Roo.factory(this.store, Roo.data);
13178 this.store.on('load', this.onLoad, this);
13179 this.store.on('beforeload', this.onBeforeLoad, this);
13183 this.cells = this.el.select('.fc-day',true);
13184 //Roo.log(this.cells);
13185 this.textNodes = this.el.query('.fc-day-number');
13186 this.cells.addClassOnOver('fc-state-hover');
13188 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13189 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13190 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13191 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13193 this.on('monthchange', this.onMonthChange, this);
13195 this.update(new Date().clearTime());
13198 resize : function() {
13199 var sz = this.el.getSize();
13201 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13202 this.el.select('.fc-day-content div',true).setHeight(34);
13207 showPrevMonth : function(e){
13208 this.update(this.activeDate.add("mo", -1));
13210 showToday : function(e){
13211 this.update(new Date().clearTime());
13214 showNextMonth : function(e){
13215 this.update(this.activeDate.add("mo", 1));
13219 showPrevYear : function(){
13220 this.update(this.activeDate.add("y", -1));
13224 showNextYear : function(){
13225 this.update(this.activeDate.add("y", 1));
13230 update : function(date)
13232 var vd = this.activeDate;
13233 this.activeDate = date;
13234 // if(vd && this.el){
13235 // var t = date.getTime();
13236 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13237 // Roo.log('using add remove');
13239 // this.fireEvent('monthchange', this, date);
13241 // this.cells.removeClass("fc-state-highlight");
13242 // this.cells.each(function(c){
13243 // if(c.dateValue == t){
13244 // c.addClass("fc-state-highlight");
13245 // setTimeout(function(){
13246 // try{c.dom.firstChild.focus();}catch(e){}
13256 var days = date.getDaysInMonth();
13258 var firstOfMonth = date.getFirstDateOfMonth();
13259 var startingPos = firstOfMonth.getDay()-this.startDay;
13261 if(startingPos < this.startDay){
13265 var pm = date.add(Date.MONTH, -1);
13266 var prevStart = pm.getDaysInMonth()-startingPos;
13268 this.cells = this.el.select('.fc-day',true);
13269 this.textNodes = this.el.query('.fc-day-number');
13270 this.cells.addClassOnOver('fc-state-hover');
13272 var cells = this.cells.elements;
13273 var textEls = this.textNodes;
13275 Roo.each(cells, function(cell){
13276 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13279 days += startingPos;
13281 // convert everything to numbers so it's fast
13282 var day = 86400000;
13283 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13286 //Roo.log(prevStart);
13288 var today = new Date().clearTime().getTime();
13289 var sel = date.clearTime().getTime();
13290 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13291 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13292 var ddMatch = this.disabledDatesRE;
13293 var ddText = this.disabledDatesText;
13294 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13295 var ddaysText = this.disabledDaysText;
13296 var format = this.format;
13298 var setCellClass = function(cal, cell){
13302 //Roo.log('set Cell Class');
13304 var t = d.getTime();
13308 cell.dateValue = t;
13310 cell.className += " fc-today";
13311 cell.className += " fc-state-highlight";
13312 cell.title = cal.todayText;
13315 // disable highlight in other month..
13316 //cell.className += " fc-state-highlight";
13321 cell.className = " fc-state-disabled";
13322 cell.title = cal.minText;
13326 cell.className = " fc-state-disabled";
13327 cell.title = cal.maxText;
13331 if(ddays.indexOf(d.getDay()) != -1){
13332 cell.title = ddaysText;
13333 cell.className = " fc-state-disabled";
13336 if(ddMatch && format){
13337 var fvalue = d.dateFormat(format);
13338 if(ddMatch.test(fvalue)){
13339 cell.title = ddText.replace("%0", fvalue);
13340 cell.className = " fc-state-disabled";
13344 if (!cell.initialClassName) {
13345 cell.initialClassName = cell.dom.className;
13348 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13353 for(; i < startingPos; i++) {
13354 textEls[i].innerHTML = (++prevStart);
13355 d.setDate(d.getDate()+1);
13357 cells[i].className = "fc-past fc-other-month";
13358 setCellClass(this, cells[i]);
13363 for(; i < days; i++){
13364 intDay = i - startingPos + 1;
13365 textEls[i].innerHTML = (intDay);
13366 d.setDate(d.getDate()+1);
13368 cells[i].className = ''; // "x-date-active";
13369 setCellClass(this, cells[i]);
13373 for(; i < 42; i++) {
13374 textEls[i].innerHTML = (++extraDays);
13375 d.setDate(d.getDate()+1);
13377 cells[i].className = "fc-future fc-other-month";
13378 setCellClass(this, cells[i]);
13381 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13383 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13385 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13386 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13388 if(totalRows != 6){
13389 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13390 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13393 this.fireEvent('monthchange', this, date);
13397 if(!this.internalRender){
13398 var main = this.el.dom.firstChild;
13399 var w = main.offsetWidth;
13400 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13401 Roo.fly(main).setWidth(w);
13402 this.internalRender = true;
13403 // opera does not respect the auto grow header center column
13404 // then, after it gets a width opera refuses to recalculate
13405 // without a second pass
13406 if(Roo.isOpera && !this.secondPass){
13407 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13408 this.secondPass = true;
13409 this.update.defer(10, this, [date]);
13416 findCell : function(dt) {
13417 dt = dt.clearTime().getTime();
13419 this.cells.each(function(c){
13420 //Roo.log("check " +c.dateValue + '?=' + dt);
13421 if(c.dateValue == dt){
13431 findCells : function(ev) {
13432 var s = ev.start.clone().clearTime().getTime();
13434 var e= ev.end.clone().clearTime().getTime();
13437 this.cells.each(function(c){
13438 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13440 if(c.dateValue > e){
13443 if(c.dateValue < s){
13452 // findBestRow: function(cells)
13456 // for (var i =0 ; i < cells.length;i++) {
13457 // ret = Math.max(cells[i].rows || 0,ret);
13464 addItem : function(ev)
13466 // look for vertical location slot in
13467 var cells = this.findCells(ev);
13469 // ev.row = this.findBestRow(cells);
13471 // work out the location.
13475 for(var i =0; i < cells.length; i++) {
13477 cells[i].row = cells[0].row;
13480 cells[i].row = cells[i].row + 1;
13490 if (crow.start.getY() == cells[i].getY()) {
13492 crow.end = cells[i];
13509 cells[0].events.push(ev);
13511 this.calevents.push(ev);
13514 clearEvents: function() {
13516 if(!this.calevents){
13520 Roo.each(this.cells.elements, function(c){
13526 Roo.each(this.calevents, function(e) {
13527 Roo.each(e.els, function(el) {
13528 el.un('mouseenter' ,this.onEventEnter, this);
13529 el.un('mouseleave' ,this.onEventLeave, this);
13534 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13540 renderEvents: function()
13544 this.cells.each(function(c) {
13553 if(c.row != c.events.length){
13554 r = 4 - (4 - (c.row - c.events.length));
13557 c.events = ev.slice(0, r);
13558 c.more = ev.slice(r);
13560 if(c.more.length && c.more.length == 1){
13561 c.events.push(c.more.pop());
13564 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13568 this.cells.each(function(c) {
13570 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13573 for (var e = 0; e < c.events.length; e++){
13574 var ev = c.events[e];
13575 var rows = ev.rows;
13577 for(var i = 0; i < rows.length; i++) {
13579 // how many rows should it span..
13582 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13583 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13585 unselectable : "on",
13588 cls: 'fc-event-inner',
13592 // cls: 'fc-event-time',
13593 // html : cells.length > 1 ? '' : ev.time
13597 cls: 'fc-event-title',
13598 html : String.format('{0}', ev.title)
13605 cls: 'ui-resizable-handle ui-resizable-e',
13606 html : '  '
13613 cfg.cls += ' fc-event-start';
13615 if ((i+1) == rows.length) {
13616 cfg.cls += ' fc-event-end';
13619 var ctr = _this.el.select('.fc-event-container',true).first();
13620 var cg = ctr.createChild(cfg);
13622 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13623 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13625 var r = (c.more.length) ? 1 : 0;
13626 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13627 cg.setWidth(ebox.right - sbox.x -2);
13629 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13630 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13631 cg.on('click', _this.onEventClick, _this, ev);
13642 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13643 style : 'position: absolute',
13644 unselectable : "on",
13647 cls: 'fc-event-inner',
13651 cls: 'fc-event-title',
13659 cls: 'ui-resizable-handle ui-resizable-e',
13660 html : '  '
13666 var ctr = _this.el.select('.fc-event-container',true).first();
13667 var cg = ctr.createChild(cfg);
13669 var sbox = c.select('.fc-day-content',true).first().getBox();
13670 var ebox = c.select('.fc-day-content',true).first().getBox();
13672 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13673 cg.setWidth(ebox.right - sbox.x -2);
13675 cg.on('click', _this.onMoreEventClick, _this, c.more);
13685 onEventEnter: function (e, el,event,d) {
13686 this.fireEvent('evententer', this, el, event);
13689 onEventLeave: function (e, el,event,d) {
13690 this.fireEvent('eventleave', this, el, event);
13693 onEventClick: function (e, el,event,d) {
13694 this.fireEvent('eventclick', this, el, event);
13697 onMonthChange: function () {
13701 onMoreEventClick: function(e, el, more)
13705 this.calpopover.placement = 'right';
13706 this.calpopover.setTitle('More');
13708 this.calpopover.setContent('');
13710 var ctr = this.calpopover.el.select('.popover-content', true).first();
13712 Roo.each(more, function(m){
13714 cls : 'fc-event-hori fc-event-draggable',
13717 var cg = ctr.createChild(cfg);
13719 cg.on('click', _this.onEventClick, _this, m);
13722 this.calpopover.show(el);
13727 onLoad: function ()
13729 this.calevents = [];
13732 if(this.store.getCount() > 0){
13733 this.store.data.each(function(d){
13736 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13737 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13738 time : d.data.start_time,
13739 title : d.data.title,
13740 description : d.data.description,
13741 venue : d.data.venue
13746 this.renderEvents();
13748 if(this.calevents.length && this.loadMask){
13749 this.maskEl.hide();
13753 onBeforeLoad: function()
13755 this.clearEvents();
13757 this.maskEl.show();
13771 * @class Roo.bootstrap.Popover
13772 * @extends Roo.bootstrap.Component
13773 * Bootstrap Popover class
13774 * @cfg {String} html contents of the popover (or false to use children..)
13775 * @cfg {String} title of popover (or false to hide)
13776 * @cfg {String} placement how it is placed
13777 * @cfg {String} trigger click || hover (or false to trigger manually)
13778 * @cfg {String} over what (parent or false to trigger manually.)
13779 * @cfg {Number} delay - delay before showing
13782 * Create a new Popover
13783 * @param {Object} config The config object
13786 Roo.bootstrap.Popover = function(config){
13787 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13790 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13792 title: 'Fill in a title',
13795 placement : 'right',
13796 trigger : 'hover', // hover
13802 can_build_overlaid : false,
13804 getChildContainer : function()
13806 return this.el.select('.popover-content',true).first();
13809 getAutoCreate : function(){
13810 Roo.log('make popover?');
13812 cls : 'popover roo-dynamic',
13813 style: 'display:block',
13819 cls : 'popover-inner',
13823 cls: 'popover-title',
13827 cls : 'popover-content',
13838 setTitle: function(str)
13840 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13842 setContent: function(str)
13844 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13846 // as it get's added to the bottom of the page.
13847 onRender : function(ct, position)
13849 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13851 var cfg = Roo.apply({}, this.getAutoCreate());
13855 cfg.cls += ' ' + this.cls;
13858 cfg.style = this.style;
13860 Roo.log("adding to ")
13861 this.el = Roo.get(document.body).createChild(cfg, position);
13867 initEvents : function()
13869 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13870 this.el.enableDisplayMode('block');
13872 if (this.over === false) {
13875 if (this.triggers === false) {
13878 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13879 var triggers = this.trigger ? this.trigger.split(' ') : [];
13880 Roo.each(triggers, function(trigger) {
13882 if (trigger == 'click') {
13883 on_el.on('click', this.toggle, this);
13884 } else if (trigger != 'manual') {
13885 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13886 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13888 on_el.on(eventIn ,this.enter, this);
13889 on_el.on(eventOut, this.leave, this);
13900 toggle : function () {
13901 this.hoverState == 'in' ? this.leave() : this.enter();
13904 enter : function () {
13907 clearTimeout(this.timeout);
13909 this.hoverState = 'in'
13911 if (!this.delay || !this.delay.show) {
13916 this.timeout = setTimeout(function () {
13917 if (_t.hoverState == 'in') {
13920 }, this.delay.show)
13922 leave : function() {
13923 clearTimeout(this.timeout);
13925 this.hoverState = 'out'
13927 if (!this.delay || !this.delay.hide) {
13932 this.timeout = setTimeout(function () {
13933 if (_t.hoverState == 'out') {
13936 }, this.delay.hide)
13939 show : function (on_el)
13942 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13945 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13946 if (this.html !== false) {
13947 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13949 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13950 if (!this.title.length) {
13951 this.el.select('.popover-title',true).hide();
13954 var placement = typeof this.placement == 'function' ?
13955 this.placement.call(this, this.el, on_el) :
13958 var autoToken = /\s?auto?\s?/i;
13959 var autoPlace = autoToken.test(placement);
13961 placement = placement.replace(autoToken, '') || 'top';
13965 //this.el.setXY([0,0]);
13967 this.el.dom.style.display='block';
13968 this.el.addClass(placement);
13970 //this.el.appendTo(on_el);
13972 var p = this.getPosition();
13973 var box = this.el.getBox();
13978 var align = Roo.bootstrap.Popover.alignment[placement]
13979 this.el.alignTo(on_el, align[0],align[1]);
13980 //var arrow = this.el.select('.arrow',true).first();
13981 //arrow.set(align[2],
13983 this.el.addClass('in');
13984 this.hoverState = null;
13986 if (this.el.hasClass('fade')) {
13993 this.el.setXY([0,0]);
13994 this.el.removeClass('in');
14001 Roo.bootstrap.Popover.alignment = {
14002 'left' : ['r-l', [-10,0], 'right'],
14003 'right' : ['l-r', [10,0], 'left'],
14004 'bottom' : ['t-b', [0,10], 'top'],
14005 'top' : [ 'b-t', [0,-10], 'bottom']
14016 * @class Roo.bootstrap.Progress
14017 * @extends Roo.bootstrap.Component
14018 * Bootstrap Progress class
14019 * @cfg {Boolean} striped striped of the progress bar
14020 * @cfg {Boolean} active animated of the progress bar
14024 * Create a new Progress
14025 * @param {Object} config The config object
14028 Roo.bootstrap.Progress = function(config){
14029 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14032 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14037 getAutoCreate : function(){
14045 cfg.cls += ' progress-striped';
14049 cfg.cls += ' active';
14068 * @class Roo.bootstrap.ProgressBar
14069 * @extends Roo.bootstrap.Component
14070 * Bootstrap ProgressBar class
14071 * @cfg {Number} aria_valuenow aria-value now
14072 * @cfg {Number} aria_valuemin aria-value min
14073 * @cfg {Number} aria_valuemax aria-value max
14074 * @cfg {String} label label for the progress bar
14075 * @cfg {String} panel (success | info | warning | danger )
14076 * @cfg {String} role role of the progress bar
14077 * @cfg {String} sr_only text
14081 * Create a new ProgressBar
14082 * @param {Object} config The config object
14085 Roo.bootstrap.ProgressBar = function(config){
14086 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14089 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14093 aria_valuemax : 100,
14099 getAutoCreate : function()
14104 cls: 'progress-bar',
14105 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14117 cfg.role = this.role;
14120 if(this.aria_valuenow){
14121 cfg['aria-valuenow'] = this.aria_valuenow;
14124 if(this.aria_valuemin){
14125 cfg['aria-valuemin'] = this.aria_valuemin;
14128 if(this.aria_valuemax){
14129 cfg['aria-valuemax'] = this.aria_valuemax;
14132 if(this.label && !this.sr_only){
14133 cfg.html = this.label;
14137 cfg.cls += ' progress-bar-' + this.panel;
14143 update : function(aria_valuenow)
14145 this.aria_valuenow = aria_valuenow;
14147 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14162 * @class Roo.bootstrap.TabGroup
14163 * @extends Roo.bootstrap.Column
14164 * Bootstrap Column class
14165 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14166 * @cfg {Boolean} carousel true to make the group behave like a carousel
14169 * Create a new TabGroup
14170 * @param {Object} config The config object
14173 Roo.bootstrap.TabGroup = function(config){
14174 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14176 this.navId = Roo.id();
14179 Roo.bootstrap.TabGroup.register(this);
14183 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14186 transition : false,
14188 getAutoCreate : function()
14190 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14192 cfg.cls += ' tab-content';
14194 if (this.carousel) {
14195 cfg.cls += ' carousel slide';
14197 cls : 'carousel-inner'
14204 getChildContainer : function()
14206 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14210 * register a Navigation item
14211 * @param {Roo.bootstrap.NavItem} the navitem to add
14213 register : function(item)
14215 this.tabs.push( item);
14216 item.navId = this.navId; // not really needed..
14220 getActivePanel : function()
14223 Roo.each(this.tabs, function(t) {
14233 getPanelByName : function(n)
14236 Roo.each(this.tabs, function(t) {
14237 if (t.tabId == n) {
14245 indexOfPanel : function(p)
14248 Roo.each(this.tabs, function(t,i) {
14249 if (t.tabId == p.tabId) {
14258 * show a specific panel
14259 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14260 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14262 showPanel : function (pan)
14265 if (typeof(pan) == 'number') {
14266 pan = this.tabs[pan];
14268 if (typeof(pan) == 'string') {
14269 pan = this.getPanelByName(pan);
14271 if (pan.tabId == this.getActivePanel().tabId) {
14274 var cur = this.getActivePanel();
14276 if (false === cur.fireEvent('beforedeactivate')) {
14280 if (this.carousel) {
14281 this.transition = true;
14282 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14283 var lr = dir == 'next' ? 'left' : 'right';
14284 pan.el.addClass(dir); // or prev
14285 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14286 cur.el.addClass(lr); // or right
14287 pan.el.addClass(lr);
14290 cur.el.on('transitionend', function() {
14291 Roo.log("trans end?");
14293 pan.el.removeClass([lr,dir]);
14294 pan.setActive(true);
14296 cur.el.removeClass([lr]);
14297 cur.setActive(false);
14299 _this.transition = false;
14301 }, this, { single: true } );
14305 cur.setActive(false);
14306 pan.setActive(true);
14310 showPanelNext : function()
14312 var i = this.indexOfPanel(this.getActivePanel());
14313 if (i > this.tabs.length) {
14316 this.showPanel(this.tabs[i+1]);
14318 showPanelPrev : function()
14320 var i = this.indexOfPanel(this.getActivePanel());
14324 this.showPanel(this.tabs[i-1]);
14335 Roo.apply(Roo.bootstrap.TabGroup, {
14339 * register a Navigation Group
14340 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14342 register : function(navgrp)
14344 this.groups[navgrp.navId] = navgrp;
14348 * fetch a Navigation Group based on the navigation ID
14349 * if one does not exist , it will get created.
14350 * @param {string} the navgroup to add
14351 * @returns {Roo.bootstrap.NavGroup} the navgroup
14353 get: function(navId) {
14354 if (typeof(this.groups[navId]) == 'undefined') {
14355 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14357 return this.groups[navId] ;
14372 * @class Roo.bootstrap.TabPanel
14373 * @extends Roo.bootstrap.Component
14374 * Bootstrap TabPanel class
14375 * @cfg {Boolean} active panel active
14376 * @cfg {String} html panel content
14377 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14378 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14382 * Create a new TabPanel
14383 * @param {Object} config The config object
14386 Roo.bootstrap.TabPanel = function(config){
14387 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14391 * Fires when the active status changes
14392 * @param {Roo.bootstrap.TabPanel} this
14393 * @param {Boolean} state the new state
14398 * @event beforedeactivate
14399 * Fires before a tab is de-activated - can be used to do validation on a form.
14400 * @param {Roo.bootstrap.TabPanel} this
14401 * @return {Boolean} false if there is an error
14404 'beforedeactivate': true
14407 this.tabId = this.tabId || Roo.id();
14411 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14418 getAutoCreate : function(){
14421 // item is needed for carousel - not sure if it has any effect otherwise
14422 cls: 'tab-pane item',
14423 html: this.html || ''
14427 cfg.cls += ' active';
14431 cfg.tabId = this.tabId;
14438 initEvents: function()
14440 Roo.log('-------- init events on tab panel ---------');
14442 var p = this.parent();
14443 this.navId = this.navId || p.navId;
14445 if (typeof(this.navId) != 'undefined') {
14446 // not really needed.. but just in case.. parent should be a NavGroup.
14447 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14448 Roo.log(['register', tg, this]);
14454 onRender : function(ct, position)
14456 // Roo.log("Call onRender: " + this.xtype);
14458 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14466 setActive: function(state)
14468 Roo.log("panel - set active " + this.tabId + "=" + state);
14470 this.active = state;
14472 this.el.removeClass('active');
14474 } else if (!this.el.hasClass('active')) {
14475 this.el.addClass('active');
14477 this.fireEvent('changed', this, state);
14494 * @class Roo.bootstrap.DateField
14495 * @extends Roo.bootstrap.Input
14496 * Bootstrap DateField class
14497 * @cfg {Number} weekStart default 0
14498 * @cfg {String} viewMode default empty, (months|years)
14499 * @cfg {String} minViewMode default empty, (months|years)
14500 * @cfg {Number} startDate default -Infinity
14501 * @cfg {Number} endDate default Infinity
14502 * @cfg {Boolean} todayHighlight default false
14503 * @cfg {Boolean} todayBtn default false
14504 * @cfg {Boolean} calendarWeeks default false
14505 * @cfg {Object} daysOfWeekDisabled default empty
14506 * @cfg {Boolean} singleMode default false (true | false)
14508 * @cfg {Boolean} keyboardNavigation default true
14509 * @cfg {String} language default en
14512 * Create a new DateField
14513 * @param {Object} config The config object
14516 Roo.bootstrap.DateField = function(config){
14517 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14521 * Fires when this field show.
14522 * @param {Roo.bootstrap.DateField} this
14523 * @param {Mixed} date The date value
14528 * Fires when this field hide.
14529 * @param {Roo.bootstrap.DateField} this
14530 * @param {Mixed} date The date value
14535 * Fires when select a date.
14536 * @param {Roo.bootstrap.DateField} this
14537 * @param {Mixed} date The date value
14543 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14546 * @cfg {String} format
14547 * The default date format string which can be overriden for localization support. The format must be
14548 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14552 * @cfg {String} altFormats
14553 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14554 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14556 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14564 todayHighlight : false,
14570 keyboardNavigation: true,
14572 calendarWeeks: false,
14574 startDate: -Infinity,
14578 daysOfWeekDisabled: [],
14582 singleMode : false,
14584 UTCDate: function()
14586 return new Date(Date.UTC.apply(Date, arguments));
14589 UTCToday: function()
14591 var today = new Date();
14592 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14595 getDate: function() {
14596 var d = this.getUTCDate();
14597 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14600 getUTCDate: function() {
14604 setDate: function(d) {
14605 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14608 setUTCDate: function(d) {
14610 this.setValue(this.formatDate(this.date));
14613 onRender: function(ct, position)
14616 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14618 this.language = this.language || 'en';
14619 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14620 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14622 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14623 this.format = this.format || 'm/d/y';
14624 this.isInline = false;
14625 this.isInput = true;
14626 this.component = this.el.select('.add-on', true).first() || false;
14627 this.component = (this.component && this.component.length === 0) ? false : this.component;
14628 this.hasInput = this.component && this.inputEL().length;
14630 if (typeof(this.minViewMode === 'string')) {
14631 switch (this.minViewMode) {
14633 this.minViewMode = 1;
14636 this.minViewMode = 2;
14639 this.minViewMode = 0;
14644 if (typeof(this.viewMode === 'string')) {
14645 switch (this.viewMode) {
14658 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14660 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14662 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14664 this.picker().on('mousedown', this.onMousedown, this);
14665 this.picker().on('click', this.onClick, this);
14667 this.picker().addClass('datepicker-dropdown');
14669 this.startViewMode = this.viewMode;
14671 if(this.singleMode){
14672 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14673 v.setVisibilityMode(Roo.Element.DISPLAY)
14677 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14678 v.setStyle('width', '189px');
14682 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14683 if(!this.calendarWeeks){
14688 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14689 v.attr('colspan', function(i, val){
14690 return parseInt(val) + 1;
14695 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14697 this.setStartDate(this.startDate);
14698 this.setEndDate(this.endDate);
14700 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14707 if(this.isInline) {
14712 picker : function()
14714 return this.pickerEl;
14715 // return this.el.select('.datepicker', true).first();
14718 fillDow: function()
14720 var dowCnt = this.weekStart;
14729 if(this.calendarWeeks){
14737 while (dowCnt < this.weekStart + 7) {
14741 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14745 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14748 fillMonths: function()
14751 var months = this.picker().select('>.datepicker-months td', true).first();
14753 months.dom.innerHTML = '';
14759 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14762 months.createChild(month);
14769 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;
14771 if (this.date < this.startDate) {
14772 this.viewDate = new Date(this.startDate);
14773 } else if (this.date > this.endDate) {
14774 this.viewDate = new Date(this.endDate);
14776 this.viewDate = new Date(this.date);
14784 var d = new Date(this.viewDate),
14785 year = d.getUTCFullYear(),
14786 month = d.getUTCMonth(),
14787 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14788 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14789 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14790 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14791 currentDate = this.date && this.date.valueOf(),
14792 today = this.UTCToday();
14794 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14796 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14798 // this.picker.select('>tfoot th.today').
14799 // .text(dates[this.language].today)
14800 // .toggle(this.todayBtn !== false);
14802 this.updateNavArrows();
14805 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14807 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14809 prevMonth.setUTCDate(day);
14811 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14813 var nextMonth = new Date(prevMonth);
14815 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14817 nextMonth = nextMonth.valueOf();
14819 var fillMonths = false;
14821 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14823 while(prevMonth.valueOf() < nextMonth) {
14826 if (prevMonth.getUTCDay() === this.weekStart) {
14828 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14836 if(this.calendarWeeks){
14837 // ISO 8601: First week contains first thursday.
14838 // ISO also states week starts on Monday, but we can be more abstract here.
14840 // Start of current week: based on weekstart/current date
14841 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14842 // Thursday of this week
14843 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14844 // First Thursday of year, year from thursday
14845 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14846 // Calendar week: ms between thursdays, div ms per day, div 7 days
14847 calWeek = (th - yth) / 864e5 / 7 + 1;
14849 fillMonths.cn.push({
14857 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14859 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14862 if (this.todayHighlight &&
14863 prevMonth.getUTCFullYear() == today.getFullYear() &&
14864 prevMonth.getUTCMonth() == today.getMonth() &&
14865 prevMonth.getUTCDate() == today.getDate()) {
14866 clsName += ' today';
14869 if (currentDate && prevMonth.valueOf() === currentDate) {
14870 clsName += ' active';
14873 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14874 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14875 clsName += ' disabled';
14878 fillMonths.cn.push({
14880 cls: 'day ' + clsName,
14881 html: prevMonth.getDate()
14884 prevMonth.setDate(prevMonth.getDate()+1);
14887 var currentYear = this.date && this.date.getUTCFullYear();
14888 var currentMonth = this.date && this.date.getUTCMonth();
14890 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14892 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14893 v.removeClass('active');
14895 if(currentYear === year && k === currentMonth){
14896 v.addClass('active');
14899 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14900 v.addClass('disabled');
14906 year = parseInt(year/10, 10) * 10;
14908 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14910 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14913 for (var i = -1; i < 11; i++) {
14914 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14916 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14924 showMode: function(dir)
14927 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14930 Roo.each(this.picker().select('>div',true).elements, function(v){
14931 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14934 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14939 if(this.isInline) return;
14941 this.picker().removeClass(['bottom', 'top']);
14943 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14945 * place to the top of element!
14949 this.picker().addClass('top');
14950 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14955 this.picker().addClass('bottom');
14957 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14960 parseDate : function(value)
14962 if(!value || value instanceof Date){
14965 var v = Date.parseDate(value, this.format);
14966 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
14967 v = Date.parseDate(value, 'Y-m-d');
14969 if(!v && this.altFormats){
14970 if(!this.altFormatsArray){
14971 this.altFormatsArray = this.altFormats.split("|");
14973 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14974 v = Date.parseDate(value, this.altFormatsArray[i]);
14980 formatDate : function(date, fmt)
14982 return (!date || !(date instanceof Date)) ?
14983 date : date.dateFormat(fmt || this.format);
14986 onFocus : function()
14988 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14992 onBlur : function()
14994 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14996 var d = this.inputEl().getValue();
15005 this.picker().show();
15009 this.fireEvent('show', this, this.date);
15014 if(this.isInline) return;
15015 this.picker().hide();
15016 this.viewMode = this.startViewMode;
15019 this.fireEvent('hide', this, this.date);
15023 onMousedown: function(e)
15025 e.stopPropagation();
15026 e.preventDefault();
15031 Roo.bootstrap.DateField.superclass.keyup.call(this);
15035 setValue: function(v)
15038 // v can be a string or a date..
15041 var d = new Date(this.parseDate(v) ).clearTime();
15043 if(isNaN(d.getTime())){
15044 this.date = this.viewDate = '';
15045 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15049 v = this.formatDate(d);
15051 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15053 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15057 this.fireEvent('select', this, this.date);
15061 getValue: function()
15063 return this.formatDate(this.date);
15066 fireKey: function(e)
15068 if (!this.picker().isVisible()){
15069 if (e.keyCode == 27) // allow escape to hide and re-show picker
15074 var dateChanged = false,
15076 newDate, newViewDate;
15081 e.preventDefault();
15085 if (!this.keyboardNavigation) break;
15086 dir = e.keyCode == 37 ? -1 : 1;
15089 newDate = this.moveYear(this.date, dir);
15090 newViewDate = this.moveYear(this.viewDate, dir);
15091 } else if (e.shiftKey){
15092 newDate = this.moveMonth(this.date, dir);
15093 newViewDate = this.moveMonth(this.viewDate, dir);
15095 newDate = new Date(this.date);
15096 newDate.setUTCDate(this.date.getUTCDate() + dir);
15097 newViewDate = new Date(this.viewDate);
15098 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15100 if (this.dateWithinRange(newDate)){
15101 this.date = newDate;
15102 this.viewDate = newViewDate;
15103 this.setValue(this.formatDate(this.date));
15105 e.preventDefault();
15106 dateChanged = true;
15111 if (!this.keyboardNavigation) break;
15112 dir = e.keyCode == 38 ? -1 : 1;
15114 newDate = this.moveYear(this.date, dir);
15115 newViewDate = this.moveYear(this.viewDate, dir);
15116 } else if (e.shiftKey){
15117 newDate = this.moveMonth(this.date, dir);
15118 newViewDate = this.moveMonth(this.viewDate, dir);
15120 newDate = new Date(this.date);
15121 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15122 newViewDate = new Date(this.viewDate);
15123 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15125 if (this.dateWithinRange(newDate)){
15126 this.date = newDate;
15127 this.viewDate = newViewDate;
15128 this.setValue(this.formatDate(this.date));
15130 e.preventDefault();
15131 dateChanged = true;
15135 this.setValue(this.formatDate(this.date));
15137 e.preventDefault();
15140 this.setValue(this.formatDate(this.date));
15154 onClick: function(e)
15156 e.stopPropagation();
15157 e.preventDefault();
15159 var target = e.getTarget();
15161 if(target.nodeName.toLowerCase() === 'i'){
15162 target = Roo.get(target).dom.parentNode;
15165 var nodeName = target.nodeName;
15166 var className = target.className;
15167 var html = target.innerHTML;
15168 //Roo.log(nodeName);
15170 switch(nodeName.toLowerCase()) {
15172 switch(className) {
15178 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15179 switch(this.viewMode){
15181 this.viewDate = this.moveMonth(this.viewDate, dir);
15185 this.viewDate = this.moveYear(this.viewDate, dir);
15191 var date = new Date();
15192 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15194 this.setValue(this.formatDate(this.date));
15201 if (className.indexOf('disabled') < 0) {
15202 this.viewDate.setUTCDate(1);
15203 if (className.indexOf('month') > -1) {
15204 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15206 var year = parseInt(html, 10) || 0;
15207 this.viewDate.setUTCFullYear(year);
15211 if(this.singleMode){
15212 this.setValue(this.formatDate(this.viewDate));
15223 //Roo.log(className);
15224 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15225 var day = parseInt(html, 10) || 1;
15226 var year = this.viewDate.getUTCFullYear(),
15227 month = this.viewDate.getUTCMonth();
15229 if (className.indexOf('old') > -1) {
15236 } else if (className.indexOf('new') > -1) {
15244 //Roo.log([year,month,day]);
15245 this.date = this.UTCDate(year, month, day,0,0,0,0);
15246 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15248 //Roo.log(this.formatDate(this.date));
15249 this.setValue(this.formatDate(this.date));
15256 setStartDate: function(startDate)
15258 this.startDate = startDate || -Infinity;
15259 if (this.startDate !== -Infinity) {
15260 this.startDate = this.parseDate(this.startDate);
15263 this.updateNavArrows();
15266 setEndDate: function(endDate)
15268 this.endDate = endDate || Infinity;
15269 if (this.endDate !== Infinity) {
15270 this.endDate = this.parseDate(this.endDate);
15273 this.updateNavArrows();
15276 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15278 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15279 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15280 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15282 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15283 return parseInt(d, 10);
15286 this.updateNavArrows();
15289 updateNavArrows: function()
15291 if(this.singleMode){
15295 var d = new Date(this.viewDate),
15296 year = d.getUTCFullYear(),
15297 month = d.getUTCMonth();
15299 Roo.each(this.picker().select('.prev', true).elements, function(v){
15301 switch (this.viewMode) {
15304 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15310 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15317 Roo.each(this.picker().select('.next', true).elements, function(v){
15319 switch (this.viewMode) {
15322 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15328 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15336 moveMonth: function(date, dir)
15338 if (!dir) return date;
15339 var new_date = new Date(date.valueOf()),
15340 day = new_date.getUTCDate(),
15341 month = new_date.getUTCMonth(),
15342 mag = Math.abs(dir),
15344 dir = dir > 0 ? 1 : -1;
15347 // If going back one month, make sure month is not current month
15348 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15350 return new_date.getUTCMonth() == month;
15352 // If going forward one month, make sure month is as expected
15353 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15355 return new_date.getUTCMonth() != new_month;
15357 new_month = month + dir;
15358 new_date.setUTCMonth(new_month);
15359 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15360 if (new_month < 0 || new_month > 11)
15361 new_month = (new_month + 12) % 12;
15363 // For magnitudes >1, move one month at a time...
15364 for (var i=0; i<mag; i++)
15365 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15366 new_date = this.moveMonth(new_date, dir);
15367 // ...then reset the day, keeping it in the new month
15368 new_month = new_date.getUTCMonth();
15369 new_date.setUTCDate(day);
15371 return new_month != new_date.getUTCMonth();
15374 // Common date-resetting loop -- if date is beyond end of month, make it
15377 new_date.setUTCDate(--day);
15378 new_date.setUTCMonth(new_month);
15383 moveYear: function(date, dir)
15385 return this.moveMonth(date, dir*12);
15388 dateWithinRange: function(date)
15390 return date >= this.startDate && date <= this.endDate;
15396 this.picker().remove();
15401 Roo.apply(Roo.bootstrap.DateField, {
15412 html: '<i class="fa fa-arrow-left"/>'
15422 html: '<i class="fa fa-arrow-right"/>'
15464 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15465 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15466 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15467 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15468 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15481 navFnc: 'FullYear',
15486 navFnc: 'FullYear',
15491 Roo.apply(Roo.bootstrap.DateField, {
15495 cls: 'datepicker dropdown-menu roo-dynamic',
15499 cls: 'datepicker-days',
15503 cls: 'table-condensed',
15505 Roo.bootstrap.DateField.head,
15509 Roo.bootstrap.DateField.footer
15516 cls: 'datepicker-months',
15520 cls: 'table-condensed',
15522 Roo.bootstrap.DateField.head,
15523 Roo.bootstrap.DateField.content,
15524 Roo.bootstrap.DateField.footer
15531 cls: 'datepicker-years',
15535 cls: 'table-condensed',
15537 Roo.bootstrap.DateField.head,
15538 Roo.bootstrap.DateField.content,
15539 Roo.bootstrap.DateField.footer
15558 * @class Roo.bootstrap.TimeField
15559 * @extends Roo.bootstrap.Input
15560 * Bootstrap DateField class
15564 * Create a new TimeField
15565 * @param {Object} config The config object
15568 Roo.bootstrap.TimeField = function(config){
15569 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15573 * Fires when this field show.
15574 * @param {Roo.bootstrap.DateField} this
15575 * @param {Mixed} date The date value
15580 * Fires when this field hide.
15581 * @param {Roo.bootstrap.DateField} this
15582 * @param {Mixed} date The date value
15587 * Fires when select a date.
15588 * @param {Roo.bootstrap.DateField} this
15589 * @param {Mixed} date The date value
15595 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15598 * @cfg {String} format
15599 * The default time format string which can be overriden for localization support. The format must be
15600 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15604 onRender: function(ct, position)
15607 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15609 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15611 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15613 this.pop = this.picker().select('>.datepicker-time',true).first();
15614 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15616 this.picker().on('mousedown', this.onMousedown, this);
15617 this.picker().on('click', this.onClick, this);
15619 this.picker().addClass('datepicker-dropdown');
15624 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15625 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15626 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15627 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15628 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15629 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15633 fireKey: function(e){
15634 if (!this.picker().isVisible()){
15635 if (e.keyCode == 27) // allow escape to hide and re-show picker
15640 e.preventDefault();
15648 this.onTogglePeriod();
15651 this.onIncrementMinutes();
15654 this.onDecrementMinutes();
15663 onClick: function(e) {
15664 e.stopPropagation();
15665 e.preventDefault();
15668 picker : function()
15670 return this.el.select('.datepicker', true).first();
15673 fillTime: function()
15675 var time = this.pop.select('tbody', true).first();
15677 time.dom.innerHTML = '';
15692 cls: 'hours-up glyphicon glyphicon-chevron-up'
15712 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15733 cls: 'timepicker-hour',
15748 cls: 'timepicker-minute',
15763 cls: 'btn btn-primary period',
15785 cls: 'hours-down glyphicon glyphicon-chevron-down'
15805 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15823 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15830 var hours = this.time.getHours();
15831 var minutes = this.time.getMinutes();
15844 hours = hours - 12;
15848 hours = '0' + hours;
15852 minutes = '0' + minutes;
15855 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15856 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15857 this.pop.select('button', true).first().dom.innerHTML = period;
15863 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15865 var cls = ['bottom'];
15867 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15874 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15879 this.picker().addClass(cls.join('-'));
15883 Roo.each(cls, function(c){
15885 _this.picker().setTop(_this.inputEl().getHeight());
15889 _this.picker().setTop(0 - _this.picker().getHeight());
15894 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15898 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15905 onFocus : function()
15907 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15911 onBlur : function()
15913 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15919 this.picker().show();
15924 this.fireEvent('show', this, this.date);
15929 this.picker().hide();
15932 this.fireEvent('hide', this, this.date);
15935 setTime : function()
15938 this.setValue(this.time.format(this.format));
15940 this.fireEvent('select', this, this.date);
15945 onMousedown: function(e){
15946 e.stopPropagation();
15947 e.preventDefault();
15950 onIncrementHours: function()
15952 Roo.log('onIncrementHours');
15953 this.time = this.time.add(Date.HOUR, 1);
15958 onDecrementHours: function()
15960 Roo.log('onDecrementHours');
15961 this.time = this.time.add(Date.HOUR, -1);
15965 onIncrementMinutes: function()
15967 Roo.log('onIncrementMinutes');
15968 this.time = this.time.add(Date.MINUTE, 1);
15972 onDecrementMinutes: function()
15974 Roo.log('onDecrementMinutes');
15975 this.time = this.time.add(Date.MINUTE, -1);
15979 onTogglePeriod: function()
15981 Roo.log('onTogglePeriod');
15982 this.time = this.time.add(Date.HOUR, 12);
15989 Roo.apply(Roo.bootstrap.TimeField, {
16019 cls: 'btn btn-info ok',
16031 Roo.apply(Roo.bootstrap.TimeField, {
16035 cls: 'datepicker dropdown-menu',
16039 cls: 'datepicker-time',
16043 cls: 'table-condensed',
16045 Roo.bootstrap.TimeField.content,
16046 Roo.bootstrap.TimeField.footer
16065 * @class Roo.bootstrap.CheckBox
16066 * @extends Roo.bootstrap.Input
16067 * Bootstrap CheckBox class
16069 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16070 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16071 * @cfg {String} boxLabel The text that appears beside the checkbox
16072 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16073 * @cfg {Boolean} checked initnal the element
16074 * @cfg {Boolean} inline inline the element (default false)
16077 * Create a new CheckBox
16078 * @param {Object} config The config object
16081 Roo.bootstrap.CheckBox = function(config){
16082 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16087 * Fires when the element is checked or unchecked.
16088 * @param {Roo.bootstrap.CheckBox} this This input
16089 * @param {Boolean} checked The new checked value
16095 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16097 inputType: 'checkbox',
16105 getAutoCreate : function()
16107 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16113 cfg.cls = 'form-group ' + this.inputType //input-group
16116 cfg.cls += ' ' + this.inputType + '-inline';
16122 type : this.inputType,
16123 value : (!this.checked) ? this.valueOff : this.inputValue,
16124 cls : 'roo-' + this.inputType, //'form-box',
16125 placeholder : this.placeholder || ''
16129 if (this.weight) { // Validity check?
16130 cfg.cls += " " + this.inputType + "-" + this.weight;
16133 if (this.disabled) {
16134 input.disabled=true;
16138 input.checked = this.checked;
16142 input.name = this.name;
16146 input.cls += ' input-' + this.size;
16150 ['xs','sm','md','lg'].map(function(size){
16151 if (settings[size]) {
16152 cfg.cls += ' col-' + size + '-' + settings[size];
16158 var inputblock = input;
16163 if (this.before || this.after) {
16166 cls : 'input-group',
16170 inputblock.cn.push({
16172 cls : 'input-group-addon',
16176 inputblock.cn.push(input);
16178 inputblock.cn.push({
16180 cls : 'input-group-addon',
16187 if (align ==='left' && this.fieldLabel.length) {
16188 Roo.log("left and has label");
16194 cls : 'control-label col-md-' + this.labelWidth,
16195 html : this.fieldLabel
16199 cls : "col-md-" + (12 - this.labelWidth),
16206 } else if ( this.fieldLabel.length) {
16211 tag: this.boxLabel ? 'span' : 'label',
16213 cls: 'control-label box-input-label',
16214 //cls : 'input-group-addon',
16215 html : this.fieldLabel
16225 Roo.log(" no label && no align");
16226 cfg.cn = [ inputblock ] ;
16233 //'for': id, // box label is handled by onclick - so no for...
16235 html: this.boxLabel
16247 * return the real input element.
16249 inputEl: function ()
16251 return this.el.select('input.roo-' + this.inputType,true).first();
16254 labelEl: function()
16256 return this.el.select('label.control-label',true).first();
16258 /* depricated... */
16262 return this.labelEl();
16265 initEvents : function()
16267 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16269 this.inputEl().on('click', this.onClick, this);
16270 if (this.boxLabel) {
16271 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16276 onClick : function()
16278 this.setChecked(!this.checked);
16281 setChecked : function(state,suppressEvent)
16283 if(this.inputType == 'radio'){
16285 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16286 e.dom.checked = false;
16289 this.inputEl().dom.checked = true;
16291 if(suppressEvent !== true){
16292 this.fireEvent('check', this, true);
16295 this.inputEl().dom.value = this.inputValue;
16300 this.checked = state;
16302 if(suppressEvent !== true){
16303 this.fireEvent('check', this, state);
16306 this.inputEl().dom.checked = state;
16308 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16312 getValue : function()
16314 if(this.inputType == 'radio'){
16315 return this.getGroupValue();
16318 return this.inputEl().getValue();
16322 getGroupValue : function()
16324 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16327 setValue : function(v,suppressEvent)
16329 if(this.inputType == 'radio'){
16330 this.setGroupValue(v, suppressEvent);
16334 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16337 setGroupValue : function(v, suppressEvent)
16339 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16340 e.dom.checked = false;
16342 if(e.dom.value == v){
16343 e.dom.checked = true;
16347 if(suppressEvent !== true){
16348 this.fireEvent('check', this, true);
16365 * @class Roo.bootstrap.Radio
16366 * @extends Roo.bootstrap.CheckBox
16367 * Bootstrap Radio class
16370 * Create a new Radio
16371 * @param {Object} config The config object
16374 Roo.bootstrap.Radio = function(config){
16375 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16379 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16381 inputType: 'radio',
16385 getAutoCreate : function()
16387 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16393 cfg.cls = 'form-group radio' //input-group
16398 type : this.inputType,
16399 //value : (!this.checked) ? this.valueOff : this.inputValue,
16400 value : this.inputValue,
16402 placeholder : this.placeholder || ''
16405 if (this.weight) { // Validity check?
16406 cfg.cls += " radio-" + this.weight;
16408 if (this.disabled) {
16409 input.disabled=true;
16413 input.checked = this.checked;
16417 input.name = this.name;
16421 input.cls += ' input-' + this.size;
16425 ['xs','sm','md','lg'].map(function(size){
16426 if (settings[size]) {
16427 cfg.cls += ' col-' + size + '-' + settings[size];
16431 var inputblock = input;
16433 if (this.before || this.after) {
16436 cls : 'input-group',
16440 inputblock.cn.push({
16442 cls : 'input-group-addon',
16446 inputblock.cn.push(input);
16448 inputblock.cn.push({
16450 cls : 'input-group-addon',
16457 if (align ==='left' && this.fieldLabel.length) {
16458 Roo.log("left and has label");
16464 cls : 'control-label col-md-' + this.labelWidth,
16465 html : this.fieldLabel
16469 cls : "col-md-" + (12 - this.labelWidth),
16476 } else if ( this.fieldLabel.length) {
16483 cls: 'control-label box-input-label',
16484 //cls : 'input-group-addon',
16485 html : this.fieldLabel
16495 Roo.log(" no label && no align");
16510 html: this.boxLabel
16517 inputEl: function ()
16519 return this.el.select('input.roo-radio',true).first();
16521 onClick : function()
16525 this.setChecked(true);
16528 setChecked : function(state,suppressEvent)
16531 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16532 v.dom.checked = false;
16536 this.checked = state;
16537 this.inputEl().dom.checked = state;
16539 if(suppressEvent !== true){
16540 this.fireEvent('check', this, state);
16543 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16547 getGroupValue : function()
16550 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16551 if(v.dom.checked == true){
16552 value = v.dom.value;
16560 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16561 * @return {Mixed} value The field value
16563 getValue : function(){
16564 return this.getGroupValue();
16570 //<script type="text/javascript">
16573 * Based Ext JS Library 1.1.1
16574 * Copyright(c) 2006-2007, Ext JS, LLC.
16580 * @class Roo.HtmlEditorCore
16581 * @extends Roo.Component
16582 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16584 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16587 Roo.HtmlEditorCore = function(config){
16590 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16595 * @event initialize
16596 * Fires when the editor is fully initialized (including the iframe)
16597 * @param {Roo.HtmlEditorCore} this
16602 * Fires when the editor is first receives the focus. Any insertion must wait
16603 * until after this event.
16604 * @param {Roo.HtmlEditorCore} this
16608 * @event beforesync
16609 * Fires before the textarea is updated with content from the editor iframe. Return false
16610 * to cancel the sync.
16611 * @param {Roo.HtmlEditorCore} this
16612 * @param {String} html
16616 * @event beforepush
16617 * Fires before the iframe editor is updated with content from the textarea. Return false
16618 * to cancel the push.
16619 * @param {Roo.HtmlEditorCore} this
16620 * @param {String} html
16625 * Fires when the textarea is updated with content from the editor iframe.
16626 * @param {Roo.HtmlEditorCore} this
16627 * @param {String} html
16632 * Fires when the iframe editor is updated with content from the textarea.
16633 * @param {Roo.HtmlEditorCore} this
16634 * @param {String} html
16639 * @event editorevent
16640 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16641 * @param {Roo.HtmlEditorCore} this
16646 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16648 // defaults : white / black...
16649 this.applyBlacklists();
16656 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16660 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16666 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16671 * @cfg {Number} height (in pixels)
16675 * @cfg {Number} width (in pixels)
16680 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16683 stylesheets: false,
16688 // private properties
16689 validationEvent : false,
16691 initialized : false,
16693 sourceEditMode : false,
16694 onFocus : Roo.emptyFn,
16696 hideMode:'offsets',
16700 // blacklist + whitelisted elements..
16707 * Protected method that will not generally be called directly. It
16708 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16709 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16711 getDocMarkup : function(){
16714 Roo.log(this.stylesheets);
16716 // inherit styels from page...??
16717 if (this.stylesheets === false) {
16719 Roo.get(document.head).select('style').each(function(node) {
16720 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16723 Roo.get(document.head).select('link').each(function(node) {
16724 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16727 } else if (!this.stylesheets.length) {
16729 st = '<style type="text/css">' +
16730 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16733 Roo.each(this.stylesheets, function(s) {
16734 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16739 st += '<style type="text/css">' +
16740 'IMG { cursor: pointer } ' +
16744 return '<html><head>' + st +
16745 //<style type="text/css">' +
16746 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16748 ' </head><body class="roo-htmleditor-body"></body></html>';
16752 onRender : function(ct, position)
16755 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16756 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16759 this.el.dom.style.border = '0 none';
16760 this.el.dom.setAttribute('tabIndex', -1);
16761 this.el.addClass('x-hidden hide');
16765 if(Roo.isIE){ // fix IE 1px bogus margin
16766 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16770 this.frameId = Roo.id();
16774 var iframe = this.owner.wrap.createChild({
16776 cls: 'form-control', // bootstrap..
16778 name: this.frameId,
16779 frameBorder : 'no',
16780 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16785 this.iframe = iframe.dom;
16787 this.assignDocWin();
16789 this.doc.designMode = 'on';
16792 this.doc.write(this.getDocMarkup());
16796 var task = { // must defer to wait for browser to be ready
16798 //console.log("run task?" + this.doc.readyState);
16799 this.assignDocWin();
16800 if(this.doc.body || this.doc.readyState == 'complete'){
16802 this.doc.designMode="on";
16806 Roo.TaskMgr.stop(task);
16807 this.initEditor.defer(10, this);
16814 Roo.TaskMgr.start(task);
16821 onResize : function(w, h)
16823 Roo.log('resize: ' +w + ',' + h );
16824 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16828 if(typeof w == 'number'){
16830 this.iframe.style.width = w + 'px';
16832 if(typeof h == 'number'){
16834 this.iframe.style.height = h + 'px';
16836 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16843 * Toggles the editor between standard and source edit mode.
16844 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16846 toggleSourceEdit : function(sourceEditMode){
16848 this.sourceEditMode = sourceEditMode === true;
16850 if(this.sourceEditMode){
16852 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16855 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16856 //this.iframe.className = '';
16859 //this.setSize(this.owner.wrap.getSize());
16860 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16867 * Protected method that will not generally be called directly. If you need/want
16868 * custom HTML cleanup, this is the method you should override.
16869 * @param {String} html The HTML to be cleaned
16870 * return {String} The cleaned HTML
16872 cleanHtml : function(html){
16873 html = String(html);
16874 if(html.length > 5){
16875 if(Roo.isSafari){ // strip safari nonsense
16876 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16879 if(html == ' '){
16886 * HTML Editor -> Textarea
16887 * Protected method that will not generally be called directly. Syncs the contents
16888 * of the editor iframe with the textarea.
16890 syncValue : function(){
16891 if(this.initialized){
16892 var bd = (this.doc.body || this.doc.documentElement);
16893 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16894 var html = bd.innerHTML;
16896 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16897 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16899 html = '<div style="'+m[0]+'">' + html + '</div>';
16902 html = this.cleanHtml(html);
16903 // fix up the special chars.. normaly like back quotes in word...
16904 // however we do not want to do this with chinese..
16905 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16906 var cc = b.charCodeAt();
16908 (cc >= 0x4E00 && cc < 0xA000 ) ||
16909 (cc >= 0x3400 && cc < 0x4E00 ) ||
16910 (cc >= 0xf900 && cc < 0xfb00 )
16916 if(this.owner.fireEvent('beforesync', this, html) !== false){
16917 this.el.dom.value = html;
16918 this.owner.fireEvent('sync', this, html);
16924 * Protected method that will not generally be called directly. Pushes the value of the textarea
16925 * into the iframe editor.
16927 pushValue : function(){
16928 if(this.initialized){
16929 var v = this.el.dom.value.trim();
16931 // if(v.length < 1){
16935 if(this.owner.fireEvent('beforepush', this, v) !== false){
16936 var d = (this.doc.body || this.doc.documentElement);
16938 this.cleanUpPaste();
16939 this.el.dom.value = d.innerHTML;
16940 this.owner.fireEvent('push', this, v);
16946 deferFocus : function(){
16947 this.focus.defer(10, this);
16951 focus : function(){
16952 if(this.win && !this.sourceEditMode){
16959 assignDocWin: function()
16961 var iframe = this.iframe;
16964 this.doc = iframe.contentWindow.document;
16965 this.win = iframe.contentWindow;
16967 // if (!Roo.get(this.frameId)) {
16970 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16971 // this.win = Roo.get(this.frameId).dom.contentWindow;
16973 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16977 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16978 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16983 initEditor : function(){
16984 //console.log("INIT EDITOR");
16985 this.assignDocWin();
16989 this.doc.designMode="on";
16991 this.doc.write(this.getDocMarkup());
16994 var dbody = (this.doc.body || this.doc.documentElement);
16995 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16996 // this copies styles from the containing element into thsi one..
16997 // not sure why we need all of this..
16998 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17000 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17001 //ss['background-attachment'] = 'fixed'; // w3c
17002 dbody.bgProperties = 'fixed'; // ie
17003 //Roo.DomHelper.applyStyles(dbody, ss);
17004 Roo.EventManager.on(this.doc, {
17005 //'mousedown': this.onEditorEvent,
17006 'mouseup': this.onEditorEvent,
17007 'dblclick': this.onEditorEvent,
17008 'click': this.onEditorEvent,
17009 'keyup': this.onEditorEvent,
17014 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17016 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17017 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17019 this.initialized = true;
17021 this.owner.fireEvent('initialize', this);
17026 onDestroy : function(){
17032 //for (var i =0; i < this.toolbars.length;i++) {
17033 // // fixme - ask toolbars for heights?
17034 // this.toolbars[i].onDestroy();
17037 //this.wrap.dom.innerHTML = '';
17038 //this.wrap.remove();
17043 onFirstFocus : function(){
17045 this.assignDocWin();
17048 this.activated = true;
17051 if(Roo.isGecko){ // prevent silly gecko errors
17053 var s = this.win.getSelection();
17054 if(!s.focusNode || s.focusNode.nodeType != 3){
17055 var r = s.getRangeAt(0);
17056 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17061 this.execCmd('useCSS', true);
17062 this.execCmd('styleWithCSS', false);
17065 this.owner.fireEvent('activate', this);
17069 adjustFont: function(btn){
17070 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17071 //if(Roo.isSafari){ // safari
17074 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17075 if(Roo.isSafari){ // safari
17076 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17077 v = (v < 10) ? 10 : v;
17078 v = (v > 48) ? 48 : v;
17079 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17084 v = Math.max(1, v+adjust);
17086 this.execCmd('FontSize', v );
17089 onEditorEvent : function(e){
17090 this.owner.fireEvent('editorevent', this, e);
17091 // this.updateToolbar();
17092 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17095 insertTag : function(tg)
17097 // could be a bit smarter... -> wrap the current selected tRoo..
17098 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17100 range = this.createRange(this.getSelection());
17101 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17102 wrappingNode.appendChild(range.extractContents());
17103 range.insertNode(wrappingNode);
17110 this.execCmd("formatblock", tg);
17114 insertText : function(txt)
17118 var range = this.createRange();
17119 range.deleteContents();
17120 //alert(Sender.getAttribute('label'));
17122 range.insertNode(this.doc.createTextNode(txt));
17128 * Executes a Midas editor command on the editor document and performs necessary focus and
17129 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17130 * @param {String} cmd The Midas command
17131 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17133 relayCmd : function(cmd, value){
17135 this.execCmd(cmd, value);
17136 this.owner.fireEvent('editorevent', this);
17137 //this.updateToolbar();
17138 this.owner.deferFocus();
17142 * Executes a Midas editor command directly on the editor document.
17143 * For visual commands, you should use {@link #relayCmd} instead.
17144 * <b>This should only be called after the editor is initialized.</b>
17145 * @param {String} cmd The Midas command
17146 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17148 execCmd : function(cmd, value){
17149 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17156 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17158 * @param {String} text | dom node..
17160 insertAtCursor : function(text)
17165 if(!this.activated){
17171 var r = this.doc.selection.createRange();
17182 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17186 // from jquery ui (MIT licenced)
17188 var win = this.win;
17190 if (win.getSelection && win.getSelection().getRangeAt) {
17191 range = win.getSelection().getRangeAt(0);
17192 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17193 range.insertNode(node);
17194 } else if (win.document.selection && win.document.selection.createRange) {
17195 // no firefox support
17196 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17197 win.document.selection.createRange().pasteHTML(txt);
17199 // no firefox support
17200 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17201 this.execCmd('InsertHTML', txt);
17210 mozKeyPress : function(e){
17212 var c = e.getCharCode(), cmd;
17215 c = String.fromCharCode(c).toLowerCase();
17229 this.cleanUpPaste.defer(100, this);
17237 e.preventDefault();
17245 fixKeys : function(){ // load time branching for fastest keydown performance
17247 return function(e){
17248 var k = e.getKey(), r;
17251 r = this.doc.selection.createRange();
17254 r.pasteHTML('    ');
17261 r = this.doc.selection.createRange();
17263 var target = r.parentElement();
17264 if(!target || target.tagName.toLowerCase() != 'li'){
17266 r.pasteHTML('<br />');
17272 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17273 this.cleanUpPaste.defer(100, this);
17279 }else if(Roo.isOpera){
17280 return function(e){
17281 var k = e.getKey();
17285 this.execCmd('InsertHTML','    ');
17288 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17289 this.cleanUpPaste.defer(100, this);
17294 }else if(Roo.isSafari){
17295 return function(e){
17296 var k = e.getKey();
17300 this.execCmd('InsertText','\t');
17304 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17305 this.cleanUpPaste.defer(100, this);
17313 getAllAncestors: function()
17315 var p = this.getSelectedNode();
17318 a.push(p); // push blank onto stack..
17319 p = this.getParentElement();
17323 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17327 a.push(this.doc.body);
17331 lastSelNode : false,
17334 getSelection : function()
17336 this.assignDocWin();
17337 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17340 getSelectedNode: function()
17342 // this may only work on Gecko!!!
17344 // should we cache this!!!!
17349 var range = this.createRange(this.getSelection()).cloneRange();
17352 var parent = range.parentElement();
17354 var testRange = range.duplicate();
17355 testRange.moveToElementText(parent);
17356 if (testRange.inRange(range)) {
17359 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17362 parent = parent.parentElement;
17367 // is ancestor a text element.
17368 var ac = range.commonAncestorContainer;
17369 if (ac.nodeType == 3) {
17370 ac = ac.parentNode;
17373 var ar = ac.childNodes;
17376 var other_nodes = [];
17377 var has_other_nodes = false;
17378 for (var i=0;i<ar.length;i++) {
17379 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17382 // fullly contained node.
17384 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17389 // probably selected..
17390 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17391 other_nodes.push(ar[i]);
17395 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17400 has_other_nodes = true;
17402 if (!nodes.length && other_nodes.length) {
17403 nodes= other_nodes;
17405 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17411 createRange: function(sel)
17413 // this has strange effects when using with
17414 // top toolbar - not sure if it's a great idea.
17415 //this.editor.contentWindow.focus();
17416 if (typeof sel != "undefined") {
17418 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17420 return this.doc.createRange();
17423 return this.doc.createRange();
17426 getParentElement: function()
17429 this.assignDocWin();
17430 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17432 var range = this.createRange(sel);
17435 var p = range.commonAncestorContainer;
17436 while (p.nodeType == 3) { // text node
17447 * Range intersection.. the hard stuff...
17451 * [ -- selected range --- ]
17455 * if end is before start or hits it. fail.
17456 * if start is after end or hits it fail.
17458 * if either hits (but other is outside. - then it's not
17464 // @see http://www.thismuchiknow.co.uk/?p=64.
17465 rangeIntersectsNode : function(range, node)
17467 var nodeRange = node.ownerDocument.createRange();
17469 nodeRange.selectNode(node);
17471 nodeRange.selectNodeContents(node);
17474 var rangeStartRange = range.cloneRange();
17475 rangeStartRange.collapse(true);
17477 var rangeEndRange = range.cloneRange();
17478 rangeEndRange.collapse(false);
17480 var nodeStartRange = nodeRange.cloneRange();
17481 nodeStartRange.collapse(true);
17483 var nodeEndRange = nodeRange.cloneRange();
17484 nodeEndRange.collapse(false);
17486 return rangeStartRange.compareBoundaryPoints(
17487 Range.START_TO_START, nodeEndRange) == -1 &&
17488 rangeEndRange.compareBoundaryPoints(
17489 Range.START_TO_START, nodeStartRange) == 1;
17493 rangeCompareNode : function(range, node)
17495 var nodeRange = node.ownerDocument.createRange();
17497 nodeRange.selectNode(node);
17499 nodeRange.selectNodeContents(node);
17503 range.collapse(true);
17505 nodeRange.collapse(true);
17507 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17508 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17510 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17512 var nodeIsBefore = ss == 1;
17513 var nodeIsAfter = ee == -1;
17515 if (nodeIsBefore && nodeIsAfter)
17517 if (!nodeIsBefore && nodeIsAfter)
17518 return 1; //right trailed.
17520 if (nodeIsBefore && !nodeIsAfter)
17521 return 2; // left trailed.
17526 // private? - in a new class?
17527 cleanUpPaste : function()
17529 // cleans up the whole document..
17530 Roo.log('cleanuppaste');
17532 this.cleanUpChildren(this.doc.body);
17533 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17534 if (clean != this.doc.body.innerHTML) {
17535 this.doc.body.innerHTML = clean;
17540 cleanWordChars : function(input) {// change the chars to hex code
17541 var he = Roo.HtmlEditorCore;
17543 var output = input;
17544 Roo.each(he.swapCodes, function(sw) {
17545 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17547 output = output.replace(swapper, sw[1]);
17554 cleanUpChildren : function (n)
17556 if (!n.childNodes.length) {
17559 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17560 this.cleanUpChild(n.childNodes[i]);
17567 cleanUpChild : function (node)
17570 //console.log(node);
17571 if (node.nodeName == "#text") {
17572 // clean up silly Windows -- stuff?
17575 if (node.nodeName == "#comment") {
17576 node.parentNode.removeChild(node);
17577 // clean up silly Windows -- stuff?
17580 var lcname = node.tagName.toLowerCase();
17581 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17582 // whitelist of tags..
17584 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17586 node.parentNode.removeChild(node);
17591 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17593 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17594 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17596 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17597 // remove_keep_children = true;
17600 if (remove_keep_children) {
17601 this.cleanUpChildren(node);
17602 // inserts everything just before this node...
17603 while (node.childNodes.length) {
17604 var cn = node.childNodes[0];
17605 node.removeChild(cn);
17606 node.parentNode.insertBefore(cn, node);
17608 node.parentNode.removeChild(node);
17612 if (!node.attributes || !node.attributes.length) {
17613 this.cleanUpChildren(node);
17617 function cleanAttr(n,v)
17620 if (v.match(/^\./) || v.match(/^\//)) {
17623 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17626 if (v.match(/^#/)) {
17629 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17630 node.removeAttribute(n);
17634 var cwhite = this.cwhite;
17635 var cblack = this.cblack;
17637 function cleanStyle(n,v)
17639 if (v.match(/expression/)) { //XSS?? should we even bother..
17640 node.removeAttribute(n);
17644 var parts = v.split(/;/);
17647 Roo.each(parts, function(p) {
17648 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17652 var l = p.split(':').shift().replace(/\s+/g,'');
17653 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17655 if ( cwhite.length && cblack.indexOf(l) > -1) {
17656 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17657 //node.removeAttribute(n);
17661 // only allow 'c whitelisted system attributes'
17662 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17663 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17664 //node.removeAttribute(n);
17674 if (clean.length) {
17675 node.setAttribute(n, clean.join(';'));
17677 node.removeAttribute(n);
17683 for (var i = node.attributes.length-1; i > -1 ; i--) {
17684 var a = node.attributes[i];
17687 if (a.name.toLowerCase().substr(0,2)=='on') {
17688 node.removeAttribute(a.name);
17691 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17692 node.removeAttribute(a.name);
17695 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17696 cleanAttr(a.name,a.value); // fixme..
17699 if (a.name == 'style') {
17700 cleanStyle(a.name,a.value);
17703 /// clean up MS crap..
17704 // tecnically this should be a list of valid class'es..
17707 if (a.name == 'class') {
17708 if (a.value.match(/^Mso/)) {
17709 node.className = '';
17712 if (a.value.match(/body/)) {
17713 node.className = '';
17724 this.cleanUpChildren(node);
17729 * Clean up MS wordisms...
17731 cleanWord : function(node)
17734 var cleanWordChildren = function()
17736 if (!node.childNodes.length) {
17739 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17740 _t.cleanWord(node.childNodes[i]);
17746 this.cleanWord(this.doc.body);
17749 if (node.nodeName == "#text") {
17750 // clean up silly Windows -- stuff?
17753 if (node.nodeName == "#comment") {
17754 node.parentNode.removeChild(node);
17755 // clean up silly Windows -- stuff?
17759 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17760 node.parentNode.removeChild(node);
17764 // remove - but keep children..
17765 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17766 while (node.childNodes.length) {
17767 var cn = node.childNodes[0];
17768 node.removeChild(cn);
17769 node.parentNode.insertBefore(cn, node);
17771 node.parentNode.removeChild(node);
17772 cleanWordChildren();
17776 if (node.className.length) {
17778 var cn = node.className.split(/\W+/);
17780 Roo.each(cn, function(cls) {
17781 if (cls.match(/Mso[a-zA-Z]+/)) {
17786 node.className = cna.length ? cna.join(' ') : '';
17788 node.removeAttribute("class");
17792 if (node.hasAttribute("lang")) {
17793 node.removeAttribute("lang");
17796 if (node.hasAttribute("style")) {
17798 var styles = node.getAttribute("style").split(";");
17800 Roo.each(styles, function(s) {
17801 if (!s.match(/:/)) {
17804 var kv = s.split(":");
17805 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17808 // what ever is left... we allow.
17811 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17812 if (!nstyle.length) {
17813 node.removeAttribute('style');
17817 cleanWordChildren();
17821 domToHTML : function(currentElement, depth, nopadtext) {
17823 depth = depth || 0;
17824 nopadtext = nopadtext || false;
17826 if (!currentElement) {
17827 return this.domToHTML(this.doc.body);
17830 //Roo.log(currentElement);
17832 var allText = false;
17833 var nodeName = currentElement.nodeName;
17834 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17836 if (nodeName == '#text') {
17837 return currentElement.nodeValue;
17842 if (nodeName != 'BODY') {
17845 // Prints the node tagName, such as <A>, <IMG>, etc
17848 for(i = 0; i < currentElement.attributes.length;i++) {
17850 var aname = currentElement.attributes.item(i).name;
17851 if (!currentElement.attributes.item(i).value.length) {
17854 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17857 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17866 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17869 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17874 // Traverse the tree
17876 var currentElementChild = currentElement.childNodes.item(i);
17877 var allText = true;
17878 var innerHTML = '';
17880 while (currentElementChild) {
17881 // Formatting code (indent the tree so it looks nice on the screen)
17882 var nopad = nopadtext;
17883 if (lastnode == 'SPAN') {
17887 if (currentElementChild.nodeName == '#text') {
17888 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17889 if (!nopad && toadd.length > 80) {
17890 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17892 innerHTML += toadd;
17895 currentElementChild = currentElement.childNodes.item(i);
17901 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17903 // Recursively traverse the tree structure of the child node
17904 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17905 lastnode = currentElementChild.nodeName;
17907 currentElementChild=currentElement.childNodes.item(i);
17913 // The remaining code is mostly for formatting the tree
17914 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17919 ret+= "</"+tagName+">";
17925 applyBlacklists : function()
17927 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17928 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17932 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17933 if (b.indexOf(tag) > -1) {
17936 this.white.push(tag);
17940 Roo.each(w, function(tag) {
17941 if (b.indexOf(tag) > -1) {
17944 if (this.white.indexOf(tag) > -1) {
17947 this.white.push(tag);
17952 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17953 if (w.indexOf(tag) > -1) {
17956 this.black.push(tag);
17960 Roo.each(b, function(tag) {
17961 if (w.indexOf(tag) > -1) {
17964 if (this.black.indexOf(tag) > -1) {
17967 this.black.push(tag);
17972 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
17973 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
17977 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17978 if (b.indexOf(tag) > -1) {
17981 this.cwhite.push(tag);
17985 Roo.each(w, function(tag) {
17986 if (b.indexOf(tag) > -1) {
17989 if (this.cwhite.indexOf(tag) > -1) {
17992 this.cwhite.push(tag);
17997 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
17998 if (w.indexOf(tag) > -1) {
18001 this.cblack.push(tag);
18005 Roo.each(b, function(tag) {
18006 if (w.indexOf(tag) > -1) {
18009 if (this.cblack.indexOf(tag) > -1) {
18012 this.cblack.push(tag);
18017 // hide stuff that is not compatible
18031 * @event specialkey
18035 * @cfg {String} fieldClass @hide
18038 * @cfg {String} focusClass @hide
18041 * @cfg {String} autoCreate @hide
18044 * @cfg {String} inputType @hide
18047 * @cfg {String} invalidClass @hide
18050 * @cfg {String} invalidText @hide
18053 * @cfg {String} msgFx @hide
18056 * @cfg {String} validateOnBlur @hide
18060 Roo.HtmlEditorCore.white = [
18061 'area', 'br', 'img', 'input', 'hr', 'wbr',
18063 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18064 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18065 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18066 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18067 'table', 'ul', 'xmp',
18069 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18072 'dir', 'menu', 'ol', 'ul', 'dl',
18078 Roo.HtmlEditorCore.black = [
18079 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18081 'base', 'basefont', 'bgsound', 'blink', 'body',
18082 'frame', 'frameset', 'head', 'html', 'ilayer',
18083 'iframe', 'layer', 'link', 'meta', 'object',
18084 'script', 'style' ,'title', 'xml' // clean later..
18086 Roo.HtmlEditorCore.clean = [
18087 'script', 'style', 'title', 'xml'
18089 Roo.HtmlEditorCore.remove = [
18094 Roo.HtmlEditorCore.ablack = [
18098 Roo.HtmlEditorCore.aclean = [
18099 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18103 Roo.HtmlEditorCore.pwhite= [
18104 'http', 'https', 'mailto'
18107 // white listed style attributes.
18108 Roo.HtmlEditorCore.cwhite= [
18109 // 'text-align', /// default is to allow most things..
18115 // black listed style attributes.
18116 Roo.HtmlEditorCore.cblack= [
18117 // 'font-size' -- this can be set by the project
18121 Roo.HtmlEditorCore.swapCodes =[
18140 * @class Roo.bootstrap.HtmlEditor
18141 * @extends Roo.bootstrap.TextArea
18142 * Bootstrap HtmlEditor class
18145 * Create a new HtmlEditor
18146 * @param {Object} config The config object
18149 Roo.bootstrap.HtmlEditor = function(config){
18150 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18151 if (!this.toolbars) {
18152 this.toolbars = [];
18154 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18157 * @event initialize
18158 * Fires when the editor is fully initialized (including the iframe)
18159 * @param {HtmlEditor} this
18164 * Fires when the editor is first receives the focus. Any insertion must wait
18165 * until after this event.
18166 * @param {HtmlEditor} this
18170 * @event beforesync
18171 * Fires before the textarea is updated with content from the editor iframe. Return false
18172 * to cancel the sync.
18173 * @param {HtmlEditor} this
18174 * @param {String} html
18178 * @event beforepush
18179 * Fires before the iframe editor is updated with content from the textarea. Return false
18180 * to cancel the push.
18181 * @param {HtmlEditor} this
18182 * @param {String} html
18187 * Fires when the textarea is updated with content from the editor iframe.
18188 * @param {HtmlEditor} this
18189 * @param {String} html
18194 * Fires when the iframe editor is updated with content from the textarea.
18195 * @param {HtmlEditor} this
18196 * @param {String} html
18200 * @event editmodechange
18201 * Fires when the editor switches edit modes
18202 * @param {HtmlEditor} this
18203 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18205 editmodechange: true,
18207 * @event editorevent
18208 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18209 * @param {HtmlEditor} this
18213 * @event firstfocus
18214 * Fires when on first focus - needed by toolbars..
18215 * @param {HtmlEditor} this
18220 * Auto save the htmlEditor value as a file into Events
18221 * @param {HtmlEditor} this
18225 * @event savedpreview
18226 * preview the saved version of htmlEditor
18227 * @param {HtmlEditor} this
18234 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18238 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18243 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18248 * @cfg {Number} height (in pixels)
18252 * @cfg {Number} width (in pixels)
18257 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18260 stylesheets: false,
18265 // private properties
18266 validationEvent : false,
18268 initialized : false,
18271 onFocus : Roo.emptyFn,
18273 hideMode:'offsets',
18276 tbContainer : false,
18278 toolbarContainer :function() {
18279 return this.wrap.select('.x-html-editor-tb',true).first();
18283 * Protected method that will not generally be called directly. It
18284 * is called when the editor creates its toolbar. Override this method if you need to
18285 * add custom toolbar buttons.
18286 * @param {HtmlEditor} editor
18288 createToolbar : function(){
18290 Roo.log("create toolbars");
18292 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18293 this.toolbars[0].render(this.toolbarContainer());
18297 // if (!editor.toolbars || !editor.toolbars.length) {
18298 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18301 // for (var i =0 ; i < editor.toolbars.length;i++) {
18302 // editor.toolbars[i] = Roo.factory(
18303 // typeof(editor.toolbars[i]) == 'string' ?
18304 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18305 // Roo.bootstrap.HtmlEditor);
18306 // editor.toolbars[i].init(editor);
18312 onRender : function(ct, position)
18314 // Roo.log("Call onRender: " + this.xtype);
18316 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18318 this.wrap = this.inputEl().wrap({
18319 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18322 this.editorcore.onRender(ct, position);
18324 if (this.resizable) {
18325 this.resizeEl = new Roo.Resizable(this.wrap, {
18329 minHeight : this.height,
18330 height: this.height,
18331 handles : this.resizable,
18334 resize : function(r, w, h) {
18335 _t.onResize(w,h); // -something
18341 this.createToolbar(this);
18344 if(!this.width && this.resizable){
18345 this.setSize(this.wrap.getSize());
18347 if (this.resizeEl) {
18348 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18349 // should trigger onReize..
18355 onResize : function(w, h)
18357 Roo.log('resize: ' +w + ',' + h );
18358 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18362 if(this.inputEl() ){
18363 if(typeof w == 'number'){
18364 var aw = w - this.wrap.getFrameWidth('lr');
18365 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18368 if(typeof h == 'number'){
18369 var tbh = -11; // fixme it needs to tool bar size!
18370 for (var i =0; i < this.toolbars.length;i++) {
18371 // fixme - ask toolbars for heights?
18372 tbh += this.toolbars[i].el.getHeight();
18373 //if (this.toolbars[i].footer) {
18374 // tbh += this.toolbars[i].footer.el.getHeight();
18382 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18383 ah -= 5; // knock a few pixes off for look..
18384 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18388 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18389 this.editorcore.onResize(ew,eh);
18394 * Toggles the editor between standard and source edit mode.
18395 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18397 toggleSourceEdit : function(sourceEditMode)
18399 this.editorcore.toggleSourceEdit(sourceEditMode);
18401 if(this.editorcore.sourceEditMode){
18402 Roo.log('editor - showing textarea');
18405 // Roo.log(this.syncValue());
18407 this.inputEl().removeClass(['hide', 'x-hidden']);
18408 this.inputEl().dom.removeAttribute('tabIndex');
18409 this.inputEl().focus();
18411 Roo.log('editor - hiding textarea');
18413 // Roo.log(this.pushValue());
18416 this.inputEl().addClass(['hide', 'x-hidden']);
18417 this.inputEl().dom.setAttribute('tabIndex', -1);
18418 //this.deferFocus();
18421 if(this.resizable){
18422 this.setSize(this.wrap.getSize());
18425 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18428 // private (for BoxComponent)
18429 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18431 // private (for BoxComponent)
18432 getResizeEl : function(){
18436 // private (for BoxComponent)
18437 getPositionEl : function(){
18442 initEvents : function(){
18443 this.originalValue = this.getValue();
18447 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18450 // markInvalid : Roo.emptyFn,
18452 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18455 // clearInvalid : Roo.emptyFn,
18457 setValue : function(v){
18458 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18459 this.editorcore.pushValue();
18464 deferFocus : function(){
18465 this.focus.defer(10, this);
18469 focus : function(){
18470 this.editorcore.focus();
18476 onDestroy : function(){
18482 for (var i =0; i < this.toolbars.length;i++) {
18483 // fixme - ask toolbars for heights?
18484 this.toolbars[i].onDestroy();
18487 this.wrap.dom.innerHTML = '';
18488 this.wrap.remove();
18493 onFirstFocus : function(){
18494 //Roo.log("onFirstFocus");
18495 this.editorcore.onFirstFocus();
18496 for (var i =0; i < this.toolbars.length;i++) {
18497 this.toolbars[i].onFirstFocus();
18503 syncValue : function()
18505 this.editorcore.syncValue();
18508 pushValue : function()
18510 this.editorcore.pushValue();
18514 // hide stuff that is not compatible
18528 * @event specialkey
18532 * @cfg {String} fieldClass @hide
18535 * @cfg {String} focusClass @hide
18538 * @cfg {String} autoCreate @hide
18541 * @cfg {String} inputType @hide
18544 * @cfg {String} invalidClass @hide
18547 * @cfg {String} invalidText @hide
18550 * @cfg {String} msgFx @hide
18553 * @cfg {String} validateOnBlur @hide
18562 Roo.namespace('Roo.bootstrap.htmleditor');
18564 * @class Roo.bootstrap.HtmlEditorToolbar1
18569 new Roo.bootstrap.HtmlEditor({
18572 new Roo.bootstrap.HtmlEditorToolbar1({
18573 disable : { fonts: 1 , format: 1, ..., ... , ...],
18579 * @cfg {Object} disable List of elements to disable..
18580 * @cfg {Array} btns List of additional buttons.
18584 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18587 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18590 Roo.apply(this, config);
18592 // default disabled, based on 'good practice'..
18593 this.disable = this.disable || {};
18594 Roo.applyIf(this.disable, {
18597 specialElements : true
18599 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18601 this.editor = config.editor;
18602 this.editorcore = config.editor.editorcore;
18604 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18606 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18607 // dont call parent... till later.
18609 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18614 editorcore : false,
18619 "h1","h2","h3","h4","h5","h6",
18621 "abbr", "acronym", "address", "cite", "samp", "var",
18625 onRender : function(ct, position)
18627 // Roo.log("Call onRender: " + this.xtype);
18629 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18631 this.el.dom.style.marginBottom = '0';
18633 var editorcore = this.editorcore;
18634 var editor= this.editor;
18637 var btn = function(id,cmd , toggle, handler){
18639 var event = toggle ? 'toggle' : 'click';
18644 xns: Roo.bootstrap,
18647 enableToggle:toggle !== false,
18649 pressed : toggle ? false : null,
18652 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18653 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18662 xns: Roo.bootstrap,
18663 glyphicon : 'font',
18667 xns: Roo.bootstrap,
18671 Roo.each(this.formats, function(f) {
18672 style.menu.items.push({
18674 xns: Roo.bootstrap,
18675 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18680 editorcore.insertTag(this.tagname);
18687 children.push(style);
18690 btn('bold',false,true);
18691 btn('italic',false,true);
18692 btn('align-left', 'justifyleft',true);
18693 btn('align-center', 'justifycenter',true);
18694 btn('align-right' , 'justifyright',true);
18695 btn('link', false, false, function(btn) {
18696 //Roo.log("create link?");
18697 var url = prompt(this.createLinkText, this.defaultLinkValue);
18698 if(url && url != 'http:/'+'/'){
18699 this.editorcore.relayCmd('createlink', url);
18702 btn('list','insertunorderedlist',true);
18703 btn('pencil', false,true, function(btn){
18706 this.toggleSourceEdit(btn.pressed);
18712 xns: Roo.bootstrap,
18717 xns: Roo.bootstrap,
18722 cog.menu.items.push({
18724 xns: Roo.bootstrap,
18725 html : Clean styles,
18730 editorcore.insertTag(this.tagname);
18739 this.xtype = 'NavSimplebar';
18741 for(var i=0;i< children.length;i++) {
18743 this.buttons.add(this.addxtypeChild(children[i]));
18747 editor.on('editorevent', this.updateToolbar, this);
18749 onBtnClick : function(id)
18751 this.editorcore.relayCmd(id);
18752 this.editorcore.focus();
18756 * Protected method that will not generally be called directly. It triggers
18757 * a toolbar update by reading the markup state of the current selection in the editor.
18759 updateToolbar: function(){
18761 if(!this.editorcore.activated){
18762 this.editor.onFirstFocus(); // is this neeed?
18766 var btns = this.buttons;
18767 var doc = this.editorcore.doc;
18768 btns.get('bold').setActive(doc.queryCommandState('bold'));
18769 btns.get('italic').setActive(doc.queryCommandState('italic'));
18770 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18772 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18773 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18774 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18776 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18777 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18780 var ans = this.editorcore.getAllAncestors();
18781 if (this.formatCombo) {
18784 var store = this.formatCombo.store;
18785 this.formatCombo.setValue("");
18786 for (var i =0; i < ans.length;i++) {
18787 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18789 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18797 // hides menus... - so this cant be on a menu...
18798 Roo.bootstrap.MenuMgr.hideAll();
18800 Roo.bootstrap.MenuMgr.hideAll();
18801 //this.editorsyncValue();
18803 onFirstFocus: function() {
18804 this.buttons.each(function(item){
18808 toggleSourceEdit : function(sourceEditMode){
18811 if(sourceEditMode){
18812 Roo.log("disabling buttons");
18813 this.buttons.each( function(item){
18814 if(item.cmd != 'pencil'){
18820 Roo.log("enabling buttons");
18821 if(this.editorcore.initialized){
18822 this.buttons.each( function(item){
18828 Roo.log("calling toggole on editor");
18829 // tell the editor that it's been pressed..
18830 this.editor.toggleSourceEdit(sourceEditMode);
18840 * @class Roo.bootstrap.Table.AbstractSelectionModel
18841 * @extends Roo.util.Observable
18842 * Abstract base class for grid SelectionModels. It provides the interface that should be
18843 * implemented by descendant classes. This class should not be directly instantiated.
18846 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18847 this.locked = false;
18848 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18852 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18853 /** @ignore Called by the grid automatically. Do not call directly. */
18854 init : function(grid){
18860 * Locks the selections.
18863 this.locked = true;
18867 * Unlocks the selections.
18869 unlock : function(){
18870 this.locked = false;
18874 * Returns true if the selections are locked.
18875 * @return {Boolean}
18877 isLocked : function(){
18878 return this.locked;
18882 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18883 * @class Roo.bootstrap.Table.RowSelectionModel
18884 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18885 * It supports multiple selections and keyboard selection/navigation.
18887 * @param {Object} config
18890 Roo.bootstrap.Table.RowSelectionModel = function(config){
18891 Roo.apply(this, config);
18892 this.selections = new Roo.util.MixedCollection(false, function(o){
18897 this.lastActive = false;
18901 * @event selectionchange
18902 * Fires when the selection changes
18903 * @param {SelectionModel} this
18905 "selectionchange" : true,
18907 * @event afterselectionchange
18908 * Fires after the selection changes (eg. by key press or clicking)
18909 * @param {SelectionModel} this
18911 "afterselectionchange" : true,
18913 * @event beforerowselect
18914 * Fires when a row is selected being selected, return false to cancel.
18915 * @param {SelectionModel} this
18916 * @param {Number} rowIndex The selected index
18917 * @param {Boolean} keepExisting False if other selections will be cleared
18919 "beforerowselect" : true,
18922 * Fires when a row is selected.
18923 * @param {SelectionModel} this
18924 * @param {Number} rowIndex The selected index
18925 * @param {Roo.data.Record} r The record
18927 "rowselect" : true,
18929 * @event rowdeselect
18930 * Fires when a row is deselected.
18931 * @param {SelectionModel} this
18932 * @param {Number} rowIndex The selected index
18934 "rowdeselect" : true
18936 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18937 this.locked = false;
18940 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18942 * @cfg {Boolean} singleSelect
18943 * True to allow selection of only one row at a time (defaults to false)
18945 singleSelect : false,
18948 initEvents : function(){
18950 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18951 this.grid.on("mousedown", this.handleMouseDown, this);
18952 }else{ // allow click to work like normal
18953 this.grid.on("rowclick", this.handleDragableRowClick, this);
18956 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18957 "up" : function(e){
18959 this.selectPrevious(e.shiftKey);
18960 }else if(this.last !== false && this.lastActive !== false){
18961 var last = this.last;
18962 this.selectRange(this.last, this.lastActive-1);
18963 this.grid.getView().focusRow(this.lastActive);
18964 if(last !== false){
18968 this.selectFirstRow();
18970 this.fireEvent("afterselectionchange", this);
18972 "down" : function(e){
18974 this.selectNext(e.shiftKey);
18975 }else if(this.last !== false && this.lastActive !== false){
18976 var last = this.last;
18977 this.selectRange(this.last, this.lastActive+1);
18978 this.grid.getView().focusRow(this.lastActive);
18979 if(last !== false){
18983 this.selectFirstRow();
18985 this.fireEvent("afterselectionchange", this);
18990 var view = this.grid.view;
18991 view.on("refresh", this.onRefresh, this);
18992 view.on("rowupdated", this.onRowUpdated, this);
18993 view.on("rowremoved", this.onRemove, this);
18997 onRefresh : function(){
18998 var ds = this.grid.dataSource, i, v = this.grid.view;
18999 var s = this.selections;
19000 s.each(function(r){
19001 if((i = ds.indexOfId(r.id)) != -1){
19010 onRemove : function(v, index, r){
19011 this.selections.remove(r);
19015 onRowUpdated : function(v, index, r){
19016 if(this.isSelected(r)){
19017 v.onRowSelect(index);
19023 * @param {Array} records The records to select
19024 * @param {Boolean} keepExisting (optional) True to keep existing selections
19026 selectRecords : function(records, keepExisting){
19028 this.clearSelections();
19030 var ds = this.grid.dataSource;
19031 for(var i = 0, len = records.length; i < len; i++){
19032 this.selectRow(ds.indexOf(records[i]), true);
19037 * Gets the number of selected rows.
19040 getCount : function(){
19041 return this.selections.length;
19045 * Selects the first row in the grid.
19047 selectFirstRow : function(){
19052 * Select the last row.
19053 * @param {Boolean} keepExisting (optional) True to keep existing selections
19055 selectLastRow : function(keepExisting){
19056 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19060 * Selects the row immediately following the last selected row.
19061 * @param {Boolean} keepExisting (optional) True to keep existing selections
19063 selectNext : function(keepExisting){
19064 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19065 this.selectRow(this.last+1, keepExisting);
19066 this.grid.getView().focusRow(this.last);
19071 * Selects the row that precedes the last selected row.
19072 * @param {Boolean} keepExisting (optional) True to keep existing selections
19074 selectPrevious : function(keepExisting){
19076 this.selectRow(this.last-1, keepExisting);
19077 this.grid.getView().focusRow(this.last);
19082 * Returns the selected records
19083 * @return {Array} Array of selected records
19085 getSelections : function(){
19086 return [].concat(this.selections.items);
19090 * Returns the first selected record.
19093 getSelected : function(){
19094 return this.selections.itemAt(0);
19099 * Clears all selections.
19101 clearSelections : function(fast){
19102 if(this.locked) return;
19104 var ds = this.grid.dataSource;
19105 var s = this.selections;
19106 s.each(function(r){
19107 this.deselectRow(ds.indexOfId(r.id));
19111 this.selections.clear();
19118 * Selects all rows.
19120 selectAll : function(){
19121 if(this.locked) return;
19122 this.selections.clear();
19123 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19124 this.selectRow(i, true);
19129 * Returns True if there is a selection.
19130 * @return {Boolean}
19132 hasSelection : function(){
19133 return this.selections.length > 0;
19137 * Returns True if the specified row is selected.
19138 * @param {Number/Record} record The record or index of the record to check
19139 * @return {Boolean}
19141 isSelected : function(index){
19142 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19143 return (r && this.selections.key(r.id) ? true : false);
19147 * Returns True if the specified record id is selected.
19148 * @param {String} id The id of record to check
19149 * @return {Boolean}
19151 isIdSelected : function(id){
19152 return (this.selections.key(id) ? true : false);
19156 handleMouseDown : function(e, t){
19157 var view = this.grid.getView(), rowIndex;
19158 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19161 if(e.shiftKey && this.last !== false){
19162 var last = this.last;
19163 this.selectRange(last, rowIndex, e.ctrlKey);
19164 this.last = last; // reset the last
19165 view.focusRow(rowIndex);
19167 var isSelected = this.isSelected(rowIndex);
19168 if(e.button !== 0 && isSelected){
19169 view.focusRow(rowIndex);
19170 }else if(e.ctrlKey && isSelected){
19171 this.deselectRow(rowIndex);
19172 }else if(!isSelected){
19173 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19174 view.focusRow(rowIndex);
19177 this.fireEvent("afterselectionchange", this);
19180 handleDragableRowClick : function(grid, rowIndex, e)
19182 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19183 this.selectRow(rowIndex, false);
19184 grid.view.focusRow(rowIndex);
19185 this.fireEvent("afterselectionchange", this);
19190 * Selects multiple rows.
19191 * @param {Array} rows Array of the indexes of the row to select
19192 * @param {Boolean} keepExisting (optional) True to keep existing selections
19194 selectRows : function(rows, keepExisting){
19196 this.clearSelections();
19198 for(var i = 0, len = rows.length; i < len; i++){
19199 this.selectRow(rows[i], true);
19204 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19205 * @param {Number} startRow The index of the first row in the range
19206 * @param {Number} endRow The index of the last row in the range
19207 * @param {Boolean} keepExisting (optional) True to retain existing selections
19209 selectRange : function(startRow, endRow, keepExisting){
19210 if(this.locked) return;
19212 this.clearSelections();
19214 if(startRow <= endRow){
19215 for(var i = startRow; i <= endRow; i++){
19216 this.selectRow(i, true);
19219 for(var i = startRow; i >= endRow; i--){
19220 this.selectRow(i, true);
19226 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19227 * @param {Number} startRow The index of the first row in the range
19228 * @param {Number} endRow The index of the last row in the range
19230 deselectRange : function(startRow, endRow, preventViewNotify){
19231 if(this.locked) return;
19232 for(var i = startRow; i <= endRow; i++){
19233 this.deselectRow(i, preventViewNotify);
19239 * @param {Number} row The index of the row to select
19240 * @param {Boolean} keepExisting (optional) True to keep existing selections
19242 selectRow : function(index, keepExisting, preventViewNotify){
19243 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19244 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19245 if(!keepExisting || this.singleSelect){
19246 this.clearSelections();
19248 var r = this.grid.dataSource.getAt(index);
19249 this.selections.add(r);
19250 this.last = this.lastActive = index;
19251 if(!preventViewNotify){
19252 this.grid.getView().onRowSelect(index);
19254 this.fireEvent("rowselect", this, index, r);
19255 this.fireEvent("selectionchange", this);
19261 * @param {Number} row The index of the row to deselect
19263 deselectRow : function(index, preventViewNotify){
19264 if(this.locked) return;
19265 if(this.last == index){
19268 if(this.lastActive == index){
19269 this.lastActive = false;
19271 var r = this.grid.dataSource.getAt(index);
19272 this.selections.remove(r);
19273 if(!preventViewNotify){
19274 this.grid.getView().onRowDeselect(index);
19276 this.fireEvent("rowdeselect", this, index);
19277 this.fireEvent("selectionchange", this);
19281 restoreLast : function(){
19283 this.last = this._last;
19288 acceptsNav : function(row, col, cm){
19289 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19293 onEditorKey : function(field, e){
19294 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19299 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19301 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19303 }else if(k == e.ENTER && !e.ctrlKey){
19307 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19309 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19311 }else if(k == e.ESC){
19315 g.startEditing(newCell[0], newCell[1]);
19320 * Ext JS Library 1.1.1
19321 * Copyright(c) 2006-2007, Ext JS, LLC.
19323 * Originally Released Under LGPL - original licence link has changed is not relivant.
19326 * <script type="text/javascript">
19330 * @class Roo.bootstrap.PagingToolbar
19332 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19334 * Create a new PagingToolbar
19335 * @param {Object} config The config object
19337 Roo.bootstrap.PagingToolbar = function(config)
19339 // old args format still supported... - xtype is prefered..
19340 // created from xtype...
19341 var ds = config.dataSource;
19342 this.toolbarItems = [];
19343 if (config.items) {
19344 this.toolbarItems = config.items;
19345 // config.items = [];
19348 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19355 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19359 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19361 * @cfg {Roo.data.Store} dataSource
19362 * The underlying data store providing the paged data
19365 * @cfg {String/HTMLElement/Element} container
19366 * container The id or element that will contain the toolbar
19369 * @cfg {Boolean} displayInfo
19370 * True to display the displayMsg (defaults to false)
19373 * @cfg {Number} pageSize
19374 * The number of records to display per page (defaults to 20)
19378 * @cfg {String} displayMsg
19379 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19381 displayMsg : 'Displaying {0} - {1} of {2}',
19383 * @cfg {String} emptyMsg
19384 * The message to display when no records are found (defaults to "No data to display")
19386 emptyMsg : 'No data to display',
19388 * Customizable piece of the default paging text (defaults to "Page")
19391 beforePageText : "Page",
19393 * Customizable piece of the default paging text (defaults to "of %0")
19396 afterPageText : "of {0}",
19398 * Customizable piece of the default paging text (defaults to "First Page")
19401 firstText : "First Page",
19403 * Customizable piece of the default paging text (defaults to "Previous Page")
19406 prevText : "Previous Page",
19408 * Customizable piece of the default paging text (defaults to "Next Page")
19411 nextText : "Next Page",
19413 * Customizable piece of the default paging text (defaults to "Last Page")
19416 lastText : "Last Page",
19418 * Customizable piece of the default paging text (defaults to "Refresh")
19421 refreshText : "Refresh",
19425 onRender : function(ct, position)
19427 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19428 this.navgroup.parentId = this.id;
19429 this.navgroup.onRender(this.el, null);
19430 // add the buttons to the navgroup
19432 if(this.displayInfo){
19433 Roo.log(this.el.select('ul.navbar-nav',true).first());
19434 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19435 this.displayEl = this.el.select('.x-paging-info', true).first();
19436 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19437 // this.displayEl = navel.el.select('span',true).first();
19443 Roo.each(_this.buttons, function(e){
19444 Roo.factory(e).onRender(_this.el, null);
19448 Roo.each(_this.toolbarItems, function(e) {
19449 _this.navgroup.addItem(e);
19452 this.first = this.navgroup.addItem({
19453 tooltip: this.firstText,
19455 icon : 'fa fa-backward',
19457 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19460 this.prev = this.navgroup.addItem({
19461 tooltip: this.prevText,
19463 icon : 'fa fa-step-backward',
19465 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19467 //this.addSeparator();
19470 var field = this.navgroup.addItem( {
19472 cls : 'x-paging-position',
19474 html : this.beforePageText +
19475 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19476 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19479 this.field = field.el.select('input', true).first();
19480 this.field.on("keydown", this.onPagingKeydown, this);
19481 this.field.on("focus", function(){this.dom.select();});
19484 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19485 //this.field.setHeight(18);
19486 //this.addSeparator();
19487 this.next = this.navgroup.addItem({
19488 tooltip: this.nextText,
19490 html : ' <i class="fa fa-step-forward">',
19492 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19494 this.last = this.navgroup.addItem({
19495 tooltip: this.lastText,
19496 icon : 'fa fa-forward',
19499 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19501 //this.addSeparator();
19502 this.loading = this.navgroup.addItem({
19503 tooltip: this.refreshText,
19504 icon: 'fa fa-refresh',
19506 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19512 updateInfo : function(){
19513 if(this.displayEl){
19514 var count = this.ds.getCount();
19515 var msg = count == 0 ?
19519 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19521 this.displayEl.update(msg);
19526 onLoad : function(ds, r, o){
19527 this.cursor = o.params ? o.params.start : 0;
19528 var d = this.getPageData(),
19532 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19533 this.field.dom.value = ap;
19534 this.first.setDisabled(ap == 1);
19535 this.prev.setDisabled(ap == 1);
19536 this.next.setDisabled(ap == ps);
19537 this.last.setDisabled(ap == ps);
19538 this.loading.enable();
19543 getPageData : function(){
19544 var total = this.ds.getTotalCount();
19547 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19548 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19553 onLoadError : function(){
19554 this.loading.enable();
19558 onPagingKeydown : function(e){
19559 var k = e.getKey();
19560 var d = this.getPageData();
19562 var v = this.field.dom.value, pageNum;
19563 if(!v || isNaN(pageNum = parseInt(v, 10))){
19564 this.field.dom.value = d.activePage;
19567 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19568 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19571 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))
19573 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19574 this.field.dom.value = pageNum;
19575 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19578 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19580 var v = this.field.dom.value, pageNum;
19581 var increment = (e.shiftKey) ? 10 : 1;
19582 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19584 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19585 this.field.dom.value = d.activePage;
19588 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19590 this.field.dom.value = parseInt(v, 10) + increment;
19591 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19592 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19599 beforeLoad : function(){
19601 this.loading.disable();
19606 onClick : function(which){
19613 ds.load({params:{start: 0, limit: this.pageSize}});
19616 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19619 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19622 var total = ds.getTotalCount();
19623 var extra = total % this.pageSize;
19624 var lastStart = extra ? (total - extra) : total-this.pageSize;
19625 ds.load({params:{start: lastStart, limit: this.pageSize}});
19628 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19634 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19635 * @param {Roo.data.Store} store The data store to unbind
19637 unbind : function(ds){
19638 ds.un("beforeload", this.beforeLoad, this);
19639 ds.un("load", this.onLoad, this);
19640 ds.un("loadexception", this.onLoadError, this);
19641 ds.un("remove", this.updateInfo, this);
19642 ds.un("add", this.updateInfo, this);
19643 this.ds = undefined;
19647 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19648 * @param {Roo.data.Store} store The data store to bind
19650 bind : function(ds){
19651 ds.on("beforeload", this.beforeLoad, this);
19652 ds.on("load", this.onLoad, this);
19653 ds.on("loadexception", this.onLoadError, this);
19654 ds.on("remove", this.updateInfo, this);
19655 ds.on("add", this.updateInfo, this);
19666 * @class Roo.bootstrap.MessageBar
19667 * @extends Roo.bootstrap.Component
19668 * Bootstrap MessageBar class
19669 * @cfg {String} html contents of the MessageBar
19670 * @cfg {String} weight (info | success | warning | danger) default info
19671 * @cfg {String} beforeClass insert the bar before the given class
19672 * @cfg {Boolean} closable (true | false) default false
19673 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19676 * Create a new Element
19677 * @param {Object} config The config object
19680 Roo.bootstrap.MessageBar = function(config){
19681 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19684 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19690 beforeClass: 'bootstrap-sticky-wrap',
19692 getAutoCreate : function(){
19696 cls: 'alert alert-dismissable alert-' + this.weight,
19701 html: this.html || ''
19707 cfg.cls += ' alert-messages-fixed';
19721 onRender : function(ct, position)
19723 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19726 var cfg = Roo.apply({}, this.getAutoCreate());
19730 cfg.cls += ' ' + this.cls;
19733 cfg.style = this.style;
19735 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19737 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19740 this.el.select('>button.close').on('click', this.hide, this);
19746 if (!this.rendered) {
19752 this.fireEvent('show', this);
19758 if (!this.rendered) {
19764 this.fireEvent('hide', this);
19767 update : function()
19769 // var e = this.el.dom.firstChild;
19771 // if(this.closable){
19772 // e = e.nextSibling;
19775 // e.data = this.html || '';
19777 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19793 * @class Roo.bootstrap.Graph
19794 * @extends Roo.bootstrap.Component
19795 * Bootstrap Graph class
19799 @cfg {String} graphtype bar | vbar | pie
19800 @cfg {number} g_x coodinator | centre x (pie)
19801 @cfg {number} g_y coodinator | centre y (pie)
19802 @cfg {number} g_r radius (pie)
19803 @cfg {number} g_height height of the chart (respected by all elements in the set)
19804 @cfg {number} g_width width of the chart (respected by all elements in the set)
19805 @cfg {Object} title The title of the chart
19808 -opts (object) options for the chart
19810 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19811 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19813 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.
19814 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19816 o stretch (boolean)
19818 -opts (object) options for the pie
19821 o startAngle (number)
19822 o endAngle (number)
19826 * Create a new Input
19827 * @param {Object} config The config object
19830 Roo.bootstrap.Graph = function(config){
19831 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19837 * The img click event for the img.
19838 * @param {Roo.EventObject} e
19844 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19855 //g_colors: this.colors,
19862 getAutoCreate : function(){
19873 onRender : function(ct,position){
19874 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19875 this.raphael = Raphael(this.el.dom);
19877 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19878 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19879 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19880 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19882 r.text(160, 10, "Single Series Chart").attr(txtattr);
19883 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19884 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19885 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19887 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19888 r.barchart(330, 10, 300, 220, data1);
19889 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19890 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19893 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19894 // r.barchart(30, 30, 560, 250, xdata, {
19895 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19896 // axis : "0 0 1 1",
19897 // axisxlabels : xdata
19898 // //yvalues : cols,
19901 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19903 // this.load(null,xdata,{
19904 // axis : "0 0 1 1",
19905 // axisxlabels : xdata
19910 load : function(graphtype,xdata,opts){
19911 this.raphael.clear();
19913 graphtype = this.graphtype;
19918 var r = this.raphael,
19919 fin = function () {
19920 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19922 fout = function () {
19923 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19925 pfin = function() {
19926 this.sector.stop();
19927 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19930 this.label[0].stop();
19931 this.label[0].attr({ r: 7.5 });
19932 this.label[1].attr({ "font-weight": 800 });
19935 pfout = function() {
19936 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19939 this.label[0].animate({ r: 5 }, 500, "bounce");
19940 this.label[1].attr({ "font-weight": 400 });
19946 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19949 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19952 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19953 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19955 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19962 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19967 setTitle: function(o)
19972 initEvents: function() {
19975 this.el.on('click', this.onClick, this);
19979 onClick : function(e)
19981 Roo.log('img onclick');
19982 this.fireEvent('click', this, e);
19994 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19997 * @class Roo.bootstrap.dash.NumberBox
19998 * @extends Roo.bootstrap.Component
19999 * Bootstrap NumberBox class
20000 * @cfg {String} headline Box headline
20001 * @cfg {String} content Box content
20002 * @cfg {String} icon Box icon
20003 * @cfg {String} footer Footer text
20004 * @cfg {String} fhref Footer href
20007 * Create a new NumberBox
20008 * @param {Object} config The config object
20012 Roo.bootstrap.dash.NumberBox = function(config){
20013 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20017 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20026 getAutoCreate : function(){
20030 cls : 'small-box ',
20038 cls : 'roo-headline',
20039 html : this.headline
20043 cls : 'roo-content',
20044 html : this.content
20058 cls : 'ion ' + this.icon
20067 cls : 'small-box-footer',
20068 href : this.fhref || '#',
20072 cfg.cn.push(footer);
20079 onRender : function(ct,position){
20080 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20087 setHeadline: function (value)
20089 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20092 setFooter: function (value, href)
20094 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20097 this.el.select('a.small-box-footer',true).first().attr('href', href);
20102 setContent: function (value)
20104 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20107 initEvents: function()
20121 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20124 * @class Roo.bootstrap.dash.TabBox
20125 * @extends Roo.bootstrap.Component
20126 * Bootstrap TabBox class
20127 * @cfg {String} title Title of the TabBox
20128 * @cfg {String} icon Icon of the TabBox
20129 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20130 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20133 * Create a new TabBox
20134 * @param {Object} config The config object
20138 Roo.bootstrap.dash.TabBox = function(config){
20139 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20144 * When a pane is added
20145 * @param {Roo.bootstrap.dash.TabPane} pane
20149 * @event activatepane
20150 * When a pane is activated
20151 * @param {Roo.bootstrap.dash.TabPane} pane
20153 "activatepane" : true
20161 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20166 tabScrollable : false,
20168 getChildContainer : function()
20170 return this.el.select('.tab-content', true).first();
20173 getAutoCreate : function(){
20177 cls: 'pull-left header',
20185 cls: 'fa ' + this.icon
20191 cls: 'nav nav-tabs pull-right',
20197 if(this.tabScrollable){
20204 cls: 'nav nav-tabs pull-right',
20215 cls: 'nav-tabs-custom',
20220 cls: 'tab-content no-padding',
20228 initEvents : function()
20230 //Roo.log('add add pane handler');
20231 this.on('addpane', this.onAddPane, this);
20234 * Updates the box title
20235 * @param {String} html to set the title to.
20237 setTitle : function(value)
20239 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20241 onAddPane : function(pane)
20243 this.panes.push(pane);
20244 //Roo.log('addpane');
20246 // tabs are rendere left to right..
20247 if(!this.showtabs){
20251 var ctr = this.el.select('.nav-tabs', true).first();
20254 var existing = ctr.select('.nav-tab',true);
20255 var qty = existing.getCount();;
20258 var tab = ctr.createChild({
20260 cls : 'nav-tab' + (qty ? '' : ' active'),
20268 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20271 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20273 pane.el.addClass('active');
20278 onTabClick : function(ev,un,ob,pane)
20280 //Roo.log('tab - prev default');
20281 ev.preventDefault();
20284 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20285 pane.tab.addClass('active');
20286 //Roo.log(pane.title);
20287 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20288 // technically we should have a deactivate event.. but maybe add later.
20289 // and it should not de-activate the selected tab...
20290 this.fireEvent('activatepane', pane);
20291 pane.el.addClass('active');
20292 pane.fireEvent('activate');
20297 getActivePane : function()
20300 Roo.each(this.panes, function(p) {
20301 if(p.el.hasClass('active')){
20322 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20324 * @class Roo.bootstrap.TabPane
20325 * @extends Roo.bootstrap.Component
20326 * Bootstrap TabPane class
20327 * @cfg {Boolean} active (false | true) Default false
20328 * @cfg {String} title title of panel
20332 * Create a new TabPane
20333 * @param {Object} config The config object
20336 Roo.bootstrap.dash.TabPane = function(config){
20337 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20343 * When a pane is activated
20344 * @param {Roo.bootstrap.dash.TabPane} pane
20351 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20356 // the tabBox that this is attached to.
20359 getAutoCreate : function()
20367 cfg.cls += ' active';
20372 initEvents : function()
20374 //Roo.log('trigger add pane handler');
20375 this.parent().fireEvent('addpane', this)
20379 * Updates the tab title
20380 * @param {String} html to set the title to.
20382 setTitle: function(str)
20388 this.tab.select('a', true).first().dom.innerHTML = str;
20405 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20408 * @class Roo.bootstrap.menu.Menu
20409 * @extends Roo.bootstrap.Component
20410 * Bootstrap Menu class - container for Menu
20411 * @cfg {String} html Text of the menu
20412 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20413 * @cfg {String} icon Font awesome icon
20414 * @cfg {String} pos Menu align to (top | bottom) default bottom
20418 * Create a new Menu
20419 * @param {Object} config The config object
20423 Roo.bootstrap.menu.Menu = function(config){
20424 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20428 * @event beforeshow
20429 * Fires before this menu is displayed
20430 * @param {Roo.bootstrap.menu.Menu} this
20434 * @event beforehide
20435 * Fires before this menu is hidden
20436 * @param {Roo.bootstrap.menu.Menu} this
20441 * Fires after this menu is displayed
20442 * @param {Roo.bootstrap.menu.Menu} this
20447 * Fires after this menu is hidden
20448 * @param {Roo.bootstrap.menu.Menu} this
20453 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20454 * @param {Roo.bootstrap.menu.Menu} this
20455 * @param {Roo.EventObject} e
20462 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20466 weight : 'default',
20471 getChildContainer : function() {
20472 if(this.isSubMenu){
20476 return this.el.select('ul.dropdown-menu', true).first();
20479 getAutoCreate : function()
20484 cls : 'roo-menu-text',
20492 cls : 'fa ' + this.icon
20503 cls : 'dropdown-button btn btn-' + this.weight,
20508 cls : 'dropdown-toggle btn btn-' + this.weight,
20518 cls : 'dropdown-menu'
20524 if(this.pos == 'top'){
20525 cfg.cls += ' dropup';
20528 if(this.isSubMenu){
20531 cls : 'dropdown-menu'
20538 onRender : function(ct, position)
20540 this.isSubMenu = ct.hasClass('dropdown-submenu');
20542 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20545 initEvents : function()
20547 if(this.isSubMenu){
20551 this.hidden = true;
20553 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20554 this.triggerEl.on('click', this.onTriggerPress, this);
20556 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20557 this.buttonEl.on('click', this.onClick, this);
20563 if(this.isSubMenu){
20567 return this.el.select('ul.dropdown-menu', true).first();
20570 onClick : function(e)
20572 this.fireEvent("click", this, e);
20575 onTriggerPress : function(e)
20577 if (this.isVisible()) {
20584 isVisible : function(){
20585 return !this.hidden;
20590 this.fireEvent("beforeshow", this);
20592 this.hidden = false;
20593 this.el.addClass('open');
20595 Roo.get(document).on("mouseup", this.onMouseUp, this);
20597 this.fireEvent("show", this);
20604 this.fireEvent("beforehide", this);
20606 this.hidden = true;
20607 this.el.removeClass('open');
20609 Roo.get(document).un("mouseup", this.onMouseUp);
20611 this.fireEvent("hide", this);
20614 onMouseUp : function()
20628 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20631 * @class Roo.bootstrap.menu.Item
20632 * @extends Roo.bootstrap.Component
20633 * Bootstrap MenuItem class
20634 * @cfg {Boolean} submenu (true | false) default false
20635 * @cfg {String} html text of the item
20636 * @cfg {String} href the link
20637 * @cfg {Boolean} disable (true | false) default false
20638 * @cfg {Boolean} preventDefault (true | false) default true
20639 * @cfg {String} icon Font awesome icon
20640 * @cfg {String} pos Submenu align to (left | right) default right
20644 * Create a new Item
20645 * @param {Object} config The config object
20649 Roo.bootstrap.menu.Item = function(config){
20650 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20654 * Fires when the mouse is hovering over this menu
20655 * @param {Roo.bootstrap.menu.Item} this
20656 * @param {Roo.EventObject} e
20661 * Fires when the mouse exits this menu
20662 * @param {Roo.bootstrap.menu.Item} this
20663 * @param {Roo.EventObject} e
20669 * The raw click event for the entire grid.
20670 * @param {Roo.EventObject} e
20676 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20681 preventDefault: true,
20686 getAutoCreate : function()
20691 cls : 'roo-menu-item-text',
20699 cls : 'fa ' + this.icon
20708 href : this.href || '#',
20715 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20719 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20721 if(this.pos == 'left'){
20722 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20729 initEvents : function()
20731 this.el.on('mouseover', this.onMouseOver, this);
20732 this.el.on('mouseout', this.onMouseOut, this);
20734 this.el.select('a', true).first().on('click', this.onClick, this);
20738 onClick : function(e)
20740 if(this.preventDefault){
20741 e.preventDefault();
20744 this.fireEvent("click", this, e);
20747 onMouseOver : function(e)
20749 if(this.submenu && this.pos == 'left'){
20750 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20753 this.fireEvent("mouseover", this, e);
20756 onMouseOut : function(e)
20758 this.fireEvent("mouseout", this, e);
20770 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20773 * @class Roo.bootstrap.menu.Separator
20774 * @extends Roo.bootstrap.Component
20775 * Bootstrap Separator class
20778 * Create a new Separator
20779 * @param {Object} config The config object
20783 Roo.bootstrap.menu.Separator = function(config){
20784 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20787 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20789 getAutoCreate : function(){
20810 * @class Roo.bootstrap.Tooltip
20811 * Bootstrap Tooltip class
20812 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20813 * to determine which dom element triggers the tooltip.
20815 * It needs to add support for additional attributes like tooltip-position
20818 * Create a new Toolti
20819 * @param {Object} config The config object
20822 Roo.bootstrap.Tooltip = function(config){
20823 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20826 Roo.apply(Roo.bootstrap.Tooltip, {
20828 * @function init initialize tooltip monitoring.
20832 currentTip : false,
20833 currentRegion : false,
20839 Roo.get(document).on('mouseover', this.enter ,this);
20840 Roo.get(document).on('mouseout', this.leave, this);
20843 this.currentTip = new Roo.bootstrap.Tooltip();
20846 enter : function(ev)
20848 var dom = ev.getTarget();
20849 //Roo.log(['enter',dom]);
20850 var el = Roo.fly(dom);
20851 if (this.currentEl) {
20853 //Roo.log(this.currentEl);
20854 //Roo.log(this.currentEl.contains(dom));
20855 if (this.currentEl == el) {
20858 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20866 if (this.currentTip.el) {
20867 this.currentTip.el.hide(); // force hiding...
20870 if (!el.attr('tooltip')) { // parents who have tip?
20873 this.currentEl = el;
20874 this.currentTip.bind(el);
20875 this.currentRegion = Roo.lib.Region.getRegion(dom);
20876 this.currentTip.enter();
20879 leave : function(ev)
20881 var dom = ev.getTarget();
20882 //Roo.log(['leave',dom]);
20883 if (!this.currentEl) {
20888 if (dom != this.currentEl.dom) {
20891 var xy = ev.getXY();
20892 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
20895 // only activate leave if mouse cursor is outside... bounding box..
20900 if (this.currentTip) {
20901 this.currentTip.leave();
20903 //Roo.log('clear currentEl');
20904 this.currentEl = false;
20909 'left' : ['r-l', [-2,0], 'right'],
20910 'right' : ['l-r', [2,0], 'left'],
20911 'bottom' : ['t-b', [0,2], 'top'],
20912 'top' : [ 'b-t', [0,-2], 'bottom']
20918 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
20923 delay : null, // can be { show : 300 , hide: 500}
20927 hoverState : null, //???
20929 placement : 'bottom',
20931 getAutoCreate : function(){
20938 cls : 'tooltip-arrow'
20941 cls : 'tooltip-inner'
20948 bind : function(el)
20954 enter : function () {
20956 if (this.timeout != null) {
20957 clearTimeout(this.timeout);
20960 this.hoverState = 'in'
20961 //Roo.log("enter - show");
20962 if (!this.delay || !this.delay.show) {
20967 this.timeout = setTimeout(function () {
20968 if (_t.hoverState == 'in') {
20971 }, this.delay.show);
20975 clearTimeout(this.timeout);
20977 this.hoverState = 'out'
20978 if (!this.delay || !this.delay.hide) {
20984 this.timeout = setTimeout(function () {
20985 //Roo.log("leave - timeout");
20987 if (_t.hoverState == 'out') {
20989 Roo.bootstrap.Tooltip.currentEl = false;
20997 this.render(document.body);
21000 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21001 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21003 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21005 var placement = typeof this.placement == 'function' ?
21006 this.placement.call(this, this.el, on_el) :
21009 var autoToken = /\s?auto?\s?/i;
21010 var autoPlace = autoToken.test(placement);
21012 placement = placement.replace(autoToken, '') || 'top';
21016 //this.el.setXY([0,0]);
21018 //this.el.dom.style.display='block';
21019 this.el.addClass(placement);
21021 //this.el.appendTo(on_el);
21023 var p = this.getPosition();
21024 var box = this.el.getBox();
21029 var align = Roo.bootstrap.Tooltip.alignment[placement]
21030 this.el.alignTo(this.bindEl, align[0],align[1]);
21031 //var arrow = this.el.select('.arrow',true).first();
21032 //arrow.set(align[2],
21034 this.el.addClass('in fade');
21035 this.hoverState = null;
21037 if (this.el.hasClass('fade')) {
21048 //this.el.setXY([0,0]);
21049 this.el.removeClass('in');
21065 * @class Roo.bootstrap.LocationPicker
21066 * @extends Roo.bootstrap.Component
21067 * Bootstrap LocationPicker class
21068 * @cfg {Number} latitude Position when init default 0
21069 * @cfg {Number} longitude Position when init default 0
21070 * @cfg {Number} zoom default 15
21071 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21072 * @cfg {Boolean} mapTypeControl default false
21073 * @cfg {Boolean} disableDoubleClickZoom default false
21074 * @cfg {Boolean} scrollwheel default true
21075 * @cfg {Boolean} streetViewControl default false
21076 * @cfg {Number} radius default 0
21077 * @cfg {String} locationName
21078 * @cfg {Boolean} draggable default true
21079 * @cfg {Boolean} enableAutocomplete default false
21080 * @cfg {Boolean} enableReverseGeocode default true
21081 * @cfg {String} markerTitle
21084 * Create a new LocationPicker
21085 * @param {Object} config The config object
21089 Roo.bootstrap.LocationPicker = function(config){
21091 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21096 * Fires when the picker initialized.
21097 * @param {Roo.bootstrap.LocationPicker} this
21098 * @param {Google Location} location
21102 * @event positionchanged
21103 * Fires when the picker position changed.
21104 * @param {Roo.bootstrap.LocationPicker} this
21105 * @param {Google Location} location
21107 positionchanged : true,
21110 * Fires when the map resize.
21111 * @param {Roo.bootstrap.LocationPicker} this
21116 * Fires when the map show.
21117 * @param {Roo.bootstrap.LocationPicker} this
21122 * Fires when the map hide.
21123 * @param {Roo.bootstrap.LocationPicker} this
21130 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
21132 gMapContext: false,
21138 mapTypeControl: false,
21139 disableDoubleClickZoom: false,
21141 streetViewControl: false,
21145 enableAutocomplete: false,
21146 enableReverseGeocode: true,
21149 getAutoCreate: function()
21154 cls: 'roo-location-picker'
21160 initEvents: function(ct, position)
21162 if(!this.mapTypeId){
21163 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
21166 if(!this.el.getWidth() || this.isApplied()){
21170 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21175 initial: function()
21177 this.gMapContext = this.GMapContext();
21181 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
21182 _this.setPosition(_this.gMapContext.marker.position);
21185 this.setPosition(this.gMapContext.location);
21187 this.fireEvent('initial', this, this.gMapContext.location);
21190 isApplied: function()
21192 return this.getGmapContext() == false ? false : true;
21195 getGmapContext: function()
21197 return this.gMapContext
21200 GMapContext: function()
21202 var _map = new google.maps.Map(this.el.dom, this);
21203 var _marker = new google.maps.Marker({
21204 position: new google.maps.LatLng(this.latitude, this.longitude),
21206 title: this.markerTitle,
21207 draggable: this.draggable
21214 location: _marker.position,
21215 radius: this.radius,
21216 locationName: this.locationName,
21217 addressComponents: {
21218 formatted_address: null,
21219 addressLine1: null,
21220 addressLine2: null,
21222 streetNumber: null,
21226 stateOrProvince: null
21229 domContainer: this.el.dom,
21230 geodecoder: new google.maps.Geocoder()
21234 drawCircle: function(center, radius, options)
21236 if (this.gMapContext.circle != null) {
21237 this.gMapContext.circle.setMap(null);
21241 options = Roo.apply({}, options, {
21242 strokeColor: "#0000FF",
21243 strokeOpacity: .35,
21245 fillColor: "#0000FF",
21249 options.map = this.gMapContext.map;
21250 options.radius = radius;
21251 options.center = center;
21252 this.gMapContext.circle = new google.maps.Circle(options);
21253 return this.gMapContext.circle;
21259 setPosition: function(location)
21261 this.gMapContext.location = location;
21262 this.gMapContext.marker.setPosition(location);
21263 this.gMapContext.map.panTo(location);
21264 this.drawCircle(location, this.gMapContext.radius, {});
21268 if (this.gMapContext.settings.enableReverseGeocode) {
21269 this.gMapContext.geodecoder.geocode({
21270 latLng: this.gMapContext.location
21271 }, function(results, status) {
21273 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21274 _this.gMapContext.locationName = results[0].formatted_address;
21275 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21277 _this.fireEvent('positionchanged', this, location);
21284 this.fireEvent('positionchanged', this, location);
21289 google.maps.event.trigger(this.gMapContext.map, "resize");
21291 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
21293 this.fireEvent('resize', this);
21296 setPositionByLatLng: function(latitude, longitude)
21298 this.setPosition(new google.maps.LatLng(latitude, longitude));
21301 getCurrentPosition: function()
21304 latitude: this.gMapContext.location.lat(),
21305 longitude: this.gMapContext.location.lng()
21309 getAddressName: function()
21311 return this.gMapContext.locationName;
21314 getAddressComponents: function()
21316 return this.gMapContext.addressComponents;
21319 address_component_from_google_geocode: function(address_components)
21323 for (var i = 0; i < address_components.length; i++) {
21324 var component = address_components[i];
21325 if (component.types.indexOf("postal_code") >= 0) {
21326 result.postalCode = component.short_name;
21327 } else if (component.types.indexOf("street_number") >= 0) {
21328 result.streetNumber = component.short_name;
21329 } else if (component.types.indexOf("route") >= 0) {
21330 result.streetName = component.short_name;
21331 } else if (component.types.indexOf("neighborhood") >= 0) {
21332 result.city = component.short_name;
21333 } else if (component.types.indexOf("locality") >= 0) {
21334 result.city = component.short_name;
21335 } else if (component.types.indexOf("sublocality") >= 0) {
21336 result.district = component.short_name;
21337 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
21338 result.stateOrProvince = component.short_name;
21339 } else if (component.types.indexOf("country") >= 0) {
21340 result.country = component.short_name;
21344 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
21345 result.addressLine2 = "";
21349 setZoomLevel: function(zoom)
21351 this.gMapContext.map.setZoom(zoom);
21364 this.fireEvent('show', this);
21375 this.fireEvent('hide', this);
21387 * @class Roo.bootstrap.Alert
21388 * @extends Roo.bootstrap.Component
21389 * Bootstrap Alert class
21390 * @cfg {String} title The title of alert
21391 * @cfg {String} html The content of alert
21392 * @cfg {String} weight ( success | info | warning | danger )
21393 * @cfg {String} faicon font-awesomeicon
21396 * Create a new alert
21397 * @param {Object} config The config object
21401 Roo.bootstrap.Alert = function(config){
21402 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
21406 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
21413 getAutoCreate : function()
21422 cls : 'roo-alert-icon'
21427 cls : 'roo-alert-title',
21432 cls : 'roo-alert-text',
21439 cfg.cn[0].cls += ' fa ' + this.faicon;
21443 cfg.cls += ' alert-' + this.weight;
21449 initEvents: function()
21451 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21454 setTitle : function(str)
21456 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
21459 setText : function(str)
21461 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
21464 setWeight : function(weight)
21467 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
21470 this.weight = weight;
21472 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
21475 setIcon : function(icon)
21478 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
21483 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);