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
4165 * @cfg {Boolean} disabled default false
4169 * Create a new PaginationItem
4170 * @param {Object} config The config object
4174 Roo.bootstrap.PaginationItem = function(config){
4175 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4180 * The raw click event for the entire grid.
4181 * @param {Roo.EventObject} e
4187 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4191 preventDefault: true,
4196 getAutoCreate : function(){
4202 href : this.href ? this.href : '#',
4203 html : this.html ? this.html : ''
4213 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4217 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4223 initEvents: function() {
4225 this.el.on('click', this.onClick, this);
4228 onClick : function(e)
4230 Roo.log('PaginationItem on click ');
4231 if(this.preventDefault){
4239 this.fireEvent('click', this, e);
4255 * @class Roo.bootstrap.Slider
4256 * @extends Roo.bootstrap.Component
4257 * Bootstrap Slider class
4260 * Create a new Slider
4261 * @param {Object} config The config object
4264 Roo.bootstrap.Slider = function(config){
4265 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4268 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4270 getAutoCreate : function(){
4274 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4278 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4290 * Ext JS Library 1.1.1
4291 * Copyright(c) 2006-2007, Ext JS, LLC.
4293 * Originally Released Under LGPL - original licence link has changed is not relivant.
4296 * <script type="text/javascript">
4301 * @class Roo.grid.ColumnModel
4302 * @extends Roo.util.Observable
4303 * This is the default implementation of a ColumnModel used by the Grid. It defines
4304 * the columns in the grid.
4307 var colModel = new Roo.grid.ColumnModel([
4308 {header: "Ticker", width: 60, sortable: true, locked: true},
4309 {header: "Company Name", width: 150, sortable: true},
4310 {header: "Market Cap.", width: 100, sortable: true},
4311 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4312 {header: "Employees", width: 100, sortable: true, resizable: false}
4317 * The config options listed for this class are options which may appear in each
4318 * individual column definition.
4319 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4321 * @param {Object} config An Array of column config objects. See this class's
4322 * config objects for details.
4324 Roo.grid.ColumnModel = function(config){
4326 * The config passed into the constructor
4328 this.config = config;
4331 // if no id, create one
4332 // if the column does not have a dataIndex mapping,
4333 // map it to the order it is in the config
4334 for(var i = 0, len = config.length; i < len; i++){
4336 if(typeof c.dataIndex == "undefined"){
4339 if(typeof c.renderer == "string"){
4340 c.renderer = Roo.util.Format[c.renderer];
4342 if(typeof c.id == "undefined"){
4345 if(c.editor && c.editor.xtype){
4346 c.editor = Roo.factory(c.editor, Roo.grid);
4348 if(c.editor && c.editor.isFormField){
4349 c.editor = new Roo.grid.GridEditor(c.editor);
4351 this.lookup[c.id] = c;
4355 * The width of columns which have no width specified (defaults to 100)
4358 this.defaultWidth = 100;
4361 * Default sortable of columns which have no sortable specified (defaults to false)
4364 this.defaultSortable = false;
4368 * @event widthchange
4369 * Fires when the width of a column changes.
4370 * @param {ColumnModel} this
4371 * @param {Number} columnIndex The column index
4372 * @param {Number} newWidth The new width
4374 "widthchange": true,
4376 * @event headerchange
4377 * Fires when the text of a header changes.
4378 * @param {ColumnModel} this
4379 * @param {Number} columnIndex The column index
4380 * @param {Number} newText The new header text
4382 "headerchange": true,
4384 * @event hiddenchange
4385 * Fires when a column is hidden or "unhidden".
4386 * @param {ColumnModel} this
4387 * @param {Number} columnIndex The column index
4388 * @param {Boolean} hidden true if hidden, false otherwise
4390 "hiddenchange": true,
4392 * @event columnmoved
4393 * Fires when a column is moved.
4394 * @param {ColumnModel} this
4395 * @param {Number} oldIndex
4396 * @param {Number} newIndex
4398 "columnmoved" : true,
4400 * @event columlockchange
4401 * Fires when a column's locked state is changed
4402 * @param {ColumnModel} this
4403 * @param {Number} colIndex
4404 * @param {Boolean} locked true if locked
4406 "columnlockchange" : true
4408 Roo.grid.ColumnModel.superclass.constructor.call(this);
4410 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4412 * @cfg {String} header The header text to display in the Grid view.
4415 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4416 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4417 * specified, the column's index is used as an index into the Record's data Array.
4420 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4421 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4424 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4425 * Defaults to the value of the {@link #defaultSortable} property.
4426 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4429 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4432 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4435 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4438 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4441 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4442 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4443 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4444 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4447 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4450 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4453 * @cfg {String} cursor (Optional)
4456 * @cfg {String} tooltip (Optional)
4459 * Returns the id of the column at the specified index.
4460 * @param {Number} index The column index
4461 * @return {String} the id
4463 getColumnId : function(index){
4464 return this.config[index].id;
4468 * Returns the column for a specified id.
4469 * @param {String} id The column id
4470 * @return {Object} the column
4472 getColumnById : function(id){
4473 return this.lookup[id];
4478 * Returns the column for a specified dataIndex.
4479 * @param {String} dataIndex The column dataIndex
4480 * @return {Object|Boolean} the column or false if not found
4482 getColumnByDataIndex: function(dataIndex){
4483 var index = this.findColumnIndex(dataIndex);
4484 return index > -1 ? this.config[index] : false;
4488 * Returns the index for a specified column id.
4489 * @param {String} id The column id
4490 * @return {Number} the index, or -1 if not found
4492 getIndexById : function(id){
4493 for(var i = 0, len = this.config.length; i < len; i++){
4494 if(this.config[i].id == id){
4502 * Returns the index for a specified column dataIndex.
4503 * @param {String} dataIndex The column dataIndex
4504 * @return {Number} the index, or -1 if not found
4507 findColumnIndex : function(dataIndex){
4508 for(var i = 0, len = this.config.length; i < len; i++){
4509 if(this.config[i].dataIndex == dataIndex){
4517 moveColumn : function(oldIndex, newIndex){
4518 var c = this.config[oldIndex];
4519 this.config.splice(oldIndex, 1);
4520 this.config.splice(newIndex, 0, c);
4521 this.dataMap = null;
4522 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4525 isLocked : function(colIndex){
4526 return this.config[colIndex].locked === true;
4529 setLocked : function(colIndex, value, suppressEvent){
4530 if(this.isLocked(colIndex) == value){
4533 this.config[colIndex].locked = value;
4535 this.fireEvent("columnlockchange", this, colIndex, value);
4539 getTotalLockedWidth : function(){
4541 for(var i = 0; i < this.config.length; i++){
4542 if(this.isLocked(i) && !this.isHidden(i)){
4543 this.totalWidth += this.getColumnWidth(i);
4549 getLockedCount : function(){
4550 for(var i = 0, len = this.config.length; i < len; i++){
4551 if(!this.isLocked(i)){
4558 * Returns the number of columns.
4561 getColumnCount : function(visibleOnly){
4562 if(visibleOnly === true){
4564 for(var i = 0, len = this.config.length; i < len; i++){
4565 if(!this.isHidden(i)){
4571 return this.config.length;
4575 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4576 * @param {Function} fn
4577 * @param {Object} scope (optional)
4578 * @return {Array} result
4580 getColumnsBy : function(fn, scope){
4582 for(var i = 0, len = this.config.length; i < len; i++){
4583 var c = this.config[i];
4584 if(fn.call(scope||this, c, i) === true){
4592 * Returns true if the specified column is sortable.
4593 * @param {Number} col The column index
4596 isSortable : function(col){
4597 if(typeof this.config[col].sortable == "undefined"){
4598 return this.defaultSortable;
4600 return this.config[col].sortable;
4604 * Returns the rendering (formatting) function defined for the column.
4605 * @param {Number} col The column index.
4606 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4608 getRenderer : function(col){
4609 if(!this.config[col].renderer){
4610 return Roo.grid.ColumnModel.defaultRenderer;
4612 return this.config[col].renderer;
4616 * Sets the rendering (formatting) function for a column.
4617 * @param {Number} col The column index
4618 * @param {Function} fn The function to use to process the cell's raw data
4619 * to return HTML markup for the grid view. The render function is called with
4620 * the following parameters:<ul>
4621 * <li>Data value.</li>
4622 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4623 * <li>css A CSS style string to apply to the table cell.</li>
4624 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4625 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4626 * <li>Row index</li>
4627 * <li>Column index</li>
4628 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4630 setRenderer : function(col, fn){
4631 this.config[col].renderer = fn;
4635 * Returns the width for the specified column.
4636 * @param {Number} col The column index
4639 getColumnWidth : function(col){
4640 return this.config[col].width * 1 || this.defaultWidth;
4644 * Sets the width for a column.
4645 * @param {Number} col The column index
4646 * @param {Number} width The new width
4648 setColumnWidth : function(col, width, suppressEvent){
4649 this.config[col].width = width;
4650 this.totalWidth = null;
4652 this.fireEvent("widthchange", this, col, width);
4657 * Returns the total width of all columns.
4658 * @param {Boolean} includeHidden True to include hidden column widths
4661 getTotalWidth : function(includeHidden){
4662 if(!this.totalWidth){
4663 this.totalWidth = 0;
4664 for(var i = 0, len = this.config.length; i < len; i++){
4665 if(includeHidden || !this.isHidden(i)){
4666 this.totalWidth += this.getColumnWidth(i);
4670 return this.totalWidth;
4674 * Returns the header for the specified column.
4675 * @param {Number} col The column index
4678 getColumnHeader : function(col){
4679 return this.config[col].header;
4683 * Sets the header for a column.
4684 * @param {Number} col The column index
4685 * @param {String} header The new header
4687 setColumnHeader : function(col, header){
4688 this.config[col].header = header;
4689 this.fireEvent("headerchange", this, col, header);
4693 * Returns the tooltip for the specified column.
4694 * @param {Number} col The column index
4697 getColumnTooltip : function(col){
4698 return this.config[col].tooltip;
4701 * Sets the tooltip for a column.
4702 * @param {Number} col The column index
4703 * @param {String} tooltip The new tooltip
4705 setColumnTooltip : function(col, tooltip){
4706 this.config[col].tooltip = tooltip;
4710 * Returns the dataIndex for the specified column.
4711 * @param {Number} col The column index
4714 getDataIndex : function(col){
4715 return this.config[col].dataIndex;
4719 * Sets the dataIndex for a column.
4720 * @param {Number} col The column index
4721 * @param {Number} dataIndex The new dataIndex
4723 setDataIndex : function(col, dataIndex){
4724 this.config[col].dataIndex = dataIndex;
4730 * Returns true if the cell is editable.
4731 * @param {Number} colIndex The column index
4732 * @param {Number} rowIndex The row index
4735 isCellEditable : function(colIndex, rowIndex){
4736 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4740 * Returns the editor defined for the cell/column.
4741 * return false or null to disable editing.
4742 * @param {Number} colIndex The column index
4743 * @param {Number} rowIndex The row index
4746 getCellEditor : function(colIndex, rowIndex){
4747 return this.config[colIndex].editor;
4751 * Sets if a column is editable.
4752 * @param {Number} col The column index
4753 * @param {Boolean} editable True if the column is editable
4755 setEditable : function(col, editable){
4756 this.config[col].editable = editable;
4761 * Returns true if the column is hidden.
4762 * @param {Number} colIndex The column index
4765 isHidden : function(colIndex){
4766 return this.config[colIndex].hidden;
4771 * Returns true if the column width cannot be changed
4773 isFixed : function(colIndex){
4774 return this.config[colIndex].fixed;
4778 * Returns true if the column can be resized
4781 isResizable : function(colIndex){
4782 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4785 * Sets if a column is hidden.
4786 * @param {Number} colIndex The column index
4787 * @param {Boolean} hidden True if the column is hidden
4789 setHidden : function(colIndex, hidden){
4790 this.config[colIndex].hidden = hidden;
4791 this.totalWidth = null;
4792 this.fireEvent("hiddenchange", this, colIndex, hidden);
4796 * Sets the editor for a column.
4797 * @param {Number} col The column index
4798 * @param {Object} editor The editor object
4800 setEditor : function(col, editor){
4801 this.config[col].editor = editor;
4805 Roo.grid.ColumnModel.defaultRenderer = function(value){
4806 if(typeof value == "string" && value.length < 1){
4812 // Alias for backwards compatibility
4813 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4816 * Ext JS Library 1.1.1
4817 * Copyright(c) 2006-2007, Ext JS, LLC.
4819 * Originally Released Under LGPL - original licence link has changed is not relivant.
4822 * <script type="text/javascript">
4826 * @class Roo.LoadMask
4827 * A simple utility class for generically masking elements while loading data. If the element being masked has
4828 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4829 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4830 * element's UpdateManager load indicator and will be destroyed after the initial load.
4832 * Create a new LoadMask
4833 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4834 * @param {Object} config The config object
4836 Roo.LoadMask = function(el, config){
4837 this.el = Roo.get(el);
4838 Roo.apply(this, config);
4840 this.store.on('beforeload', this.onBeforeLoad, this);
4841 this.store.on('load', this.onLoad, this);
4842 this.store.on('loadexception', this.onLoadException, this);
4843 this.removeMask = false;
4845 var um = this.el.getUpdateManager();
4846 um.showLoadIndicator = false; // disable the default indicator
4847 um.on('beforeupdate', this.onBeforeLoad, this);
4848 um.on('update', this.onLoad, this);
4849 um.on('failure', this.onLoad, this);
4850 this.removeMask = true;
4854 Roo.LoadMask.prototype = {
4856 * @cfg {Boolean} removeMask
4857 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4858 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4862 * The text to display in a centered loading message box (defaults to 'Loading...')
4866 * @cfg {String} msgCls
4867 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4869 msgCls : 'x-mask-loading',
4872 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4878 * Disables the mask to prevent it from being displayed
4880 disable : function(){
4881 this.disabled = true;
4885 * Enables the mask so that it can be displayed
4887 enable : function(){
4888 this.disabled = false;
4891 onLoadException : function()
4895 if (typeof(arguments[3]) != 'undefined') {
4896 Roo.MessageBox.alert("Error loading",arguments[3]);
4900 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4901 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4910 this.el.unmask(this.removeMask);
4915 this.el.unmask(this.removeMask);
4919 onBeforeLoad : function(){
4921 this.el.mask(this.msg, this.msgCls);
4926 destroy : function(){
4928 this.store.un('beforeload', this.onBeforeLoad, this);
4929 this.store.un('load', this.onLoad, this);
4930 this.store.un('loadexception', this.onLoadException, this);
4932 var um = this.el.getUpdateManager();
4933 um.un('beforeupdate', this.onBeforeLoad, this);
4934 um.un('update', this.onLoad, this);
4935 um.un('failure', this.onLoad, this);
4946 * @class Roo.bootstrap.Table
4947 * @extends Roo.bootstrap.Component
4948 * Bootstrap Table class
4949 * @cfg {String} cls table class
4950 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4951 * @cfg {String} bgcolor Specifies the background color for a table
4952 * @cfg {Number} border Specifies whether the table cells should have borders or not
4953 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4954 * @cfg {Number} cellspacing Specifies the space between cells
4955 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4956 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4957 * @cfg {String} sortable Specifies that the table should be sortable
4958 * @cfg {String} summary Specifies a summary of the content of a table
4959 * @cfg {Number} width Specifies the width of a table
4960 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4962 * @cfg {boolean} striped Should the rows be alternative striped
4963 * @cfg {boolean} bordered Add borders to the table
4964 * @cfg {boolean} hover Add hover highlighting
4965 * @cfg {boolean} condensed Format condensed
4966 * @cfg {boolean} responsive Format condensed
4967 * @cfg {Boolean} loadMask (true|false) default false
4968 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4969 * @cfg {Boolean} thead (true|false) generate thead, default true
4970 * @cfg {Boolean} RowSelection (true|false) default false
4971 * @cfg {Boolean} CellSelection (true|false) default false
4972 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4976 * Create a new Table
4977 * @param {Object} config The config object
4980 Roo.bootstrap.Table = function(config){
4981 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4984 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4985 this.sm = this.selModel;
4986 this.sm.xmodule = this.xmodule || false;
4988 if (this.cm && typeof(this.cm.config) == 'undefined') {
4989 this.colModel = new Roo.grid.ColumnModel(this.cm);
4990 this.cm = this.colModel;
4991 this.cm.xmodule = this.xmodule || false;
4994 this.store= Roo.factory(this.store, Roo.data);
4995 this.ds = this.store;
4996 this.ds.xmodule = this.xmodule || false;
4999 if (this.footer && this.store) {
5000 this.footer.dataSource = this.ds;
5001 this.footer = Roo.factory(this.footer);
5008 * Fires when a cell is clicked
5009 * @param {Roo.bootstrap.Table} this
5010 * @param {Roo.Element} el
5011 * @param {Number} rowIndex
5012 * @param {Number} columnIndex
5013 * @param {Roo.EventObject} e
5017 * @event celldblclick
5018 * Fires when a cell is double clicked
5019 * @param {Roo.bootstrap.Table} this
5020 * @param {Roo.Element} el
5021 * @param {Number} rowIndex
5022 * @param {Number} columnIndex
5023 * @param {Roo.EventObject} e
5025 "celldblclick" : true,
5028 * Fires when a row is clicked
5029 * @param {Roo.bootstrap.Table} this
5030 * @param {Roo.Element} el
5031 * @param {Number} rowIndex
5032 * @param {Roo.EventObject} e
5036 * @event rowdblclick
5037 * Fires when a row is double clicked
5038 * @param {Roo.bootstrap.Table} this
5039 * @param {Roo.Element} el
5040 * @param {Number} rowIndex
5041 * @param {Roo.EventObject} e
5043 "rowdblclick" : true,
5046 * Fires when a mouseover occur
5047 * @param {Roo.bootstrap.Table} this
5048 * @param {Roo.Element} el
5049 * @param {Number} rowIndex
5050 * @param {Number} columnIndex
5051 * @param {Roo.EventObject} e
5056 * Fires when a mouseout occur
5057 * @param {Roo.bootstrap.Table} this
5058 * @param {Roo.Element} el
5059 * @param {Number} rowIndex
5060 * @param {Number} columnIndex
5061 * @param {Roo.EventObject} e
5066 * Fires when a row is rendered, so you can change add a style to it.
5067 * @param {Roo.bootstrap.Table} this
5068 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5072 * @event rowsrendered
5073 * Fires when all the rows have been rendered
5074 * @param {Roo.bootstrap.Table} this
5076 'rowsrendered' : true
5081 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5105 RowSelection : false,
5106 CellSelection : false,
5109 // Roo.Element - the tbody
5112 getAutoCreate : function(){
5113 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5122 cfg.cls += ' table-striped';
5126 cfg.cls += ' table-hover';
5128 if (this.bordered) {
5129 cfg.cls += ' table-bordered';
5131 if (this.condensed) {
5132 cfg.cls += ' table-condensed';
5134 if (this.responsive) {
5135 cfg.cls += ' table-responsive';
5139 cfg.cls+= ' ' +this.cls;
5142 // this lot should be simplifed...
5145 cfg.align=this.align;
5148 cfg.bgcolor=this.bgcolor;
5151 cfg.border=this.border;
5153 if (this.cellpadding) {
5154 cfg.cellpadding=this.cellpadding;
5156 if (this.cellspacing) {
5157 cfg.cellspacing=this.cellspacing;
5160 cfg.frame=this.frame;
5163 cfg.rules=this.rules;
5165 if (this.sortable) {
5166 cfg.sortable=this.sortable;
5169 cfg.summary=this.summary;
5172 cfg.width=this.width;
5175 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5178 if(this.store || this.cm){
5180 cfg.cn.push(this.renderHeader());
5183 cfg.cn.push(this.renderBody());
5186 cfg.cn.push(this.renderFooter());
5189 cfg.cls+= ' TableGrid';
5192 return { cn : [ cfg ] };
5195 initEvents : function()
5197 if(!this.store || !this.cm){
5201 //Roo.log('initEvents with ds!!!!');
5203 this.mainBody = this.el.select('tbody', true).first();
5208 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5209 e.on('click', _this.sort, _this);
5212 this.el.on("click", this.onClick, this);
5213 this.el.on("dblclick", this.onDblClick, this);
5215 // why is this done????? = it breaks dialogs??
5216 //this.parent().el.setStyle('position', 'relative');
5220 this.footer.parentId = this.id;
5221 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5224 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5226 this.store.on('load', this.onLoad, this);
5227 this.store.on('beforeload', this.onBeforeLoad, this);
5228 this.store.on('update', this.onUpdate, this);
5229 this.store.on('add', this.onAdd, this);
5233 onMouseover : function(e, el)
5235 var cell = Roo.get(el);
5241 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5242 cell = cell.findParent('td', false, true);
5245 var row = cell.findParent('tr', false, true);
5246 var cellIndex = cell.dom.cellIndex;
5247 var rowIndex = row.dom.rowIndex - 1; // start from 0
5249 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5253 onMouseout : function(e, el)
5255 var cell = Roo.get(el);
5261 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5262 cell = cell.findParent('td', false, true);
5265 var row = cell.findParent('tr', false, true);
5266 var cellIndex = cell.dom.cellIndex;
5267 var rowIndex = row.dom.rowIndex - 1; // start from 0
5269 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5273 onClick : function(e, el)
5275 var cell = Roo.get(el);
5277 if(!cell || (!this.CellSelection && !this.RowSelection)){
5282 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5283 cell = cell.findParent('td', false, true);
5286 var row = cell.findParent('tr', false, true);
5287 var cellIndex = cell.dom.cellIndex;
5288 var rowIndex = this.getRowIndex(row);
5290 if(this.CellSelection){
5291 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5294 if(this.RowSelection){
5295 this.fireEvent('rowclick', this, row, rowIndex, e);
5301 onDblClick : function(e,el)
5303 var cell = Roo.get(el);
5305 if(!cell || (!this.CellSelection && !this.RowSelection)){
5309 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5310 cell = cell.findParent('td', false, true);
5313 var row = cell.findParent('tr', false, true);
5314 var cellIndex = cell.dom.cellIndex;
5315 var rowIndex = this.getRowIndex(row);
5317 if(this.CellSelection){
5318 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5321 if(this.RowSelection){
5322 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5326 sort : function(e,el)
5328 var col = Roo.get(el)
5330 if(!col.hasClass('sortable')){
5334 var sort = col.attr('sort');
5337 if(col.hasClass('glyphicon-arrow-up')){
5341 this.store.sortInfo = {field : sort, direction : dir};
5344 Roo.log("calling footer first");
5345 this.footer.onClick('first');
5348 this.store.load({ params : { start : 0 } });
5352 renderHeader : function()
5361 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5363 var config = cm.config[i];
5368 html: cm.getColumnHeader(i)
5371 if(typeof(config.tooltip != 'undefined')){
5372 c.tooltip = config.tooltip;
5375 if(typeof(config.hidden) != 'undefined' && config.hidden){
5376 c.style += ' display:none;';
5379 if(typeof(config.dataIndex) != 'undefined'){
5380 c.sort = config.dataIndex;
5383 if(typeof(config.sortable) != 'undefined' && config.sortable){
5387 if(typeof(config.align) != 'undefined' && config.align.length){
5388 c.style += ' text-align:' + config.align + ';';
5391 if(typeof(config.width) != 'undefined'){
5392 c.style += ' width:' + config.width + 'px;';
5401 renderBody : function()
5411 colspan : this.cm.getColumnCount()
5421 renderFooter : function()
5431 colspan : this.cm.getColumnCount()
5445 Roo.log('ds onload');
5450 var ds = this.store;
5452 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5453 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5455 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5456 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5459 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5460 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5464 var tbody = this.mainBody;
5466 if(ds.getCount() > 0){
5467 ds.data.each(function(d,rowIndex){
5468 var row = this.renderRow(cm, ds, rowIndex);
5470 tbody.createChild(row);
5474 if(row.cellObjects.length){
5475 Roo.each(row.cellObjects, function(r){
5476 _this.renderCellObject(r);
5483 Roo.each(this.el.select('tbody td', true).elements, function(e){
5484 e.on('mouseover', _this.onMouseover, _this);
5487 Roo.each(this.el.select('tbody td', true).elements, function(e){
5488 e.on('mouseout', _this.onMouseout, _this);
5490 this.fireEvent('rowsrendered', this);
5491 //if(this.loadMask){
5492 // this.maskEl.hide();
5497 onUpdate : function(ds,record)
5499 this.refreshRow(record);
5502 onRemove : function(ds, record, index, isUpdate){
5503 if(isUpdate !== true){
5504 this.fireEvent("beforerowremoved", this, index, record);
5506 var bt = this.mainBody.dom;
5508 var rows = this.el.select('tbody > tr', true).elements;
5510 if(typeof(rows[index]) != 'undefined'){
5511 bt.removeChild(rows[index].dom);
5514 // if(bt.rows[index]){
5515 // bt.removeChild(bt.rows[index]);
5518 if(isUpdate !== true){
5519 //this.stripeRows(index);
5520 //this.syncRowHeights(index, index);
5522 this.fireEvent("rowremoved", this, index, record);
5526 onAdd : function(ds, records, rowIndex)
5528 //Roo.log('on Add called');
5529 // - note this does not handle multiple adding very well..
5530 var bt = this.mainBody.dom;
5531 for (var i =0 ; i < records.length;i++) {
5532 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5533 //Roo.log(records[i]);
5534 //Roo.log(this.store.getAt(rowIndex+i));
5535 this.insertRow(this.store, rowIndex + i, false);
5542 refreshRow : function(record){
5543 var ds = this.store, index;
5544 if(typeof record == 'number'){
5546 record = ds.getAt(index);
5548 index = ds.indexOf(record);
5550 this.insertRow(ds, index, true);
5551 this.onRemove(ds, record, index+1, true);
5552 //this.syncRowHeights(index, index);
5554 this.fireEvent("rowupdated", this, index, record);
5557 insertRow : function(dm, rowIndex, isUpdate){
5560 this.fireEvent("beforerowsinserted", this, rowIndex);
5562 //var s = this.getScrollState();
5563 var row = this.renderRow(this.cm, this.store, rowIndex);
5564 // insert before rowIndex..
5565 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5569 if(row.cellObjects.length){
5570 Roo.each(row.cellObjects, function(r){
5571 _this.renderCellObject(r);
5576 this.fireEvent("rowsinserted", this, rowIndex);
5577 //this.syncRowHeights(firstRow, lastRow);
5578 //this.stripeRows(firstRow);
5585 getRowDom : function(rowIndex)
5587 var rows = this.el.select('tbody > tr', true).elements;
5589 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5592 // returns the object tree for a tr..
5595 renderRow : function(cm, ds, rowIndex)
5598 var d = ds.getAt(rowIndex);
5605 var cellObjects = [];
5607 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5608 var config = cm.config[i];
5610 var renderer = cm.getRenderer(i);
5614 if(typeof(renderer) !== 'undefined'){
5615 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5617 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5618 // and are rendered into the cells after the row is rendered - using the id for the element.
5620 if(typeof(value) === 'object'){
5630 rowIndex : rowIndex,
5635 this.fireEvent('rowclass', this, rowcfg);
5639 cls : rowcfg.rowClass,
5641 html: (typeof(value) === 'object') ? '' : value
5648 if(typeof(config.hidden) != 'undefined' && config.hidden){
5649 td.style += ' display:none;';
5652 if(typeof(config.align) != 'undefined' && config.align.length){
5653 td.style += ' text-align:' + config.align + ';';
5656 if(typeof(config.width) != 'undefined'){
5657 td.style += ' width:' + config.width + 'px;';
5660 if(typeof(config.cursor) != 'undefined'){
5661 td.style += ' cursor:' + config.cursor + ';';
5668 row.cellObjects = cellObjects;
5676 onBeforeLoad : function()
5678 //Roo.log('ds onBeforeLoad');
5682 //if(this.loadMask){
5683 // this.maskEl.show();
5691 this.el.select('tbody', true).first().dom.innerHTML = '';
5694 * Show or hide a row.
5695 * @param {Number} rowIndex to show or hide
5696 * @param {Boolean} state hide
5698 setRowVisibility : function(rowIndex, state)
5700 var bt = this.mainBody.dom;
5702 var rows = this.el.select('tbody > tr', true).elements;
5704 if(typeof(rows[rowIndex]) == 'undefined'){
5707 rows[rowIndex].dom.style.display = state ? '' : 'none';
5711 getSelectionModel : function(){
5713 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5715 return this.selModel;
5718 * Render the Roo.bootstrap object from renderder
5720 renderCellObject : function(r)
5724 var t = r.cfg.render(r.container);
5727 Roo.each(r.cfg.cn, function(c){
5729 container: t.getChildContainer(),
5732 _this.renderCellObject(child);
5737 getRowIndex : function(row)
5741 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5764 * @class Roo.bootstrap.TableCell
5765 * @extends Roo.bootstrap.Component
5766 * Bootstrap TableCell class
5767 * @cfg {String} html cell contain text
5768 * @cfg {String} cls cell class
5769 * @cfg {String} tag cell tag (td|th) default td
5770 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5771 * @cfg {String} align Aligns the content in a cell
5772 * @cfg {String} axis Categorizes cells
5773 * @cfg {String} bgcolor Specifies the background color of a cell
5774 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5775 * @cfg {Number} colspan Specifies the number of columns a cell should span
5776 * @cfg {String} headers Specifies one or more header cells a cell is related to
5777 * @cfg {Number} height Sets the height of a cell
5778 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5779 * @cfg {Number} rowspan Sets the number of rows a cell should span
5780 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5781 * @cfg {String} valign Vertical aligns the content in a cell
5782 * @cfg {Number} width Specifies the width of a cell
5785 * Create a new TableCell
5786 * @param {Object} config The config object
5789 Roo.bootstrap.TableCell = function(config){
5790 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5793 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5813 getAutoCreate : function(){
5814 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5834 cfg.align=this.align
5840 cfg.bgcolor=this.bgcolor
5843 cfg.charoff=this.charoff
5846 cfg.colspan=this.colspan
5849 cfg.headers=this.headers
5852 cfg.height=this.height
5855 cfg.nowrap=this.nowrap
5858 cfg.rowspan=this.rowspan
5861 cfg.scope=this.scope
5864 cfg.valign=this.valign
5867 cfg.width=this.width
5886 * @class Roo.bootstrap.TableRow
5887 * @extends Roo.bootstrap.Component
5888 * Bootstrap TableRow class
5889 * @cfg {String} cls row class
5890 * @cfg {String} align Aligns the content in a table row
5891 * @cfg {String} bgcolor Specifies a background color for a table row
5892 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5893 * @cfg {String} valign Vertical aligns the content in a table row
5896 * Create a new TableRow
5897 * @param {Object} config The config object
5900 Roo.bootstrap.TableRow = function(config){
5901 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5904 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5912 getAutoCreate : function(){
5913 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5923 cfg.align = this.align;
5926 cfg.bgcolor = this.bgcolor;
5929 cfg.charoff = this.charoff;
5932 cfg.valign = this.valign;
5950 * @class Roo.bootstrap.TableBody
5951 * @extends Roo.bootstrap.Component
5952 * Bootstrap TableBody class
5953 * @cfg {String} cls element class
5954 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5955 * @cfg {String} align Aligns the content inside the element
5956 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5957 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5960 * Create a new TableBody
5961 * @param {Object} config The config object
5964 Roo.bootstrap.TableBody = function(config){
5965 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5968 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5976 getAutoCreate : function(){
5977 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5991 cfg.align = this.align;
5994 cfg.charoff = this.charoff;
5997 cfg.valign = this.valign;
6004 // initEvents : function()
6011 // this.store = Roo.factory(this.store, Roo.data);
6012 // this.store.on('load', this.onLoad, this);
6014 // this.store.load();
6018 // onLoad: function ()
6020 // this.fireEvent('load', this);
6030 * Ext JS Library 1.1.1
6031 * Copyright(c) 2006-2007, Ext JS, LLC.
6033 * Originally Released Under LGPL - original licence link has changed is not relivant.
6036 * <script type="text/javascript">
6039 // as we use this in bootstrap.
6040 Roo.namespace('Roo.form');
6042 * @class Roo.form.Action
6043 * Internal Class used to handle form actions
6045 * @param {Roo.form.BasicForm} el The form element or its id
6046 * @param {Object} config Configuration options
6051 // define the action interface
6052 Roo.form.Action = function(form, options){
6054 this.options = options || {};
6057 * Client Validation Failed
6060 Roo.form.Action.CLIENT_INVALID = 'client';
6062 * Server Validation Failed
6065 Roo.form.Action.SERVER_INVALID = 'server';
6067 * Connect to Server Failed
6070 Roo.form.Action.CONNECT_FAILURE = 'connect';
6072 * Reading Data from Server Failed
6075 Roo.form.Action.LOAD_FAILURE = 'load';
6077 Roo.form.Action.prototype = {
6079 failureType : undefined,
6080 response : undefined,
6084 run : function(options){
6089 success : function(response){
6094 handleResponse : function(response){
6098 // default connection failure
6099 failure : function(response){
6101 this.response = response;
6102 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6103 this.form.afterAction(this, false);
6106 processResponse : function(response){
6107 this.response = response;
6108 if(!response.responseText){
6111 this.result = this.handleResponse(response);
6115 // utility functions used internally
6116 getUrl : function(appendParams){
6117 var url = this.options.url || this.form.url || this.form.el.dom.action;
6119 var p = this.getParams();
6121 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6127 getMethod : function(){
6128 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6131 getParams : function(){
6132 var bp = this.form.baseParams;
6133 var p = this.options.params;
6135 if(typeof p == "object"){
6136 p = Roo.urlEncode(Roo.applyIf(p, bp));
6137 }else if(typeof p == 'string' && bp){
6138 p += '&' + Roo.urlEncode(bp);
6141 p = Roo.urlEncode(bp);
6146 createCallback : function(){
6148 success: this.success,
6149 failure: this.failure,
6151 timeout: (this.form.timeout*1000),
6152 upload: this.form.fileUpload ? this.success : undefined
6157 Roo.form.Action.Submit = function(form, options){
6158 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6161 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6164 haveProgress : false,
6165 uploadComplete : false,
6167 // uploadProgress indicator.
6168 uploadProgress : function()
6170 if (!this.form.progressUrl) {
6174 if (!this.haveProgress) {
6175 Roo.MessageBox.progress("Uploading", "Uploading");
6177 if (this.uploadComplete) {
6178 Roo.MessageBox.hide();
6182 this.haveProgress = true;
6184 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6186 var c = new Roo.data.Connection();
6188 url : this.form.progressUrl,
6193 success : function(req){
6194 //console.log(data);
6198 rdata = Roo.decode(req.responseText)
6200 Roo.log("Invalid data from server..");
6204 if (!rdata || !rdata.success) {
6206 Roo.MessageBox.alert(Roo.encode(rdata));
6209 var data = rdata.data;
6211 if (this.uploadComplete) {
6212 Roo.MessageBox.hide();
6217 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6218 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6221 this.uploadProgress.defer(2000,this);
6224 failure: function(data) {
6225 Roo.log('progress url failed ');
6236 // run get Values on the form, so it syncs any secondary forms.
6237 this.form.getValues();
6239 var o = this.options;
6240 var method = this.getMethod();
6241 var isPost = method == 'POST';
6242 if(o.clientValidation === false || this.form.isValid()){
6244 if (this.form.progressUrl) {
6245 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6246 (new Date() * 1) + '' + Math.random());
6251 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6252 form:this.form.el.dom,
6253 url:this.getUrl(!isPost),
6255 params:isPost ? this.getParams() : null,
6256 isUpload: this.form.fileUpload
6259 this.uploadProgress();
6261 }else if (o.clientValidation !== false){ // client validation failed
6262 this.failureType = Roo.form.Action.CLIENT_INVALID;
6263 this.form.afterAction(this, false);
6267 success : function(response)
6269 this.uploadComplete= true;
6270 if (this.haveProgress) {
6271 Roo.MessageBox.hide();
6275 var result = this.processResponse(response);
6276 if(result === true || result.success){
6277 this.form.afterAction(this, true);
6281 this.form.markInvalid(result.errors);
6282 this.failureType = Roo.form.Action.SERVER_INVALID;
6284 this.form.afterAction(this, false);
6286 failure : function(response)
6288 this.uploadComplete= true;
6289 if (this.haveProgress) {
6290 Roo.MessageBox.hide();
6293 this.response = response;
6294 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6295 this.form.afterAction(this, false);
6298 handleResponse : function(response){
6299 if(this.form.errorReader){
6300 var rs = this.form.errorReader.read(response);
6303 for(var i = 0, len = rs.records.length; i < len; i++) {
6304 var r = rs.records[i];
6308 if(errors.length < 1){
6312 success : rs.success,
6318 ret = Roo.decode(response.responseText);
6322 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6332 Roo.form.Action.Load = function(form, options){
6333 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6334 this.reader = this.form.reader;
6337 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6342 Roo.Ajax.request(Roo.apply(
6343 this.createCallback(), {
6344 method:this.getMethod(),
6345 url:this.getUrl(false),
6346 params:this.getParams()
6350 success : function(response){
6352 var result = this.processResponse(response);
6353 if(result === true || !result.success || !result.data){
6354 this.failureType = Roo.form.Action.LOAD_FAILURE;
6355 this.form.afterAction(this, false);
6358 this.form.clearInvalid();
6359 this.form.setValues(result.data);
6360 this.form.afterAction(this, true);
6363 handleResponse : function(response){
6364 if(this.form.reader){
6365 var rs = this.form.reader.read(response);
6366 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6368 success : rs.success,
6372 return Roo.decode(response.responseText);
6376 Roo.form.Action.ACTION_TYPES = {
6377 'load' : Roo.form.Action.Load,
6378 'submit' : Roo.form.Action.Submit
6387 * @class Roo.bootstrap.Form
6388 * @extends Roo.bootstrap.Component
6389 * Bootstrap Form class
6390 * @cfg {String} method GET | POST (default POST)
6391 * @cfg {String} labelAlign top | left (default top)
6392 * @cfg {String} align left | right - for navbars
6393 * @cfg {Boolean} loadMask load mask when submit (default true)
6398 * @param {Object} config The config object
6402 Roo.bootstrap.Form = function(config){
6403 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6406 * @event clientvalidation
6407 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6408 * @param {Form} this
6409 * @param {Boolean} valid true if the form has passed client-side validation
6411 clientvalidation: true,
6413 * @event beforeaction
6414 * Fires before any action is performed. Return false to cancel the action.
6415 * @param {Form} this
6416 * @param {Action} action The action to be performed
6420 * @event actionfailed
6421 * Fires when an action fails.
6422 * @param {Form} this
6423 * @param {Action} action The action that failed
6425 actionfailed : true,
6427 * @event actioncomplete
6428 * Fires when an action is completed.
6429 * @param {Form} this
6430 * @param {Action} action The action that completed
6432 actioncomplete : true
6437 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6440 * @cfg {String} method
6441 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6446 * The URL to use for form actions if one isn't supplied in the action options.
6449 * @cfg {Boolean} fileUpload
6450 * Set to true if this form is a file upload.
6454 * @cfg {Object} baseParams
6455 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6459 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6463 * @cfg {Sting} align (left|right) for navbar forms
6468 activeAction : null,
6471 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6472 * element by passing it or its id or mask the form itself by passing in true.
6475 waitMsgTarget : false,
6479 getAutoCreate : function(){
6483 method : this.method || 'POST',
6484 id : this.id || Roo.id(),
6487 if (this.parent().xtype.match(/^Nav/)) {
6488 cfg.cls = 'navbar-form navbar-' + this.align;
6492 if (this.labelAlign == 'left' ) {
6493 cfg.cls += ' form-horizontal';
6499 initEvents : function()
6501 this.el.on('submit', this.onSubmit, this);
6502 // this was added as random key presses on the form where triggering form submit.
6503 this.el.on('keypress', function(e) {
6504 if (e.getCharCode() != 13) {
6507 // we might need to allow it for textareas.. and some other items.
6508 // check e.getTarget().
6510 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6514 Roo.log("keypress blocked");
6522 onSubmit : function(e){
6527 * Returns true if client-side validation on the form is successful.
6530 isValid : function(){
6531 var items = this.getItems();
6533 items.each(function(f){
6542 * Returns true if any fields in this form have changed since their original load.
6545 isDirty : function(){
6547 var items = this.getItems();
6548 items.each(function(f){
6558 * Performs a predefined action (submit or load) or custom actions you define on this form.
6559 * @param {String} actionName The name of the action type
6560 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6561 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6562 * accept other config options):
6564 Property Type Description
6565 ---------------- --------------- ----------------------------------------------------------------------------------
6566 url String The url for the action (defaults to the form's url)
6567 method String The form method to use (defaults to the form's method, or POST if not defined)
6568 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6569 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6570 validate the form on the client (defaults to false)
6572 * @return {BasicForm} this
6574 doAction : function(action, options){
6575 if(typeof action == 'string'){
6576 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6578 if(this.fireEvent('beforeaction', this, action) !== false){
6579 this.beforeAction(action);
6580 action.run.defer(100, action);
6586 beforeAction : function(action){
6587 var o = action.options;
6590 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6592 // not really supported yet.. ??
6594 //if(this.waitMsgTarget === true){
6595 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6596 //}else if(this.waitMsgTarget){
6597 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6598 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6600 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6606 afterAction : function(action, success){
6607 this.activeAction = null;
6608 var o = action.options;
6610 //if(this.waitMsgTarget === true){
6612 //}else if(this.waitMsgTarget){
6613 // this.waitMsgTarget.unmask();
6615 // Roo.MessageBox.updateProgress(1);
6616 // Roo.MessageBox.hide();
6623 Roo.callback(o.success, o.scope, [this, action]);
6624 this.fireEvent('actioncomplete', this, action);
6628 // failure condition..
6629 // we have a scenario where updates need confirming.
6630 // eg. if a locking scenario exists..
6631 // we look for { errors : { needs_confirm : true }} in the response.
6633 (typeof(action.result) != 'undefined') &&
6634 (typeof(action.result.errors) != 'undefined') &&
6635 (typeof(action.result.errors.needs_confirm) != 'undefined')
6638 Roo.log("not supported yet");
6641 Roo.MessageBox.confirm(
6642 "Change requires confirmation",
6643 action.result.errorMsg,
6648 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6658 Roo.callback(o.failure, o.scope, [this, action]);
6659 // show an error message if no failed handler is set..
6660 if (!this.hasListener('actionfailed')) {
6661 Roo.log("need to add dialog support");
6663 Roo.MessageBox.alert("Error",
6664 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6665 action.result.errorMsg :
6666 "Saving Failed, please check your entries or try again"
6671 this.fireEvent('actionfailed', this, action);
6676 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6677 * @param {String} id The value to search for
6680 findField : function(id){
6681 var items = this.getItems();
6682 var field = items.get(id);
6684 items.each(function(f){
6685 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6692 return field || null;
6695 * Mark fields in this form invalid in bulk.
6696 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6697 * @return {BasicForm} this
6699 markInvalid : function(errors){
6700 if(errors instanceof Array){
6701 for(var i = 0, len = errors.length; i < len; i++){
6702 var fieldError = errors[i];
6703 var f = this.findField(fieldError.id);
6705 f.markInvalid(fieldError.msg);
6711 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6712 field.markInvalid(errors[id]);
6716 //Roo.each(this.childForms || [], function (f) {
6717 // f.markInvalid(errors);
6724 * Set values for fields in this form in bulk.
6725 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6726 * @return {BasicForm} this
6728 setValues : function(values){
6729 if(values instanceof Array){ // array of objects
6730 for(var i = 0, len = values.length; i < len; i++){
6732 var f = this.findField(v.id);
6734 f.setValue(v.value);
6735 if(this.trackResetOnLoad){
6736 f.originalValue = f.getValue();
6740 }else{ // object hash
6743 if(typeof values[id] != 'function' && (field = this.findField(id))){
6745 if (field.setFromData &&
6747 field.displayField &&
6748 // combos' with local stores can
6749 // be queried via setValue()
6750 // to set their value..
6751 (field.store && !field.store.isLocal)
6755 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6756 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6757 field.setFromData(sd);
6760 field.setValue(values[id]);
6764 if(this.trackResetOnLoad){
6765 field.originalValue = field.getValue();
6771 //Roo.each(this.childForms || [], function (f) {
6772 // f.setValues(values);
6779 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6780 * they are returned as an array.
6781 * @param {Boolean} asString
6784 getValues : function(asString){
6785 //if (this.childForms) {
6786 // copy values from the child forms
6787 // Roo.each(this.childForms, function (f) {
6788 // this.setValues(f.getValues());
6794 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6795 if(asString === true){
6798 return Roo.urlDecode(fs);
6802 * Returns the fields in this form as an object with key/value pairs.
6803 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6806 getFieldValues : function(with_hidden)
6808 var items = this.getItems();
6810 items.each(function(f){
6814 var v = f.getValue();
6815 if (f.inputType =='radio') {
6816 if (typeof(ret[f.getName()]) == 'undefined') {
6817 ret[f.getName()] = ''; // empty..
6820 if (!f.el.dom.checked) {
6828 // not sure if this supported any more..
6829 if ((typeof(v) == 'object') && f.getRawValue) {
6830 v = f.getRawValue() ; // dates..
6832 // combo boxes where name != hiddenName...
6833 if (f.name != f.getName()) {
6834 ret[f.name] = f.getRawValue();
6836 ret[f.getName()] = v;
6843 * Clears all invalid messages in this form.
6844 * @return {BasicForm} this
6846 clearInvalid : function(){
6847 var items = this.getItems();
6849 items.each(function(f){
6860 * @return {BasicForm} this
6863 var items = this.getItems();
6864 items.each(function(f){
6868 Roo.each(this.childForms || [], function (f) {
6875 getItems : function()
6877 var r=new Roo.util.MixedCollection(false, function(o){
6878 return o.id || (o.id = Roo.id());
6880 var iter = function(el) {
6887 Roo.each(el.items,function(e) {
6906 * Ext JS Library 1.1.1
6907 * Copyright(c) 2006-2007, Ext JS, LLC.
6909 * Originally Released Under LGPL - original licence link has changed is not relivant.
6912 * <script type="text/javascript">
6915 * @class Roo.form.VTypes
6916 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6919 Roo.form.VTypes = function(){
6920 // closure these in so they are only created once.
6921 var alpha = /^[a-zA-Z_]+$/;
6922 var alphanum = /^[a-zA-Z0-9_]+$/;
6923 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6924 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6926 // All these messages and functions are configurable
6929 * The function used to validate email addresses
6930 * @param {String} value The email address
6932 'email' : function(v){
6933 return email.test(v);
6936 * The error text to display when the email validation function returns false
6939 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6941 * The keystroke filter mask to be applied on email input
6944 'emailMask' : /[a-z0-9_\.\-@]/i,
6947 * The function used to validate URLs
6948 * @param {String} value The URL
6950 'url' : function(v){
6954 * The error text to display when the url validation function returns false
6957 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6960 * The function used to validate alpha values
6961 * @param {String} value The value
6963 'alpha' : function(v){
6964 return alpha.test(v);
6967 * The error text to display when the alpha validation function returns false
6970 'alphaText' : 'This field should only contain letters and _',
6972 * The keystroke filter mask to be applied on alpha input
6975 'alphaMask' : /[a-z_]/i,
6978 * The function used to validate alphanumeric values
6979 * @param {String} value The value
6981 'alphanum' : function(v){
6982 return alphanum.test(v);
6985 * The error text to display when the alphanumeric validation function returns false
6988 'alphanumText' : 'This field should only contain letters, numbers and _',
6990 * The keystroke filter mask to be applied on alphanumeric input
6993 'alphanumMask' : /[a-z0-9_]/i
7003 * @class Roo.bootstrap.Input
7004 * @extends Roo.bootstrap.Component
7005 * Bootstrap Input class
7006 * @cfg {Boolean} disabled is it disabled
7007 * @cfg {String} fieldLabel - the label associated
7008 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7009 * @cfg {String} name name of the input
7010 * @cfg {string} fieldLabel - the label associated
7011 * @cfg {string} inputType - input / file submit ...
7012 * @cfg {string} placeholder - placeholder to put in text.
7013 * @cfg {string} before - input group add on before
7014 * @cfg {string} after - input group add on after
7015 * @cfg {string} size - (lg|sm) or leave empty..
7016 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7017 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7018 * @cfg {Number} md colspan out of 12 for computer-sized screens
7019 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7020 * @cfg {string} value default value of the input
7021 * @cfg {Number} labelWidth set the width of label (0-12)
7022 * @cfg {String} labelAlign (top|left)
7023 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7024 * @cfg {String} align (left|center|right) Default left
7028 * Create a new Input
7029 * @param {Object} config The config object
7032 Roo.bootstrap.Input = function(config){
7033 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7038 * Fires when this field receives input focus.
7039 * @param {Roo.form.Field} this
7044 * Fires when this field loses input focus.
7045 * @param {Roo.form.Field} this
7050 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7051 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7052 * @param {Roo.form.Field} this
7053 * @param {Roo.EventObject} e The event object
7058 * Fires just before the field blurs if the field value has changed.
7059 * @param {Roo.form.Field} this
7060 * @param {Mixed} newValue The new value
7061 * @param {Mixed} oldValue The original value
7066 * Fires after the field has been marked as invalid.
7067 * @param {Roo.form.Field} this
7068 * @param {String} msg The validation message
7073 * Fires after the field has been validated with no errors.
7074 * @param {Roo.form.Field} this
7079 * Fires after the key up
7080 * @param {Roo.form.Field} this
7081 * @param {Roo.EventObject} e The event Object
7087 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7089 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7090 automatic validation (defaults to "keyup").
7092 validationEvent : "keyup",
7094 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7096 validateOnBlur : true,
7098 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7100 validationDelay : 250,
7102 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7104 focusClass : "x-form-focus", // not needed???
7108 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7110 invalidClass : "has-error",
7113 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7115 selectOnFocus : false,
7118 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7122 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7127 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7129 disableKeyFilter : false,
7132 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7136 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7140 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7142 blankText : "This field is required",
7145 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7149 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7151 maxLength : Number.MAX_VALUE,
7153 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7155 minLengthText : "The minimum length for this field is {0}",
7157 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7159 maxLengthText : "The maximum length for this field is {0}",
7163 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7164 * If available, this function will be called only after the basic validators all return true, and will be passed the
7165 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7169 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7170 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7171 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7175 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7198 formatedValue : false,
7200 parentLabelAlign : function()
7203 while (parent.parent()) {
7204 parent = parent.parent();
7205 if (typeof(parent.labelAlign) !='undefined') {
7206 return parent.labelAlign;
7213 getAutoCreate : function(){
7215 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7221 if(this.inputType != 'hidden'){
7222 cfg.cls = 'form-group' //input-group
7228 type : this.inputType,
7230 cls : 'form-control',
7231 placeholder : this.placeholder || ''
7236 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7239 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7240 input.maxLength = this.maxLength;
7243 if (this.disabled) {
7244 input.disabled=true;
7247 if (this.readOnly) {
7248 input.readonly=true;
7252 input.name = this.name;
7255 input.cls += ' input-' + this.size;
7258 ['xs','sm','md','lg'].map(function(size){
7259 if (settings[size]) {
7260 cfg.cls += ' col-' + size + '-' + settings[size];
7264 var inputblock = input;
7266 if (this.before || this.after) {
7269 cls : 'input-group',
7272 if (this.before && typeof(this.before) == 'string') {
7274 inputblock.cn.push({
7276 cls : 'roo-input-before input-group-addon',
7280 if (this.before && typeof(this.before) == 'object') {
7281 this.before = Roo.factory(this.before);
7282 Roo.log(this.before);
7283 inputblock.cn.push({
7285 cls : 'roo-input-before input-group-' +
7286 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7290 inputblock.cn.push(input);
7292 if (this.after && typeof(this.after) == 'string') {
7293 inputblock.cn.push({
7295 cls : 'roo-input-after input-group-addon',
7299 if (this.after && typeof(this.after) == 'object') {
7300 this.after = Roo.factory(this.after);
7301 Roo.log(this.after);
7302 inputblock.cn.push({
7304 cls : 'roo-input-after input-group-' +
7305 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7310 if (align ==='left' && this.fieldLabel.length) {
7311 Roo.log("left and has label");
7317 cls : 'control-label col-sm-' + this.labelWidth,
7318 html : this.fieldLabel
7322 cls : "col-sm-" + (12 - this.labelWidth),
7329 } else if ( this.fieldLabel.length) {
7335 //cls : 'input-group-addon',
7336 html : this.fieldLabel
7346 Roo.log(" no label && no align");
7355 Roo.log('input-parentType: ' + this.parentType);
7357 if (this.parentType === 'Navbar' && this.parent().bar) {
7358 cfg.cls += ' navbar-form';
7366 * return the real input element.
7368 inputEl: function ()
7370 return this.el.select('input.form-control',true).first();
7373 tooltipEl : function()
7375 return this.inputEl();
7378 setDisabled : function(v)
7380 var i = this.inputEl().dom;
7382 i.removeAttribute('disabled');
7386 i.setAttribute('disabled','true');
7388 initEvents : function()
7391 this.inputEl().on("keydown" , this.fireKey, this);
7392 this.inputEl().on("focus", this.onFocus, this);
7393 this.inputEl().on("blur", this.onBlur, this);
7395 this.inputEl().relayEvent('keyup', this);
7397 // reference to original value for reset
7398 this.originalValue = this.getValue();
7399 //Roo.form.TextField.superclass.initEvents.call(this);
7400 if(this.validationEvent == 'keyup'){
7401 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7402 this.inputEl().on('keyup', this.filterValidation, this);
7404 else if(this.validationEvent !== false){
7405 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7408 if(this.selectOnFocus){
7409 this.on("focus", this.preFocus, this);
7412 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7413 this.inputEl().on("keypress", this.filterKeys, this);
7416 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7417 this.el.on("click", this.autoSize, this);
7420 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7421 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7424 if (typeof(this.before) == 'object') {
7425 this.before.render(this.el.select('.roo-input-before',true).first());
7427 if (typeof(this.after) == 'object') {
7428 this.after.render(this.el.select('.roo-input-after',true).first());
7433 filterValidation : function(e){
7434 if(!e.isNavKeyPress()){
7435 this.validationTask.delay(this.validationDelay);
7439 * Validates the field value
7440 * @return {Boolean} True if the value is valid, else false
7442 validate : function(){
7443 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7444 if(this.disabled || this.validateValue(this.getRawValue())){
7445 this.clearInvalid();
7453 * Validates a value according to the field's validation rules and marks the field as invalid
7454 * if the validation fails
7455 * @param {Mixed} value The value to validate
7456 * @return {Boolean} True if the value is valid, else false
7458 validateValue : function(value){
7459 if(value.length < 1) { // if it's blank
7460 if(this.allowBlank){
7461 this.clearInvalid();
7464 this.markInvalid(this.blankText);
7468 if(value.length < this.minLength){
7469 this.markInvalid(String.format(this.minLengthText, this.minLength));
7472 if(value.length > this.maxLength){
7473 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7477 var vt = Roo.form.VTypes;
7478 if(!vt[this.vtype](value, this)){
7479 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7483 if(typeof this.validator == "function"){
7484 var msg = this.validator(value);
7486 this.markInvalid(msg);
7490 if(this.regex && !this.regex.test(value)){
7491 this.markInvalid(this.regexText);
7500 fireKey : function(e){
7501 //Roo.log('field ' + e.getKey());
7502 if(e.isNavKeyPress()){
7503 this.fireEvent("specialkey", this, e);
7506 focus : function (selectText){
7508 this.inputEl().focus();
7509 if(selectText === true){
7510 this.inputEl().dom.select();
7516 onFocus : function(){
7517 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7518 // this.el.addClass(this.focusClass);
7521 this.hasFocus = true;
7522 this.startValue = this.getValue();
7523 this.fireEvent("focus", this);
7527 beforeBlur : Roo.emptyFn,
7531 onBlur : function(){
7533 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7534 //this.el.removeClass(this.focusClass);
7536 this.hasFocus = false;
7537 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7540 var v = this.getValue();
7541 if(String(v) !== String(this.startValue)){
7542 this.fireEvent('change', this, v, this.startValue);
7544 this.fireEvent("blur", this);
7548 * Resets the current field value to the originally loaded value and clears any validation messages
7551 this.setValue(this.originalValue);
7552 this.clearInvalid();
7555 * Returns the name of the field
7556 * @return {Mixed} name The name field
7558 getName: function(){
7562 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7563 * @return {Mixed} value The field value
7565 getValue : function(){
7567 var v = this.inputEl().getValue();
7572 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7573 * @return {Mixed} value The field value
7575 getRawValue : function(){
7576 var v = this.inputEl().getValue();
7582 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7583 * @param {Mixed} value The value to set
7585 setRawValue : function(v){
7586 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7589 selectText : function(start, end){
7590 var v = this.getRawValue();
7592 start = start === undefined ? 0 : start;
7593 end = end === undefined ? v.length : end;
7594 var d = this.inputEl().dom;
7595 if(d.setSelectionRange){
7596 d.setSelectionRange(start, end);
7597 }else if(d.createTextRange){
7598 var range = d.createTextRange();
7599 range.moveStart("character", start);
7600 range.moveEnd("character", v.length-end);
7607 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7608 * @param {Mixed} value The value to set
7610 setValue : function(v){
7613 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7619 processValue : function(value){
7620 if(this.stripCharsRe){
7621 var newValue = value.replace(this.stripCharsRe, '');
7622 if(newValue !== value){
7623 this.setRawValue(newValue);
7630 preFocus : function(){
7632 if(this.selectOnFocus){
7633 this.inputEl().dom.select();
7636 filterKeys : function(e){
7638 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7641 var c = e.getCharCode(), cc = String.fromCharCode(c);
7642 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7645 if(!this.maskRe.test(cc)){
7650 * Clear any invalid styles/messages for this field
7652 clearInvalid : function(){
7654 if(!this.el || this.preventMark){ // not rendered
7657 this.el.removeClass(this.invalidClass);
7659 switch(this.msgTarget){
7661 this.el.dom.qtip = '';
7664 this.el.dom.title = '';
7668 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7673 this.errorIcon.dom.qtip = '';
7674 this.errorIcon.hide();
7675 this.un('resize', this.alignErrorIcon, this);
7679 var t = Roo.getDom(this.msgTarget);
7681 t.style.display = 'none';
7685 this.fireEvent('valid', this);
7688 * Mark this field as invalid
7689 * @param {String} msg The validation message
7691 markInvalid : function(msg){
7692 if(!this.el || this.preventMark){ // not rendered
7695 this.el.addClass(this.invalidClass);
7697 msg = msg || this.invalidText;
7698 switch(this.msgTarget){
7700 this.el.dom.qtip = msg;
7701 this.el.dom.qclass = 'x-form-invalid-tip';
7702 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7703 Roo.QuickTips.enable();
7707 this.el.dom.title = msg;
7711 var elp = this.el.findParent('.x-form-element', 5, true);
7712 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7713 this.errorEl.setWidth(elp.getWidth(true)-20);
7715 this.errorEl.update(msg);
7716 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7719 if(!this.errorIcon){
7720 var elp = this.el.findParent('.x-form-element', 5, true);
7721 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7723 this.alignErrorIcon();
7724 this.errorIcon.dom.qtip = msg;
7725 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7726 this.errorIcon.show();
7727 this.on('resize', this.alignErrorIcon, this);
7730 var t = Roo.getDom(this.msgTarget);
7732 t.style.display = this.msgDisplay;
7736 this.fireEvent('invalid', this, msg);
7739 SafariOnKeyDown : function(event)
7741 // this is a workaround for a password hang bug on chrome/ webkit.
7743 var isSelectAll = false;
7745 if(this.inputEl().dom.selectionEnd > 0){
7746 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7748 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7749 event.preventDefault();
7754 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7756 event.preventDefault();
7757 // this is very hacky as keydown always get's upper case.
7759 var cc = String.fromCharCode(event.getCharCode());
7760 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7764 adjustWidth : function(tag, w){
7765 tag = tag.toLowerCase();
7766 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7767 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7771 if(tag == 'textarea'){
7774 }else if(Roo.isOpera){
7778 if(tag == 'textarea'){
7797 * @class Roo.bootstrap.TextArea
7798 * @extends Roo.bootstrap.Input
7799 * Bootstrap TextArea class
7800 * @cfg {Number} cols Specifies the visible width of a text area
7801 * @cfg {Number} rows Specifies the visible number of lines in a text area
7802 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7803 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7804 * @cfg {string} html text
7807 * Create a new TextArea
7808 * @param {Object} config The config object
7811 Roo.bootstrap.TextArea = function(config){
7812 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7816 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7826 getAutoCreate : function(){
7828 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7839 value : this.value || '',
7840 html: this.html || '',
7841 cls : 'form-control',
7842 placeholder : this.placeholder || ''
7846 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7847 input.maxLength = this.maxLength;
7851 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7855 input.cols = this.cols;
7858 if (this.readOnly) {
7859 input.readonly = true;
7863 input.name = this.name;
7867 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7871 ['xs','sm','md','lg'].map(function(size){
7872 if (settings[size]) {
7873 cfg.cls += ' col-' + size + '-' + settings[size];
7877 var inputblock = input;
7879 if (this.before || this.after) {
7882 cls : 'input-group',
7886 inputblock.cn.push({
7888 cls : 'input-group-addon',
7892 inputblock.cn.push(input);
7894 inputblock.cn.push({
7896 cls : 'input-group-addon',
7903 if (align ==='left' && this.fieldLabel.length) {
7904 Roo.log("left and has label");
7910 cls : 'control-label col-sm-' + this.labelWidth,
7911 html : this.fieldLabel
7915 cls : "col-sm-" + (12 - this.labelWidth),
7922 } else if ( this.fieldLabel.length) {
7928 //cls : 'input-group-addon',
7929 html : this.fieldLabel
7939 Roo.log(" no label && no align");
7949 if (this.disabled) {
7950 input.disabled=true;
7957 * return the real textarea element.
7959 inputEl: function ()
7961 return this.el.select('textarea.form-control',true).first();
7969 * trigger field - base class for combo..
7974 * @class Roo.bootstrap.TriggerField
7975 * @extends Roo.bootstrap.Input
7976 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7977 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7978 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7979 * for which you can provide a custom implementation. For example:
7981 var trigger = new Roo.bootstrap.TriggerField();
7982 trigger.onTriggerClick = myTriggerFn;
7983 trigger.applyTo('my-field');
7986 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7987 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7988 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7989 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7990 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
7993 * Create a new TriggerField.
7994 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7995 * to the base TextField)
7997 Roo.bootstrap.TriggerField = function(config){
7998 this.mimicing = false;
7999 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8002 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8004 * @cfg {String} triggerClass A CSS class to apply to the trigger
8007 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8011 /** @cfg {Boolean} grow @hide */
8012 /** @cfg {Number} growMin @hide */
8013 /** @cfg {Number} growMax @hide */
8019 autoSize: Roo.emptyFn,
8026 actionMode : 'wrap',
8031 getAutoCreate : function(){
8033 var align = this.labelAlign || this.parentLabelAlign();
8038 cls: 'form-group' //input-group
8045 type : this.inputType,
8046 cls : 'form-control',
8047 autocomplete: 'false',
8048 placeholder : this.placeholder || ''
8052 input.name = this.name;
8055 input.cls += ' input-' + this.size;
8058 if (this.disabled) {
8059 input.disabled=true;
8062 var inputblock = input;
8064 if (this.before || this.after) {
8067 cls : 'input-group',
8071 inputblock.cn.push({
8073 cls : 'input-group-addon',
8077 inputblock.cn.push(input);
8079 inputblock.cn.push({
8081 cls : 'input-group-addon',
8094 cls: 'form-hidden-field'
8102 Roo.log('multiple');
8110 cls: 'form-hidden-field'
8114 cls: 'select2-choices',
8118 cls: 'select2-search-field',
8131 cls: 'select2-container input-group',
8136 // cls: 'typeahead typeahead-long dropdown-menu',
8137 // style: 'display:none'
8142 if(!this.multiple && this.showToggleBtn){
8148 if (this.caret != false) {
8151 cls: 'fa fa-' + this.caret
8158 cls : 'input-group-addon btn dropdown-toggle',
8163 cls: 'combobox-clear',
8177 combobox.cls += ' select2-container-multi';
8180 if (align ==='left' && this.fieldLabel.length) {
8182 Roo.log("left and has label");
8188 cls : 'control-label col-sm-' + this.labelWidth,
8189 html : this.fieldLabel
8193 cls : "col-sm-" + (12 - this.labelWidth),
8200 } else if ( this.fieldLabel.length) {
8206 //cls : 'input-group-addon',
8207 html : this.fieldLabel
8217 Roo.log(" no label && no align");
8224 ['xs','sm','md','lg'].map(function(size){
8225 if (settings[size]) {
8226 cfg.cls += ' col-' + size + '-' + settings[size];
8237 onResize : function(w, h){
8238 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8239 // if(typeof w == 'number'){
8240 // var x = w - this.trigger.getWidth();
8241 // this.inputEl().setWidth(this.adjustWidth('input', x));
8242 // this.trigger.setStyle('left', x+'px');
8247 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8250 getResizeEl : function(){
8251 return this.inputEl();
8255 getPositionEl : function(){
8256 return this.inputEl();
8260 alignErrorIcon : function(){
8261 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8265 initEvents : function(){
8269 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8270 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8271 if(!this.multiple && this.showToggleBtn){
8272 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8273 if(this.hideTrigger){
8274 this.trigger.setDisplayed(false);
8276 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8280 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8283 //this.trigger.addClassOnOver('x-form-trigger-over');
8284 //this.trigger.addClassOnClick('x-form-trigger-click');
8287 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8291 createList : function()
8293 this.list = Roo.get(document.body).createChild({
8295 cls: 'typeahead typeahead-long dropdown-menu',
8296 style: 'display:none'
8299 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8304 initTrigger : function(){
8309 onDestroy : function(){
8311 this.trigger.removeAllListeners();
8312 // this.trigger.remove();
8315 // this.wrap.remove();
8317 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8321 onFocus : function(){
8322 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8325 this.wrap.addClass('x-trigger-wrap-focus');
8326 this.mimicing = true;
8327 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8328 if(this.monitorTab){
8329 this.el.on("keydown", this.checkTab, this);
8336 checkTab : function(e){
8337 if(e.getKey() == e.TAB){
8343 onBlur : function(){
8348 mimicBlur : function(e, t){
8350 if(!this.wrap.contains(t) && this.validateBlur()){
8357 triggerBlur : function(){
8358 this.mimicing = false;
8359 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8360 if(this.monitorTab){
8361 this.el.un("keydown", this.checkTab, this);
8363 //this.wrap.removeClass('x-trigger-wrap-focus');
8364 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8368 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8369 validateBlur : function(e, t){
8374 onDisable : function(){
8375 this.inputEl().dom.disabled = true;
8376 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8378 // this.wrap.addClass('x-item-disabled');
8383 onEnable : function(){
8384 this.inputEl().dom.disabled = false;
8385 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8387 // this.el.removeClass('x-item-disabled');
8392 onShow : function(){
8393 var ae = this.getActionEl();
8396 ae.dom.style.display = '';
8397 ae.dom.style.visibility = 'visible';
8403 onHide : function(){
8404 var ae = this.getActionEl();
8405 ae.dom.style.display = 'none';
8409 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8410 * by an implementing function.
8412 * @param {EventObject} e
8414 onTriggerClick : Roo.emptyFn
8418 * Ext JS Library 1.1.1
8419 * Copyright(c) 2006-2007, Ext JS, LLC.
8421 * Originally Released Under LGPL - original licence link has changed is not relivant.
8424 * <script type="text/javascript">
8429 * @class Roo.data.SortTypes
8431 * Defines the default sorting (casting?) comparison functions used when sorting data.
8433 Roo.data.SortTypes = {
8435 * Default sort that does nothing
8436 * @param {Mixed} s The value being converted
8437 * @return {Mixed} The comparison value
8444 * The regular expression used to strip tags
8448 stripTagsRE : /<\/?[^>]+>/gi,
8451 * Strips all HTML tags to sort on text only
8452 * @param {Mixed} s The value being converted
8453 * @return {String} The comparison value
8455 asText : function(s){
8456 return String(s).replace(this.stripTagsRE, "");
8460 * Strips all HTML tags to sort on text only - Case insensitive
8461 * @param {Mixed} s The value being converted
8462 * @return {String} The comparison value
8464 asUCText : function(s){
8465 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8469 * Case insensitive string
8470 * @param {Mixed} s The value being converted
8471 * @return {String} The comparison value
8473 asUCString : function(s) {
8474 return String(s).toUpperCase();
8479 * @param {Mixed} s The value being converted
8480 * @return {Number} The comparison value
8482 asDate : function(s) {
8486 if(s instanceof Date){
8489 return Date.parse(String(s));
8494 * @param {Mixed} s The value being converted
8495 * @return {Float} The comparison value
8497 asFloat : function(s) {
8498 var val = parseFloat(String(s).replace(/,/g, ""));
8499 if(isNaN(val)) val = 0;
8505 * @param {Mixed} s The value being converted
8506 * @return {Number} The comparison value
8508 asInt : function(s) {
8509 var val = parseInt(String(s).replace(/,/g, ""));
8510 if(isNaN(val)) val = 0;
8515 * Ext JS Library 1.1.1
8516 * Copyright(c) 2006-2007, Ext JS, LLC.
8518 * Originally Released Under LGPL - original licence link has changed is not relivant.
8521 * <script type="text/javascript">
8525 * @class Roo.data.Record
8526 * Instances of this class encapsulate both record <em>definition</em> information, and record
8527 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8528 * to access Records cached in an {@link Roo.data.Store} object.<br>
8530 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8531 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8534 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8536 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8537 * {@link #create}. The parameters are the same.
8538 * @param {Array} data An associative Array of data values keyed by the field name.
8539 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8540 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8541 * not specified an integer id is generated.
8543 Roo.data.Record = function(data, id){
8544 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8549 * Generate a constructor for a specific record layout.
8550 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8551 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8552 * Each field definition object may contain the following properties: <ul>
8553 * <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,
8554 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8555 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8556 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8557 * is being used, then this is a string containing the javascript expression to reference the data relative to
8558 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8559 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8560 * this may be omitted.</p></li>
8561 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8562 * <ul><li>auto (Default, implies no conversion)</li>
8567 * <li>date</li></ul></p></li>
8568 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8569 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8570 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8571 * by the Reader into an object that will be stored in the Record. It is passed the
8572 * following parameters:<ul>
8573 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8575 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8577 * <br>usage:<br><pre><code>
8578 var TopicRecord = Roo.data.Record.create(
8579 {name: 'title', mapping: 'topic_title'},
8580 {name: 'author', mapping: 'username'},
8581 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8582 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8583 {name: 'lastPoster', mapping: 'user2'},
8584 {name: 'excerpt', mapping: 'post_text'}
8587 var myNewRecord = new TopicRecord({
8588 title: 'Do my job please',
8591 lastPost: new Date(),
8592 lastPoster: 'Animal',
8593 excerpt: 'No way dude!'
8595 myStore.add(myNewRecord);
8600 Roo.data.Record.create = function(o){
8602 f.superclass.constructor.apply(this, arguments);
8604 Roo.extend(f, Roo.data.Record);
8605 var p = f.prototype;
8606 p.fields = new Roo.util.MixedCollection(false, function(field){
8609 for(var i = 0, len = o.length; i < len; i++){
8610 p.fields.add(new Roo.data.Field(o[i]));
8612 f.getField = function(name){
8613 return p.fields.get(name);
8618 Roo.data.Record.AUTO_ID = 1000;
8619 Roo.data.Record.EDIT = 'edit';
8620 Roo.data.Record.REJECT = 'reject';
8621 Roo.data.Record.COMMIT = 'commit';
8623 Roo.data.Record.prototype = {
8625 * Readonly flag - true if this record has been modified.
8634 join : function(store){
8639 * Set the named field to the specified value.
8640 * @param {String} name The name of the field to set.
8641 * @param {Object} value The value to set the field to.
8643 set : function(name, value){
8644 if(this.data[name] == value){
8651 if(typeof this.modified[name] == 'undefined'){
8652 this.modified[name] = this.data[name];
8654 this.data[name] = value;
8655 if(!this.editing && this.store){
8656 this.store.afterEdit(this);
8661 * Get the value of the named field.
8662 * @param {String} name The name of the field to get the value of.
8663 * @return {Object} The value of the field.
8665 get : function(name){
8666 return this.data[name];
8670 beginEdit : function(){
8671 this.editing = true;
8676 cancelEdit : function(){
8677 this.editing = false;
8678 delete this.modified;
8682 endEdit : function(){
8683 this.editing = false;
8684 if(this.dirty && this.store){
8685 this.store.afterEdit(this);
8690 * Usually called by the {@link Roo.data.Store} which owns the Record.
8691 * Rejects all changes made to the Record since either creation, or the last commit operation.
8692 * Modified fields are reverted to their original values.
8694 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8695 * of reject operations.
8697 reject : function(){
8698 var m = this.modified;
8700 if(typeof m[n] != "function"){
8701 this.data[n] = m[n];
8705 delete this.modified;
8706 this.editing = false;
8708 this.store.afterReject(this);
8713 * Usually called by the {@link Roo.data.Store} which owns the Record.
8714 * Commits all changes made to the Record since either creation, or the last commit operation.
8716 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8717 * of commit operations.
8719 commit : function(){
8721 delete this.modified;
8722 this.editing = false;
8724 this.store.afterCommit(this);
8729 hasError : function(){
8730 return this.error != null;
8734 clearError : function(){
8739 * Creates a copy of this record.
8740 * @param {String} id (optional) A new record id if you don't want to use this record's id
8743 copy : function(newId) {
8744 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8748 * Ext JS Library 1.1.1
8749 * Copyright(c) 2006-2007, Ext JS, LLC.
8751 * Originally Released Under LGPL - original licence link has changed is not relivant.
8754 * <script type="text/javascript">
8760 * @class Roo.data.Store
8761 * @extends Roo.util.Observable
8762 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8763 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8765 * 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
8766 * has no knowledge of the format of the data returned by the Proxy.<br>
8768 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8769 * instances from the data object. These records are cached and made available through accessor functions.
8771 * Creates a new Store.
8772 * @param {Object} config A config object containing the objects needed for the Store to access data,
8773 * and read the data into Records.
8775 Roo.data.Store = function(config){
8776 this.data = new Roo.util.MixedCollection(false);
8777 this.data.getKey = function(o){
8780 this.baseParams = {};
8787 "multisort" : "_multisort"
8790 if(config && config.data){
8791 this.inlineData = config.data;
8795 Roo.apply(this, config);
8797 if(this.reader){ // reader passed
8798 this.reader = Roo.factory(this.reader, Roo.data);
8799 this.reader.xmodule = this.xmodule || false;
8800 if(!this.recordType){
8801 this.recordType = this.reader.recordType;
8803 if(this.reader.onMetaChange){
8804 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8808 if(this.recordType){
8809 this.fields = this.recordType.prototype.fields;
8815 * @event datachanged
8816 * Fires when the data cache has changed, and a widget which is using this Store
8817 * as a Record cache should refresh its view.
8818 * @param {Store} this
8823 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8824 * @param {Store} this
8825 * @param {Object} meta The JSON metadata
8830 * Fires when Records have been added to the Store
8831 * @param {Store} this
8832 * @param {Roo.data.Record[]} records The array of Records added
8833 * @param {Number} index The index at which the record(s) were added
8838 * Fires when a Record has been removed from the Store
8839 * @param {Store} this
8840 * @param {Roo.data.Record} record The Record that was removed
8841 * @param {Number} index The index at which the record was removed
8846 * Fires when a Record has been updated
8847 * @param {Store} this
8848 * @param {Roo.data.Record} record The Record that was updated
8849 * @param {String} operation The update operation being performed. Value may be one of:
8851 Roo.data.Record.EDIT
8852 Roo.data.Record.REJECT
8853 Roo.data.Record.COMMIT
8859 * Fires when the data cache has been cleared.
8860 * @param {Store} this
8865 * Fires before a request is made for a new data object. If the beforeload handler returns false
8866 * the load action will be canceled.
8867 * @param {Store} this
8868 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8872 * @event beforeloadadd
8873 * Fires after a new set of Records has been loaded.
8874 * @param {Store} this
8875 * @param {Roo.data.Record[]} records The Records that were loaded
8876 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8878 beforeloadadd : true,
8881 * Fires after a new set of Records has been loaded, before they are added to the store.
8882 * @param {Store} this
8883 * @param {Roo.data.Record[]} records The Records that were loaded
8884 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8885 * @params {Object} return from reader
8889 * @event loadexception
8890 * Fires if an exception occurs in the Proxy during loading.
8891 * Called with the signature of the Proxy's "loadexception" event.
8892 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8895 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8896 * @param {Object} load options
8897 * @param {Object} jsonData from your request (normally this contains the Exception)
8899 loadexception : true
8903 this.proxy = Roo.factory(this.proxy, Roo.data);
8904 this.proxy.xmodule = this.xmodule || false;
8905 this.relayEvents(this.proxy, ["loadexception"]);
8907 this.sortToggle = {};
8908 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8910 Roo.data.Store.superclass.constructor.call(this);
8912 if(this.inlineData){
8913 this.loadData(this.inlineData);
8914 delete this.inlineData;
8918 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8920 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8921 * without a remote query - used by combo/forms at present.
8925 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8928 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8931 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8932 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8935 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8936 * on any HTTP request
8939 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8942 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8946 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8947 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8952 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8953 * loaded or when a record is removed. (defaults to false).
8955 pruneModifiedRecords : false,
8961 * Add Records to the Store and fires the add event.
8962 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8964 add : function(records){
8965 records = [].concat(records);
8966 for(var i = 0, len = records.length; i < len; i++){
8967 records[i].join(this);
8969 var index = this.data.length;
8970 this.data.addAll(records);
8971 this.fireEvent("add", this, records, index);
8975 * Remove a Record from the Store and fires the remove event.
8976 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8978 remove : function(record){
8979 var index = this.data.indexOf(record);
8980 this.data.removeAt(index);
8981 if(this.pruneModifiedRecords){
8982 this.modified.remove(record);
8984 this.fireEvent("remove", this, record, index);
8988 * Remove all Records from the Store and fires the clear event.
8990 removeAll : function(){
8992 if(this.pruneModifiedRecords){
8995 this.fireEvent("clear", this);
8999 * Inserts Records to the Store at the given index and fires the add event.
9000 * @param {Number} index The start index at which to insert the passed Records.
9001 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9003 insert : function(index, records){
9004 records = [].concat(records);
9005 for(var i = 0, len = records.length; i < len; i++){
9006 this.data.insert(index, records[i]);
9007 records[i].join(this);
9009 this.fireEvent("add", this, records, index);
9013 * Get the index within the cache of the passed Record.
9014 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9015 * @return {Number} The index of the passed Record. Returns -1 if not found.
9017 indexOf : function(record){
9018 return this.data.indexOf(record);
9022 * Get the index within the cache of the Record with the passed id.
9023 * @param {String} id The id of the Record to find.
9024 * @return {Number} The index of the Record. Returns -1 if not found.
9026 indexOfId : function(id){
9027 return this.data.indexOfKey(id);
9031 * Get the Record with the specified id.
9032 * @param {String} id The id of the Record to find.
9033 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9035 getById : function(id){
9036 return this.data.key(id);
9040 * Get the Record at the specified index.
9041 * @param {Number} index The index of the Record to find.
9042 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9044 getAt : function(index){
9045 return this.data.itemAt(index);
9049 * Returns a range of Records between specified indices.
9050 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9051 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9052 * @return {Roo.data.Record[]} An array of Records
9054 getRange : function(start, end){
9055 return this.data.getRange(start, end);
9059 storeOptions : function(o){
9060 o = Roo.apply({}, o);
9063 this.lastOptions = o;
9067 * Loads the Record cache from the configured Proxy using the configured Reader.
9069 * If using remote paging, then the first load call must specify the <em>start</em>
9070 * and <em>limit</em> properties in the options.params property to establish the initial
9071 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9073 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9074 * and this call will return before the new data has been loaded. Perform any post-processing
9075 * in a callback function, or in a "load" event handler.</strong>
9077 * @param {Object} options An object containing properties which control loading options:<ul>
9078 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9079 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9080 * passed the following arguments:<ul>
9081 * <li>r : Roo.data.Record[]</li>
9082 * <li>options: Options object from the load call</li>
9083 * <li>success: Boolean success indicator</li></ul></li>
9084 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9085 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9088 load : function(options){
9089 options = options || {};
9090 if(this.fireEvent("beforeload", this, options) !== false){
9091 this.storeOptions(options);
9092 var p = Roo.apply(options.params || {}, this.baseParams);
9093 // if meta was not loaded from remote source.. try requesting it.
9094 if (!this.reader.metaFromRemote) {
9097 if(this.sortInfo && this.remoteSort){
9098 var pn = this.paramNames;
9099 p[pn["sort"]] = this.sortInfo.field;
9100 p[pn["dir"]] = this.sortInfo.direction;
9102 if (this.multiSort) {
9103 var pn = this.paramNames;
9104 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9107 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9112 * Reloads the Record cache from the configured Proxy using the configured Reader and
9113 * the options from the last load operation performed.
9114 * @param {Object} options (optional) An object containing properties which may override the options
9115 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9116 * the most recently used options are reused).
9118 reload : function(options){
9119 this.load(Roo.applyIf(options||{}, this.lastOptions));
9123 // Called as a callback by the Reader during a load operation.
9124 loadRecords : function(o, options, success){
9125 if(!o || success === false){
9126 if(success !== false){
9127 this.fireEvent("load", this, [], options, o);
9129 if(options.callback){
9130 options.callback.call(options.scope || this, [], options, false);
9134 // if data returned failure - throw an exception.
9135 if (o.success === false) {
9136 // show a message if no listener is registered.
9137 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9138 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9140 // loadmask wil be hooked into this..
9141 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9144 var r = o.records, t = o.totalRecords || r.length;
9146 this.fireEvent("beforeloadadd", this, r, options, o);
9148 if(!options || options.add !== true){
9149 if(this.pruneModifiedRecords){
9152 for(var i = 0, len = r.length; i < len; i++){
9156 this.data = this.snapshot;
9157 delete this.snapshot;
9160 this.data.addAll(r);
9161 this.totalLength = t;
9163 this.fireEvent("datachanged", this);
9165 this.totalLength = Math.max(t, this.data.length+r.length);
9168 this.fireEvent("load", this, r, options, o);
9169 if(options.callback){
9170 options.callback.call(options.scope || this, r, options, true);
9176 * Loads data from a passed data block. A Reader which understands the format of the data
9177 * must have been configured in the constructor.
9178 * @param {Object} data The data block from which to read the Records. The format of the data expected
9179 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9180 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9182 loadData : function(o, append){
9183 var r = this.reader.readRecords(o);
9184 this.loadRecords(r, {add: append}, true);
9188 * Gets the number of cached records.
9190 * <em>If using paging, this may not be the total size of the dataset. If the data object
9191 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9192 * the data set size</em>
9194 getCount : function(){
9195 return this.data.length || 0;
9199 * Gets the total number of records in the dataset as returned by the server.
9201 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9202 * the dataset size</em>
9204 getTotalCount : function(){
9205 return this.totalLength || 0;
9209 * Returns the sort state of the Store as an object with two properties:
9211 field {String} The name of the field by which the Records are sorted
9212 direction {String} The sort order, "ASC" or "DESC"
9215 getSortState : function(){
9216 return this.sortInfo;
9220 applySort : function(){
9221 if(this.sortInfo && !this.remoteSort){
9222 var s = this.sortInfo, f = s.field;
9223 var st = this.fields.get(f).sortType;
9224 var fn = function(r1, r2){
9225 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9226 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9228 this.data.sort(s.direction, fn);
9229 if(this.snapshot && this.snapshot != this.data){
9230 this.snapshot.sort(s.direction, fn);
9236 * Sets the default sort column and order to be used by the next load operation.
9237 * @param {String} fieldName The name of the field to sort by.
9238 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9240 setDefaultSort : function(field, dir){
9241 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9246 * If remote sorting is used, the sort is performed on the server, and the cache is
9247 * reloaded. If local sorting is used, the cache is sorted internally.
9248 * @param {String} fieldName The name of the field to sort by.
9249 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9251 sort : function(fieldName, dir){
9252 var f = this.fields.get(fieldName);
9254 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9256 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9257 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9262 this.sortToggle[f.name] = dir;
9263 this.sortInfo = {field: f.name, direction: dir};
9264 if(!this.remoteSort){
9266 this.fireEvent("datachanged", this);
9268 this.load(this.lastOptions);
9273 * Calls the specified function for each of the Records in the cache.
9274 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9275 * Returning <em>false</em> aborts and exits the iteration.
9276 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9278 each : function(fn, scope){
9279 this.data.each(fn, scope);
9283 * Gets all records modified since the last commit. Modified records are persisted across load operations
9284 * (e.g., during paging).
9285 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9287 getModifiedRecords : function(){
9288 return this.modified;
9292 createFilterFn : function(property, value, anyMatch){
9293 if(!value.exec){ // not a regex
9294 value = String(value);
9295 if(value.length == 0){
9298 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9301 return value.test(r.data[property]);
9306 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9307 * @param {String} property A field on your records
9308 * @param {Number} start The record index to start at (defaults to 0)
9309 * @param {Number} end The last record index to include (defaults to length - 1)
9310 * @return {Number} The sum
9312 sum : function(property, start, end){
9313 var rs = this.data.items, v = 0;
9315 end = (end || end === 0) ? end : rs.length-1;
9317 for(var i = start; i <= end; i++){
9318 v += (rs[i].data[property] || 0);
9324 * Filter the records by a specified property.
9325 * @param {String} field A field on your records
9326 * @param {String/RegExp} value Either a string that the field
9327 * should start with or a RegExp to test against the field
9328 * @param {Boolean} anyMatch True to match any part not just the beginning
9330 filter : function(property, value, anyMatch){
9331 var fn = this.createFilterFn(property, value, anyMatch);
9332 return fn ? this.filterBy(fn) : this.clearFilter();
9336 * Filter by a function. The specified function will be called with each
9337 * record in this data source. If the function returns true the record is included,
9338 * otherwise it is filtered.
9339 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9340 * @param {Object} scope (optional) The scope of the function (defaults to this)
9342 filterBy : function(fn, scope){
9343 this.snapshot = this.snapshot || this.data;
9344 this.data = this.queryBy(fn, scope||this);
9345 this.fireEvent("datachanged", this);
9349 * Query the records by a specified property.
9350 * @param {String} field A field on your records
9351 * @param {String/RegExp} value Either a string that the field
9352 * should start with or a RegExp to test against the field
9353 * @param {Boolean} anyMatch True to match any part not just the beginning
9354 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9356 query : function(property, value, anyMatch){
9357 var fn = this.createFilterFn(property, value, anyMatch);
9358 return fn ? this.queryBy(fn) : this.data.clone();
9362 * Query by a function. The specified function will be called with each
9363 * record in this data source. If the function returns true the record is included
9365 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9366 * @param {Object} scope (optional) The scope of the function (defaults to this)
9367 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9369 queryBy : function(fn, scope){
9370 var data = this.snapshot || this.data;
9371 return data.filterBy(fn, scope||this);
9375 * Collects unique values for a particular dataIndex from this store.
9376 * @param {String} dataIndex The property to collect
9377 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9378 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9379 * @return {Array} An array of the unique values
9381 collect : function(dataIndex, allowNull, bypassFilter){
9382 var d = (bypassFilter === true && this.snapshot) ?
9383 this.snapshot.items : this.data.items;
9384 var v, sv, r = [], l = {};
9385 for(var i = 0, len = d.length; i < len; i++){
9386 v = d[i].data[dataIndex];
9388 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9397 * Revert to a view of the Record cache with no filtering applied.
9398 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9400 clearFilter : function(suppressEvent){
9401 if(this.snapshot && this.snapshot != this.data){
9402 this.data = this.snapshot;
9403 delete this.snapshot;
9404 if(suppressEvent !== true){
9405 this.fireEvent("datachanged", this);
9411 afterEdit : function(record){
9412 if(this.modified.indexOf(record) == -1){
9413 this.modified.push(record);
9415 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9419 afterReject : function(record){
9420 this.modified.remove(record);
9421 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9425 afterCommit : function(record){
9426 this.modified.remove(record);
9427 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9431 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9432 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9434 commitChanges : function(){
9435 var m = this.modified.slice(0);
9437 for(var i = 0, len = m.length; i < len; i++){
9443 * Cancel outstanding changes on all changed records.
9445 rejectChanges : function(){
9446 var m = this.modified.slice(0);
9448 for(var i = 0, len = m.length; i < len; i++){
9453 onMetaChange : function(meta, rtype, o){
9454 this.recordType = rtype;
9455 this.fields = rtype.prototype.fields;
9456 delete this.snapshot;
9457 this.sortInfo = meta.sortInfo || this.sortInfo;
9459 this.fireEvent('metachange', this, this.reader.meta);
9462 moveIndex : function(data, type)
9464 var index = this.indexOf(data);
9466 var newIndex = index + type;
9470 this.insert(newIndex, data);
9475 * Ext JS Library 1.1.1
9476 * Copyright(c) 2006-2007, Ext JS, LLC.
9478 * Originally Released Under LGPL - original licence link has changed is not relivant.
9481 * <script type="text/javascript">
9485 * @class Roo.data.SimpleStore
9486 * @extends Roo.data.Store
9487 * Small helper class to make creating Stores from Array data easier.
9488 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9489 * @cfg {Array} fields An array of field definition objects, or field name strings.
9490 * @cfg {Array} data The multi-dimensional array of data
9492 * @param {Object} config
9494 Roo.data.SimpleStore = function(config){
9495 Roo.data.SimpleStore.superclass.constructor.call(this, {
9497 reader: new Roo.data.ArrayReader({
9500 Roo.data.Record.create(config.fields)
9502 proxy : new Roo.data.MemoryProxy(config.data)
9506 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9508 * Ext JS Library 1.1.1
9509 * Copyright(c) 2006-2007, Ext JS, LLC.
9511 * Originally Released Under LGPL - original licence link has changed is not relivant.
9514 * <script type="text/javascript">
9519 * @extends Roo.data.Store
9520 * @class Roo.data.JsonStore
9521 * Small helper class to make creating Stores for JSON data easier. <br/>
9523 var store = new Roo.data.JsonStore({
9524 url: 'get-images.php',
9526 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9529 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9530 * JsonReader and HttpProxy (unless inline data is provided).</b>
9531 * @cfg {Array} fields An array of field definition objects, or field name strings.
9533 * @param {Object} config
9535 Roo.data.JsonStore = function(c){
9536 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9537 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9538 reader: new Roo.data.JsonReader(c, c.fields)
9541 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9543 * Ext JS Library 1.1.1
9544 * Copyright(c) 2006-2007, Ext JS, LLC.
9546 * Originally Released Under LGPL - original licence link has changed is not relivant.
9549 * <script type="text/javascript">
9553 Roo.data.Field = function(config){
9554 if(typeof config == "string"){
9555 config = {name: config};
9557 Roo.apply(this, config);
9563 var st = Roo.data.SortTypes;
9564 // named sortTypes are supported, here we look them up
9565 if(typeof this.sortType == "string"){
9566 this.sortType = st[this.sortType];
9569 // set default sortType for strings and dates
9573 this.sortType = st.asUCString;
9576 this.sortType = st.asDate;
9579 this.sortType = st.none;
9584 var stripRe = /[\$,%]/g;
9586 // prebuilt conversion function for this field, instead of
9587 // switching every time we're reading a value
9589 var cv, dateFormat = this.dateFormat;
9594 cv = function(v){ return v; };
9597 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9601 return v !== undefined && v !== null && v !== '' ?
9602 parseInt(String(v).replace(stripRe, ""), 10) : '';
9607 return v !== undefined && v !== null && v !== '' ?
9608 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9613 cv = function(v){ return v === true || v === "true" || v == 1; };
9620 if(v instanceof Date){
9624 if(dateFormat == "timestamp"){
9625 return new Date(v*1000);
9627 return Date.parseDate(v, dateFormat);
9629 var parsed = Date.parse(v);
9630 return parsed ? new Date(parsed) : null;
9639 Roo.data.Field.prototype = {
9647 * Ext JS Library 1.1.1
9648 * Copyright(c) 2006-2007, Ext JS, LLC.
9650 * Originally Released Under LGPL - original licence link has changed is not relivant.
9653 * <script type="text/javascript">
9656 // Base class for reading structured data from a data source. This class is intended to be
9657 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9660 * @class Roo.data.DataReader
9661 * Base class for reading structured data from a data source. This class is intended to be
9662 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9665 Roo.data.DataReader = function(meta, recordType){
9669 this.recordType = recordType instanceof Array ?
9670 Roo.data.Record.create(recordType) : recordType;
9673 Roo.data.DataReader.prototype = {
9675 * Create an empty record
9676 * @param {Object} data (optional) - overlay some values
9677 * @return {Roo.data.Record} record created.
9679 newRow : function(d) {
9681 this.recordType.prototype.fields.each(function(c) {
9683 case 'int' : da[c.name] = 0; break;
9684 case 'date' : da[c.name] = new Date(); break;
9685 case 'float' : da[c.name] = 0.0; break;
9686 case 'boolean' : da[c.name] = false; break;
9687 default : da[c.name] = ""; break;
9691 return new this.recordType(Roo.apply(da, d));
9696 * Ext JS Library 1.1.1
9697 * Copyright(c) 2006-2007, Ext JS, LLC.
9699 * Originally Released Under LGPL - original licence link has changed is not relivant.
9702 * <script type="text/javascript">
9706 * @class Roo.data.DataProxy
9707 * @extends Roo.data.Observable
9708 * This class is an abstract base class for implementations which provide retrieval of
9709 * unformatted data objects.<br>
9711 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9712 * (of the appropriate type which knows how to parse the data object) to provide a block of
9713 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9715 * Custom implementations must implement the load method as described in
9716 * {@link Roo.data.HttpProxy#load}.
9718 Roo.data.DataProxy = function(){
9722 * Fires before a network request is made to retrieve a data object.
9723 * @param {Object} This DataProxy object.
9724 * @param {Object} params The params parameter to the load function.
9729 * Fires before the load method's callback is called.
9730 * @param {Object} This DataProxy object.
9731 * @param {Object} o The data object.
9732 * @param {Object} arg The callback argument object passed to the load function.
9736 * @event loadexception
9737 * Fires if an Exception occurs during data retrieval.
9738 * @param {Object} This DataProxy object.
9739 * @param {Object} o The data object.
9740 * @param {Object} arg The callback argument object passed to the load function.
9741 * @param {Object} e The Exception.
9743 loadexception : true
9745 Roo.data.DataProxy.superclass.constructor.call(this);
9748 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9751 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9755 * Ext JS Library 1.1.1
9756 * Copyright(c) 2006-2007, Ext JS, LLC.
9758 * Originally Released Under LGPL - original licence link has changed is not relivant.
9761 * <script type="text/javascript">
9764 * @class Roo.data.MemoryProxy
9765 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9766 * to the Reader when its load method is called.
9768 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9770 Roo.data.MemoryProxy = function(data){
9774 Roo.data.MemoryProxy.superclass.constructor.call(this);
9778 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9780 * Load data from the requested source (in this case an in-memory
9781 * data object passed to the constructor), read the data object into
9782 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9783 * process that block using the passed callback.
9784 * @param {Object} params This parameter is not used by the MemoryProxy class.
9785 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9786 * object into a block of Roo.data.Records.
9787 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9788 * The function must be passed <ul>
9789 * <li>The Record block object</li>
9790 * <li>The "arg" argument from the load function</li>
9791 * <li>A boolean success indicator</li>
9793 * @param {Object} scope The scope in which to call the callback
9794 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9796 load : function(params, reader, callback, scope, arg){
9797 params = params || {};
9800 result = reader.readRecords(this.data);
9802 this.fireEvent("loadexception", this, arg, null, e);
9803 callback.call(scope, null, arg, false);
9806 callback.call(scope, result, arg, true);
9810 update : function(params, records){
9815 * Ext JS Library 1.1.1
9816 * Copyright(c) 2006-2007, Ext JS, LLC.
9818 * Originally Released Under LGPL - original licence link has changed is not relivant.
9821 * <script type="text/javascript">
9824 * @class Roo.data.HttpProxy
9825 * @extends Roo.data.DataProxy
9826 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9827 * configured to reference a certain URL.<br><br>
9829 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9830 * from which the running page was served.<br><br>
9832 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9834 * Be aware that to enable the browser to parse an XML document, the server must set
9835 * the Content-Type header in the HTTP response to "text/xml".
9837 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9838 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9839 * will be used to make the request.
9841 Roo.data.HttpProxy = function(conn){
9842 Roo.data.HttpProxy.superclass.constructor.call(this);
9843 // is conn a conn config or a real conn?
9845 this.useAjax = !conn || !conn.events;
9849 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9850 // thse are take from connection...
9853 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9856 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9857 * extra parameters to each request made by this object. (defaults to undefined)
9860 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9861 * to each request made by this object. (defaults to undefined)
9864 * @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)
9867 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9870 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9876 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9880 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9881 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9882 * a finer-grained basis than the DataProxy events.
9884 getConnection : function(){
9885 return this.useAjax ? Roo.Ajax : this.conn;
9889 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9890 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9891 * process that block using the passed callback.
9892 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9893 * for the request to the remote server.
9894 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9895 * object into a block of Roo.data.Records.
9896 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9897 * The function must be passed <ul>
9898 * <li>The Record block object</li>
9899 * <li>The "arg" argument from the load function</li>
9900 * <li>A boolean success indicator</li>
9902 * @param {Object} scope The scope in which to call the callback
9903 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9905 load : function(params, reader, callback, scope, arg){
9906 if(this.fireEvent("beforeload", this, params) !== false){
9908 params : params || {},
9910 callback : callback,
9915 callback : this.loadResponse,
9919 Roo.applyIf(o, this.conn);
9920 if(this.activeRequest){
9921 Roo.Ajax.abort(this.activeRequest);
9923 this.activeRequest = Roo.Ajax.request(o);
9925 this.conn.request(o);
9928 callback.call(scope||this, null, arg, false);
9933 loadResponse : function(o, success, response){
9934 delete this.activeRequest;
9936 this.fireEvent("loadexception", this, o, response);
9937 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9942 result = o.reader.read(response);
9944 this.fireEvent("loadexception", this, o, response, e);
9945 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9949 this.fireEvent("load", this, o, o.request.arg);
9950 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9954 update : function(dataSet){
9959 updateResponse : function(dataSet){
9964 * Ext JS Library 1.1.1
9965 * Copyright(c) 2006-2007, Ext JS, LLC.
9967 * Originally Released Under LGPL - original licence link has changed is not relivant.
9970 * <script type="text/javascript">
9974 * @class Roo.data.ScriptTagProxy
9975 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9976 * other than the originating domain of the running page.<br><br>
9978 * <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
9979 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9981 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9982 * source code that is used as the source inside a <script> tag.<br><br>
9984 * In order for the browser to process the returned data, the server must wrap the data object
9985 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9986 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9987 * depending on whether the callback name was passed:
9990 boolean scriptTag = false;
9991 String cb = request.getParameter("callback");
9994 response.setContentType("text/javascript");
9996 response.setContentType("application/x-json");
9998 Writer out = response.getWriter();
10000 out.write(cb + "(");
10002 out.print(dataBlock.toJsonString());
10009 * @param {Object} config A configuration object.
10011 Roo.data.ScriptTagProxy = function(config){
10012 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10013 Roo.apply(this, config);
10014 this.head = document.getElementsByTagName("head")[0];
10017 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10019 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10021 * @cfg {String} url The URL from which to request the data object.
10024 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10028 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10029 * the server the name of the callback function set up by the load call to process the returned data object.
10030 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10031 * javascript output which calls this named function passing the data object as its only parameter.
10033 callbackParam : "callback",
10035 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10036 * name to the request.
10041 * Load data from the configured URL, read the data object into
10042 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10043 * process that block using the passed callback.
10044 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10045 * for the request to the remote server.
10046 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10047 * object into a block of Roo.data.Records.
10048 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10049 * The function must be passed <ul>
10050 * <li>The Record block object</li>
10051 * <li>The "arg" argument from the load function</li>
10052 * <li>A boolean success indicator</li>
10054 * @param {Object} scope The scope in which to call the callback
10055 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10057 load : function(params, reader, callback, scope, arg){
10058 if(this.fireEvent("beforeload", this, params) !== false){
10060 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10062 var url = this.url;
10063 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10065 url += "&_dc=" + (new Date().getTime());
10067 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10070 cb : "stcCallback"+transId,
10071 scriptId : "stcScript"+transId,
10075 callback : callback,
10081 window[trans.cb] = function(o){
10082 conn.handleResponse(o, trans);
10085 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10087 if(this.autoAbort !== false){
10091 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10093 var script = document.createElement("script");
10094 script.setAttribute("src", url);
10095 script.setAttribute("type", "text/javascript");
10096 script.setAttribute("id", trans.scriptId);
10097 this.head.appendChild(script);
10099 this.trans = trans;
10101 callback.call(scope||this, null, arg, false);
10106 isLoading : function(){
10107 return this.trans ? true : false;
10111 * Abort the current server request.
10113 abort : function(){
10114 if(this.isLoading()){
10115 this.destroyTrans(this.trans);
10120 destroyTrans : function(trans, isLoaded){
10121 this.head.removeChild(document.getElementById(trans.scriptId));
10122 clearTimeout(trans.timeoutId);
10124 window[trans.cb] = undefined;
10126 delete window[trans.cb];
10129 // if hasn't been loaded, wait for load to remove it to prevent script error
10130 window[trans.cb] = function(){
10131 window[trans.cb] = undefined;
10133 delete window[trans.cb];
10140 handleResponse : function(o, trans){
10141 this.trans = false;
10142 this.destroyTrans(trans, true);
10145 result = trans.reader.readRecords(o);
10147 this.fireEvent("loadexception", this, o, trans.arg, e);
10148 trans.callback.call(trans.scope||window, null, trans.arg, false);
10151 this.fireEvent("load", this, o, trans.arg);
10152 trans.callback.call(trans.scope||window, result, trans.arg, true);
10156 handleFailure : function(trans){
10157 this.trans = false;
10158 this.destroyTrans(trans, false);
10159 this.fireEvent("loadexception", this, null, trans.arg);
10160 trans.callback.call(trans.scope||window, null, trans.arg, false);
10164 * Ext JS Library 1.1.1
10165 * Copyright(c) 2006-2007, Ext JS, LLC.
10167 * Originally Released Under LGPL - original licence link has changed is not relivant.
10170 * <script type="text/javascript">
10174 * @class Roo.data.JsonReader
10175 * @extends Roo.data.DataReader
10176 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10177 * based on mappings in a provided Roo.data.Record constructor.
10179 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10180 * in the reply previously.
10185 var RecordDef = Roo.data.Record.create([
10186 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10187 {name: 'occupation'} // This field will use "occupation" as the mapping.
10189 var myReader = new Roo.data.JsonReader({
10190 totalProperty: "results", // The property which contains the total dataset size (optional)
10191 root: "rows", // The property which contains an Array of row objects
10192 id: "id" // The property within each row object that provides an ID for the record (optional)
10196 * This would consume a JSON file like this:
10198 { 'results': 2, 'rows': [
10199 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10200 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10203 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10204 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10205 * paged from the remote server.
10206 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10207 * @cfg {String} root name of the property which contains the Array of row objects.
10208 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10210 * Create a new JsonReader
10211 * @param {Object} meta Metadata configuration options
10212 * @param {Object} recordType Either an Array of field definition objects,
10213 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10215 Roo.data.JsonReader = function(meta, recordType){
10218 // set some defaults:
10219 Roo.applyIf(meta, {
10220 totalProperty: 'total',
10221 successProperty : 'success',
10226 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10228 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10231 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10232 * Used by Store query builder to append _requestMeta to params.
10235 metaFromRemote : false,
10237 * This method is only used by a DataProxy which has retrieved data from a remote server.
10238 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10239 * @return {Object} data A data block which is used by an Roo.data.Store object as
10240 * a cache of Roo.data.Records.
10242 read : function(response){
10243 var json = response.responseText;
10245 var o = /* eval:var:o */ eval("("+json+")");
10247 throw {message: "JsonReader.read: Json object not found"};
10253 this.metaFromRemote = true;
10254 this.meta = o.metaData;
10255 this.recordType = Roo.data.Record.create(o.metaData.fields);
10256 this.onMetaChange(this.meta, this.recordType, o);
10258 return this.readRecords(o);
10261 // private function a store will implement
10262 onMetaChange : function(meta, recordType, o){
10269 simpleAccess: function(obj, subsc) {
10276 getJsonAccessor: function(){
10278 return function(expr) {
10280 return(re.test(expr))
10281 ? new Function("obj", "return obj." + expr)
10286 return Roo.emptyFn;
10291 * Create a data block containing Roo.data.Records from an XML document.
10292 * @param {Object} o An object which contains an Array of row objects in the property specified
10293 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10294 * which contains the total size of the dataset.
10295 * @return {Object} data A data block which is used by an Roo.data.Store object as
10296 * a cache of Roo.data.Records.
10298 readRecords : function(o){
10300 * After any data loads, the raw JSON data is available for further custom processing.
10304 var s = this.meta, Record = this.recordType,
10305 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10307 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10309 if(s.totalProperty) {
10310 this.getTotal = this.getJsonAccessor(s.totalProperty);
10312 if(s.successProperty) {
10313 this.getSuccess = this.getJsonAccessor(s.successProperty);
10315 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10317 var g = this.getJsonAccessor(s.id);
10318 this.getId = function(rec) {
10320 return (r === undefined || r === "") ? null : r;
10323 this.getId = function(){return null;};
10326 for(var jj = 0; jj < fl; jj++){
10328 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10329 this.ef[jj] = this.getJsonAccessor(map);
10333 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10334 if(s.totalProperty){
10335 var vt = parseInt(this.getTotal(o), 10);
10340 if(s.successProperty){
10341 var vs = this.getSuccess(o);
10342 if(vs === false || vs === 'false'){
10347 for(var i = 0; i < c; i++){
10350 var id = this.getId(n);
10351 for(var j = 0; j < fl; j++){
10353 var v = this.ef[j](n);
10355 Roo.log('missing convert for ' + f.name);
10359 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10361 var record = new Record(values, id);
10363 records[i] = record;
10369 totalRecords : totalRecords
10374 * Ext JS Library 1.1.1
10375 * Copyright(c) 2006-2007, Ext JS, LLC.
10377 * Originally Released Under LGPL - original licence link has changed is not relivant.
10380 * <script type="text/javascript">
10384 * @class Roo.data.ArrayReader
10385 * @extends Roo.data.DataReader
10386 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10387 * Each element of that Array represents a row of data fields. The
10388 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10389 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10393 var RecordDef = Roo.data.Record.create([
10394 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10395 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10397 var myReader = new Roo.data.ArrayReader({
10398 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10402 * This would consume an Array like this:
10404 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10406 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10408 * Create a new JsonReader
10409 * @param {Object} meta Metadata configuration options.
10410 * @param {Object} recordType Either an Array of field definition objects
10411 * as specified to {@link Roo.data.Record#create},
10412 * or an {@link Roo.data.Record} object
10413 * created using {@link Roo.data.Record#create}.
10415 Roo.data.ArrayReader = function(meta, recordType){
10416 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10419 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10421 * Create a data block containing Roo.data.Records from an XML document.
10422 * @param {Object} o An Array of row objects which represents the dataset.
10423 * @return {Object} data A data block which is used by an Roo.data.Store object as
10424 * a cache of Roo.data.Records.
10426 readRecords : function(o){
10427 var sid = this.meta ? this.meta.id : null;
10428 var recordType = this.recordType, fields = recordType.prototype.fields;
10431 for(var i = 0; i < root.length; i++){
10434 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10435 for(var j = 0, jlen = fields.length; j < jlen; j++){
10436 var f = fields.items[j];
10437 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10438 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10440 values[f.name] = v;
10442 var record = new recordType(values, id);
10444 records[records.length] = record;
10448 totalRecords : records.length
10457 * @class Roo.bootstrap.ComboBox
10458 * @extends Roo.bootstrap.TriggerField
10459 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10460 * @cfg {Boolean} append (true|false) default false
10461 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10462 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10463 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10464 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10465 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10467 * Create a new ComboBox.
10468 * @param {Object} config Configuration options
10470 Roo.bootstrap.ComboBox = function(config){
10471 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10475 * Fires when the dropdown list is expanded
10476 * @param {Roo.bootstrap.ComboBox} combo This combo box
10481 * Fires when the dropdown list is collapsed
10482 * @param {Roo.bootstrap.ComboBox} combo This combo box
10486 * @event beforeselect
10487 * Fires before a list item is selected. Return false to cancel the selection.
10488 * @param {Roo.bootstrap.ComboBox} combo This combo box
10489 * @param {Roo.data.Record} record The data record returned from the underlying store
10490 * @param {Number} index The index of the selected item in the dropdown list
10492 'beforeselect' : true,
10495 * Fires when a list item is selected
10496 * @param {Roo.bootstrap.ComboBox} combo This combo box
10497 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10498 * @param {Number} index The index of the selected item in the dropdown list
10502 * @event beforequery
10503 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10504 * The event object passed has these properties:
10505 * @param {Roo.bootstrap.ComboBox} combo This combo box
10506 * @param {String} query The query
10507 * @param {Boolean} forceAll true to force "all" query
10508 * @param {Boolean} cancel true to cancel the query
10509 * @param {Object} e The query event object
10511 'beforequery': true,
10514 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10515 * @param {Roo.bootstrap.ComboBox} combo This combo box
10520 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10521 * @param {Roo.bootstrap.ComboBox} combo This combo box
10522 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10527 * Fires when the remove value from the combobox array
10528 * @param {Roo.bootstrap.ComboBox} combo This combo box
10535 this.tickItems = [];
10537 this.selectedIndex = -1;
10538 if(this.mode == 'local'){
10539 if(config.queryDelay === undefined){
10540 this.queryDelay = 10;
10542 if(config.minChars === undefined){
10548 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10551 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10552 * rendering into an Roo.Editor, defaults to false)
10555 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10556 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10559 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10562 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10563 * the dropdown list (defaults to undefined, with no header element)
10567 * @cfg {String/Roo.Template} tpl The template to use to render the output
10571 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10573 listWidth: undefined,
10575 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10576 * mode = 'remote' or 'text' if mode = 'local')
10578 displayField: undefined,
10580 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10581 * mode = 'remote' or 'value' if mode = 'local').
10582 * Note: use of a valueField requires the user make a selection
10583 * in order for a value to be mapped.
10585 valueField: undefined,
10589 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10590 * field's data value (defaults to the underlying DOM element's name)
10592 hiddenName: undefined,
10594 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10598 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10600 selectedClass: 'active',
10603 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10607 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10608 * anchor positions (defaults to 'tl-bl')
10610 listAlign: 'tl-bl?',
10612 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10616 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10617 * query specified by the allQuery config option (defaults to 'query')
10619 triggerAction: 'query',
10621 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10622 * (defaults to 4, does not apply if editable = false)
10626 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10627 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10631 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10632 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10636 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10637 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10641 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10642 * when editable = true (defaults to false)
10644 selectOnFocus:false,
10646 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10648 queryParam: 'query',
10650 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10651 * when mode = 'remote' (defaults to 'Loading...')
10653 loadingText: 'Loading...',
10655 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10659 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10663 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10664 * traditional select (defaults to true)
10668 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10672 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10676 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10677 * listWidth has a higher value)
10681 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10682 * allow the user to set arbitrary text into the field (defaults to false)
10684 forceSelection:false,
10686 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10687 * if typeAhead = true (defaults to 250)
10689 typeAheadDelay : 250,
10691 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10692 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10694 valueNotFoundText : undefined,
10696 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10698 blockFocus : false,
10701 * @cfg {Boolean} disableClear Disable showing of clear button.
10703 disableClear : false,
10705 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10707 alwaysQuery : false,
10710 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10724 btnPosition : 'right',
10725 triggerList : true,
10726 showToggleBtn : true,
10727 // element that contains real text value.. (when hidden is used..)
10729 getAutoCreate : function()
10736 if(!this.tickable){
10737 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10742 * ComboBox with tickable selections
10745 var align = this.labelAlign || this.parentLabelAlign();
10748 cls : 'form-group roo-combobox-tickable' //input-group
10754 cls : 'tickable-buttons',
10759 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10766 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10773 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10780 Roo.each(buttons.cn, function(c){
10782 c.cls += ' btn-' + _this.size;
10785 if (_this.disabled) {
10796 cls: 'form-hidden-field'
10800 cls: 'select2-choices',
10804 cls: 'select2-search-field',
10816 cls: 'select2-container input-group select2-container-multi',
10821 // cls: 'typeahead typeahead-long dropdown-menu',
10822 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10827 if (align ==='left' && this.fieldLabel.length) {
10829 Roo.log("left and has label");
10835 cls : 'control-label col-sm-' + this.labelWidth,
10836 html : this.fieldLabel
10840 cls : "col-sm-" + (12 - this.labelWidth),
10847 } else if ( this.fieldLabel.length) {
10853 //cls : 'input-group-addon',
10854 html : this.fieldLabel
10864 Roo.log(" no label && no align");
10871 ['xs','sm','md','lg'].map(function(size){
10872 if (settings[size]) {
10873 cfg.cls += ' col-' + size + '-' + settings[size];
10882 initEvents: function()
10886 throw "can not find store for combo";
10888 this.store = Roo.factory(this.store, Roo.data);
10891 this.initTickableEvents();
10895 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10897 if(this.hiddenName){
10899 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10901 this.hiddenField.dom.value =
10902 this.hiddenValue !== undefined ? this.hiddenValue :
10903 this.value !== undefined ? this.value : '';
10905 // prevent input submission
10906 this.el.dom.removeAttribute('name');
10907 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10912 // this.el.dom.setAttribute('autocomplete', 'off');
10915 var cls = 'x-combo-list';
10917 //this.list = new Roo.Layer({
10918 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10924 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10925 _this.list.setWidth(lw);
10928 this.list.on('mouseover', this.onViewOver, this);
10929 this.list.on('mousemove', this.onViewMove, this);
10931 this.list.on('scroll', this.onViewScroll, this);
10934 this.list.swallowEvent('mousewheel');
10935 this.assetHeight = 0;
10938 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10939 this.assetHeight += this.header.getHeight();
10942 this.innerList = this.list.createChild({cls:cls+'-inner'});
10943 this.innerList.on('mouseover', this.onViewOver, this);
10944 this.innerList.on('mousemove', this.onViewMove, this);
10945 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10947 if(this.allowBlank && !this.pageSize && !this.disableClear){
10948 this.footer = this.list.createChild({cls:cls+'-ft'});
10949 this.pageTb = new Roo.Toolbar(this.footer);
10953 this.footer = this.list.createChild({cls:cls+'-ft'});
10954 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10955 {pageSize: this.pageSize});
10959 if (this.pageTb && this.allowBlank && !this.disableClear) {
10961 this.pageTb.add(new Roo.Toolbar.Fill(), {
10962 cls: 'x-btn-icon x-btn-clear',
10964 handler: function()
10967 _this.clearValue();
10968 _this.onSelect(false, -1);
10973 this.assetHeight += this.footer.getHeight();
10978 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10981 this.view = new Roo.View(this.list, this.tpl, {
10982 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10984 //this.view.wrapEl.setDisplayed(false);
10985 this.view.on('click', this.onViewClick, this);
10989 this.store.on('beforeload', this.onBeforeLoad, this);
10990 this.store.on('load', this.onLoad, this);
10991 this.store.on('loadexception', this.onLoadException, this);
10993 if(this.resizable){
10994 this.resizer = new Roo.Resizable(this.list, {
10995 pinned:true, handles:'se'
10997 this.resizer.on('resize', function(r, w, h){
10998 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10999 this.listWidth = w;
11000 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11001 this.restrictHeight();
11003 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11006 if(!this.editable){
11007 this.editable = true;
11008 this.setEditable(false);
11013 if (typeof(this.events.add.listeners) != 'undefined') {
11015 this.addicon = this.wrap.createChild(
11016 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11018 this.addicon.on('click', function(e) {
11019 this.fireEvent('add', this);
11022 if (typeof(this.events.edit.listeners) != 'undefined') {
11024 this.editicon = this.wrap.createChild(
11025 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11026 if (this.addicon) {
11027 this.editicon.setStyle('margin-left', '40px');
11029 this.editicon.on('click', function(e) {
11031 // we fire even if inothing is selected..
11032 this.fireEvent('edit', this, this.lastData );
11038 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11039 "up" : function(e){
11040 this.inKeyMode = true;
11044 "down" : function(e){
11045 if(!this.isExpanded()){
11046 this.onTriggerClick();
11048 this.inKeyMode = true;
11053 "enter" : function(e){
11054 // this.onViewClick();
11058 if(this.fireEvent("specialkey", this, e)){
11059 this.onViewClick(false);
11065 "esc" : function(e){
11069 "tab" : function(e){
11072 if(this.fireEvent("specialkey", this, e)){
11073 this.onViewClick(false);
11081 doRelay : function(foo, bar, hname){
11082 if(hname == 'down' || this.scope.isExpanded()){
11083 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11092 this.queryDelay = Math.max(this.queryDelay || 10,
11093 this.mode == 'local' ? 10 : 250);
11096 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11098 if(this.typeAhead){
11099 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11101 if(this.editable !== false){
11102 this.inputEl().on("keyup", this.onKeyUp, this);
11104 if(this.forceSelection){
11105 this.inputEl().on('blur', this.doForce, this);
11109 this.choices = this.el.select('ul.select2-choices', true).first();
11110 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11114 initTickableEvents: function()
11118 if(this.hiddenName){
11120 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11122 this.hiddenField.dom.value =
11123 this.hiddenValue !== undefined ? this.hiddenValue :
11124 this.value !== undefined ? this.value : '';
11126 // prevent input submission
11127 this.el.dom.removeAttribute('name');
11128 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11133 // this.list = this.el.select('ul.dropdown-menu',true).first();
11135 this.choices = this.el.select('ul.select2-choices', true).first();
11136 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11137 if(this.triggerList){
11138 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11141 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11142 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11144 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11145 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11147 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11148 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11150 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11151 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11152 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11155 this.cancelBtn.hide();
11160 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11161 _this.list.setWidth(lw);
11164 this.list.on('mouseover', this.onViewOver, this);
11165 this.list.on('mousemove', this.onViewMove, this);
11167 this.list.on('scroll', this.onViewScroll, this);
11170 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>';
11173 this.view = new Roo.View(this.list, this.tpl, {
11174 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11177 //this.view.wrapEl.setDisplayed(false);
11178 this.view.on('click', this.onViewClick, this);
11182 this.store.on('beforeload', this.onBeforeLoad, this);
11183 this.store.on('load', this.onLoad, this);
11184 this.store.on('loadexception', this.onLoadException, this);
11186 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11187 // "up" : function(e){
11188 // this.inKeyMode = true;
11189 // this.selectPrev();
11192 // "down" : function(e){
11193 // if(!this.isExpanded()){
11194 // this.onTriggerClick();
11196 // this.inKeyMode = true;
11197 // this.selectNext();
11201 // "enter" : function(e){
11202 //// this.onViewClick();
11204 // this.collapse();
11206 // if(this.fireEvent("specialkey", this, e)){
11207 // this.onViewClick(false);
11213 // "esc" : function(e){
11214 // this.collapse();
11217 // "tab" : function(e){
11218 // this.collapse();
11220 // if(this.fireEvent("specialkey", this, e)){
11221 // this.onViewClick(false);
11229 // doRelay : function(foo, bar, hname){
11230 // if(hname == 'down' || this.scope.isExpanded()){
11231 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11236 // forceKeyDown: true
11240 this.queryDelay = Math.max(this.queryDelay || 10,
11241 this.mode == 'local' ? 10 : 250);
11244 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11246 if(this.typeAhead){
11247 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11251 onDestroy : function(){
11253 this.view.setStore(null);
11254 this.view.el.removeAllListeners();
11255 this.view.el.remove();
11256 this.view.purgeListeners();
11259 this.list.dom.innerHTML = '';
11263 this.store.un('beforeload', this.onBeforeLoad, this);
11264 this.store.un('load', this.onLoad, this);
11265 this.store.un('loadexception', this.onLoadException, this);
11267 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11271 fireKey : function(e){
11272 if(e.isNavKeyPress() && !this.list.isVisible()){
11273 this.fireEvent("specialkey", this, e);
11278 onResize: function(w, h){
11279 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11281 // if(typeof w != 'number'){
11282 // // we do not handle it!?!?
11285 // var tw = this.trigger.getWidth();
11286 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11287 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11289 // this.inputEl().setWidth( this.adjustWidth('input', x));
11291 // //this.trigger.setStyle('left', x+'px');
11293 // if(this.list && this.listWidth === undefined){
11294 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11295 // this.list.setWidth(lw);
11296 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11304 * Allow or prevent the user from directly editing the field text. If false is passed,
11305 * the user will only be able to select from the items defined in the dropdown list. This method
11306 * is the runtime equivalent of setting the 'editable' config option at config time.
11307 * @param {Boolean} value True to allow the user to directly edit the field text
11309 setEditable : function(value){
11310 if(value == this.editable){
11313 this.editable = value;
11315 this.inputEl().dom.setAttribute('readOnly', true);
11316 this.inputEl().on('mousedown', this.onTriggerClick, this);
11317 this.inputEl().addClass('x-combo-noedit');
11319 this.inputEl().dom.setAttribute('readOnly', false);
11320 this.inputEl().un('mousedown', this.onTriggerClick, this);
11321 this.inputEl().removeClass('x-combo-noedit');
11327 onBeforeLoad : function(combo,opts){
11328 if(!this.hasFocus){
11332 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11334 this.restrictHeight();
11335 this.selectedIndex = -1;
11339 onLoad : function(){
11341 this.hasQuery = false;
11343 if(!this.hasFocus){
11347 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11348 this.loading.hide();
11351 if(this.store.getCount() > 0){
11353 // this.restrictHeight();
11354 if(this.lastQuery == this.allQuery){
11355 if(this.editable && !this.tickable){
11356 this.inputEl().dom.select();
11360 !this.selectByValue(this.value, true) &&
11361 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11362 this.store.lastOptions.add != true)
11364 this.select(0, true);
11367 if(this.autoFocus){
11370 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11371 this.taTask.delay(this.typeAheadDelay);
11375 this.onEmptyResults();
11381 onLoadException : function()
11383 this.hasQuery = false;
11385 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11386 this.loading.hide();
11390 Roo.log(this.store.reader.jsonData);
11391 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11393 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11399 onTypeAhead : function(){
11400 if(this.store.getCount() > 0){
11401 var r = this.store.getAt(0);
11402 var newValue = r.data[this.displayField];
11403 var len = newValue.length;
11404 var selStart = this.getRawValue().length;
11406 if(selStart != len){
11407 this.setRawValue(newValue);
11408 this.selectText(selStart, newValue.length);
11414 onSelect : function(record, index){
11416 if(this.fireEvent('beforeselect', this, record, index) !== false){
11418 this.setFromData(index > -1 ? record.data : false);
11421 this.fireEvent('select', this, record, index);
11426 * Returns the currently selected field value or empty string if no value is set.
11427 * @return {String} value The selected value
11429 getValue : function(){
11432 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11435 if(this.valueField){
11436 return typeof this.value != 'undefined' ? this.value : '';
11438 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11443 * Clears any text/value currently set in the field
11445 clearValue : function(){
11446 if(this.hiddenField){
11447 this.hiddenField.dom.value = '';
11450 this.setRawValue('');
11451 this.lastSelectionText = '';
11456 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11457 * will be displayed in the field. If the value does not match the data value of an existing item,
11458 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11459 * Otherwise the field will be blank (although the value will still be set).
11460 * @param {String} value The value to match
11462 setValue : function(v){
11469 if(this.valueField){
11470 var r = this.findRecord(this.valueField, v);
11472 text = r.data[this.displayField];
11473 }else if(this.valueNotFoundText !== undefined){
11474 text = this.valueNotFoundText;
11477 this.lastSelectionText = text;
11478 if(this.hiddenField){
11479 this.hiddenField.dom.value = v;
11481 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11485 * @property {Object} the last set data for the element
11490 * Sets the value of the field based on a object which is related to the record format for the store.
11491 * @param {Object} value the value to set as. or false on reset?
11493 setFromData : function(o){
11500 var dv = ''; // display value
11501 var vv = ''; // value value..
11503 if (this.displayField) {
11504 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11506 // this is an error condition!!!
11507 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11510 if(this.valueField){
11511 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11514 if(this.hiddenField){
11515 this.hiddenField.dom.value = vv;
11517 this.lastSelectionText = dv;
11518 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11522 // no hidden field.. - we store the value in 'value', but still display
11523 // display field!!!!
11524 this.lastSelectionText = dv;
11525 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11531 reset : function(){
11532 // overridden so that last data is reset..
11533 this.setValue(this.originalValue);
11534 this.clearInvalid();
11535 this.lastData = false;
11537 this.view.clearSelections();
11541 findRecord : function(prop, value){
11543 if(this.store.getCount() > 0){
11544 this.store.each(function(r){
11545 if(r.data[prop] == value){
11555 getName: function()
11557 // returns hidden if it's set..
11558 if (!this.rendered) {return ''};
11559 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11563 onViewMove : function(e, t){
11564 this.inKeyMode = false;
11568 onViewOver : function(e, t){
11569 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11572 var item = this.view.findItemFromChild(t);
11575 var index = this.view.indexOf(item);
11576 this.select(index, false);
11581 onViewClick : function(view, doFocus, el, e)
11583 var index = this.view.getSelectedIndexes()[0];
11585 var r = this.store.getAt(index);
11589 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11596 Roo.each(this.tickItems, function(v,k){
11598 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11599 _this.tickItems.splice(k, 1);
11609 this.tickItems.push(r.data);
11614 this.onSelect(r, index);
11616 if(doFocus !== false && !this.blockFocus){
11617 this.inputEl().focus();
11622 restrictHeight : function(){
11623 //this.innerList.dom.style.height = '';
11624 //var inner = this.innerList.dom;
11625 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11626 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11627 //this.list.beginUpdate();
11628 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11629 this.list.alignTo(this.inputEl(), this.listAlign);
11630 this.list.alignTo(this.inputEl(), this.listAlign);
11631 //this.list.endUpdate();
11635 onEmptyResults : function(){
11640 * Returns true if the dropdown list is expanded, else false.
11642 isExpanded : function(){
11643 return this.list.isVisible();
11647 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11648 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11649 * @param {String} value The data value of the item to select
11650 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11651 * selected item if it is not currently in view (defaults to true)
11652 * @return {Boolean} True if the value matched an item in the list, else false
11654 selectByValue : function(v, scrollIntoView){
11655 if(v !== undefined && v !== null){
11656 var r = this.findRecord(this.valueField || this.displayField, v);
11658 this.select(this.store.indexOf(r), scrollIntoView);
11666 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11667 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11668 * @param {Number} index The zero-based index of the list item to select
11669 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11670 * selected item if it is not currently in view (defaults to true)
11672 select : function(index, scrollIntoView){
11673 this.selectedIndex = index;
11674 this.view.select(index);
11675 if(scrollIntoView !== false){
11676 var el = this.view.getNode(index);
11677 if(el && !this.multiple && !this.tickable){
11678 this.list.scrollChildIntoView(el, false);
11684 selectNext : function(){
11685 var ct = this.store.getCount();
11687 if(this.selectedIndex == -1){
11689 }else if(this.selectedIndex < ct-1){
11690 this.select(this.selectedIndex+1);
11696 selectPrev : function(){
11697 var ct = this.store.getCount();
11699 if(this.selectedIndex == -1){
11701 }else if(this.selectedIndex != 0){
11702 this.select(this.selectedIndex-1);
11708 onKeyUp : function(e){
11709 if(this.editable !== false && !e.isSpecialKey()){
11710 this.lastKey = e.getKey();
11711 this.dqTask.delay(this.queryDelay);
11716 validateBlur : function(){
11717 return !this.list || !this.list.isVisible();
11721 initQuery : function(){
11722 this.doQuery(this.getRawValue());
11726 doForce : function(){
11727 if(this.inputEl().dom.value.length > 0){
11728 this.inputEl().dom.value =
11729 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11735 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11736 * query allowing the query action to be canceled if needed.
11737 * @param {String} query The SQL query to execute
11738 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11739 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11740 * saved in the current store (defaults to false)
11742 doQuery : function(q, forceAll){
11744 if(q === undefined || q === null){
11749 forceAll: forceAll,
11753 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11758 forceAll = qe.forceAll;
11759 if(forceAll === true || (q.length >= this.minChars)){
11761 this.hasQuery = true;
11763 if(this.lastQuery != q || this.alwaysQuery){
11764 this.lastQuery = q;
11765 if(this.mode == 'local'){
11766 this.selectedIndex = -1;
11768 this.store.clearFilter();
11770 this.store.filter(this.displayField, q);
11774 this.store.baseParams[this.queryParam] = q;
11776 var options = {params : this.getParams(q)};
11779 options.add = true;
11780 options.params.start = this.page * this.pageSize;
11783 this.store.load(options);
11785 * this code will make the page width larger, at the beginning, the list not align correctly,
11786 * we should expand the list on onLoad
11787 * so command out it
11792 this.selectedIndex = -1;
11797 this.loadNext = false;
11801 getParams : function(q){
11803 //p[this.queryParam] = q;
11807 p.limit = this.pageSize;
11813 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11815 collapse : function(){
11816 if(!this.isExpanded()){
11824 this.cancelBtn.hide();
11825 this.trigger.show();
11828 Roo.get(document).un('mousedown', this.collapseIf, this);
11829 Roo.get(document).un('mousewheel', this.collapseIf, this);
11830 if (!this.editable) {
11831 Roo.get(document).un('keydown', this.listKeyPress, this);
11833 this.fireEvent('collapse', this);
11837 collapseIf : function(e){
11838 var in_combo = e.within(this.el);
11839 var in_list = e.within(this.list);
11840 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11842 if (in_combo || in_list || is_list) {
11843 //e.stopPropagation();
11848 this.onTickableFooterButtonClick(e, false, false);
11856 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11858 expand : function(){
11860 if(this.isExpanded() || !this.hasFocus){
11864 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11865 this.list.setWidth(lw);
11872 this.restrictHeight();
11876 this.tickItems = Roo.apply([], this.item);
11879 this.cancelBtn.show();
11880 this.trigger.hide();
11884 Roo.get(document).on('mousedown', this.collapseIf, this);
11885 Roo.get(document).on('mousewheel', this.collapseIf, this);
11886 if (!this.editable) {
11887 Roo.get(document).on('keydown', this.listKeyPress, this);
11890 this.fireEvent('expand', this);
11894 // Implements the default empty TriggerField.onTriggerClick function
11895 onTriggerClick : function(e)
11897 Roo.log('trigger click');
11899 if(this.disabled || !this.triggerList){
11904 this.loadNext = false;
11906 if(this.isExpanded()){
11908 if (!this.blockFocus) {
11909 this.inputEl().focus();
11913 this.hasFocus = true;
11914 if(this.triggerAction == 'all') {
11915 this.doQuery(this.allQuery, true);
11917 this.doQuery(this.getRawValue());
11919 if (!this.blockFocus) {
11920 this.inputEl().focus();
11925 onTickableTriggerClick : function(e)
11932 this.loadNext = false;
11933 this.hasFocus = true;
11935 if(this.triggerAction == 'all') {
11936 this.doQuery(this.allQuery, true);
11938 this.doQuery(this.getRawValue());
11942 onSearchFieldClick : function(e)
11944 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11949 this.loadNext = false;
11950 this.hasFocus = true;
11952 if(this.triggerAction == 'all') {
11953 this.doQuery(this.allQuery, true);
11955 this.doQuery(this.getRawValue());
11959 listKeyPress : function(e)
11961 //Roo.log('listkeypress');
11962 // scroll to first matching element based on key pres..
11963 if (e.isSpecialKey()) {
11966 var k = String.fromCharCode(e.getKey()).toUpperCase();
11969 var csel = this.view.getSelectedNodes();
11970 var cselitem = false;
11972 var ix = this.view.indexOf(csel[0]);
11973 cselitem = this.store.getAt(ix);
11974 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11980 this.store.each(function(v) {
11982 // start at existing selection.
11983 if (cselitem.id == v.id) {
11989 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11990 match = this.store.indexOf(v);
11996 if (match === false) {
11997 return true; // no more action?
12000 this.view.select(match);
12001 var sn = Roo.get(this.view.getSelectedNodes()[0])
12002 sn.scrollIntoView(sn.dom.parentNode, false);
12005 onViewScroll : function(e, t){
12007 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){
12011 this.hasQuery = true;
12013 this.loading = this.list.select('.loading', true).first();
12015 if(this.loading === null){
12016 this.list.createChild({
12018 cls: 'loading select2-more-results select2-active',
12019 html: 'Loading more results...'
12022 this.loading = this.list.select('.loading', true).first();
12024 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12026 this.loading.hide();
12029 this.loading.show();
12034 this.loadNext = true;
12036 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12041 addItem : function(o)
12043 var dv = ''; // display value
12045 if (this.displayField) {
12046 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12048 // this is an error condition!!!
12049 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12056 var choice = this.choices.createChild({
12058 cls: 'select2-search-choice',
12067 cls: 'select2-search-choice-close',
12072 }, this.searchField);
12074 var close = choice.select('a.select2-search-choice-close', true).first()
12076 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12084 this.inputEl().dom.value = '';
12088 onRemoveItem : function(e, _self, o)
12090 e.preventDefault();
12091 var index = this.item.indexOf(o.data) * 1;
12094 Roo.log('not this item?!');
12098 this.item.splice(index, 1);
12103 this.fireEvent('remove', this, e);
12107 syncValue : function()
12109 if(!this.item.length){
12116 Roo.each(this.item, function(i){
12117 if(_this.valueField){
12118 value.push(i[_this.valueField]);
12125 this.value = value.join(',');
12127 if(this.hiddenField){
12128 this.hiddenField.dom.value = this.value;
12132 clearItem : function()
12134 if(!this.multiple){
12140 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12147 inputEl: function ()
12150 return this.searchField;
12152 return this.el.select('input.form-control',true).first();
12156 onTickableFooterButtonClick : function(e, btn, el)
12158 e.preventDefault();
12160 if(btn && btn.name == 'cancel'){
12161 this.tickItems = Roo.apply([], this.item);
12170 Roo.each(this.tickItems, function(o){
12178 validate : function()
12180 var v = this.getRawValue();
12183 v = this.getValue();
12186 if(this.disabled || this.validateValue(v)){
12187 this.clearInvalid();
12196 * @cfg {Boolean} grow
12200 * @cfg {Number} growMin
12204 * @cfg {Number} growMax
12214 * Ext JS Library 1.1.1
12215 * Copyright(c) 2006-2007, Ext JS, LLC.
12217 * Originally Released Under LGPL - original licence link has changed is not relivant.
12220 * <script type="text/javascript">
12225 * @extends Roo.util.Observable
12226 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12227 * This class also supports single and multi selection modes. <br>
12228 * Create a data model bound view:
12230 var store = new Roo.data.Store(...);
12232 var view = new Roo.View({
12234 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12236 singleSelect: true,
12237 selectedClass: "ydataview-selected",
12241 // listen for node click?
12242 view.on("click", function(vw, index, node, e){
12243 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12247 dataModel.load("foobar.xml");
12249 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12251 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12252 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12254 * Note: old style constructor is still suported (container, template, config)
12257 * Create a new View
12258 * @param {Object} config The config object
12261 Roo.View = function(config, depreciated_tpl, depreciated_config){
12263 this.parent = false;
12265 if (typeof(depreciated_tpl) == 'undefined') {
12266 // new way.. - universal constructor.
12267 Roo.apply(this, config);
12268 this.el = Roo.get(this.el);
12271 this.el = Roo.get(config);
12272 this.tpl = depreciated_tpl;
12273 Roo.apply(this, depreciated_config);
12275 this.wrapEl = this.el.wrap().wrap();
12276 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12279 if(typeof(this.tpl) == "string"){
12280 this.tpl = new Roo.Template(this.tpl);
12282 // support xtype ctors..
12283 this.tpl = new Roo.factory(this.tpl, Roo);
12287 this.tpl.compile();
12292 * @event beforeclick
12293 * Fires before a click is processed. Returns false to cancel the default action.
12294 * @param {Roo.View} this
12295 * @param {Number} index The index of the target node
12296 * @param {HTMLElement} node The target node
12297 * @param {Roo.EventObject} e The raw event object
12299 "beforeclick" : true,
12302 * Fires when a template node is clicked.
12303 * @param {Roo.View} this
12304 * @param {Number} index The index of the target node
12305 * @param {HTMLElement} node The target node
12306 * @param {Roo.EventObject} e The raw event object
12311 * Fires when a template node is double clicked.
12312 * @param {Roo.View} this
12313 * @param {Number} index The index of the target node
12314 * @param {HTMLElement} node The target node
12315 * @param {Roo.EventObject} e The raw event object
12319 * @event contextmenu
12320 * Fires when a template node is right clicked.
12321 * @param {Roo.View} this
12322 * @param {Number} index The index of the target node
12323 * @param {HTMLElement} node The target node
12324 * @param {Roo.EventObject} e The raw event object
12326 "contextmenu" : true,
12328 * @event selectionchange
12329 * Fires when the selected nodes change.
12330 * @param {Roo.View} this
12331 * @param {Array} selections Array of the selected nodes
12333 "selectionchange" : true,
12336 * @event beforeselect
12337 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12338 * @param {Roo.View} this
12339 * @param {HTMLElement} node The node to be selected
12340 * @param {Array} selections Array of currently selected nodes
12342 "beforeselect" : true,
12344 * @event preparedata
12345 * Fires on every row to render, to allow you to change the data.
12346 * @param {Roo.View} this
12347 * @param {Object} data to be rendered (change this)
12349 "preparedata" : true
12357 "click": this.onClick,
12358 "dblclick": this.onDblClick,
12359 "contextmenu": this.onContextMenu,
12363 this.selections = [];
12365 this.cmp = new Roo.CompositeElementLite([]);
12367 this.store = Roo.factory(this.store, Roo.data);
12368 this.setStore(this.store, true);
12371 if ( this.footer && this.footer.xtype) {
12373 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12375 this.footer.dataSource = this.store
12376 this.footer.container = fctr;
12377 this.footer = Roo.factory(this.footer, Roo);
12378 fctr.insertFirst(this.el);
12380 // this is a bit insane - as the paging toolbar seems to detach the el..
12381 // dom.parentNode.parentNode.parentNode
12382 // they get detached?
12386 Roo.View.superclass.constructor.call(this);
12391 Roo.extend(Roo.View, Roo.util.Observable, {
12394 * @cfg {Roo.data.Store} store Data store to load data from.
12399 * @cfg {String|Roo.Element} el The container element.
12404 * @cfg {String|Roo.Template} tpl The template used by this View
12408 * @cfg {String} dataName the named area of the template to use as the data area
12409 * Works with domtemplates roo-name="name"
12413 * @cfg {String} selectedClass The css class to add to selected nodes
12415 selectedClass : "x-view-selected",
12417 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12422 * @cfg {String} text to display on mask (default Loading)
12426 * @cfg {Boolean} multiSelect Allow multiple selection
12428 multiSelect : false,
12430 * @cfg {Boolean} singleSelect Allow single selection
12432 singleSelect: false,
12435 * @cfg {Boolean} toggleSelect - selecting
12437 toggleSelect : false,
12440 * @cfg {Boolean} tickable - selecting
12445 * Returns the element this view is bound to.
12446 * @return {Roo.Element}
12448 getEl : function(){
12449 return this.wrapEl;
12455 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12457 refresh : function(){
12458 //Roo.log('refresh');
12461 // if we are using something like 'domtemplate', then
12462 // the what gets used is:
12463 // t.applySubtemplate(NAME, data, wrapping data..)
12464 // the outer template then get' applied with
12465 // the store 'extra data'
12466 // and the body get's added to the
12467 // roo-name="data" node?
12468 // <span class='roo-tpl-{name}'></span> ?????
12472 this.clearSelections();
12473 this.el.update("");
12475 var records = this.store.getRange();
12476 if(records.length < 1) {
12478 // is this valid?? = should it render a template??
12480 this.el.update(this.emptyText);
12484 if (this.dataName) {
12485 this.el.update(t.apply(this.store.meta)); //????
12486 el = this.el.child('.roo-tpl-' + this.dataName);
12489 for(var i = 0, len = records.length; i < len; i++){
12490 var data = this.prepareData(records[i].data, i, records[i]);
12491 this.fireEvent("preparedata", this, data, i, records[i]);
12493 var d = Roo.apply({}, data);
12496 Roo.apply(d, {'roo-id' : Roo.id()});
12500 Roo.each(this.parent.item, function(item){
12501 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12504 Roo.apply(d, {'roo-data-checked' : 'checked'});
12508 html[html.length] = Roo.util.Format.trim(
12510 t.applySubtemplate(this.dataName, d, this.store.meta) :
12517 el.update(html.join(""));
12518 this.nodes = el.dom.childNodes;
12519 this.updateIndexes(0);
12524 * Function to override to reformat the data that is sent to
12525 * the template for each node.
12526 * DEPRICATED - use the preparedata event handler.
12527 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12528 * a JSON object for an UpdateManager bound view).
12530 prepareData : function(data, index, record)
12532 this.fireEvent("preparedata", this, data, index, record);
12536 onUpdate : function(ds, record){
12537 // Roo.log('on update');
12538 this.clearSelections();
12539 var index = this.store.indexOf(record);
12540 var n = this.nodes[index];
12541 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12542 n.parentNode.removeChild(n);
12543 this.updateIndexes(index, index);
12549 onAdd : function(ds, records, index)
12551 //Roo.log(['on Add', ds, records, index] );
12552 this.clearSelections();
12553 if(this.nodes.length == 0){
12557 var n = this.nodes[index];
12558 for(var i = 0, len = records.length; i < len; i++){
12559 var d = this.prepareData(records[i].data, i, records[i]);
12561 this.tpl.insertBefore(n, d);
12564 this.tpl.append(this.el, d);
12567 this.updateIndexes(index);
12570 onRemove : function(ds, record, index){
12571 // Roo.log('onRemove');
12572 this.clearSelections();
12573 var el = this.dataName ?
12574 this.el.child('.roo-tpl-' + this.dataName) :
12577 el.dom.removeChild(this.nodes[index]);
12578 this.updateIndexes(index);
12582 * Refresh an individual node.
12583 * @param {Number} index
12585 refreshNode : function(index){
12586 this.onUpdate(this.store, this.store.getAt(index));
12589 updateIndexes : function(startIndex, endIndex){
12590 var ns = this.nodes;
12591 startIndex = startIndex || 0;
12592 endIndex = endIndex || ns.length - 1;
12593 for(var i = startIndex; i <= endIndex; i++){
12594 ns[i].nodeIndex = i;
12599 * Changes the data store this view uses and refresh the view.
12600 * @param {Store} store
12602 setStore : function(store, initial){
12603 if(!initial && this.store){
12604 this.store.un("datachanged", this.refresh);
12605 this.store.un("add", this.onAdd);
12606 this.store.un("remove", this.onRemove);
12607 this.store.un("update", this.onUpdate);
12608 this.store.un("clear", this.refresh);
12609 this.store.un("beforeload", this.onBeforeLoad);
12610 this.store.un("load", this.onLoad);
12611 this.store.un("loadexception", this.onLoad);
12615 store.on("datachanged", this.refresh, this);
12616 store.on("add", this.onAdd, this);
12617 store.on("remove", this.onRemove, this);
12618 store.on("update", this.onUpdate, this);
12619 store.on("clear", this.refresh, this);
12620 store.on("beforeload", this.onBeforeLoad, this);
12621 store.on("load", this.onLoad, this);
12622 store.on("loadexception", this.onLoad, this);
12630 * onbeforeLoad - masks the loading area.
12633 onBeforeLoad : function(store,opts)
12635 //Roo.log('onBeforeLoad');
12637 this.el.update("");
12639 this.el.mask(this.mask ? this.mask : "Loading" );
12641 onLoad : function ()
12648 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12649 * @param {HTMLElement} node
12650 * @return {HTMLElement} The template node
12652 findItemFromChild : function(node){
12653 var el = this.dataName ?
12654 this.el.child('.roo-tpl-' + this.dataName,true) :
12657 if(!node || node.parentNode == el){
12660 var p = node.parentNode;
12661 while(p && p != el){
12662 if(p.parentNode == el){
12671 onClick : function(e){
12672 var item = this.findItemFromChild(e.getTarget());
12674 var index = this.indexOf(item);
12675 if(this.onItemClick(item, index, e) !== false){
12676 this.fireEvent("click", this, index, item, e);
12679 this.clearSelections();
12684 onContextMenu : function(e){
12685 var item = this.findItemFromChild(e.getTarget());
12687 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12692 onDblClick : function(e){
12693 var item = this.findItemFromChild(e.getTarget());
12695 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12699 onItemClick : function(item, index, e)
12701 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12704 if (this.toggleSelect) {
12705 var m = this.isSelected(item) ? 'unselect' : 'select';
12708 _t[m](item, true, false);
12711 if(this.multiSelect || this.singleSelect){
12712 if(this.multiSelect && e.shiftKey && this.lastSelection){
12713 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12715 this.select(item, this.multiSelect && e.ctrlKey);
12716 this.lastSelection = item;
12719 if(!this.tickable){
12720 e.preventDefault();
12728 * Get the number of selected nodes.
12731 getSelectionCount : function(){
12732 return this.selections.length;
12736 * Get the currently selected nodes.
12737 * @return {Array} An array of HTMLElements
12739 getSelectedNodes : function(){
12740 return this.selections;
12744 * Get the indexes of the selected nodes.
12747 getSelectedIndexes : function(){
12748 var indexes = [], s = this.selections;
12749 for(var i = 0, len = s.length; i < len; i++){
12750 indexes.push(s[i].nodeIndex);
12756 * Clear all selections
12757 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12759 clearSelections : function(suppressEvent){
12760 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12761 this.cmp.elements = this.selections;
12762 this.cmp.removeClass(this.selectedClass);
12763 this.selections = [];
12764 if(!suppressEvent){
12765 this.fireEvent("selectionchange", this, this.selections);
12771 * Returns true if the passed node is selected
12772 * @param {HTMLElement/Number} node The node or node index
12773 * @return {Boolean}
12775 isSelected : function(node){
12776 var s = this.selections;
12780 node = this.getNode(node);
12781 return s.indexOf(node) !== -1;
12786 * @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
12787 * @param {Boolean} keepExisting (optional) true to keep existing selections
12788 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12790 select : function(nodeInfo, keepExisting, suppressEvent){
12791 if(nodeInfo instanceof Array){
12793 this.clearSelections(true);
12795 for(var i = 0, len = nodeInfo.length; i < len; i++){
12796 this.select(nodeInfo[i], true, true);
12800 var node = this.getNode(nodeInfo);
12801 if(!node || this.isSelected(node)){
12802 return; // already selected.
12805 this.clearSelections(true);
12808 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12809 Roo.fly(node).addClass(this.selectedClass);
12810 this.selections.push(node);
12811 if(!suppressEvent){
12812 this.fireEvent("selectionchange", this, this.selections);
12820 * @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
12821 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12822 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12824 unselect : function(nodeInfo, keepExisting, suppressEvent)
12826 if(nodeInfo instanceof Array){
12827 Roo.each(this.selections, function(s) {
12828 this.unselect(s, nodeInfo);
12832 var node = this.getNode(nodeInfo);
12833 if(!node || !this.isSelected(node)){
12834 //Roo.log("not selected");
12835 return; // not selected.
12839 Roo.each(this.selections, function(s) {
12841 Roo.fly(node).removeClass(this.selectedClass);
12848 this.selections= ns;
12849 this.fireEvent("selectionchange", this, this.selections);
12853 * Gets a template node.
12854 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12855 * @return {HTMLElement} The node or null if it wasn't found
12857 getNode : function(nodeInfo){
12858 if(typeof nodeInfo == "string"){
12859 return document.getElementById(nodeInfo);
12860 }else if(typeof nodeInfo == "number"){
12861 return this.nodes[nodeInfo];
12867 * Gets a range template nodes.
12868 * @param {Number} startIndex
12869 * @param {Number} endIndex
12870 * @return {Array} An array of nodes
12872 getNodes : function(start, end){
12873 var ns = this.nodes;
12874 start = start || 0;
12875 end = typeof end == "undefined" ? ns.length - 1 : end;
12878 for(var i = start; i <= end; i++){
12882 for(var i = start; i >= end; i--){
12890 * Finds the index of the passed node
12891 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12892 * @return {Number} The index of the node or -1
12894 indexOf : function(node){
12895 node = this.getNode(node);
12896 if(typeof node.nodeIndex == "number"){
12897 return node.nodeIndex;
12899 var ns = this.nodes;
12900 for(var i = 0, len = ns.length; i < len; i++){
12911 * based on jquery fullcalendar
12915 Roo.bootstrap = Roo.bootstrap || {};
12917 * @class Roo.bootstrap.Calendar
12918 * @extends Roo.bootstrap.Component
12919 * Bootstrap Calendar class
12920 * @cfg {Boolean} loadMask (true|false) default false
12921 * @cfg {Object} header generate the user specific header of the calendar, default false
12924 * Create a new Container
12925 * @param {Object} config The config object
12930 Roo.bootstrap.Calendar = function(config){
12931 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12935 * Fires when a date is selected
12936 * @param {DatePicker} this
12937 * @param {Date} date The selected date
12941 * @event monthchange
12942 * Fires when the displayed month changes
12943 * @param {DatePicker} this
12944 * @param {Date} date The selected month
12946 'monthchange': true,
12948 * @event evententer
12949 * Fires when mouse over an event
12950 * @param {Calendar} this
12951 * @param {event} Event
12953 'evententer': true,
12955 * @event eventleave
12956 * Fires when the mouse leaves an
12957 * @param {Calendar} this
12960 'eventleave': true,
12962 * @event eventclick
12963 * Fires when the mouse click an
12964 * @param {Calendar} this
12973 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12976 * @cfg {Number} startDay
12977 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12985 getAutoCreate : function(){
12988 var fc_button = function(name, corner, style, content ) {
12989 return Roo.apply({},{
12991 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12993 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12996 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13007 style : 'width:100%',
13014 cls : 'fc-header-left',
13016 fc_button('prev', 'left', 'arrow', '‹' ),
13017 fc_button('next', 'right', 'arrow', '›' ),
13018 { tag: 'span', cls: 'fc-header-space' },
13019 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13027 cls : 'fc-header-center',
13031 cls: 'fc-header-title',
13034 html : 'month / year'
13042 cls : 'fc-header-right',
13044 /* fc_button('month', 'left', '', 'month' ),
13045 fc_button('week', '', '', 'week' ),
13046 fc_button('day', 'right', '', 'day' )
13058 header = this.header;
13061 var cal_heads = function() {
13063 // fixme - handle this.
13065 for (var i =0; i < Date.dayNames.length; i++) {
13066 var d = Date.dayNames[i];
13069 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13070 html : d.substring(0,3)
13074 ret[0].cls += ' fc-first';
13075 ret[6].cls += ' fc-last';
13078 var cal_cell = function(n) {
13081 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13086 cls: 'fc-day-number',
13090 cls: 'fc-day-content',
13094 style: 'position: relative;' // height: 17px;
13106 var cal_rows = function() {
13109 for (var r = 0; r < 6; r++) {
13116 for (var i =0; i < Date.dayNames.length; i++) {
13117 var d = Date.dayNames[i];
13118 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13121 row.cn[0].cls+=' fc-first';
13122 row.cn[0].cn[0].style = 'min-height:90px';
13123 row.cn[6].cls+=' fc-last';
13127 ret[0].cls += ' fc-first';
13128 ret[4].cls += ' fc-prev-last';
13129 ret[5].cls += ' fc-last';
13136 cls: 'fc-border-separate',
13137 style : 'width:100%',
13145 cls : 'fc-first fc-last',
13163 cls : 'fc-content',
13164 style : "position: relative;",
13167 cls : 'fc-view fc-view-month fc-grid',
13168 style : 'position: relative',
13169 unselectable : 'on',
13172 cls : 'fc-event-container',
13173 style : 'position:absolute;z-index:8;top:0;left:0;'
13191 initEvents : function()
13194 throw "can not find store for calendar";
13200 style: "text-align:center",
13204 style: "background-color:white;width:50%;margin:250 auto",
13208 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13219 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13221 var size = this.el.select('.fc-content', true).first().getSize();
13222 this.maskEl.setSize(size.width, size.height);
13223 this.maskEl.enableDisplayMode("block");
13224 if(!this.loadMask){
13225 this.maskEl.hide();
13228 this.store = Roo.factory(this.store, Roo.data);
13229 this.store.on('load', this.onLoad, this);
13230 this.store.on('beforeload', this.onBeforeLoad, this);
13234 this.cells = this.el.select('.fc-day',true);
13235 //Roo.log(this.cells);
13236 this.textNodes = this.el.query('.fc-day-number');
13237 this.cells.addClassOnOver('fc-state-hover');
13239 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13240 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13241 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13242 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13244 this.on('monthchange', this.onMonthChange, this);
13246 this.update(new Date().clearTime());
13249 resize : function() {
13250 var sz = this.el.getSize();
13252 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13253 this.el.select('.fc-day-content div',true).setHeight(34);
13258 showPrevMonth : function(e){
13259 this.update(this.activeDate.add("mo", -1));
13261 showToday : function(e){
13262 this.update(new Date().clearTime());
13265 showNextMonth : function(e){
13266 this.update(this.activeDate.add("mo", 1));
13270 showPrevYear : function(){
13271 this.update(this.activeDate.add("y", -1));
13275 showNextYear : function(){
13276 this.update(this.activeDate.add("y", 1));
13281 update : function(date)
13283 var vd = this.activeDate;
13284 this.activeDate = date;
13285 // if(vd && this.el){
13286 // var t = date.getTime();
13287 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13288 // Roo.log('using add remove');
13290 // this.fireEvent('monthchange', this, date);
13292 // this.cells.removeClass("fc-state-highlight");
13293 // this.cells.each(function(c){
13294 // if(c.dateValue == t){
13295 // c.addClass("fc-state-highlight");
13296 // setTimeout(function(){
13297 // try{c.dom.firstChild.focus();}catch(e){}
13307 var days = date.getDaysInMonth();
13309 var firstOfMonth = date.getFirstDateOfMonth();
13310 var startingPos = firstOfMonth.getDay()-this.startDay;
13312 if(startingPos < this.startDay){
13316 var pm = date.add(Date.MONTH, -1);
13317 var prevStart = pm.getDaysInMonth()-startingPos;
13319 this.cells = this.el.select('.fc-day',true);
13320 this.textNodes = this.el.query('.fc-day-number');
13321 this.cells.addClassOnOver('fc-state-hover');
13323 var cells = this.cells.elements;
13324 var textEls = this.textNodes;
13326 Roo.each(cells, function(cell){
13327 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13330 days += startingPos;
13332 // convert everything to numbers so it's fast
13333 var day = 86400000;
13334 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13337 //Roo.log(prevStart);
13339 var today = new Date().clearTime().getTime();
13340 var sel = date.clearTime().getTime();
13341 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13342 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13343 var ddMatch = this.disabledDatesRE;
13344 var ddText = this.disabledDatesText;
13345 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13346 var ddaysText = this.disabledDaysText;
13347 var format = this.format;
13349 var setCellClass = function(cal, cell){
13353 //Roo.log('set Cell Class');
13355 var t = d.getTime();
13359 cell.dateValue = t;
13361 cell.className += " fc-today";
13362 cell.className += " fc-state-highlight";
13363 cell.title = cal.todayText;
13366 // disable highlight in other month..
13367 //cell.className += " fc-state-highlight";
13372 cell.className = " fc-state-disabled";
13373 cell.title = cal.minText;
13377 cell.className = " fc-state-disabled";
13378 cell.title = cal.maxText;
13382 if(ddays.indexOf(d.getDay()) != -1){
13383 cell.title = ddaysText;
13384 cell.className = " fc-state-disabled";
13387 if(ddMatch && format){
13388 var fvalue = d.dateFormat(format);
13389 if(ddMatch.test(fvalue)){
13390 cell.title = ddText.replace("%0", fvalue);
13391 cell.className = " fc-state-disabled";
13395 if (!cell.initialClassName) {
13396 cell.initialClassName = cell.dom.className;
13399 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13404 for(; i < startingPos; i++) {
13405 textEls[i].innerHTML = (++prevStart);
13406 d.setDate(d.getDate()+1);
13408 cells[i].className = "fc-past fc-other-month";
13409 setCellClass(this, cells[i]);
13414 for(; i < days; i++){
13415 intDay = i - startingPos + 1;
13416 textEls[i].innerHTML = (intDay);
13417 d.setDate(d.getDate()+1);
13419 cells[i].className = ''; // "x-date-active";
13420 setCellClass(this, cells[i]);
13424 for(; i < 42; i++) {
13425 textEls[i].innerHTML = (++extraDays);
13426 d.setDate(d.getDate()+1);
13428 cells[i].className = "fc-future fc-other-month";
13429 setCellClass(this, cells[i]);
13432 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13434 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13436 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13437 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13439 if(totalRows != 6){
13440 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13441 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13444 this.fireEvent('monthchange', this, date);
13448 if(!this.internalRender){
13449 var main = this.el.dom.firstChild;
13450 var w = main.offsetWidth;
13451 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13452 Roo.fly(main).setWidth(w);
13453 this.internalRender = true;
13454 // opera does not respect the auto grow header center column
13455 // then, after it gets a width opera refuses to recalculate
13456 // without a second pass
13457 if(Roo.isOpera && !this.secondPass){
13458 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13459 this.secondPass = true;
13460 this.update.defer(10, this, [date]);
13467 findCell : function(dt) {
13468 dt = dt.clearTime().getTime();
13470 this.cells.each(function(c){
13471 //Roo.log("check " +c.dateValue + '?=' + dt);
13472 if(c.dateValue == dt){
13482 findCells : function(ev) {
13483 var s = ev.start.clone().clearTime().getTime();
13485 var e= ev.end.clone().clearTime().getTime();
13488 this.cells.each(function(c){
13489 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13491 if(c.dateValue > e){
13494 if(c.dateValue < s){
13503 // findBestRow: function(cells)
13507 // for (var i =0 ; i < cells.length;i++) {
13508 // ret = Math.max(cells[i].rows || 0,ret);
13515 addItem : function(ev)
13517 // look for vertical location slot in
13518 var cells = this.findCells(ev);
13520 // ev.row = this.findBestRow(cells);
13522 // work out the location.
13526 for(var i =0; i < cells.length; i++) {
13528 cells[i].row = cells[0].row;
13531 cells[i].row = cells[i].row + 1;
13541 if (crow.start.getY() == cells[i].getY()) {
13543 crow.end = cells[i];
13560 cells[0].events.push(ev);
13562 this.calevents.push(ev);
13565 clearEvents: function() {
13567 if(!this.calevents){
13571 Roo.each(this.cells.elements, function(c){
13577 Roo.each(this.calevents, function(e) {
13578 Roo.each(e.els, function(el) {
13579 el.un('mouseenter' ,this.onEventEnter, this);
13580 el.un('mouseleave' ,this.onEventLeave, this);
13585 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13591 renderEvents: function()
13595 this.cells.each(function(c) {
13604 if(c.row != c.events.length){
13605 r = 4 - (4 - (c.row - c.events.length));
13608 c.events = ev.slice(0, r);
13609 c.more = ev.slice(r);
13611 if(c.more.length && c.more.length == 1){
13612 c.events.push(c.more.pop());
13615 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13619 this.cells.each(function(c) {
13621 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13624 for (var e = 0; e < c.events.length; e++){
13625 var ev = c.events[e];
13626 var rows = ev.rows;
13628 for(var i = 0; i < rows.length; i++) {
13630 // how many rows should it span..
13633 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13634 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13636 unselectable : "on",
13639 cls: 'fc-event-inner',
13643 // cls: 'fc-event-time',
13644 // html : cells.length > 1 ? '' : ev.time
13648 cls: 'fc-event-title',
13649 html : String.format('{0}', ev.title)
13656 cls: 'ui-resizable-handle ui-resizable-e',
13657 html : '  '
13664 cfg.cls += ' fc-event-start';
13666 if ((i+1) == rows.length) {
13667 cfg.cls += ' fc-event-end';
13670 var ctr = _this.el.select('.fc-event-container',true).first();
13671 var cg = ctr.createChild(cfg);
13673 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13674 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13676 var r = (c.more.length) ? 1 : 0;
13677 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13678 cg.setWidth(ebox.right - sbox.x -2);
13680 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13681 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13682 cg.on('click', _this.onEventClick, _this, ev);
13693 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13694 style : 'position: absolute',
13695 unselectable : "on",
13698 cls: 'fc-event-inner',
13702 cls: 'fc-event-title',
13710 cls: 'ui-resizable-handle ui-resizable-e',
13711 html : '  '
13717 var ctr = _this.el.select('.fc-event-container',true).first();
13718 var cg = ctr.createChild(cfg);
13720 var sbox = c.select('.fc-day-content',true).first().getBox();
13721 var ebox = c.select('.fc-day-content',true).first().getBox();
13723 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13724 cg.setWidth(ebox.right - sbox.x -2);
13726 cg.on('click', _this.onMoreEventClick, _this, c.more);
13736 onEventEnter: function (e, el,event,d) {
13737 this.fireEvent('evententer', this, el, event);
13740 onEventLeave: function (e, el,event,d) {
13741 this.fireEvent('eventleave', this, el, event);
13744 onEventClick: function (e, el,event,d) {
13745 this.fireEvent('eventclick', this, el, event);
13748 onMonthChange: function () {
13752 onMoreEventClick: function(e, el, more)
13756 this.calpopover.placement = 'right';
13757 this.calpopover.setTitle('More');
13759 this.calpopover.setContent('');
13761 var ctr = this.calpopover.el.select('.popover-content', true).first();
13763 Roo.each(more, function(m){
13765 cls : 'fc-event-hori fc-event-draggable',
13768 var cg = ctr.createChild(cfg);
13770 cg.on('click', _this.onEventClick, _this, m);
13773 this.calpopover.show(el);
13778 onLoad: function ()
13780 this.calevents = [];
13783 if(this.store.getCount() > 0){
13784 this.store.data.each(function(d){
13787 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13788 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13789 time : d.data.start_time,
13790 title : d.data.title,
13791 description : d.data.description,
13792 venue : d.data.venue
13797 this.renderEvents();
13799 if(this.calevents.length && this.loadMask){
13800 this.maskEl.hide();
13804 onBeforeLoad: function()
13806 this.clearEvents();
13808 this.maskEl.show();
13822 * @class Roo.bootstrap.Popover
13823 * @extends Roo.bootstrap.Component
13824 * Bootstrap Popover class
13825 * @cfg {String} html contents of the popover (or false to use children..)
13826 * @cfg {String} title of popover (or false to hide)
13827 * @cfg {String} placement how it is placed
13828 * @cfg {String} trigger click || hover (or false to trigger manually)
13829 * @cfg {String} over what (parent or false to trigger manually.)
13830 * @cfg {Number} delay - delay before showing
13833 * Create a new Popover
13834 * @param {Object} config The config object
13837 Roo.bootstrap.Popover = function(config){
13838 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13841 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13843 title: 'Fill in a title',
13846 placement : 'right',
13847 trigger : 'hover', // hover
13853 can_build_overlaid : false,
13855 getChildContainer : function()
13857 return this.el.select('.popover-content',true).first();
13860 getAutoCreate : function(){
13861 Roo.log('make popover?');
13863 cls : 'popover roo-dynamic',
13864 style: 'display:block',
13870 cls : 'popover-inner',
13874 cls: 'popover-title',
13878 cls : 'popover-content',
13889 setTitle: function(str)
13891 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13893 setContent: function(str)
13895 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13897 // as it get's added to the bottom of the page.
13898 onRender : function(ct, position)
13900 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13902 var cfg = Roo.apply({}, this.getAutoCreate());
13906 cfg.cls += ' ' + this.cls;
13909 cfg.style = this.style;
13911 Roo.log("adding to ")
13912 this.el = Roo.get(document.body).createChild(cfg, position);
13918 initEvents : function()
13920 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13921 this.el.enableDisplayMode('block');
13923 if (this.over === false) {
13926 if (this.triggers === false) {
13929 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13930 var triggers = this.trigger ? this.trigger.split(' ') : [];
13931 Roo.each(triggers, function(trigger) {
13933 if (trigger == 'click') {
13934 on_el.on('click', this.toggle, this);
13935 } else if (trigger != 'manual') {
13936 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13937 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13939 on_el.on(eventIn ,this.enter, this);
13940 on_el.on(eventOut, this.leave, this);
13951 toggle : function () {
13952 this.hoverState == 'in' ? this.leave() : this.enter();
13955 enter : function () {
13958 clearTimeout(this.timeout);
13960 this.hoverState = 'in'
13962 if (!this.delay || !this.delay.show) {
13967 this.timeout = setTimeout(function () {
13968 if (_t.hoverState == 'in') {
13971 }, this.delay.show)
13973 leave : function() {
13974 clearTimeout(this.timeout);
13976 this.hoverState = 'out'
13978 if (!this.delay || !this.delay.hide) {
13983 this.timeout = setTimeout(function () {
13984 if (_t.hoverState == 'out') {
13987 }, this.delay.hide)
13990 show : function (on_el)
13993 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13996 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13997 if (this.html !== false) {
13998 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14000 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14001 if (!this.title.length) {
14002 this.el.select('.popover-title',true).hide();
14005 var placement = typeof this.placement == 'function' ?
14006 this.placement.call(this, this.el, on_el) :
14009 var autoToken = /\s?auto?\s?/i;
14010 var autoPlace = autoToken.test(placement);
14012 placement = placement.replace(autoToken, '') || 'top';
14016 //this.el.setXY([0,0]);
14018 this.el.dom.style.display='block';
14019 this.el.addClass(placement);
14021 //this.el.appendTo(on_el);
14023 var p = this.getPosition();
14024 var box = this.el.getBox();
14029 var align = Roo.bootstrap.Popover.alignment[placement]
14030 this.el.alignTo(on_el, align[0],align[1]);
14031 //var arrow = this.el.select('.arrow',true).first();
14032 //arrow.set(align[2],
14034 this.el.addClass('in');
14035 this.hoverState = null;
14037 if (this.el.hasClass('fade')) {
14044 this.el.setXY([0,0]);
14045 this.el.removeClass('in');
14052 Roo.bootstrap.Popover.alignment = {
14053 'left' : ['r-l', [-10,0], 'right'],
14054 'right' : ['l-r', [10,0], 'left'],
14055 'bottom' : ['t-b', [0,10], 'top'],
14056 'top' : [ 'b-t', [0,-10], 'bottom']
14067 * @class Roo.bootstrap.Progress
14068 * @extends Roo.bootstrap.Component
14069 * Bootstrap Progress class
14070 * @cfg {Boolean} striped striped of the progress bar
14071 * @cfg {Boolean} active animated of the progress bar
14075 * Create a new Progress
14076 * @param {Object} config The config object
14079 Roo.bootstrap.Progress = function(config){
14080 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14083 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14088 getAutoCreate : function(){
14096 cfg.cls += ' progress-striped';
14100 cfg.cls += ' active';
14119 * @class Roo.bootstrap.ProgressBar
14120 * @extends Roo.bootstrap.Component
14121 * Bootstrap ProgressBar class
14122 * @cfg {Number} aria_valuenow aria-value now
14123 * @cfg {Number} aria_valuemin aria-value min
14124 * @cfg {Number} aria_valuemax aria-value max
14125 * @cfg {String} label label for the progress bar
14126 * @cfg {String} panel (success | info | warning | danger )
14127 * @cfg {String} role role of the progress bar
14128 * @cfg {String} sr_only text
14132 * Create a new ProgressBar
14133 * @param {Object} config The config object
14136 Roo.bootstrap.ProgressBar = function(config){
14137 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14140 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14144 aria_valuemax : 100,
14150 getAutoCreate : function()
14155 cls: 'progress-bar',
14156 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14168 cfg.role = this.role;
14171 if(this.aria_valuenow){
14172 cfg['aria-valuenow'] = this.aria_valuenow;
14175 if(this.aria_valuemin){
14176 cfg['aria-valuemin'] = this.aria_valuemin;
14179 if(this.aria_valuemax){
14180 cfg['aria-valuemax'] = this.aria_valuemax;
14183 if(this.label && !this.sr_only){
14184 cfg.html = this.label;
14188 cfg.cls += ' progress-bar-' + this.panel;
14194 update : function(aria_valuenow)
14196 this.aria_valuenow = aria_valuenow;
14198 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14213 * @class Roo.bootstrap.TabGroup
14214 * @extends Roo.bootstrap.Column
14215 * Bootstrap Column class
14216 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14217 * @cfg {Boolean} carousel true to make the group behave like a carousel
14220 * Create a new TabGroup
14221 * @param {Object} config The config object
14224 Roo.bootstrap.TabGroup = function(config){
14225 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14227 this.navId = Roo.id();
14230 Roo.bootstrap.TabGroup.register(this);
14234 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14237 transition : false,
14239 getAutoCreate : function()
14241 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14243 cfg.cls += ' tab-content';
14245 if (this.carousel) {
14246 cfg.cls += ' carousel slide';
14248 cls : 'carousel-inner'
14255 getChildContainer : function()
14257 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14261 * register a Navigation item
14262 * @param {Roo.bootstrap.NavItem} the navitem to add
14264 register : function(item)
14266 this.tabs.push( item);
14267 item.navId = this.navId; // not really needed..
14271 getActivePanel : function()
14274 Roo.each(this.tabs, function(t) {
14284 getPanelByName : function(n)
14287 Roo.each(this.tabs, function(t) {
14288 if (t.tabId == n) {
14296 indexOfPanel : function(p)
14299 Roo.each(this.tabs, function(t,i) {
14300 if (t.tabId == p.tabId) {
14309 * show a specific panel
14310 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14311 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14313 showPanel : function (pan)
14316 if (typeof(pan) == 'number') {
14317 pan = this.tabs[pan];
14319 if (typeof(pan) == 'string') {
14320 pan = this.getPanelByName(pan);
14322 if (pan.tabId == this.getActivePanel().tabId) {
14325 var cur = this.getActivePanel();
14327 if (false === cur.fireEvent('beforedeactivate')) {
14331 if (this.carousel) {
14332 this.transition = true;
14333 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14334 var lr = dir == 'next' ? 'left' : 'right';
14335 pan.el.addClass(dir); // or prev
14336 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14337 cur.el.addClass(lr); // or right
14338 pan.el.addClass(lr);
14341 cur.el.on('transitionend', function() {
14342 Roo.log("trans end?");
14344 pan.el.removeClass([lr,dir]);
14345 pan.setActive(true);
14347 cur.el.removeClass([lr]);
14348 cur.setActive(false);
14350 _this.transition = false;
14352 }, this, { single: true } );
14356 cur.setActive(false);
14357 pan.setActive(true);
14361 showPanelNext : function()
14363 var i = this.indexOfPanel(this.getActivePanel());
14364 if (i > this.tabs.length) {
14367 this.showPanel(this.tabs[i+1]);
14369 showPanelPrev : function()
14371 var i = this.indexOfPanel(this.getActivePanel());
14375 this.showPanel(this.tabs[i-1]);
14386 Roo.apply(Roo.bootstrap.TabGroup, {
14390 * register a Navigation Group
14391 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14393 register : function(navgrp)
14395 this.groups[navgrp.navId] = navgrp;
14399 * fetch a Navigation Group based on the navigation ID
14400 * if one does not exist , it will get created.
14401 * @param {string} the navgroup to add
14402 * @returns {Roo.bootstrap.NavGroup} the navgroup
14404 get: function(navId) {
14405 if (typeof(this.groups[navId]) == 'undefined') {
14406 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14408 return this.groups[navId] ;
14423 * @class Roo.bootstrap.TabPanel
14424 * @extends Roo.bootstrap.Component
14425 * Bootstrap TabPanel class
14426 * @cfg {Boolean} active panel active
14427 * @cfg {String} html panel content
14428 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14429 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14433 * Create a new TabPanel
14434 * @param {Object} config The config object
14437 Roo.bootstrap.TabPanel = function(config){
14438 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14442 * Fires when the active status changes
14443 * @param {Roo.bootstrap.TabPanel} this
14444 * @param {Boolean} state the new state
14449 * @event beforedeactivate
14450 * Fires before a tab is de-activated - can be used to do validation on a form.
14451 * @param {Roo.bootstrap.TabPanel} this
14452 * @return {Boolean} false if there is an error
14455 'beforedeactivate': true
14458 this.tabId = this.tabId || Roo.id();
14462 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14469 getAutoCreate : function(){
14472 // item is needed for carousel - not sure if it has any effect otherwise
14473 cls: 'tab-pane item',
14474 html: this.html || ''
14478 cfg.cls += ' active';
14482 cfg.tabId = this.tabId;
14489 initEvents: function()
14491 Roo.log('-------- init events on tab panel ---------');
14493 var p = this.parent();
14494 this.navId = this.navId || p.navId;
14496 if (typeof(this.navId) != 'undefined') {
14497 // not really needed.. but just in case.. parent should be a NavGroup.
14498 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14499 Roo.log(['register', tg, this]);
14505 onRender : function(ct, position)
14507 // Roo.log("Call onRender: " + this.xtype);
14509 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14517 setActive: function(state)
14519 Roo.log("panel - set active " + this.tabId + "=" + state);
14521 this.active = state;
14523 this.el.removeClass('active');
14525 } else if (!this.el.hasClass('active')) {
14526 this.el.addClass('active');
14528 this.fireEvent('changed', this, state);
14545 * @class Roo.bootstrap.DateField
14546 * @extends Roo.bootstrap.Input
14547 * Bootstrap DateField class
14548 * @cfg {Number} weekStart default 0
14549 * @cfg {String} viewMode default empty, (months|years)
14550 * @cfg {String} minViewMode default empty, (months|years)
14551 * @cfg {Number} startDate default -Infinity
14552 * @cfg {Number} endDate default Infinity
14553 * @cfg {Boolean} todayHighlight default false
14554 * @cfg {Boolean} todayBtn default false
14555 * @cfg {Boolean} calendarWeeks default false
14556 * @cfg {Object} daysOfWeekDisabled default empty
14557 * @cfg {Boolean} singleMode default false (true | false)
14559 * @cfg {Boolean} keyboardNavigation default true
14560 * @cfg {String} language default en
14563 * Create a new DateField
14564 * @param {Object} config The config object
14567 Roo.bootstrap.DateField = function(config){
14568 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14572 * Fires when this field show.
14573 * @param {Roo.bootstrap.DateField} this
14574 * @param {Mixed} date The date value
14579 * Fires when this field hide.
14580 * @param {Roo.bootstrap.DateField} this
14581 * @param {Mixed} date The date value
14586 * Fires when select a date.
14587 * @param {Roo.bootstrap.DateField} this
14588 * @param {Mixed} date The date value
14594 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14597 * @cfg {String} format
14598 * The default date format string which can be overriden for localization support. The format must be
14599 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14603 * @cfg {String} altFormats
14604 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14605 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14607 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14615 todayHighlight : false,
14621 keyboardNavigation: true,
14623 calendarWeeks: false,
14625 startDate: -Infinity,
14629 daysOfWeekDisabled: [],
14633 singleMode : false,
14635 UTCDate: function()
14637 return new Date(Date.UTC.apply(Date, arguments));
14640 UTCToday: function()
14642 var today = new Date();
14643 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14646 getDate: function() {
14647 var d = this.getUTCDate();
14648 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14651 getUTCDate: function() {
14655 setDate: function(d) {
14656 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14659 setUTCDate: function(d) {
14661 this.setValue(this.formatDate(this.date));
14664 onRender: function(ct, position)
14667 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14669 this.language = this.language || 'en';
14670 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14671 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14673 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14674 this.format = this.format || 'm/d/y';
14675 this.isInline = false;
14676 this.isInput = true;
14677 this.component = this.el.select('.add-on', true).first() || false;
14678 this.component = (this.component && this.component.length === 0) ? false : this.component;
14679 this.hasInput = this.component && this.inputEL().length;
14681 if (typeof(this.minViewMode === 'string')) {
14682 switch (this.minViewMode) {
14684 this.minViewMode = 1;
14687 this.minViewMode = 2;
14690 this.minViewMode = 0;
14695 if (typeof(this.viewMode === 'string')) {
14696 switch (this.viewMode) {
14709 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14711 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14713 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14715 this.picker().on('mousedown', this.onMousedown, this);
14716 this.picker().on('click', this.onClick, this);
14718 this.picker().addClass('datepicker-dropdown');
14720 this.startViewMode = this.viewMode;
14722 if(this.singleMode){
14723 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14724 v.setVisibilityMode(Roo.Element.DISPLAY)
14728 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14729 v.setStyle('width', '189px');
14733 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14734 if(!this.calendarWeeks){
14739 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14740 v.attr('colspan', function(i, val){
14741 return parseInt(val) + 1;
14746 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14748 this.setStartDate(this.startDate);
14749 this.setEndDate(this.endDate);
14751 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14758 if(this.isInline) {
14763 picker : function()
14765 return this.pickerEl;
14766 // return this.el.select('.datepicker', true).first();
14769 fillDow: function()
14771 var dowCnt = this.weekStart;
14780 if(this.calendarWeeks){
14788 while (dowCnt < this.weekStart + 7) {
14792 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14796 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14799 fillMonths: function()
14802 var months = this.picker().select('>.datepicker-months td', true).first();
14804 months.dom.innerHTML = '';
14810 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14813 months.createChild(month);
14820 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;
14822 if (this.date < this.startDate) {
14823 this.viewDate = new Date(this.startDate);
14824 } else if (this.date > this.endDate) {
14825 this.viewDate = new Date(this.endDate);
14827 this.viewDate = new Date(this.date);
14835 var d = new Date(this.viewDate),
14836 year = d.getUTCFullYear(),
14837 month = d.getUTCMonth(),
14838 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14839 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14840 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14841 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14842 currentDate = this.date && this.date.valueOf(),
14843 today = this.UTCToday();
14845 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14847 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14849 // this.picker.select('>tfoot th.today').
14850 // .text(dates[this.language].today)
14851 // .toggle(this.todayBtn !== false);
14853 this.updateNavArrows();
14856 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14858 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14860 prevMonth.setUTCDate(day);
14862 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14864 var nextMonth = new Date(prevMonth);
14866 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14868 nextMonth = nextMonth.valueOf();
14870 var fillMonths = false;
14872 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14874 while(prevMonth.valueOf() < nextMonth) {
14877 if (prevMonth.getUTCDay() === this.weekStart) {
14879 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14887 if(this.calendarWeeks){
14888 // ISO 8601: First week contains first thursday.
14889 // ISO also states week starts on Monday, but we can be more abstract here.
14891 // Start of current week: based on weekstart/current date
14892 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14893 // Thursday of this week
14894 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14895 // First Thursday of year, year from thursday
14896 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14897 // Calendar week: ms between thursdays, div ms per day, div 7 days
14898 calWeek = (th - yth) / 864e5 / 7 + 1;
14900 fillMonths.cn.push({
14908 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14910 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14913 if (this.todayHighlight &&
14914 prevMonth.getUTCFullYear() == today.getFullYear() &&
14915 prevMonth.getUTCMonth() == today.getMonth() &&
14916 prevMonth.getUTCDate() == today.getDate()) {
14917 clsName += ' today';
14920 if (currentDate && prevMonth.valueOf() === currentDate) {
14921 clsName += ' active';
14924 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14925 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14926 clsName += ' disabled';
14929 fillMonths.cn.push({
14931 cls: 'day ' + clsName,
14932 html: prevMonth.getDate()
14935 prevMonth.setDate(prevMonth.getDate()+1);
14938 var currentYear = this.date && this.date.getUTCFullYear();
14939 var currentMonth = this.date && this.date.getUTCMonth();
14941 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14943 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14944 v.removeClass('active');
14946 if(currentYear === year && k === currentMonth){
14947 v.addClass('active');
14950 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14951 v.addClass('disabled');
14957 year = parseInt(year/10, 10) * 10;
14959 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14961 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14964 for (var i = -1; i < 11; i++) {
14965 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14967 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14975 showMode: function(dir)
14978 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14981 Roo.each(this.picker().select('>div',true).elements, function(v){
14982 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14985 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14990 if(this.isInline) return;
14992 this.picker().removeClass(['bottom', 'top']);
14994 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14996 * place to the top of element!
15000 this.picker().addClass('top');
15001 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15006 this.picker().addClass('bottom');
15008 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15011 parseDate : function(value)
15013 if(!value || value instanceof Date){
15016 var v = Date.parseDate(value, this.format);
15017 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15018 v = Date.parseDate(value, 'Y-m-d');
15020 if(!v && this.altFormats){
15021 if(!this.altFormatsArray){
15022 this.altFormatsArray = this.altFormats.split("|");
15024 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15025 v = Date.parseDate(value, this.altFormatsArray[i]);
15031 formatDate : function(date, fmt)
15033 return (!date || !(date instanceof Date)) ?
15034 date : date.dateFormat(fmt || this.format);
15037 onFocus : function()
15039 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15043 onBlur : function()
15045 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15047 var d = this.inputEl().getValue();
15056 this.picker().show();
15060 this.fireEvent('show', this, this.date);
15065 if(this.isInline) return;
15066 this.picker().hide();
15067 this.viewMode = this.startViewMode;
15070 this.fireEvent('hide', this, this.date);
15074 onMousedown: function(e)
15076 e.stopPropagation();
15077 e.preventDefault();
15082 Roo.bootstrap.DateField.superclass.keyup.call(this);
15086 setValue: function(v)
15089 // v can be a string or a date..
15092 var d = new Date(this.parseDate(v) ).clearTime();
15094 if(isNaN(d.getTime())){
15095 this.date = this.viewDate = '';
15096 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15100 v = this.formatDate(d);
15102 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15104 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15108 this.fireEvent('select', this, this.date);
15112 getValue: function()
15114 return this.formatDate(this.date);
15117 fireKey: function(e)
15119 if (!this.picker().isVisible()){
15120 if (e.keyCode == 27) // allow escape to hide and re-show picker
15125 var dateChanged = false,
15127 newDate, newViewDate;
15132 e.preventDefault();
15136 if (!this.keyboardNavigation) break;
15137 dir = e.keyCode == 37 ? -1 : 1;
15140 newDate = this.moveYear(this.date, dir);
15141 newViewDate = this.moveYear(this.viewDate, dir);
15142 } else if (e.shiftKey){
15143 newDate = this.moveMonth(this.date, dir);
15144 newViewDate = this.moveMonth(this.viewDate, dir);
15146 newDate = new Date(this.date);
15147 newDate.setUTCDate(this.date.getUTCDate() + dir);
15148 newViewDate = new Date(this.viewDate);
15149 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15151 if (this.dateWithinRange(newDate)){
15152 this.date = newDate;
15153 this.viewDate = newViewDate;
15154 this.setValue(this.formatDate(this.date));
15156 e.preventDefault();
15157 dateChanged = true;
15162 if (!this.keyboardNavigation) break;
15163 dir = e.keyCode == 38 ? -1 : 1;
15165 newDate = this.moveYear(this.date, dir);
15166 newViewDate = this.moveYear(this.viewDate, dir);
15167 } else if (e.shiftKey){
15168 newDate = this.moveMonth(this.date, dir);
15169 newViewDate = this.moveMonth(this.viewDate, dir);
15171 newDate = new Date(this.date);
15172 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15173 newViewDate = new Date(this.viewDate);
15174 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15176 if (this.dateWithinRange(newDate)){
15177 this.date = newDate;
15178 this.viewDate = newViewDate;
15179 this.setValue(this.formatDate(this.date));
15181 e.preventDefault();
15182 dateChanged = true;
15186 this.setValue(this.formatDate(this.date));
15188 e.preventDefault();
15191 this.setValue(this.formatDate(this.date));
15205 onClick: function(e)
15207 e.stopPropagation();
15208 e.preventDefault();
15210 var target = e.getTarget();
15212 if(target.nodeName.toLowerCase() === 'i'){
15213 target = Roo.get(target).dom.parentNode;
15216 var nodeName = target.nodeName;
15217 var className = target.className;
15218 var html = target.innerHTML;
15219 //Roo.log(nodeName);
15221 switch(nodeName.toLowerCase()) {
15223 switch(className) {
15229 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15230 switch(this.viewMode){
15232 this.viewDate = this.moveMonth(this.viewDate, dir);
15236 this.viewDate = this.moveYear(this.viewDate, dir);
15242 var date = new Date();
15243 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15245 this.setValue(this.formatDate(this.date));
15252 if (className.indexOf('disabled') < 0) {
15253 this.viewDate.setUTCDate(1);
15254 if (className.indexOf('month') > -1) {
15255 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15257 var year = parseInt(html, 10) || 0;
15258 this.viewDate.setUTCFullYear(year);
15262 if(this.singleMode){
15263 this.setValue(this.formatDate(this.viewDate));
15274 //Roo.log(className);
15275 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15276 var day = parseInt(html, 10) || 1;
15277 var year = this.viewDate.getUTCFullYear(),
15278 month = this.viewDate.getUTCMonth();
15280 if (className.indexOf('old') > -1) {
15287 } else if (className.indexOf('new') > -1) {
15295 //Roo.log([year,month,day]);
15296 this.date = this.UTCDate(year, month, day,0,0,0,0);
15297 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15299 //Roo.log(this.formatDate(this.date));
15300 this.setValue(this.formatDate(this.date));
15307 setStartDate: function(startDate)
15309 this.startDate = startDate || -Infinity;
15310 if (this.startDate !== -Infinity) {
15311 this.startDate = this.parseDate(this.startDate);
15314 this.updateNavArrows();
15317 setEndDate: function(endDate)
15319 this.endDate = endDate || Infinity;
15320 if (this.endDate !== Infinity) {
15321 this.endDate = this.parseDate(this.endDate);
15324 this.updateNavArrows();
15327 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15329 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15330 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15331 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15333 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15334 return parseInt(d, 10);
15337 this.updateNavArrows();
15340 updateNavArrows: function()
15342 if(this.singleMode){
15346 var d = new Date(this.viewDate),
15347 year = d.getUTCFullYear(),
15348 month = d.getUTCMonth();
15350 Roo.each(this.picker().select('.prev', true).elements, function(v){
15352 switch (this.viewMode) {
15355 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15361 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15368 Roo.each(this.picker().select('.next', true).elements, function(v){
15370 switch (this.viewMode) {
15373 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15379 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15387 moveMonth: function(date, dir)
15389 if (!dir) return date;
15390 var new_date = new Date(date.valueOf()),
15391 day = new_date.getUTCDate(),
15392 month = new_date.getUTCMonth(),
15393 mag = Math.abs(dir),
15395 dir = dir > 0 ? 1 : -1;
15398 // If going back one month, make sure month is not current month
15399 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15401 return new_date.getUTCMonth() == month;
15403 // If going forward one month, make sure month is as expected
15404 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15406 return new_date.getUTCMonth() != new_month;
15408 new_month = month + dir;
15409 new_date.setUTCMonth(new_month);
15410 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15411 if (new_month < 0 || new_month > 11)
15412 new_month = (new_month + 12) % 12;
15414 // For magnitudes >1, move one month at a time...
15415 for (var i=0; i<mag; i++)
15416 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15417 new_date = this.moveMonth(new_date, dir);
15418 // ...then reset the day, keeping it in the new month
15419 new_month = new_date.getUTCMonth();
15420 new_date.setUTCDate(day);
15422 return new_month != new_date.getUTCMonth();
15425 // Common date-resetting loop -- if date is beyond end of month, make it
15428 new_date.setUTCDate(--day);
15429 new_date.setUTCMonth(new_month);
15434 moveYear: function(date, dir)
15436 return this.moveMonth(date, dir*12);
15439 dateWithinRange: function(date)
15441 return date >= this.startDate && date <= this.endDate;
15447 this.picker().remove();
15452 Roo.apply(Roo.bootstrap.DateField, {
15463 html: '<i class="fa fa-arrow-left"/>'
15473 html: '<i class="fa fa-arrow-right"/>'
15515 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15516 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15517 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15518 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15519 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15532 navFnc: 'FullYear',
15537 navFnc: 'FullYear',
15542 Roo.apply(Roo.bootstrap.DateField, {
15546 cls: 'datepicker dropdown-menu roo-dynamic',
15550 cls: 'datepicker-days',
15554 cls: 'table-condensed',
15556 Roo.bootstrap.DateField.head,
15560 Roo.bootstrap.DateField.footer
15567 cls: 'datepicker-months',
15571 cls: 'table-condensed',
15573 Roo.bootstrap.DateField.head,
15574 Roo.bootstrap.DateField.content,
15575 Roo.bootstrap.DateField.footer
15582 cls: 'datepicker-years',
15586 cls: 'table-condensed',
15588 Roo.bootstrap.DateField.head,
15589 Roo.bootstrap.DateField.content,
15590 Roo.bootstrap.DateField.footer
15609 * @class Roo.bootstrap.TimeField
15610 * @extends Roo.bootstrap.Input
15611 * Bootstrap DateField class
15615 * Create a new TimeField
15616 * @param {Object} config The config object
15619 Roo.bootstrap.TimeField = function(config){
15620 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15624 * Fires when this field show.
15625 * @param {Roo.bootstrap.DateField} this
15626 * @param {Mixed} date The date value
15631 * Fires when this field hide.
15632 * @param {Roo.bootstrap.DateField} this
15633 * @param {Mixed} date The date value
15638 * Fires when select a date.
15639 * @param {Roo.bootstrap.DateField} this
15640 * @param {Mixed} date The date value
15646 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15649 * @cfg {String} format
15650 * The default time format string which can be overriden for localization support. The format must be
15651 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15655 onRender: function(ct, position)
15658 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15660 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15662 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15664 this.pop = this.picker().select('>.datepicker-time',true).first();
15665 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15667 this.picker().on('mousedown', this.onMousedown, this);
15668 this.picker().on('click', this.onClick, this);
15670 this.picker().addClass('datepicker-dropdown');
15675 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15676 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15677 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15678 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15679 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15680 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15684 fireKey: function(e){
15685 if (!this.picker().isVisible()){
15686 if (e.keyCode == 27) // allow escape to hide and re-show picker
15691 e.preventDefault();
15699 this.onTogglePeriod();
15702 this.onIncrementMinutes();
15705 this.onDecrementMinutes();
15714 onClick: function(e) {
15715 e.stopPropagation();
15716 e.preventDefault();
15719 picker : function()
15721 return this.el.select('.datepicker', true).first();
15724 fillTime: function()
15726 var time = this.pop.select('tbody', true).first();
15728 time.dom.innerHTML = '';
15743 cls: 'hours-up glyphicon glyphicon-chevron-up'
15763 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15784 cls: 'timepicker-hour',
15799 cls: 'timepicker-minute',
15814 cls: 'btn btn-primary period',
15836 cls: 'hours-down glyphicon glyphicon-chevron-down'
15856 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15874 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15881 var hours = this.time.getHours();
15882 var minutes = this.time.getMinutes();
15895 hours = hours - 12;
15899 hours = '0' + hours;
15903 minutes = '0' + minutes;
15906 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15907 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15908 this.pop.select('button', true).first().dom.innerHTML = period;
15914 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15916 var cls = ['bottom'];
15918 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15925 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15930 this.picker().addClass(cls.join('-'));
15934 Roo.each(cls, function(c){
15936 _this.picker().setTop(_this.inputEl().getHeight());
15940 _this.picker().setTop(0 - _this.picker().getHeight());
15945 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15949 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15956 onFocus : function()
15958 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15962 onBlur : function()
15964 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15970 this.picker().show();
15975 this.fireEvent('show', this, this.date);
15980 this.picker().hide();
15983 this.fireEvent('hide', this, this.date);
15986 setTime : function()
15989 this.setValue(this.time.format(this.format));
15991 this.fireEvent('select', this, this.date);
15996 onMousedown: function(e){
15997 e.stopPropagation();
15998 e.preventDefault();
16001 onIncrementHours: function()
16003 Roo.log('onIncrementHours');
16004 this.time = this.time.add(Date.HOUR, 1);
16009 onDecrementHours: function()
16011 Roo.log('onDecrementHours');
16012 this.time = this.time.add(Date.HOUR, -1);
16016 onIncrementMinutes: function()
16018 Roo.log('onIncrementMinutes');
16019 this.time = this.time.add(Date.MINUTE, 1);
16023 onDecrementMinutes: function()
16025 Roo.log('onDecrementMinutes');
16026 this.time = this.time.add(Date.MINUTE, -1);
16030 onTogglePeriod: function()
16032 Roo.log('onTogglePeriod');
16033 this.time = this.time.add(Date.HOUR, 12);
16040 Roo.apply(Roo.bootstrap.TimeField, {
16070 cls: 'btn btn-info ok',
16082 Roo.apply(Roo.bootstrap.TimeField, {
16086 cls: 'datepicker dropdown-menu',
16090 cls: 'datepicker-time',
16094 cls: 'table-condensed',
16096 Roo.bootstrap.TimeField.content,
16097 Roo.bootstrap.TimeField.footer
16116 * @class Roo.bootstrap.CheckBox
16117 * @extends Roo.bootstrap.Input
16118 * Bootstrap CheckBox class
16120 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16121 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16122 * @cfg {String} boxLabel The text that appears beside the checkbox
16123 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16124 * @cfg {Boolean} checked initnal the element
16125 * @cfg {Boolean} inline inline the element (default false)
16128 * Create a new CheckBox
16129 * @param {Object} config The config object
16132 Roo.bootstrap.CheckBox = function(config){
16133 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16138 * Fires when the element is checked or unchecked.
16139 * @param {Roo.bootstrap.CheckBox} this This input
16140 * @param {Boolean} checked The new checked value
16146 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16148 inputType: 'checkbox',
16156 getAutoCreate : function()
16158 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16164 cfg.cls = 'form-group ' + this.inputType //input-group
16167 cfg.cls += ' ' + this.inputType + '-inline';
16173 type : this.inputType,
16174 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16175 cls : 'roo-' + this.inputType, //'form-box',
16176 placeholder : this.placeholder || ''
16180 if (this.weight) { // Validity check?
16181 cfg.cls += " " + this.inputType + "-" + this.weight;
16184 if (this.disabled) {
16185 input.disabled=true;
16189 input.checked = this.checked;
16193 input.name = this.name;
16197 input.cls += ' input-' + this.size;
16201 ['xs','sm','md','lg'].map(function(size){
16202 if (settings[size]) {
16203 cfg.cls += ' col-' + size + '-' + settings[size];
16209 var inputblock = input;
16214 if (this.before || this.after) {
16217 cls : 'input-group',
16221 inputblock.cn.push({
16223 cls : 'input-group-addon',
16227 inputblock.cn.push(input);
16229 inputblock.cn.push({
16231 cls : 'input-group-addon',
16238 if (align ==='left' && this.fieldLabel.length) {
16239 Roo.log("left and has label");
16245 cls : 'control-label col-md-' + this.labelWidth,
16246 html : this.fieldLabel
16250 cls : "col-md-" + (12 - this.labelWidth),
16257 } else if ( this.fieldLabel.length) {
16262 tag: this.boxLabel ? 'span' : 'label',
16264 cls: 'control-label box-input-label',
16265 //cls : 'input-group-addon',
16266 html : this.fieldLabel
16276 Roo.log(" no label && no align");
16277 cfg.cn = [ inputblock ] ;
16282 var boxLabelCfg = {
16284 //'for': id, // box label is handled by onclick - so no for...
16286 html: this.boxLabel
16290 boxLabelCfg.tooltip = this.tooltip;
16293 cfg.cn.push(boxLabelCfg);
16303 * return the real input element.
16305 inputEl: function ()
16307 return this.el.select('input.roo-' + this.inputType,true).first();
16310 labelEl: function()
16312 return this.el.select('label.control-label',true).first();
16314 /* depricated... */
16318 return this.labelEl();
16321 initEvents : function()
16323 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16325 this.inputEl().on('click', this.onClick, this);
16326 if (this.boxLabel) {
16327 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16332 onClick : function()
16334 this.setChecked(!this.checked);
16337 setChecked : function(state,suppressEvent)
16339 if(this.inputType == 'radio'){
16341 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16342 e.dom.checked = false;
16345 this.inputEl().dom.checked = true;
16347 if(suppressEvent !== true){
16348 this.fireEvent('check', this, true);
16351 this.inputEl().dom.value = this.inputValue;
16356 this.checked = state;
16358 if(suppressEvent !== true){
16359 this.fireEvent('check', this, state);
16362 this.inputEl().dom.checked = state;
16364 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16368 getValue : function()
16370 if(this.inputType == 'radio'){
16371 return this.getGroupValue();
16374 return this.inputEl().getValue();
16378 getGroupValue : function()
16380 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16383 setValue : function(v,suppressEvent)
16385 if(this.inputType == 'radio'){
16386 this.setGroupValue(v, suppressEvent);
16390 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16393 setGroupValue : function(v, suppressEvent)
16395 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16396 e.dom.checked = false;
16398 if(e.dom.value == v){
16399 e.dom.checked = true;
16403 if(suppressEvent !== true){
16404 this.fireEvent('check', this, true);
16420 *<div class="radio">
16422 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
16423 Option one is this and that—be sure to include why it's great
16430 *<label class="radio-inline">fieldLabel</label>
16431 *<label class="radio-inline">
16432 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
16440 * @class Roo.bootstrap.Radio
16441 * @extends Roo.bootstrap.CheckBox
16442 * Bootstrap Radio class
16445 * Create a new Radio
16446 * @param {Object} config The config object
16449 Roo.bootstrap.Radio = function(config){
16450 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16454 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16456 inputType: 'radio',
16460 getAutoCreate : function()
16462 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16463 align = align || 'left'; // default...
16470 tag : this.inline ? 'span' : 'div',
16475 var inline = this.inline ? ' radio-inline' : '';
16479 // does not need for, as we wrap the input with it..
16481 cls : 'control-label box-label' + inline,
16487 cls : 'control-label' + inline,
16488 html : this.fieldLabel
16497 type : this.inputType,
16498 //value : (!this.checked) ? this.valueOff : this.inputValue,
16499 value : this.inputValue,
16501 placeholder : this.placeholder || '' // ?? needed????
16504 if (this.weight) { // Validity check?
16505 input.cls += " radio-" + this.weight;
16507 if (this.disabled) {
16508 input.disabled=true;
16512 input.checked = this.checked;
16516 input.name = this.name;
16520 input.cls += ' input-' + this.size;
16523 //?? can span's inline have a width??
16526 ['xs','sm','md','lg'].map(function(size){
16527 if (settings[size]) {
16528 cfg.cls += ' col-' + size + '-' + settings[size];
16532 var inputblock = input;
16534 if (this.before || this.after) {
16537 cls : 'input-group',
16542 inputblock.cn.push({
16544 cls : 'input-group-addon',
16548 inputblock.cn.push(input);
16550 inputblock.cn.push({
16552 cls : 'input-group-addon',
16560 if (this.fieldLabel && this.fieldLabel.length) {
16561 cfg.cn.push(fieldLabel);
16564 lbl.cn.push(inputblock);
16567 cls: 'radio' + inline,
16576 html: this.boxLabel
16584 inputEl: function ()
16586 return this.el.select('input.roo-radio',true).first();
16588 onClick : function()
16592 this.setChecked(true);
16595 setChecked : function(state,suppressEvent)
16598 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16599 v.dom.checked = false;
16603 this.checked = state;
16604 this.inputEl().dom.checked = state;
16606 if(suppressEvent !== true){
16607 this.fireEvent('check', this, state);
16610 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16614 getGroupValue : function()
16617 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16618 if(v.dom.checked == true){
16619 value = v.dom.value;
16627 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16628 * @return {Mixed} value The field value
16630 getValue : function(){
16631 return this.getGroupValue();
16637 //<script type="text/javascript">
16640 * Based Ext JS Library 1.1.1
16641 * Copyright(c) 2006-2007, Ext JS, LLC.
16647 * @class Roo.HtmlEditorCore
16648 * @extends Roo.Component
16649 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16651 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16654 Roo.HtmlEditorCore = function(config){
16657 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16662 * @event initialize
16663 * Fires when the editor is fully initialized (including the iframe)
16664 * @param {Roo.HtmlEditorCore} this
16669 * Fires when the editor is first receives the focus. Any insertion must wait
16670 * until after this event.
16671 * @param {Roo.HtmlEditorCore} this
16675 * @event beforesync
16676 * Fires before the textarea is updated with content from the editor iframe. Return false
16677 * to cancel the sync.
16678 * @param {Roo.HtmlEditorCore} this
16679 * @param {String} html
16683 * @event beforepush
16684 * Fires before the iframe editor is updated with content from the textarea. Return false
16685 * to cancel the push.
16686 * @param {Roo.HtmlEditorCore} this
16687 * @param {String} html
16692 * Fires when the textarea is updated with content from the editor iframe.
16693 * @param {Roo.HtmlEditorCore} this
16694 * @param {String} html
16699 * Fires when the iframe editor is updated with content from the textarea.
16700 * @param {Roo.HtmlEditorCore} this
16701 * @param {String} html
16706 * @event editorevent
16707 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16708 * @param {Roo.HtmlEditorCore} this
16714 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16716 // defaults : white / black...
16717 this.applyBlacklists();
16724 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16728 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16734 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16739 * @cfg {Number} height (in pixels)
16743 * @cfg {Number} width (in pixels)
16748 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16751 stylesheets: false,
16756 // private properties
16757 validationEvent : false,
16759 initialized : false,
16761 sourceEditMode : false,
16762 onFocus : Roo.emptyFn,
16764 hideMode:'offsets',
16768 // blacklist + whitelisted elements..
16775 * Protected method that will not generally be called directly. It
16776 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16777 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16779 getDocMarkup : function(){
16783 // inherit styels from page...??
16784 if (this.stylesheets === false) {
16786 Roo.get(document.head).select('style').each(function(node) {
16787 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16790 Roo.get(document.head).select('link').each(function(node) {
16791 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16794 } else if (!this.stylesheets.length) {
16796 st = '<style type="text/css">' +
16797 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16803 st += '<style type="text/css">' +
16804 'IMG { cursor: pointer } ' +
16808 return '<html><head>' + st +
16809 //<style type="text/css">' +
16810 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16812 ' </head><body class="roo-htmleditor-body"></body></html>';
16816 onRender : function(ct, position)
16819 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16820 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16823 this.el.dom.style.border = '0 none';
16824 this.el.dom.setAttribute('tabIndex', -1);
16825 this.el.addClass('x-hidden hide');
16829 if(Roo.isIE){ // fix IE 1px bogus margin
16830 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16834 this.frameId = Roo.id();
16838 var iframe = this.owner.wrap.createChild({
16840 cls: 'form-control', // bootstrap..
16842 name: this.frameId,
16843 frameBorder : 'no',
16844 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16849 this.iframe = iframe.dom;
16851 this.assignDocWin();
16853 this.doc.designMode = 'on';
16856 this.doc.write(this.getDocMarkup());
16860 var task = { // must defer to wait for browser to be ready
16862 //console.log("run task?" + this.doc.readyState);
16863 this.assignDocWin();
16864 if(this.doc.body || this.doc.readyState == 'complete'){
16866 this.doc.designMode="on";
16870 Roo.TaskMgr.stop(task);
16871 this.initEditor.defer(10, this);
16878 Roo.TaskMgr.start(task);
16883 onResize : function(w, h)
16885 Roo.log('resize: ' +w + ',' + h );
16886 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16890 if(typeof w == 'number'){
16892 this.iframe.style.width = w + 'px';
16894 if(typeof h == 'number'){
16896 this.iframe.style.height = h + 'px';
16898 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16905 * Toggles the editor between standard and source edit mode.
16906 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16908 toggleSourceEdit : function(sourceEditMode){
16910 this.sourceEditMode = sourceEditMode === true;
16912 if(this.sourceEditMode){
16914 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16917 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16918 //this.iframe.className = '';
16921 //this.setSize(this.owner.wrap.getSize());
16922 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16929 * Protected method that will not generally be called directly. If you need/want
16930 * custom HTML cleanup, this is the method you should override.
16931 * @param {String} html The HTML to be cleaned
16932 * return {String} The cleaned HTML
16934 cleanHtml : function(html){
16935 html = String(html);
16936 if(html.length > 5){
16937 if(Roo.isSafari){ // strip safari nonsense
16938 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16941 if(html == ' '){
16948 * HTML Editor -> Textarea
16949 * Protected method that will not generally be called directly. Syncs the contents
16950 * of the editor iframe with the textarea.
16952 syncValue : function(){
16953 if(this.initialized){
16954 var bd = (this.doc.body || this.doc.documentElement);
16955 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16956 var html = bd.innerHTML;
16958 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16959 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16961 html = '<div style="'+m[0]+'">' + html + '</div>';
16964 html = this.cleanHtml(html);
16965 // fix up the special chars.. normaly like back quotes in word...
16966 // however we do not want to do this with chinese..
16967 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16968 var cc = b.charCodeAt();
16970 (cc >= 0x4E00 && cc < 0xA000 ) ||
16971 (cc >= 0x3400 && cc < 0x4E00 ) ||
16972 (cc >= 0xf900 && cc < 0xfb00 )
16978 if(this.owner.fireEvent('beforesync', this, html) !== false){
16979 this.el.dom.value = html;
16980 this.owner.fireEvent('sync', this, html);
16986 * Protected method that will not generally be called directly. Pushes the value of the textarea
16987 * into the iframe editor.
16989 pushValue : function(){
16990 if(this.initialized){
16991 var v = this.el.dom.value.trim();
16993 // if(v.length < 1){
16997 if(this.owner.fireEvent('beforepush', this, v) !== false){
16998 var d = (this.doc.body || this.doc.documentElement);
17000 this.cleanUpPaste();
17001 this.el.dom.value = d.innerHTML;
17002 this.owner.fireEvent('push', this, v);
17008 deferFocus : function(){
17009 this.focus.defer(10, this);
17013 focus : function(){
17014 if(this.win && !this.sourceEditMode){
17021 assignDocWin: function()
17023 var iframe = this.iframe;
17026 this.doc = iframe.contentWindow.document;
17027 this.win = iframe.contentWindow;
17029 // if (!Roo.get(this.frameId)) {
17032 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17033 // this.win = Roo.get(this.frameId).dom.contentWindow;
17035 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17039 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17040 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17045 initEditor : function(){
17046 //console.log("INIT EDITOR");
17047 this.assignDocWin();
17051 this.doc.designMode="on";
17053 this.doc.write(this.getDocMarkup());
17056 var dbody = (this.doc.body || this.doc.documentElement);
17057 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17058 // this copies styles from the containing element into thsi one..
17059 // not sure why we need all of this..
17060 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17062 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17063 //ss['background-attachment'] = 'fixed'; // w3c
17064 dbody.bgProperties = 'fixed'; // ie
17065 //Roo.DomHelper.applyStyles(dbody, ss);
17066 Roo.EventManager.on(this.doc, {
17067 //'mousedown': this.onEditorEvent,
17068 'mouseup': this.onEditorEvent,
17069 'dblclick': this.onEditorEvent,
17070 'click': this.onEditorEvent,
17071 'keyup': this.onEditorEvent,
17076 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17078 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17079 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17081 this.initialized = true;
17083 this.owner.fireEvent('initialize', this);
17088 onDestroy : function(){
17094 //for (var i =0; i < this.toolbars.length;i++) {
17095 // // fixme - ask toolbars for heights?
17096 // this.toolbars[i].onDestroy();
17099 //this.wrap.dom.innerHTML = '';
17100 //this.wrap.remove();
17105 onFirstFocus : function(){
17107 this.assignDocWin();
17110 this.activated = true;
17113 if(Roo.isGecko){ // prevent silly gecko errors
17115 var s = this.win.getSelection();
17116 if(!s.focusNode || s.focusNode.nodeType != 3){
17117 var r = s.getRangeAt(0);
17118 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17123 this.execCmd('useCSS', true);
17124 this.execCmd('styleWithCSS', false);
17127 this.owner.fireEvent('activate', this);
17131 adjustFont: function(btn){
17132 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17133 //if(Roo.isSafari){ // safari
17136 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17137 if(Roo.isSafari){ // safari
17138 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17139 v = (v < 10) ? 10 : v;
17140 v = (v > 48) ? 48 : v;
17141 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17146 v = Math.max(1, v+adjust);
17148 this.execCmd('FontSize', v );
17151 onEditorEvent : function(e){
17152 this.owner.fireEvent('editorevent', this, e);
17153 // this.updateToolbar();
17154 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17157 insertTag : function(tg)
17159 // could be a bit smarter... -> wrap the current selected tRoo..
17160 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17162 range = this.createRange(this.getSelection());
17163 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17164 wrappingNode.appendChild(range.extractContents());
17165 range.insertNode(wrappingNode);
17172 this.execCmd("formatblock", tg);
17176 insertText : function(txt)
17180 var range = this.createRange();
17181 range.deleteContents();
17182 //alert(Sender.getAttribute('label'));
17184 range.insertNode(this.doc.createTextNode(txt));
17190 * Executes a Midas editor command on the editor document and performs necessary focus and
17191 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17192 * @param {String} cmd The Midas command
17193 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17195 relayCmd : function(cmd, value){
17197 this.execCmd(cmd, value);
17198 this.owner.fireEvent('editorevent', this);
17199 //this.updateToolbar();
17200 this.owner.deferFocus();
17204 * Executes a Midas editor command directly on the editor document.
17205 * For visual commands, you should use {@link #relayCmd} instead.
17206 * <b>This should only be called after the editor is initialized.</b>
17207 * @param {String} cmd The Midas command
17208 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17210 execCmd : function(cmd, value){
17211 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17218 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17220 * @param {String} text | dom node..
17222 insertAtCursor : function(text)
17227 if(!this.activated){
17233 var r = this.doc.selection.createRange();
17244 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17248 // from jquery ui (MIT licenced)
17250 var win = this.win;
17252 if (win.getSelection && win.getSelection().getRangeAt) {
17253 range = win.getSelection().getRangeAt(0);
17254 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17255 range.insertNode(node);
17256 } else if (win.document.selection && win.document.selection.createRange) {
17257 // no firefox support
17258 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17259 win.document.selection.createRange().pasteHTML(txt);
17261 // no firefox support
17262 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17263 this.execCmd('InsertHTML', txt);
17272 mozKeyPress : function(e){
17274 var c = e.getCharCode(), cmd;
17277 c = String.fromCharCode(c).toLowerCase();
17291 this.cleanUpPaste.defer(100, this);
17299 e.preventDefault();
17307 fixKeys : function(){ // load time branching for fastest keydown performance
17309 return function(e){
17310 var k = e.getKey(), r;
17313 r = this.doc.selection.createRange();
17316 r.pasteHTML('    ');
17323 r = this.doc.selection.createRange();
17325 var target = r.parentElement();
17326 if(!target || target.tagName.toLowerCase() != 'li'){
17328 r.pasteHTML('<br />');
17334 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17335 this.cleanUpPaste.defer(100, this);
17341 }else if(Roo.isOpera){
17342 return function(e){
17343 var k = e.getKey();
17347 this.execCmd('InsertHTML','    ');
17350 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17351 this.cleanUpPaste.defer(100, this);
17356 }else if(Roo.isSafari){
17357 return function(e){
17358 var k = e.getKey();
17362 this.execCmd('InsertText','\t');
17366 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17367 this.cleanUpPaste.defer(100, this);
17375 getAllAncestors: function()
17377 var p = this.getSelectedNode();
17380 a.push(p); // push blank onto stack..
17381 p = this.getParentElement();
17385 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17389 a.push(this.doc.body);
17393 lastSelNode : false,
17396 getSelection : function()
17398 this.assignDocWin();
17399 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17402 getSelectedNode: function()
17404 // this may only work on Gecko!!!
17406 // should we cache this!!!!
17411 var range = this.createRange(this.getSelection()).cloneRange();
17414 var parent = range.parentElement();
17416 var testRange = range.duplicate();
17417 testRange.moveToElementText(parent);
17418 if (testRange.inRange(range)) {
17421 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17424 parent = parent.parentElement;
17429 // is ancestor a text element.
17430 var ac = range.commonAncestorContainer;
17431 if (ac.nodeType == 3) {
17432 ac = ac.parentNode;
17435 var ar = ac.childNodes;
17438 var other_nodes = [];
17439 var has_other_nodes = false;
17440 for (var i=0;i<ar.length;i++) {
17441 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17444 // fullly contained node.
17446 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17451 // probably selected..
17452 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17453 other_nodes.push(ar[i]);
17457 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17462 has_other_nodes = true;
17464 if (!nodes.length && other_nodes.length) {
17465 nodes= other_nodes;
17467 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17473 createRange: function(sel)
17475 // this has strange effects when using with
17476 // top toolbar - not sure if it's a great idea.
17477 //this.editor.contentWindow.focus();
17478 if (typeof sel != "undefined") {
17480 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17482 return this.doc.createRange();
17485 return this.doc.createRange();
17488 getParentElement: function()
17491 this.assignDocWin();
17492 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17494 var range = this.createRange(sel);
17497 var p = range.commonAncestorContainer;
17498 while (p.nodeType == 3) { // text node
17509 * Range intersection.. the hard stuff...
17513 * [ -- selected range --- ]
17517 * if end is before start or hits it. fail.
17518 * if start is after end or hits it fail.
17520 * if either hits (but other is outside. - then it's not
17526 // @see http://www.thismuchiknow.co.uk/?p=64.
17527 rangeIntersectsNode : function(range, node)
17529 var nodeRange = node.ownerDocument.createRange();
17531 nodeRange.selectNode(node);
17533 nodeRange.selectNodeContents(node);
17536 var rangeStartRange = range.cloneRange();
17537 rangeStartRange.collapse(true);
17539 var rangeEndRange = range.cloneRange();
17540 rangeEndRange.collapse(false);
17542 var nodeStartRange = nodeRange.cloneRange();
17543 nodeStartRange.collapse(true);
17545 var nodeEndRange = nodeRange.cloneRange();
17546 nodeEndRange.collapse(false);
17548 return rangeStartRange.compareBoundaryPoints(
17549 Range.START_TO_START, nodeEndRange) == -1 &&
17550 rangeEndRange.compareBoundaryPoints(
17551 Range.START_TO_START, nodeStartRange) == 1;
17555 rangeCompareNode : function(range, node)
17557 var nodeRange = node.ownerDocument.createRange();
17559 nodeRange.selectNode(node);
17561 nodeRange.selectNodeContents(node);
17565 range.collapse(true);
17567 nodeRange.collapse(true);
17569 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17570 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17572 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17574 var nodeIsBefore = ss == 1;
17575 var nodeIsAfter = ee == -1;
17577 if (nodeIsBefore && nodeIsAfter)
17579 if (!nodeIsBefore && nodeIsAfter)
17580 return 1; //right trailed.
17582 if (nodeIsBefore && !nodeIsAfter)
17583 return 2; // left trailed.
17588 // private? - in a new class?
17589 cleanUpPaste : function()
17591 // cleans up the whole document..
17592 Roo.log('cleanuppaste');
17594 this.cleanUpChildren(this.doc.body);
17595 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17596 if (clean != this.doc.body.innerHTML) {
17597 this.doc.body.innerHTML = clean;
17602 cleanWordChars : function(input) {// change the chars to hex code
17603 var he = Roo.HtmlEditorCore;
17605 var output = input;
17606 Roo.each(he.swapCodes, function(sw) {
17607 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17609 output = output.replace(swapper, sw[1]);
17616 cleanUpChildren : function (n)
17618 if (!n.childNodes.length) {
17621 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17622 this.cleanUpChild(n.childNodes[i]);
17629 cleanUpChild : function (node)
17632 //console.log(node);
17633 if (node.nodeName == "#text") {
17634 // clean up silly Windows -- stuff?
17637 if (node.nodeName == "#comment") {
17638 node.parentNode.removeChild(node);
17639 // clean up silly Windows -- stuff?
17642 var lcname = node.tagName.toLowerCase();
17643 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17644 // whitelist of tags..
17646 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17648 node.parentNode.removeChild(node);
17653 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17655 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17656 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17658 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17659 // remove_keep_children = true;
17662 if (remove_keep_children) {
17663 this.cleanUpChildren(node);
17664 // inserts everything just before this node...
17665 while (node.childNodes.length) {
17666 var cn = node.childNodes[0];
17667 node.removeChild(cn);
17668 node.parentNode.insertBefore(cn, node);
17670 node.parentNode.removeChild(node);
17674 if (!node.attributes || !node.attributes.length) {
17675 this.cleanUpChildren(node);
17679 function cleanAttr(n,v)
17682 if (v.match(/^\./) || v.match(/^\//)) {
17685 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17688 if (v.match(/^#/)) {
17691 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17692 node.removeAttribute(n);
17696 var cwhite = this.cwhite;
17697 var cblack = this.cblack;
17699 function cleanStyle(n,v)
17701 if (v.match(/expression/)) { //XSS?? should we even bother..
17702 node.removeAttribute(n);
17706 var parts = v.split(/;/);
17709 Roo.each(parts, function(p) {
17710 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17714 var l = p.split(':').shift().replace(/\s+/g,'');
17715 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17717 if ( cwhite.length && cblack.indexOf(l) > -1) {
17718 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17719 //node.removeAttribute(n);
17723 // only allow 'c whitelisted system attributes'
17724 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17725 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17726 //node.removeAttribute(n);
17736 if (clean.length) {
17737 node.setAttribute(n, clean.join(';'));
17739 node.removeAttribute(n);
17745 for (var i = node.attributes.length-1; i > -1 ; i--) {
17746 var a = node.attributes[i];
17749 if (a.name.toLowerCase().substr(0,2)=='on') {
17750 node.removeAttribute(a.name);
17753 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17754 node.removeAttribute(a.name);
17757 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17758 cleanAttr(a.name,a.value); // fixme..
17761 if (a.name == 'style') {
17762 cleanStyle(a.name,a.value);
17765 /// clean up MS crap..
17766 // tecnically this should be a list of valid class'es..
17769 if (a.name == 'class') {
17770 if (a.value.match(/^Mso/)) {
17771 node.className = '';
17774 if (a.value.match(/body/)) {
17775 node.className = '';
17786 this.cleanUpChildren(node);
17791 * Clean up MS wordisms...
17793 cleanWord : function(node)
17796 var cleanWordChildren = function()
17798 if (!node.childNodes.length) {
17801 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17802 _t.cleanWord(node.childNodes[i]);
17808 this.cleanWord(this.doc.body);
17811 if (node.nodeName == "#text") {
17812 // clean up silly Windows -- stuff?
17815 if (node.nodeName == "#comment") {
17816 node.parentNode.removeChild(node);
17817 // clean up silly Windows -- stuff?
17821 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17822 node.parentNode.removeChild(node);
17826 // remove - but keep children..
17827 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17828 while (node.childNodes.length) {
17829 var cn = node.childNodes[0];
17830 node.removeChild(cn);
17831 node.parentNode.insertBefore(cn, node);
17833 node.parentNode.removeChild(node);
17834 cleanWordChildren();
17838 if (node.className.length) {
17840 var cn = node.className.split(/\W+/);
17842 Roo.each(cn, function(cls) {
17843 if (cls.match(/Mso[a-zA-Z]+/)) {
17848 node.className = cna.length ? cna.join(' ') : '';
17850 node.removeAttribute("class");
17854 if (node.hasAttribute("lang")) {
17855 node.removeAttribute("lang");
17858 if (node.hasAttribute("style")) {
17860 var styles = node.getAttribute("style").split(";");
17862 Roo.each(styles, function(s) {
17863 if (!s.match(/:/)) {
17866 var kv = s.split(":");
17867 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17870 // what ever is left... we allow.
17873 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17874 if (!nstyle.length) {
17875 node.removeAttribute('style');
17879 cleanWordChildren();
17883 domToHTML : function(currentElement, depth, nopadtext) {
17885 depth = depth || 0;
17886 nopadtext = nopadtext || false;
17888 if (!currentElement) {
17889 return this.domToHTML(this.doc.body);
17892 //Roo.log(currentElement);
17894 var allText = false;
17895 var nodeName = currentElement.nodeName;
17896 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17898 if (nodeName == '#text') {
17900 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
17905 if (nodeName != 'BODY') {
17908 // Prints the node tagName, such as <A>, <IMG>, etc
17911 for(i = 0; i < currentElement.attributes.length;i++) {
17913 var aname = currentElement.attributes.item(i).name;
17914 if (!currentElement.attributes.item(i).value.length) {
17917 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17920 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17929 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17932 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17937 // Traverse the tree
17939 var currentElementChild = currentElement.childNodes.item(i);
17940 var allText = true;
17941 var innerHTML = '';
17943 while (currentElementChild) {
17944 // Formatting code (indent the tree so it looks nice on the screen)
17945 var nopad = nopadtext;
17946 if (lastnode == 'SPAN') {
17950 if (currentElementChild.nodeName == '#text') {
17951 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17952 toadd = nopadtext ? toadd : toadd.trim();
17953 if (!nopad && toadd.length > 80) {
17954 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17956 innerHTML += toadd;
17959 currentElementChild = currentElement.childNodes.item(i);
17965 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17967 // Recursively traverse the tree structure of the child node
17968 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17969 lastnode = currentElementChild.nodeName;
17971 currentElementChild=currentElement.childNodes.item(i);
17977 // The remaining code is mostly for formatting the tree
17978 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17983 ret+= "</"+tagName+">";
17989 applyBlacklists : function()
17991 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17992 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17996 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17997 if (b.indexOf(tag) > -1) {
18000 this.white.push(tag);
18004 Roo.each(w, function(tag) {
18005 if (b.indexOf(tag) > -1) {
18008 if (this.white.indexOf(tag) > -1) {
18011 this.white.push(tag);
18016 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18017 if (w.indexOf(tag) > -1) {
18020 this.black.push(tag);
18024 Roo.each(b, function(tag) {
18025 if (w.indexOf(tag) > -1) {
18028 if (this.black.indexOf(tag) > -1) {
18031 this.black.push(tag);
18036 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18037 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18041 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18042 if (b.indexOf(tag) > -1) {
18045 this.cwhite.push(tag);
18049 Roo.each(w, function(tag) {
18050 if (b.indexOf(tag) > -1) {
18053 if (this.cwhite.indexOf(tag) > -1) {
18056 this.cwhite.push(tag);
18061 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18062 if (w.indexOf(tag) > -1) {
18065 this.cblack.push(tag);
18069 Roo.each(b, function(tag) {
18070 if (w.indexOf(tag) > -1) {
18073 if (this.cblack.indexOf(tag) > -1) {
18076 this.cblack.push(tag);
18081 setStylesheets : function(stylesheets)
18083 if(typeof(stylesheets) == 'string'){
18084 Roo.get(this.iframe.contentDocument.head).createChild({
18086 rel : 'stylesheet',
18095 Roo.each(stylesheets, function(s) {
18100 Roo.get(_this.iframe.contentDocument.head).createChild({
18102 rel : 'stylesheet',
18111 removeStylesheets : function()
18115 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18120 // hide stuff that is not compatible
18134 * @event specialkey
18138 * @cfg {String} fieldClass @hide
18141 * @cfg {String} focusClass @hide
18144 * @cfg {String} autoCreate @hide
18147 * @cfg {String} inputType @hide
18150 * @cfg {String} invalidClass @hide
18153 * @cfg {String} invalidText @hide
18156 * @cfg {String} msgFx @hide
18159 * @cfg {String} validateOnBlur @hide
18163 Roo.HtmlEditorCore.white = [
18164 'area', 'br', 'img', 'input', 'hr', 'wbr',
18166 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18167 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18168 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18169 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18170 'table', 'ul', 'xmp',
18172 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18175 'dir', 'menu', 'ol', 'ul', 'dl',
18181 Roo.HtmlEditorCore.black = [
18182 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18184 'base', 'basefont', 'bgsound', 'blink', 'body',
18185 'frame', 'frameset', 'head', 'html', 'ilayer',
18186 'iframe', 'layer', 'link', 'meta', 'object',
18187 'script', 'style' ,'title', 'xml' // clean later..
18189 Roo.HtmlEditorCore.clean = [
18190 'script', 'style', 'title', 'xml'
18192 Roo.HtmlEditorCore.remove = [
18197 Roo.HtmlEditorCore.ablack = [
18201 Roo.HtmlEditorCore.aclean = [
18202 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18206 Roo.HtmlEditorCore.pwhite= [
18207 'http', 'https', 'mailto'
18210 // white listed style attributes.
18211 Roo.HtmlEditorCore.cwhite= [
18212 // 'text-align', /// default is to allow most things..
18218 // black listed style attributes.
18219 Roo.HtmlEditorCore.cblack= [
18220 // 'font-size' -- this can be set by the project
18224 Roo.HtmlEditorCore.swapCodes =[
18243 * @class Roo.bootstrap.HtmlEditor
18244 * @extends Roo.bootstrap.TextArea
18245 * Bootstrap HtmlEditor class
18248 * Create a new HtmlEditor
18249 * @param {Object} config The config object
18252 Roo.bootstrap.HtmlEditor = function(config){
18253 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18254 if (!this.toolbars) {
18255 this.toolbars = [];
18257 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18260 * @event initialize
18261 * Fires when the editor is fully initialized (including the iframe)
18262 * @param {HtmlEditor} this
18267 * Fires when the editor is first receives the focus. Any insertion must wait
18268 * until after this event.
18269 * @param {HtmlEditor} this
18273 * @event beforesync
18274 * Fires before the textarea is updated with content from the editor iframe. Return false
18275 * to cancel the sync.
18276 * @param {HtmlEditor} this
18277 * @param {String} html
18281 * @event beforepush
18282 * Fires before the iframe editor is updated with content from the textarea. Return false
18283 * to cancel the push.
18284 * @param {HtmlEditor} this
18285 * @param {String} html
18290 * Fires when the textarea is updated with content from the editor iframe.
18291 * @param {HtmlEditor} this
18292 * @param {String} html
18297 * Fires when the iframe editor is updated with content from the textarea.
18298 * @param {HtmlEditor} this
18299 * @param {String} html
18303 * @event editmodechange
18304 * Fires when the editor switches edit modes
18305 * @param {HtmlEditor} this
18306 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18308 editmodechange: true,
18310 * @event editorevent
18311 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18312 * @param {HtmlEditor} this
18316 * @event firstfocus
18317 * Fires when on first focus - needed by toolbars..
18318 * @param {HtmlEditor} this
18323 * Auto save the htmlEditor value as a file into Events
18324 * @param {HtmlEditor} this
18328 * @event savedpreview
18329 * preview the saved version of htmlEditor
18330 * @param {HtmlEditor} this
18337 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18341 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18346 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18351 * @cfg {Number} height (in pixels)
18355 * @cfg {Number} width (in pixels)
18360 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18363 stylesheets: false,
18368 // private properties
18369 validationEvent : false,
18371 initialized : false,
18374 onFocus : Roo.emptyFn,
18376 hideMode:'offsets',
18379 tbContainer : false,
18381 toolbarContainer :function() {
18382 return this.wrap.select('.x-html-editor-tb',true).first();
18386 * Protected method that will not generally be called directly. It
18387 * is called when the editor creates its toolbar. Override this method if you need to
18388 * add custom toolbar buttons.
18389 * @param {HtmlEditor} editor
18391 createToolbar : function(){
18393 Roo.log("create toolbars");
18395 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18396 this.toolbars[0].render(this.toolbarContainer());
18400 // if (!editor.toolbars || !editor.toolbars.length) {
18401 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18404 // for (var i =0 ; i < editor.toolbars.length;i++) {
18405 // editor.toolbars[i] = Roo.factory(
18406 // typeof(editor.toolbars[i]) == 'string' ?
18407 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18408 // Roo.bootstrap.HtmlEditor);
18409 // editor.toolbars[i].init(editor);
18415 onRender : function(ct, position)
18417 // Roo.log("Call onRender: " + this.xtype);
18419 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18421 this.wrap = this.inputEl().wrap({
18422 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18425 this.editorcore.onRender(ct, position);
18427 if (this.resizable) {
18428 this.resizeEl = new Roo.Resizable(this.wrap, {
18432 minHeight : this.height,
18433 height: this.height,
18434 handles : this.resizable,
18437 resize : function(r, w, h) {
18438 _t.onResize(w,h); // -something
18444 this.createToolbar(this);
18447 if(!this.width && this.resizable){
18448 this.setSize(this.wrap.getSize());
18450 if (this.resizeEl) {
18451 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18452 // should trigger onReize..
18458 onResize : function(w, h)
18460 Roo.log('resize: ' +w + ',' + h );
18461 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18465 if(this.inputEl() ){
18466 if(typeof w == 'number'){
18467 var aw = w - this.wrap.getFrameWidth('lr');
18468 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18471 if(typeof h == 'number'){
18472 var tbh = -11; // fixme it needs to tool bar size!
18473 for (var i =0; i < this.toolbars.length;i++) {
18474 // fixme - ask toolbars for heights?
18475 tbh += this.toolbars[i].el.getHeight();
18476 //if (this.toolbars[i].footer) {
18477 // tbh += this.toolbars[i].footer.el.getHeight();
18485 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18486 ah -= 5; // knock a few pixes off for look..
18487 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18491 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18492 this.editorcore.onResize(ew,eh);
18497 * Toggles the editor between standard and source edit mode.
18498 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18500 toggleSourceEdit : function(sourceEditMode)
18502 this.editorcore.toggleSourceEdit(sourceEditMode);
18504 if(this.editorcore.sourceEditMode){
18505 Roo.log('editor - showing textarea');
18508 // Roo.log(this.syncValue());
18510 this.inputEl().removeClass(['hide', 'x-hidden']);
18511 this.inputEl().dom.removeAttribute('tabIndex');
18512 this.inputEl().focus();
18514 Roo.log('editor - hiding textarea');
18516 // Roo.log(this.pushValue());
18519 this.inputEl().addClass(['hide', 'x-hidden']);
18520 this.inputEl().dom.setAttribute('tabIndex', -1);
18521 //this.deferFocus();
18524 if(this.resizable){
18525 this.setSize(this.wrap.getSize());
18528 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18531 // private (for BoxComponent)
18532 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18534 // private (for BoxComponent)
18535 getResizeEl : function(){
18539 // private (for BoxComponent)
18540 getPositionEl : function(){
18545 initEvents : function(){
18546 this.originalValue = this.getValue();
18550 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18553 // markInvalid : Roo.emptyFn,
18555 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18558 // clearInvalid : Roo.emptyFn,
18560 setValue : function(v){
18561 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18562 this.editorcore.pushValue();
18567 deferFocus : function(){
18568 this.focus.defer(10, this);
18572 focus : function(){
18573 this.editorcore.focus();
18579 onDestroy : function(){
18585 for (var i =0; i < this.toolbars.length;i++) {
18586 // fixme - ask toolbars for heights?
18587 this.toolbars[i].onDestroy();
18590 this.wrap.dom.innerHTML = '';
18591 this.wrap.remove();
18596 onFirstFocus : function(){
18597 //Roo.log("onFirstFocus");
18598 this.editorcore.onFirstFocus();
18599 for (var i =0; i < this.toolbars.length;i++) {
18600 this.toolbars[i].onFirstFocus();
18606 syncValue : function()
18608 this.editorcore.syncValue();
18611 pushValue : function()
18613 this.editorcore.pushValue();
18617 // hide stuff that is not compatible
18631 * @event specialkey
18635 * @cfg {String} fieldClass @hide
18638 * @cfg {String} focusClass @hide
18641 * @cfg {String} autoCreate @hide
18644 * @cfg {String} inputType @hide
18647 * @cfg {String} invalidClass @hide
18650 * @cfg {String} invalidText @hide
18653 * @cfg {String} msgFx @hide
18656 * @cfg {String} validateOnBlur @hide
18665 Roo.namespace('Roo.bootstrap.htmleditor');
18667 * @class Roo.bootstrap.HtmlEditorToolbar1
18672 new Roo.bootstrap.HtmlEditor({
18675 new Roo.bootstrap.HtmlEditorToolbar1({
18676 disable : { fonts: 1 , format: 1, ..., ... , ...],
18682 * @cfg {Object} disable List of elements to disable..
18683 * @cfg {Array} btns List of additional buttons.
18687 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18690 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18693 Roo.apply(this, config);
18695 // default disabled, based on 'good practice'..
18696 this.disable = this.disable || {};
18697 Roo.applyIf(this.disable, {
18700 specialElements : true
18702 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18704 this.editor = config.editor;
18705 this.editorcore = config.editor.editorcore;
18707 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18709 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18710 // dont call parent... till later.
18712 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18717 editorcore : false,
18722 "h1","h2","h3","h4","h5","h6",
18724 "abbr", "acronym", "address", "cite", "samp", "var",
18728 onRender : function(ct, position)
18730 // Roo.log("Call onRender: " + this.xtype);
18732 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18734 this.el.dom.style.marginBottom = '0';
18736 var editorcore = this.editorcore;
18737 var editor= this.editor;
18740 var btn = function(id,cmd , toggle, handler){
18742 var event = toggle ? 'toggle' : 'click';
18747 xns: Roo.bootstrap,
18750 enableToggle:toggle !== false,
18752 pressed : toggle ? false : null,
18755 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18756 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18765 xns: Roo.bootstrap,
18766 glyphicon : 'font',
18770 xns: Roo.bootstrap,
18774 Roo.each(this.formats, function(f) {
18775 style.menu.items.push({
18777 xns: Roo.bootstrap,
18778 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18783 editorcore.insertTag(this.tagname);
18790 children.push(style);
18793 btn('bold',false,true);
18794 btn('italic',false,true);
18795 btn('align-left', 'justifyleft',true);
18796 btn('align-center', 'justifycenter',true);
18797 btn('align-right' , 'justifyright',true);
18798 btn('link', false, false, function(btn) {
18799 //Roo.log("create link?");
18800 var url = prompt(this.createLinkText, this.defaultLinkValue);
18801 if(url && url != 'http:/'+'/'){
18802 this.editorcore.relayCmd('createlink', url);
18805 btn('list','insertunorderedlist',true);
18806 btn('pencil', false,true, function(btn){
18809 this.toggleSourceEdit(btn.pressed);
18815 xns: Roo.bootstrap,
18820 xns: Roo.bootstrap,
18825 cog.menu.items.push({
18827 xns: Roo.bootstrap,
18828 html : Clean styles,
18833 editorcore.insertTag(this.tagname);
18842 this.xtype = 'NavSimplebar';
18844 for(var i=0;i< children.length;i++) {
18846 this.buttons.add(this.addxtypeChild(children[i]));
18850 editor.on('editorevent', this.updateToolbar, this);
18852 onBtnClick : function(id)
18854 this.editorcore.relayCmd(id);
18855 this.editorcore.focus();
18859 * Protected method that will not generally be called directly. It triggers
18860 * a toolbar update by reading the markup state of the current selection in the editor.
18862 updateToolbar: function(){
18864 if(!this.editorcore.activated){
18865 this.editor.onFirstFocus(); // is this neeed?
18869 var btns = this.buttons;
18870 var doc = this.editorcore.doc;
18871 btns.get('bold').setActive(doc.queryCommandState('bold'));
18872 btns.get('italic').setActive(doc.queryCommandState('italic'));
18873 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18875 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18876 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18877 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18879 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18880 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18883 var ans = this.editorcore.getAllAncestors();
18884 if (this.formatCombo) {
18887 var store = this.formatCombo.store;
18888 this.formatCombo.setValue("");
18889 for (var i =0; i < ans.length;i++) {
18890 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18892 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18900 // hides menus... - so this cant be on a menu...
18901 Roo.bootstrap.MenuMgr.hideAll();
18903 Roo.bootstrap.MenuMgr.hideAll();
18904 //this.editorsyncValue();
18906 onFirstFocus: function() {
18907 this.buttons.each(function(item){
18911 toggleSourceEdit : function(sourceEditMode){
18914 if(sourceEditMode){
18915 Roo.log("disabling buttons");
18916 this.buttons.each( function(item){
18917 if(item.cmd != 'pencil'){
18923 Roo.log("enabling buttons");
18924 if(this.editorcore.initialized){
18925 this.buttons.each( function(item){
18931 Roo.log("calling toggole on editor");
18932 // tell the editor that it's been pressed..
18933 this.editor.toggleSourceEdit(sourceEditMode);
18943 * @class Roo.bootstrap.Table.AbstractSelectionModel
18944 * @extends Roo.util.Observable
18945 * Abstract base class for grid SelectionModels. It provides the interface that should be
18946 * implemented by descendant classes. This class should not be directly instantiated.
18949 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18950 this.locked = false;
18951 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18955 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18956 /** @ignore Called by the grid automatically. Do not call directly. */
18957 init : function(grid){
18963 * Locks the selections.
18966 this.locked = true;
18970 * Unlocks the selections.
18972 unlock : function(){
18973 this.locked = false;
18977 * Returns true if the selections are locked.
18978 * @return {Boolean}
18980 isLocked : function(){
18981 return this.locked;
18985 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18986 * @class Roo.bootstrap.Table.RowSelectionModel
18987 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18988 * It supports multiple selections and keyboard selection/navigation.
18990 * @param {Object} config
18993 Roo.bootstrap.Table.RowSelectionModel = function(config){
18994 Roo.apply(this, config);
18995 this.selections = new Roo.util.MixedCollection(false, function(o){
19000 this.lastActive = false;
19004 * @event selectionchange
19005 * Fires when the selection changes
19006 * @param {SelectionModel} this
19008 "selectionchange" : true,
19010 * @event afterselectionchange
19011 * Fires after the selection changes (eg. by key press or clicking)
19012 * @param {SelectionModel} this
19014 "afterselectionchange" : true,
19016 * @event beforerowselect
19017 * Fires when a row is selected being selected, return false to cancel.
19018 * @param {SelectionModel} this
19019 * @param {Number} rowIndex The selected index
19020 * @param {Boolean} keepExisting False if other selections will be cleared
19022 "beforerowselect" : true,
19025 * Fires when a row is selected.
19026 * @param {SelectionModel} this
19027 * @param {Number} rowIndex The selected index
19028 * @param {Roo.data.Record} r The record
19030 "rowselect" : true,
19032 * @event rowdeselect
19033 * Fires when a row is deselected.
19034 * @param {SelectionModel} this
19035 * @param {Number} rowIndex The selected index
19037 "rowdeselect" : true
19039 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19040 this.locked = false;
19043 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19045 * @cfg {Boolean} singleSelect
19046 * True to allow selection of only one row at a time (defaults to false)
19048 singleSelect : false,
19051 initEvents : function(){
19053 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19054 this.grid.on("mousedown", this.handleMouseDown, this);
19055 }else{ // allow click to work like normal
19056 this.grid.on("rowclick", this.handleDragableRowClick, this);
19059 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19060 "up" : function(e){
19062 this.selectPrevious(e.shiftKey);
19063 }else if(this.last !== false && this.lastActive !== false){
19064 var last = this.last;
19065 this.selectRange(this.last, this.lastActive-1);
19066 this.grid.getView().focusRow(this.lastActive);
19067 if(last !== false){
19071 this.selectFirstRow();
19073 this.fireEvent("afterselectionchange", this);
19075 "down" : function(e){
19077 this.selectNext(e.shiftKey);
19078 }else if(this.last !== false && this.lastActive !== false){
19079 var last = this.last;
19080 this.selectRange(this.last, this.lastActive+1);
19081 this.grid.getView().focusRow(this.lastActive);
19082 if(last !== false){
19086 this.selectFirstRow();
19088 this.fireEvent("afterselectionchange", this);
19093 var view = this.grid.view;
19094 view.on("refresh", this.onRefresh, this);
19095 view.on("rowupdated", this.onRowUpdated, this);
19096 view.on("rowremoved", this.onRemove, this);
19100 onRefresh : function(){
19101 var ds = this.grid.dataSource, i, v = this.grid.view;
19102 var s = this.selections;
19103 s.each(function(r){
19104 if((i = ds.indexOfId(r.id)) != -1){
19113 onRemove : function(v, index, r){
19114 this.selections.remove(r);
19118 onRowUpdated : function(v, index, r){
19119 if(this.isSelected(r)){
19120 v.onRowSelect(index);
19126 * @param {Array} records The records to select
19127 * @param {Boolean} keepExisting (optional) True to keep existing selections
19129 selectRecords : function(records, keepExisting){
19131 this.clearSelections();
19133 var ds = this.grid.dataSource;
19134 for(var i = 0, len = records.length; i < len; i++){
19135 this.selectRow(ds.indexOf(records[i]), true);
19140 * Gets the number of selected rows.
19143 getCount : function(){
19144 return this.selections.length;
19148 * Selects the first row in the grid.
19150 selectFirstRow : function(){
19155 * Select the last row.
19156 * @param {Boolean} keepExisting (optional) True to keep existing selections
19158 selectLastRow : function(keepExisting){
19159 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19163 * Selects the row immediately following the last selected row.
19164 * @param {Boolean} keepExisting (optional) True to keep existing selections
19166 selectNext : function(keepExisting){
19167 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19168 this.selectRow(this.last+1, keepExisting);
19169 this.grid.getView().focusRow(this.last);
19174 * Selects the row that precedes the last selected row.
19175 * @param {Boolean} keepExisting (optional) True to keep existing selections
19177 selectPrevious : function(keepExisting){
19179 this.selectRow(this.last-1, keepExisting);
19180 this.grid.getView().focusRow(this.last);
19185 * Returns the selected records
19186 * @return {Array} Array of selected records
19188 getSelections : function(){
19189 return [].concat(this.selections.items);
19193 * Returns the first selected record.
19196 getSelected : function(){
19197 return this.selections.itemAt(0);
19202 * Clears all selections.
19204 clearSelections : function(fast){
19205 if(this.locked) return;
19207 var ds = this.grid.dataSource;
19208 var s = this.selections;
19209 s.each(function(r){
19210 this.deselectRow(ds.indexOfId(r.id));
19214 this.selections.clear();
19221 * Selects all rows.
19223 selectAll : function(){
19224 if(this.locked) return;
19225 this.selections.clear();
19226 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19227 this.selectRow(i, true);
19232 * Returns True if there is a selection.
19233 * @return {Boolean}
19235 hasSelection : function(){
19236 return this.selections.length > 0;
19240 * Returns True if the specified row is selected.
19241 * @param {Number/Record} record The record or index of the record to check
19242 * @return {Boolean}
19244 isSelected : function(index){
19245 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19246 return (r && this.selections.key(r.id) ? true : false);
19250 * Returns True if the specified record id is selected.
19251 * @param {String} id The id of record to check
19252 * @return {Boolean}
19254 isIdSelected : function(id){
19255 return (this.selections.key(id) ? true : false);
19259 handleMouseDown : function(e, t){
19260 var view = this.grid.getView(), rowIndex;
19261 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19264 if(e.shiftKey && this.last !== false){
19265 var last = this.last;
19266 this.selectRange(last, rowIndex, e.ctrlKey);
19267 this.last = last; // reset the last
19268 view.focusRow(rowIndex);
19270 var isSelected = this.isSelected(rowIndex);
19271 if(e.button !== 0 && isSelected){
19272 view.focusRow(rowIndex);
19273 }else if(e.ctrlKey && isSelected){
19274 this.deselectRow(rowIndex);
19275 }else if(!isSelected){
19276 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19277 view.focusRow(rowIndex);
19280 this.fireEvent("afterselectionchange", this);
19283 handleDragableRowClick : function(grid, rowIndex, e)
19285 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19286 this.selectRow(rowIndex, false);
19287 grid.view.focusRow(rowIndex);
19288 this.fireEvent("afterselectionchange", this);
19293 * Selects multiple rows.
19294 * @param {Array} rows Array of the indexes of the row to select
19295 * @param {Boolean} keepExisting (optional) True to keep existing selections
19297 selectRows : function(rows, keepExisting){
19299 this.clearSelections();
19301 for(var i = 0, len = rows.length; i < len; i++){
19302 this.selectRow(rows[i], true);
19307 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19308 * @param {Number} startRow The index of the first row in the range
19309 * @param {Number} endRow The index of the last row in the range
19310 * @param {Boolean} keepExisting (optional) True to retain existing selections
19312 selectRange : function(startRow, endRow, keepExisting){
19313 if(this.locked) return;
19315 this.clearSelections();
19317 if(startRow <= endRow){
19318 for(var i = startRow; i <= endRow; i++){
19319 this.selectRow(i, true);
19322 for(var i = startRow; i >= endRow; i--){
19323 this.selectRow(i, true);
19329 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19330 * @param {Number} startRow The index of the first row in the range
19331 * @param {Number} endRow The index of the last row in the range
19333 deselectRange : function(startRow, endRow, preventViewNotify){
19334 if(this.locked) return;
19335 for(var i = startRow; i <= endRow; i++){
19336 this.deselectRow(i, preventViewNotify);
19342 * @param {Number} row The index of the row to select
19343 * @param {Boolean} keepExisting (optional) True to keep existing selections
19345 selectRow : function(index, keepExisting, preventViewNotify){
19346 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19347 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19348 if(!keepExisting || this.singleSelect){
19349 this.clearSelections();
19351 var r = this.grid.dataSource.getAt(index);
19352 this.selections.add(r);
19353 this.last = this.lastActive = index;
19354 if(!preventViewNotify){
19355 this.grid.getView().onRowSelect(index);
19357 this.fireEvent("rowselect", this, index, r);
19358 this.fireEvent("selectionchange", this);
19364 * @param {Number} row The index of the row to deselect
19366 deselectRow : function(index, preventViewNotify){
19367 if(this.locked) return;
19368 if(this.last == index){
19371 if(this.lastActive == index){
19372 this.lastActive = false;
19374 var r = this.grid.dataSource.getAt(index);
19375 this.selections.remove(r);
19376 if(!preventViewNotify){
19377 this.grid.getView().onRowDeselect(index);
19379 this.fireEvent("rowdeselect", this, index);
19380 this.fireEvent("selectionchange", this);
19384 restoreLast : function(){
19386 this.last = this._last;
19391 acceptsNav : function(row, col, cm){
19392 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19396 onEditorKey : function(field, e){
19397 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19402 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19404 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19406 }else if(k == e.ENTER && !e.ctrlKey){
19410 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19412 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19414 }else if(k == e.ESC){
19418 g.startEditing(newCell[0], newCell[1]);
19423 * Ext JS Library 1.1.1
19424 * Copyright(c) 2006-2007, Ext JS, LLC.
19426 * Originally Released Under LGPL - original licence link has changed is not relivant.
19429 * <script type="text/javascript">
19433 * @class Roo.bootstrap.PagingToolbar
19435 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19437 * Create a new PagingToolbar
19438 * @param {Object} config The config object
19440 Roo.bootstrap.PagingToolbar = function(config)
19442 // old args format still supported... - xtype is prefered..
19443 // created from xtype...
19444 var ds = config.dataSource;
19445 this.toolbarItems = [];
19446 if (config.items) {
19447 this.toolbarItems = config.items;
19448 // config.items = [];
19451 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19458 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19462 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19464 * @cfg {Roo.data.Store} dataSource
19465 * The underlying data store providing the paged data
19468 * @cfg {String/HTMLElement/Element} container
19469 * container The id or element that will contain the toolbar
19472 * @cfg {Boolean} displayInfo
19473 * True to display the displayMsg (defaults to false)
19476 * @cfg {Number} pageSize
19477 * The number of records to display per page (defaults to 20)
19481 * @cfg {String} displayMsg
19482 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19484 displayMsg : 'Displaying {0} - {1} of {2}',
19486 * @cfg {String} emptyMsg
19487 * The message to display when no records are found (defaults to "No data to display")
19489 emptyMsg : 'No data to display',
19491 * Customizable piece of the default paging text (defaults to "Page")
19494 beforePageText : "Page",
19496 * Customizable piece of the default paging text (defaults to "of %0")
19499 afterPageText : "of {0}",
19501 * Customizable piece of the default paging text (defaults to "First Page")
19504 firstText : "First Page",
19506 * Customizable piece of the default paging text (defaults to "Previous Page")
19509 prevText : "Previous Page",
19511 * Customizable piece of the default paging text (defaults to "Next Page")
19514 nextText : "Next Page",
19516 * Customizable piece of the default paging text (defaults to "Last Page")
19519 lastText : "Last Page",
19521 * Customizable piece of the default paging text (defaults to "Refresh")
19524 refreshText : "Refresh",
19528 onRender : function(ct, position)
19530 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19531 this.navgroup.parentId = this.id;
19532 this.navgroup.onRender(this.el, null);
19533 // add the buttons to the navgroup
19535 if(this.displayInfo){
19536 Roo.log(this.el.select('ul.navbar-nav',true).first());
19537 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19538 this.displayEl = this.el.select('.x-paging-info', true).first();
19539 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19540 // this.displayEl = navel.el.select('span',true).first();
19546 Roo.each(_this.buttons, function(e){
19547 Roo.factory(e).onRender(_this.el, null);
19551 Roo.each(_this.toolbarItems, function(e) {
19552 _this.navgroup.addItem(e);
19555 this.first = this.navgroup.addItem({
19556 tooltip: this.firstText,
19558 icon : 'fa fa-backward',
19560 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19563 this.prev = this.navgroup.addItem({
19564 tooltip: this.prevText,
19566 icon : 'fa fa-step-backward',
19568 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19570 //this.addSeparator();
19573 var field = this.navgroup.addItem( {
19575 cls : 'x-paging-position',
19577 html : this.beforePageText +
19578 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19579 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19582 this.field = field.el.select('input', true).first();
19583 this.field.on("keydown", this.onPagingKeydown, this);
19584 this.field.on("focus", function(){this.dom.select();});
19587 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19588 //this.field.setHeight(18);
19589 //this.addSeparator();
19590 this.next = this.navgroup.addItem({
19591 tooltip: this.nextText,
19593 html : ' <i class="fa fa-step-forward">',
19595 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19597 this.last = this.navgroup.addItem({
19598 tooltip: this.lastText,
19599 icon : 'fa fa-forward',
19602 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19604 //this.addSeparator();
19605 this.loading = this.navgroup.addItem({
19606 tooltip: this.refreshText,
19607 icon: 'fa fa-refresh',
19609 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19615 updateInfo : function(){
19616 if(this.displayEl){
19617 var count = this.ds.getCount();
19618 var msg = count == 0 ?
19622 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19624 this.displayEl.update(msg);
19629 onLoad : function(ds, r, o){
19630 this.cursor = o.params ? o.params.start : 0;
19631 var d = this.getPageData(),
19635 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19636 this.field.dom.value = ap;
19637 this.first.setDisabled(ap == 1);
19638 this.prev.setDisabled(ap == 1);
19639 this.next.setDisabled(ap == ps);
19640 this.last.setDisabled(ap == ps);
19641 this.loading.enable();
19646 getPageData : function(){
19647 var total = this.ds.getTotalCount();
19650 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19651 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19656 onLoadError : function(){
19657 this.loading.enable();
19661 onPagingKeydown : function(e){
19662 var k = e.getKey();
19663 var d = this.getPageData();
19665 var v = this.field.dom.value, pageNum;
19666 if(!v || isNaN(pageNum = parseInt(v, 10))){
19667 this.field.dom.value = d.activePage;
19670 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19671 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19674 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))
19676 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19677 this.field.dom.value = pageNum;
19678 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19681 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19683 var v = this.field.dom.value, pageNum;
19684 var increment = (e.shiftKey) ? 10 : 1;
19685 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19687 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19688 this.field.dom.value = d.activePage;
19691 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19693 this.field.dom.value = parseInt(v, 10) + increment;
19694 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19695 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19702 beforeLoad : function(){
19704 this.loading.disable();
19709 onClick : function(which){
19716 ds.load({params:{start: 0, limit: this.pageSize}});
19719 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19722 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19725 var total = ds.getTotalCount();
19726 var extra = total % this.pageSize;
19727 var lastStart = extra ? (total - extra) : total-this.pageSize;
19728 ds.load({params:{start: lastStart, limit: this.pageSize}});
19731 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19737 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19738 * @param {Roo.data.Store} store The data store to unbind
19740 unbind : function(ds){
19741 ds.un("beforeload", this.beforeLoad, this);
19742 ds.un("load", this.onLoad, this);
19743 ds.un("loadexception", this.onLoadError, this);
19744 ds.un("remove", this.updateInfo, this);
19745 ds.un("add", this.updateInfo, this);
19746 this.ds = undefined;
19750 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19751 * @param {Roo.data.Store} store The data store to bind
19753 bind : function(ds){
19754 ds.on("beforeload", this.beforeLoad, this);
19755 ds.on("load", this.onLoad, this);
19756 ds.on("loadexception", this.onLoadError, this);
19757 ds.on("remove", this.updateInfo, this);
19758 ds.on("add", this.updateInfo, this);
19769 * @class Roo.bootstrap.MessageBar
19770 * @extends Roo.bootstrap.Component
19771 * Bootstrap MessageBar class
19772 * @cfg {String} html contents of the MessageBar
19773 * @cfg {String} weight (info | success | warning | danger) default info
19774 * @cfg {String} beforeClass insert the bar before the given class
19775 * @cfg {Boolean} closable (true | false) default false
19776 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19779 * Create a new Element
19780 * @param {Object} config The config object
19783 Roo.bootstrap.MessageBar = function(config){
19784 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19787 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19793 beforeClass: 'bootstrap-sticky-wrap',
19795 getAutoCreate : function(){
19799 cls: 'alert alert-dismissable alert-' + this.weight,
19804 html: this.html || ''
19810 cfg.cls += ' alert-messages-fixed';
19824 onRender : function(ct, position)
19826 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19829 var cfg = Roo.apply({}, this.getAutoCreate());
19833 cfg.cls += ' ' + this.cls;
19836 cfg.style = this.style;
19838 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19840 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19843 this.el.select('>button.close').on('click', this.hide, this);
19849 if (!this.rendered) {
19855 this.fireEvent('show', this);
19861 if (!this.rendered) {
19867 this.fireEvent('hide', this);
19870 update : function()
19872 // var e = this.el.dom.firstChild;
19874 // if(this.closable){
19875 // e = e.nextSibling;
19878 // e.data = this.html || '';
19880 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19896 * @class Roo.bootstrap.Graph
19897 * @extends Roo.bootstrap.Component
19898 * Bootstrap Graph class
19902 @cfg {String} graphtype bar | vbar | pie
19903 @cfg {number} g_x coodinator | centre x (pie)
19904 @cfg {number} g_y coodinator | centre y (pie)
19905 @cfg {number} g_r radius (pie)
19906 @cfg {number} g_height height of the chart (respected by all elements in the set)
19907 @cfg {number} g_width width of the chart (respected by all elements in the set)
19908 @cfg {Object} title The title of the chart
19911 -opts (object) options for the chart
19913 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19914 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19916 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.
19917 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19919 o stretch (boolean)
19921 -opts (object) options for the pie
19924 o startAngle (number)
19925 o endAngle (number)
19929 * Create a new Input
19930 * @param {Object} config The config object
19933 Roo.bootstrap.Graph = function(config){
19934 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19940 * The img click event for the img.
19941 * @param {Roo.EventObject} e
19947 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19958 //g_colors: this.colors,
19965 getAutoCreate : function(){
19976 onRender : function(ct,position){
19977 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19978 this.raphael = Raphael(this.el.dom);
19980 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19981 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19982 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19983 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19985 r.text(160, 10, "Single Series Chart").attr(txtattr);
19986 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19987 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19988 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19990 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19991 r.barchart(330, 10, 300, 220, data1);
19992 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19993 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19996 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19997 // r.barchart(30, 30, 560, 250, xdata, {
19998 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19999 // axis : "0 0 1 1",
20000 // axisxlabels : xdata
20001 // //yvalues : cols,
20004 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20006 // this.load(null,xdata,{
20007 // axis : "0 0 1 1",
20008 // axisxlabels : xdata
20013 load : function(graphtype,xdata,opts){
20014 this.raphael.clear();
20016 graphtype = this.graphtype;
20021 var r = this.raphael,
20022 fin = function () {
20023 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20025 fout = function () {
20026 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20028 pfin = function() {
20029 this.sector.stop();
20030 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20033 this.label[0].stop();
20034 this.label[0].attr({ r: 7.5 });
20035 this.label[1].attr({ "font-weight": 800 });
20038 pfout = function() {
20039 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20042 this.label[0].animate({ r: 5 }, 500, "bounce");
20043 this.label[1].attr({ "font-weight": 400 });
20049 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20052 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20055 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20056 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20058 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20065 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20070 setTitle: function(o)
20075 initEvents: function() {
20078 this.el.on('click', this.onClick, this);
20082 onClick : function(e)
20084 Roo.log('img onclick');
20085 this.fireEvent('click', this, e);
20097 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20100 * @class Roo.bootstrap.dash.NumberBox
20101 * @extends Roo.bootstrap.Component
20102 * Bootstrap NumberBox class
20103 * @cfg {String} headline Box headline
20104 * @cfg {String} content Box content
20105 * @cfg {String} icon Box icon
20106 * @cfg {String} footer Footer text
20107 * @cfg {String} fhref Footer href
20110 * Create a new NumberBox
20111 * @param {Object} config The config object
20115 Roo.bootstrap.dash.NumberBox = function(config){
20116 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20120 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20129 getAutoCreate : function(){
20133 cls : 'small-box ',
20141 cls : 'roo-headline',
20142 html : this.headline
20146 cls : 'roo-content',
20147 html : this.content
20161 cls : 'ion ' + this.icon
20170 cls : 'small-box-footer',
20171 href : this.fhref || '#',
20175 cfg.cn.push(footer);
20182 onRender : function(ct,position){
20183 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20190 setHeadline: function (value)
20192 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20195 setFooter: function (value, href)
20197 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20200 this.el.select('a.small-box-footer',true).first().attr('href', href);
20205 setContent: function (value)
20207 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20210 initEvents: function()
20224 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20227 * @class Roo.bootstrap.dash.TabBox
20228 * @extends Roo.bootstrap.Component
20229 * Bootstrap TabBox class
20230 * @cfg {String} title Title of the TabBox
20231 * @cfg {String} icon Icon of the TabBox
20232 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20233 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20236 * Create a new TabBox
20237 * @param {Object} config The config object
20241 Roo.bootstrap.dash.TabBox = function(config){
20242 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20247 * When a pane is added
20248 * @param {Roo.bootstrap.dash.TabPane} pane
20252 * @event activatepane
20253 * When a pane is activated
20254 * @param {Roo.bootstrap.dash.TabPane} pane
20256 "activatepane" : true
20264 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20269 tabScrollable : false,
20271 getChildContainer : function()
20273 return this.el.select('.tab-content', true).first();
20276 getAutoCreate : function(){
20280 cls: 'pull-left header',
20288 cls: 'fa ' + this.icon
20294 cls: 'nav nav-tabs pull-right',
20300 if(this.tabScrollable){
20307 cls: 'nav nav-tabs pull-right',
20318 cls: 'nav-tabs-custom',
20323 cls: 'tab-content no-padding',
20331 initEvents : function()
20333 //Roo.log('add add pane handler');
20334 this.on('addpane', this.onAddPane, this);
20337 * Updates the box title
20338 * @param {String} html to set the title to.
20340 setTitle : function(value)
20342 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20344 onAddPane : function(pane)
20346 this.panes.push(pane);
20347 //Roo.log('addpane');
20349 // tabs are rendere left to right..
20350 if(!this.showtabs){
20354 var ctr = this.el.select('.nav-tabs', true).first();
20357 var existing = ctr.select('.nav-tab',true);
20358 var qty = existing.getCount();;
20361 var tab = ctr.createChild({
20363 cls : 'nav-tab' + (qty ? '' : ' active'),
20371 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20374 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20376 pane.el.addClass('active');
20381 onTabClick : function(ev,un,ob,pane)
20383 //Roo.log('tab - prev default');
20384 ev.preventDefault();
20387 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20388 pane.tab.addClass('active');
20389 //Roo.log(pane.title);
20390 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20391 // technically we should have a deactivate event.. but maybe add later.
20392 // and it should not de-activate the selected tab...
20393 this.fireEvent('activatepane', pane);
20394 pane.el.addClass('active');
20395 pane.fireEvent('activate');
20400 getActivePane : function()
20403 Roo.each(this.panes, function(p) {
20404 if(p.el.hasClass('active')){
20425 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20427 * @class Roo.bootstrap.TabPane
20428 * @extends Roo.bootstrap.Component
20429 * Bootstrap TabPane class
20430 * @cfg {Boolean} active (false | true) Default false
20431 * @cfg {String} title title of panel
20435 * Create a new TabPane
20436 * @param {Object} config The config object
20439 Roo.bootstrap.dash.TabPane = function(config){
20440 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20446 * When a pane is activated
20447 * @param {Roo.bootstrap.dash.TabPane} pane
20454 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20459 // the tabBox that this is attached to.
20462 getAutoCreate : function()
20470 cfg.cls += ' active';
20475 initEvents : function()
20477 //Roo.log('trigger add pane handler');
20478 this.parent().fireEvent('addpane', this)
20482 * Updates the tab title
20483 * @param {String} html to set the title to.
20485 setTitle: function(str)
20491 this.tab.select('a', true).first().dom.innerHTML = str;
20508 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20511 * @class Roo.bootstrap.menu.Menu
20512 * @extends Roo.bootstrap.Component
20513 * Bootstrap Menu class - container for Menu
20514 * @cfg {String} html Text of the menu
20515 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20516 * @cfg {String} icon Font awesome icon
20517 * @cfg {String} pos Menu align to (top | bottom) default bottom
20521 * Create a new Menu
20522 * @param {Object} config The config object
20526 Roo.bootstrap.menu.Menu = function(config){
20527 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20531 * @event beforeshow
20532 * Fires before this menu is displayed
20533 * @param {Roo.bootstrap.menu.Menu} this
20537 * @event beforehide
20538 * Fires before this menu is hidden
20539 * @param {Roo.bootstrap.menu.Menu} this
20544 * Fires after this menu is displayed
20545 * @param {Roo.bootstrap.menu.Menu} this
20550 * Fires after this menu is hidden
20551 * @param {Roo.bootstrap.menu.Menu} this
20556 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20557 * @param {Roo.bootstrap.menu.Menu} this
20558 * @param {Roo.EventObject} e
20565 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20569 weight : 'default',
20574 getChildContainer : function() {
20575 if(this.isSubMenu){
20579 return this.el.select('ul.dropdown-menu', true).first();
20582 getAutoCreate : function()
20587 cls : 'roo-menu-text',
20595 cls : 'fa ' + this.icon
20606 cls : 'dropdown-button btn btn-' + this.weight,
20611 cls : 'dropdown-toggle btn btn-' + this.weight,
20621 cls : 'dropdown-menu'
20627 if(this.pos == 'top'){
20628 cfg.cls += ' dropup';
20631 if(this.isSubMenu){
20634 cls : 'dropdown-menu'
20641 onRender : function(ct, position)
20643 this.isSubMenu = ct.hasClass('dropdown-submenu');
20645 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20648 initEvents : function()
20650 if(this.isSubMenu){
20654 this.hidden = true;
20656 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20657 this.triggerEl.on('click', this.onTriggerPress, this);
20659 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20660 this.buttonEl.on('click', this.onClick, this);
20666 if(this.isSubMenu){
20670 return this.el.select('ul.dropdown-menu', true).first();
20673 onClick : function(e)
20675 this.fireEvent("click", this, e);
20678 onTriggerPress : function(e)
20680 if (this.isVisible()) {
20687 isVisible : function(){
20688 return !this.hidden;
20693 this.fireEvent("beforeshow", this);
20695 this.hidden = false;
20696 this.el.addClass('open');
20698 Roo.get(document).on("mouseup", this.onMouseUp, this);
20700 this.fireEvent("show", this);
20707 this.fireEvent("beforehide", this);
20709 this.hidden = true;
20710 this.el.removeClass('open');
20712 Roo.get(document).un("mouseup", this.onMouseUp);
20714 this.fireEvent("hide", this);
20717 onMouseUp : function()
20731 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20734 * @class Roo.bootstrap.menu.Item
20735 * @extends Roo.bootstrap.Component
20736 * Bootstrap MenuItem class
20737 * @cfg {Boolean} submenu (true | false) default false
20738 * @cfg {String} html text of the item
20739 * @cfg {String} href the link
20740 * @cfg {Boolean} disable (true | false) default false
20741 * @cfg {Boolean} preventDefault (true | false) default true
20742 * @cfg {String} icon Font awesome icon
20743 * @cfg {String} pos Submenu align to (left | right) default right
20747 * Create a new Item
20748 * @param {Object} config The config object
20752 Roo.bootstrap.menu.Item = function(config){
20753 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20757 * Fires when the mouse is hovering over this menu
20758 * @param {Roo.bootstrap.menu.Item} this
20759 * @param {Roo.EventObject} e
20764 * Fires when the mouse exits this menu
20765 * @param {Roo.bootstrap.menu.Item} this
20766 * @param {Roo.EventObject} e
20772 * The raw click event for the entire grid.
20773 * @param {Roo.EventObject} e
20779 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20784 preventDefault: true,
20789 getAutoCreate : function()
20794 cls : 'roo-menu-item-text',
20802 cls : 'fa ' + this.icon
20811 href : this.href || '#',
20818 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20822 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20824 if(this.pos == 'left'){
20825 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20832 initEvents : function()
20834 this.el.on('mouseover', this.onMouseOver, this);
20835 this.el.on('mouseout', this.onMouseOut, this);
20837 this.el.select('a', true).first().on('click', this.onClick, this);
20841 onClick : function(e)
20843 if(this.preventDefault){
20844 e.preventDefault();
20847 this.fireEvent("click", this, e);
20850 onMouseOver : function(e)
20852 if(this.submenu && this.pos == 'left'){
20853 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20856 this.fireEvent("mouseover", this, e);
20859 onMouseOut : function(e)
20861 this.fireEvent("mouseout", this, e);
20873 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20876 * @class Roo.bootstrap.menu.Separator
20877 * @extends Roo.bootstrap.Component
20878 * Bootstrap Separator class
20881 * Create a new Separator
20882 * @param {Object} config The config object
20886 Roo.bootstrap.menu.Separator = function(config){
20887 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20890 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20892 getAutoCreate : function(){
20913 * @class Roo.bootstrap.Tooltip
20914 * Bootstrap Tooltip class
20915 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20916 * to determine which dom element triggers the tooltip.
20918 * It needs to add support for additional attributes like tooltip-position
20921 * Create a new Toolti
20922 * @param {Object} config The config object
20925 Roo.bootstrap.Tooltip = function(config){
20926 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20929 Roo.apply(Roo.bootstrap.Tooltip, {
20931 * @function init initialize tooltip monitoring.
20935 currentTip : false,
20936 currentRegion : false,
20942 Roo.get(document).on('mouseover', this.enter ,this);
20943 Roo.get(document).on('mouseout', this.leave, this);
20946 this.currentTip = new Roo.bootstrap.Tooltip();
20949 enter : function(ev)
20951 var dom = ev.getTarget();
20952 //Roo.log(['enter',dom]);
20953 var el = Roo.fly(dom);
20954 if (this.currentEl) {
20956 //Roo.log(this.currentEl);
20957 //Roo.log(this.currentEl.contains(dom));
20958 if (this.currentEl == el) {
20961 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20969 if (this.currentTip.el) {
20970 this.currentTip.el.hide(); // force hiding...
20973 if (!el.attr('tooltip')) { // parents who have tip?
20976 this.currentEl = el;
20977 this.currentTip.bind(el);
20978 this.currentRegion = Roo.lib.Region.getRegion(dom);
20979 this.currentTip.enter();
20982 leave : function(ev)
20984 var dom = ev.getTarget();
20985 //Roo.log(['leave',dom]);
20986 if (!this.currentEl) {
20991 if (dom != this.currentEl.dom) {
20994 var xy = ev.getXY();
20995 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
20998 // only activate leave if mouse cursor is outside... bounding box..
21003 if (this.currentTip) {
21004 this.currentTip.leave();
21006 //Roo.log('clear currentEl');
21007 this.currentEl = false;
21012 'left' : ['r-l', [-2,0], 'right'],
21013 'right' : ['l-r', [2,0], 'left'],
21014 'bottom' : ['t-b', [0,2], 'top'],
21015 'top' : [ 'b-t', [0,-2], 'bottom']
21021 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21026 delay : null, // can be { show : 300 , hide: 500}
21030 hoverState : null, //???
21032 placement : 'bottom',
21034 getAutoCreate : function(){
21041 cls : 'tooltip-arrow'
21044 cls : 'tooltip-inner'
21051 bind : function(el)
21057 enter : function () {
21059 if (this.timeout != null) {
21060 clearTimeout(this.timeout);
21063 this.hoverState = 'in'
21064 //Roo.log("enter - show");
21065 if (!this.delay || !this.delay.show) {
21070 this.timeout = setTimeout(function () {
21071 if (_t.hoverState == 'in') {
21074 }, this.delay.show);
21078 clearTimeout(this.timeout);
21080 this.hoverState = 'out'
21081 if (!this.delay || !this.delay.hide) {
21087 this.timeout = setTimeout(function () {
21088 //Roo.log("leave - timeout");
21090 if (_t.hoverState == 'out') {
21092 Roo.bootstrap.Tooltip.currentEl = false;
21100 this.render(document.body);
21103 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21104 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21106 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21108 var placement = typeof this.placement == 'function' ?
21109 this.placement.call(this, this.el, on_el) :
21112 var autoToken = /\s?auto?\s?/i;
21113 var autoPlace = autoToken.test(placement);
21115 placement = placement.replace(autoToken, '') || 'top';
21119 //this.el.setXY([0,0]);
21121 //this.el.dom.style.display='block';
21122 this.el.addClass(placement);
21124 //this.el.appendTo(on_el);
21126 var p = this.getPosition();
21127 var box = this.el.getBox();
21132 var align = Roo.bootstrap.Tooltip.alignment[placement]
21133 this.el.alignTo(this.bindEl, align[0],align[1]);
21134 //var arrow = this.el.select('.arrow',true).first();
21135 //arrow.set(align[2],
21137 this.el.addClass('in fade');
21138 this.hoverState = null;
21140 if (this.el.hasClass('fade')) {
21151 //this.el.setXY([0,0]);
21152 this.el.removeClass('in');
21168 * @class Roo.bootstrap.LocationPicker
21169 * @extends Roo.bootstrap.Component
21170 * Bootstrap LocationPicker class
21171 * @cfg {Number} latitude Position when init default 0
21172 * @cfg {Number} longitude Position when init default 0
21173 * @cfg {Number} zoom default 15
21174 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21175 * @cfg {Boolean} mapTypeControl default false
21176 * @cfg {Boolean} disableDoubleClickZoom default false
21177 * @cfg {Boolean} scrollwheel default true
21178 * @cfg {Boolean} streetViewControl default false
21179 * @cfg {Number} radius default 0
21180 * @cfg {String} locationName
21181 * @cfg {Boolean} draggable default true
21182 * @cfg {Boolean} enableAutocomplete default false
21183 * @cfg {Boolean} enableReverseGeocode default true
21184 * @cfg {String} markerTitle
21187 * Create a new LocationPicker
21188 * @param {Object} config The config object
21192 Roo.bootstrap.LocationPicker = function(config){
21194 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21199 * Fires when the picker initialized.
21200 * @param {Roo.bootstrap.LocationPicker} this
21201 * @param {Google Location} location
21205 * @event positionchanged
21206 * Fires when the picker position changed.
21207 * @param {Roo.bootstrap.LocationPicker} this
21208 * @param {Google Location} location
21210 positionchanged : true,
21213 * Fires when the map resize.
21214 * @param {Roo.bootstrap.LocationPicker} this
21219 * Fires when the map show.
21220 * @param {Roo.bootstrap.LocationPicker} this
21225 * Fires when the map hide.
21226 * @param {Roo.bootstrap.LocationPicker} this
21233 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
21235 gMapContext: false,
21241 mapTypeControl: false,
21242 disableDoubleClickZoom: false,
21244 streetViewControl: false,
21248 enableAutocomplete: false,
21249 enableReverseGeocode: true,
21252 getAutoCreate: function()
21257 cls: 'roo-location-picker'
21263 initEvents: function(ct, position)
21265 if(!this.mapTypeId){
21266 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
21269 if(!this.el.getWidth() || this.isApplied()){
21273 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21278 initial: function()
21280 this.gMapContext = this.GMapContext();
21284 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
21285 _this.setPosition(_this.gMapContext.marker.position);
21288 this.setPosition(this.gMapContext.location);
21290 this.fireEvent('initial', this, this.gMapContext.location);
21293 isApplied: function()
21295 return this.getGmapContext() == false ? false : true;
21298 getGmapContext: function()
21300 return this.gMapContext
21303 GMapContext: function()
21305 var _map = new google.maps.Map(this.el.dom, this);
21306 var _marker = new google.maps.Marker({
21307 position: new google.maps.LatLng(this.latitude, this.longitude),
21309 title: this.markerTitle,
21310 draggable: this.draggable
21317 location: _marker.position,
21318 radius: this.radius,
21319 locationName: this.locationName,
21320 addressComponents: {
21321 formatted_address: null,
21322 addressLine1: null,
21323 addressLine2: null,
21325 streetNumber: null,
21329 stateOrProvince: null
21332 domContainer: this.el.dom,
21333 geodecoder: new google.maps.Geocoder()
21337 drawCircle: function(center, radius, options)
21339 if (this.gMapContext.circle != null) {
21340 this.gMapContext.circle.setMap(null);
21344 options = Roo.apply({}, options, {
21345 strokeColor: "#0000FF",
21346 strokeOpacity: .35,
21348 fillColor: "#0000FF",
21352 options.map = this.gMapContext.map;
21353 options.radius = radius;
21354 options.center = center;
21355 this.gMapContext.circle = new google.maps.Circle(options);
21356 return this.gMapContext.circle;
21362 setPosition: function(location)
21364 this.gMapContext.location = location;
21365 this.gMapContext.marker.setPosition(location);
21366 this.gMapContext.map.panTo(location);
21367 this.drawCircle(location, this.gMapContext.radius, {});
21371 if (this.gMapContext.settings.enableReverseGeocode) {
21372 this.gMapContext.geodecoder.geocode({
21373 latLng: this.gMapContext.location
21374 }, function(results, status) {
21376 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21377 _this.gMapContext.locationName = results[0].formatted_address;
21378 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21380 _this.fireEvent('positionchanged', this, location);
21387 this.fireEvent('positionchanged', this, location);
21392 google.maps.event.trigger(this.gMapContext.map, "resize");
21394 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
21396 this.fireEvent('resize', this);
21399 setPositionByLatLng: function(latitude, longitude)
21401 this.setPosition(new google.maps.LatLng(latitude, longitude));
21404 getCurrentPosition: function()
21407 latitude: this.gMapContext.location.lat(),
21408 longitude: this.gMapContext.location.lng()
21412 getAddressName: function()
21414 return this.gMapContext.locationName;
21417 getAddressComponents: function()
21419 return this.gMapContext.addressComponents;
21422 address_component_from_google_geocode: function(address_components)
21426 for (var i = 0; i < address_components.length; i++) {
21427 var component = address_components[i];
21428 if (component.types.indexOf("postal_code") >= 0) {
21429 result.postalCode = component.short_name;
21430 } else if (component.types.indexOf("street_number") >= 0) {
21431 result.streetNumber = component.short_name;
21432 } else if (component.types.indexOf("route") >= 0) {
21433 result.streetName = component.short_name;
21434 } else if (component.types.indexOf("neighborhood") >= 0) {
21435 result.city = component.short_name;
21436 } else if (component.types.indexOf("locality") >= 0) {
21437 result.city = component.short_name;
21438 } else if (component.types.indexOf("sublocality") >= 0) {
21439 result.district = component.short_name;
21440 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
21441 result.stateOrProvince = component.short_name;
21442 } else if (component.types.indexOf("country") >= 0) {
21443 result.country = component.short_name;
21447 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
21448 result.addressLine2 = "";
21452 setZoomLevel: function(zoom)
21454 this.gMapContext.map.setZoom(zoom);
21467 this.fireEvent('show', this);
21478 this.fireEvent('hide', this);
21490 * @class Roo.bootstrap.Alert
21491 * @extends Roo.bootstrap.Component
21492 * Bootstrap Alert class
21493 * @cfg {String} title The title of alert
21494 * @cfg {String} html The content of alert
21495 * @cfg {String} weight ( success | info | warning | danger )
21496 * @cfg {String} faicon font-awesomeicon
21499 * Create a new alert
21500 * @param {Object} config The config object
21504 Roo.bootstrap.Alert = function(config){
21505 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
21509 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
21516 getAutoCreate : function()
21525 cls : 'roo-alert-icon'
21530 cls : 'roo-alert-title',
21535 cls : 'roo-alert-text',
21542 cfg.cn[0].cls += ' fa ' + this.faicon;
21546 cfg.cls += ' alert-' + this.weight;
21552 initEvents: function()
21554 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21557 setTitle : function(str)
21559 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
21562 setText : function(str)
21564 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
21567 setWeight : function(weight)
21570 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
21573 this.weight = weight;
21575 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
21578 setIcon : function(icon)
21581 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
21586 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);