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..
16480 cls : 'control-label box-label' + inline,
16486 cls : 'control-label' + inline,
16487 html : this.fieldLabel
16496 type : this.inputType,
16497 //value : (!this.checked) ? this.valueOff : this.inputValue,
16498 value : this.inputValue,
16500 placeholder : this.placeholder || '' // ?? needed????
16503 if (this.weight) { // Validity check?
16504 input.cls += " radio-" + this.weight;
16506 if (this.disabled) {
16507 input.disabled=true;
16511 input.checked = this.checked;
16515 input.name = this.name;
16519 input.cls += ' input-' + this.size;
16522 //?? can span's inline have a width??
16525 ['xs','sm','md','lg'].map(function(size){
16526 if (settings[size]) {
16527 cfg.cls += ' col-' + size + '-' + settings[size];
16531 var inputblock = input;
16533 if (this.before || this.after) {
16536 cls : 'input-group',
16541 inputblock.cn.push({
16543 cls : 'input-group-addon',
16547 inputblock.cn.push(input);
16549 inputblock.cn.push({
16551 cls : 'input-group-addon',
16559 if (this.fieldLabel && this.fieldLabel.length) {
16560 cfg.cn.push(fieldLabel);
16563 lbl.cn.push(inputblock);
16566 cls: 'radio' + inline,
16575 html: this.boxLabel
16583 inputEl: function ()
16585 return this.el.select('input.roo-radio',true).first();
16587 onClick : function()
16591 this.setChecked(true);
16594 setChecked : function(state,suppressEvent)
16597 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16598 v.dom.checked = false;
16602 this.checked = state;
16603 this.inputEl().dom.checked = state;
16605 if(suppressEvent !== true){
16606 this.fireEvent('check', this, state);
16609 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16613 getGroupValue : function()
16616 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16617 if(v.dom.checked == true){
16618 value = v.dom.value;
16626 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16627 * @return {Mixed} value The field value
16629 getValue : function(){
16630 return this.getGroupValue();
16636 //<script type="text/javascript">
16639 * Based Ext JS Library 1.1.1
16640 * Copyright(c) 2006-2007, Ext JS, LLC.
16646 * @class Roo.HtmlEditorCore
16647 * @extends Roo.Component
16648 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16650 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16653 Roo.HtmlEditorCore = function(config){
16656 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16661 * @event initialize
16662 * Fires when the editor is fully initialized (including the iframe)
16663 * @param {Roo.HtmlEditorCore} this
16668 * Fires when the editor is first receives the focus. Any insertion must wait
16669 * until after this event.
16670 * @param {Roo.HtmlEditorCore} this
16674 * @event beforesync
16675 * Fires before the textarea is updated with content from the editor iframe. Return false
16676 * to cancel the sync.
16677 * @param {Roo.HtmlEditorCore} this
16678 * @param {String} html
16682 * @event beforepush
16683 * Fires before the iframe editor is updated with content from the textarea. Return false
16684 * to cancel the push.
16685 * @param {Roo.HtmlEditorCore} this
16686 * @param {String} html
16691 * Fires when the textarea is updated with content from the editor iframe.
16692 * @param {Roo.HtmlEditorCore} this
16693 * @param {String} html
16698 * Fires when the iframe editor is updated with content from the textarea.
16699 * @param {Roo.HtmlEditorCore} this
16700 * @param {String} html
16705 * @event editorevent
16706 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16707 * @param {Roo.HtmlEditorCore} this
16713 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16715 // defaults : white / black...
16716 this.applyBlacklists();
16723 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16727 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16733 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16738 * @cfg {Number} height (in pixels)
16742 * @cfg {Number} width (in pixels)
16747 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16750 stylesheets: false,
16755 // private properties
16756 validationEvent : false,
16758 initialized : false,
16760 sourceEditMode : false,
16761 onFocus : Roo.emptyFn,
16763 hideMode:'offsets',
16767 // blacklist + whitelisted elements..
16774 * Protected method that will not generally be called directly. It
16775 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16776 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16778 getDocMarkup : function(){
16782 // inherit styels from page...??
16783 if (this.stylesheets === false) {
16785 Roo.get(document.head).select('style').each(function(node) {
16786 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16789 Roo.get(document.head).select('link').each(function(node) {
16790 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16793 } else if (!this.stylesheets.length) {
16795 st = '<style type="text/css">' +
16796 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16802 st += '<style type="text/css">' +
16803 'IMG { cursor: pointer } ' +
16807 return '<html><head>' + st +
16808 //<style type="text/css">' +
16809 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16811 ' </head><body class="roo-htmleditor-body"></body></html>';
16815 onRender : function(ct, position)
16818 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16819 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16822 this.el.dom.style.border = '0 none';
16823 this.el.dom.setAttribute('tabIndex', -1);
16824 this.el.addClass('x-hidden hide');
16828 if(Roo.isIE){ // fix IE 1px bogus margin
16829 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16833 this.frameId = Roo.id();
16837 var iframe = this.owner.wrap.createChild({
16839 cls: 'form-control', // bootstrap..
16841 name: this.frameId,
16842 frameBorder : 'no',
16843 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16848 this.iframe = iframe.dom;
16850 this.assignDocWin();
16852 this.doc.designMode = 'on';
16855 this.doc.write(this.getDocMarkup());
16859 var task = { // must defer to wait for browser to be ready
16861 //console.log("run task?" + this.doc.readyState);
16862 this.assignDocWin();
16863 if(this.doc.body || this.doc.readyState == 'complete'){
16865 this.doc.designMode="on";
16869 Roo.TaskMgr.stop(task);
16870 this.initEditor.defer(10, this);
16877 Roo.TaskMgr.start(task);
16882 onResize : function(w, h)
16884 Roo.log('resize: ' +w + ',' + h );
16885 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16889 if(typeof w == 'number'){
16891 this.iframe.style.width = w + 'px';
16893 if(typeof h == 'number'){
16895 this.iframe.style.height = h + 'px';
16897 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16904 * Toggles the editor between standard and source edit mode.
16905 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16907 toggleSourceEdit : function(sourceEditMode){
16909 this.sourceEditMode = sourceEditMode === true;
16911 if(this.sourceEditMode){
16913 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16916 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16917 //this.iframe.className = '';
16920 //this.setSize(this.owner.wrap.getSize());
16921 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16928 * Protected method that will not generally be called directly. If you need/want
16929 * custom HTML cleanup, this is the method you should override.
16930 * @param {String} html The HTML to be cleaned
16931 * return {String} The cleaned HTML
16933 cleanHtml : function(html){
16934 html = String(html);
16935 if(html.length > 5){
16936 if(Roo.isSafari){ // strip safari nonsense
16937 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16940 if(html == ' '){
16947 * HTML Editor -> Textarea
16948 * Protected method that will not generally be called directly. Syncs the contents
16949 * of the editor iframe with the textarea.
16951 syncValue : function(){
16952 if(this.initialized){
16953 var bd = (this.doc.body || this.doc.documentElement);
16954 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16955 var html = bd.innerHTML;
16957 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16958 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16960 html = '<div style="'+m[0]+'">' + html + '</div>';
16963 html = this.cleanHtml(html);
16964 // fix up the special chars.. normaly like back quotes in word...
16965 // however we do not want to do this with chinese..
16966 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16967 var cc = b.charCodeAt();
16969 (cc >= 0x4E00 && cc < 0xA000 ) ||
16970 (cc >= 0x3400 && cc < 0x4E00 ) ||
16971 (cc >= 0xf900 && cc < 0xfb00 )
16977 if(this.owner.fireEvent('beforesync', this, html) !== false){
16978 this.el.dom.value = html;
16979 this.owner.fireEvent('sync', this, html);
16985 * Protected method that will not generally be called directly. Pushes the value of the textarea
16986 * into the iframe editor.
16988 pushValue : function(){
16989 if(this.initialized){
16990 var v = this.el.dom.value.trim();
16992 // if(v.length < 1){
16996 if(this.owner.fireEvent('beforepush', this, v) !== false){
16997 var d = (this.doc.body || this.doc.documentElement);
16999 this.cleanUpPaste();
17000 this.el.dom.value = d.innerHTML;
17001 this.owner.fireEvent('push', this, v);
17007 deferFocus : function(){
17008 this.focus.defer(10, this);
17012 focus : function(){
17013 if(this.win && !this.sourceEditMode){
17020 assignDocWin: function()
17022 var iframe = this.iframe;
17025 this.doc = iframe.contentWindow.document;
17026 this.win = iframe.contentWindow;
17028 // if (!Roo.get(this.frameId)) {
17031 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17032 // this.win = Roo.get(this.frameId).dom.contentWindow;
17034 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17038 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17039 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17044 initEditor : function(){
17045 //console.log("INIT EDITOR");
17046 this.assignDocWin();
17050 this.doc.designMode="on";
17052 this.doc.write(this.getDocMarkup());
17055 var dbody = (this.doc.body || this.doc.documentElement);
17056 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17057 // this copies styles from the containing element into thsi one..
17058 // not sure why we need all of this..
17059 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17061 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17062 //ss['background-attachment'] = 'fixed'; // w3c
17063 dbody.bgProperties = 'fixed'; // ie
17064 //Roo.DomHelper.applyStyles(dbody, ss);
17065 Roo.EventManager.on(this.doc, {
17066 //'mousedown': this.onEditorEvent,
17067 'mouseup': this.onEditorEvent,
17068 'dblclick': this.onEditorEvent,
17069 'click': this.onEditorEvent,
17070 'keyup': this.onEditorEvent,
17075 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17077 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17078 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17080 this.initialized = true;
17082 this.owner.fireEvent('initialize', this);
17087 onDestroy : function(){
17093 //for (var i =0; i < this.toolbars.length;i++) {
17094 // // fixme - ask toolbars for heights?
17095 // this.toolbars[i].onDestroy();
17098 //this.wrap.dom.innerHTML = '';
17099 //this.wrap.remove();
17104 onFirstFocus : function(){
17106 this.assignDocWin();
17109 this.activated = true;
17112 if(Roo.isGecko){ // prevent silly gecko errors
17114 var s = this.win.getSelection();
17115 if(!s.focusNode || s.focusNode.nodeType != 3){
17116 var r = s.getRangeAt(0);
17117 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17122 this.execCmd('useCSS', true);
17123 this.execCmd('styleWithCSS', false);
17126 this.owner.fireEvent('activate', this);
17130 adjustFont: function(btn){
17131 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17132 //if(Roo.isSafari){ // safari
17135 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17136 if(Roo.isSafari){ // safari
17137 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17138 v = (v < 10) ? 10 : v;
17139 v = (v > 48) ? 48 : v;
17140 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17145 v = Math.max(1, v+adjust);
17147 this.execCmd('FontSize', v );
17150 onEditorEvent : function(e){
17151 this.owner.fireEvent('editorevent', this, e);
17152 // this.updateToolbar();
17153 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17156 insertTag : function(tg)
17158 // could be a bit smarter... -> wrap the current selected tRoo..
17159 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17161 range = this.createRange(this.getSelection());
17162 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17163 wrappingNode.appendChild(range.extractContents());
17164 range.insertNode(wrappingNode);
17171 this.execCmd("formatblock", tg);
17175 insertText : function(txt)
17179 var range = this.createRange();
17180 range.deleteContents();
17181 //alert(Sender.getAttribute('label'));
17183 range.insertNode(this.doc.createTextNode(txt));
17189 * Executes a Midas editor command on the editor document and performs necessary focus and
17190 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17191 * @param {String} cmd The Midas command
17192 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17194 relayCmd : function(cmd, value){
17196 this.execCmd(cmd, value);
17197 this.owner.fireEvent('editorevent', this);
17198 //this.updateToolbar();
17199 this.owner.deferFocus();
17203 * Executes a Midas editor command directly on the editor document.
17204 * For visual commands, you should use {@link #relayCmd} instead.
17205 * <b>This should only be called after the editor is initialized.</b>
17206 * @param {String} cmd The Midas command
17207 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17209 execCmd : function(cmd, value){
17210 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17217 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17219 * @param {String} text | dom node..
17221 insertAtCursor : function(text)
17226 if(!this.activated){
17232 var r = this.doc.selection.createRange();
17243 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17247 // from jquery ui (MIT licenced)
17249 var win = this.win;
17251 if (win.getSelection && win.getSelection().getRangeAt) {
17252 range = win.getSelection().getRangeAt(0);
17253 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17254 range.insertNode(node);
17255 } else if (win.document.selection && win.document.selection.createRange) {
17256 // no firefox support
17257 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17258 win.document.selection.createRange().pasteHTML(txt);
17260 // no firefox support
17261 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17262 this.execCmd('InsertHTML', txt);
17271 mozKeyPress : function(e){
17273 var c = e.getCharCode(), cmd;
17276 c = String.fromCharCode(c).toLowerCase();
17290 this.cleanUpPaste.defer(100, this);
17298 e.preventDefault();
17306 fixKeys : function(){ // load time branching for fastest keydown performance
17308 return function(e){
17309 var k = e.getKey(), r;
17312 r = this.doc.selection.createRange();
17315 r.pasteHTML('    ');
17322 r = this.doc.selection.createRange();
17324 var target = r.parentElement();
17325 if(!target || target.tagName.toLowerCase() != 'li'){
17327 r.pasteHTML('<br />');
17333 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17334 this.cleanUpPaste.defer(100, this);
17340 }else if(Roo.isOpera){
17341 return function(e){
17342 var k = e.getKey();
17346 this.execCmd('InsertHTML','    ');
17349 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17350 this.cleanUpPaste.defer(100, this);
17355 }else if(Roo.isSafari){
17356 return function(e){
17357 var k = e.getKey();
17361 this.execCmd('InsertText','\t');
17365 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17366 this.cleanUpPaste.defer(100, this);
17374 getAllAncestors: function()
17376 var p = this.getSelectedNode();
17379 a.push(p); // push blank onto stack..
17380 p = this.getParentElement();
17384 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17388 a.push(this.doc.body);
17392 lastSelNode : false,
17395 getSelection : function()
17397 this.assignDocWin();
17398 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17401 getSelectedNode: function()
17403 // this may only work on Gecko!!!
17405 // should we cache this!!!!
17410 var range = this.createRange(this.getSelection()).cloneRange();
17413 var parent = range.parentElement();
17415 var testRange = range.duplicate();
17416 testRange.moveToElementText(parent);
17417 if (testRange.inRange(range)) {
17420 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17423 parent = parent.parentElement;
17428 // is ancestor a text element.
17429 var ac = range.commonAncestorContainer;
17430 if (ac.nodeType == 3) {
17431 ac = ac.parentNode;
17434 var ar = ac.childNodes;
17437 var other_nodes = [];
17438 var has_other_nodes = false;
17439 for (var i=0;i<ar.length;i++) {
17440 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17443 // fullly contained node.
17445 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17450 // probably selected..
17451 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17452 other_nodes.push(ar[i]);
17456 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17461 has_other_nodes = true;
17463 if (!nodes.length && other_nodes.length) {
17464 nodes= other_nodes;
17466 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17472 createRange: function(sel)
17474 // this has strange effects when using with
17475 // top toolbar - not sure if it's a great idea.
17476 //this.editor.contentWindow.focus();
17477 if (typeof sel != "undefined") {
17479 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17481 return this.doc.createRange();
17484 return this.doc.createRange();
17487 getParentElement: function()
17490 this.assignDocWin();
17491 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17493 var range = this.createRange(sel);
17496 var p = range.commonAncestorContainer;
17497 while (p.nodeType == 3) { // text node
17508 * Range intersection.. the hard stuff...
17512 * [ -- selected range --- ]
17516 * if end is before start or hits it. fail.
17517 * if start is after end or hits it fail.
17519 * if either hits (but other is outside. - then it's not
17525 // @see http://www.thismuchiknow.co.uk/?p=64.
17526 rangeIntersectsNode : function(range, node)
17528 var nodeRange = node.ownerDocument.createRange();
17530 nodeRange.selectNode(node);
17532 nodeRange.selectNodeContents(node);
17535 var rangeStartRange = range.cloneRange();
17536 rangeStartRange.collapse(true);
17538 var rangeEndRange = range.cloneRange();
17539 rangeEndRange.collapse(false);
17541 var nodeStartRange = nodeRange.cloneRange();
17542 nodeStartRange.collapse(true);
17544 var nodeEndRange = nodeRange.cloneRange();
17545 nodeEndRange.collapse(false);
17547 return rangeStartRange.compareBoundaryPoints(
17548 Range.START_TO_START, nodeEndRange) == -1 &&
17549 rangeEndRange.compareBoundaryPoints(
17550 Range.START_TO_START, nodeStartRange) == 1;
17554 rangeCompareNode : function(range, node)
17556 var nodeRange = node.ownerDocument.createRange();
17558 nodeRange.selectNode(node);
17560 nodeRange.selectNodeContents(node);
17564 range.collapse(true);
17566 nodeRange.collapse(true);
17568 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17569 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17571 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17573 var nodeIsBefore = ss == 1;
17574 var nodeIsAfter = ee == -1;
17576 if (nodeIsBefore && nodeIsAfter)
17578 if (!nodeIsBefore && nodeIsAfter)
17579 return 1; //right trailed.
17581 if (nodeIsBefore && !nodeIsAfter)
17582 return 2; // left trailed.
17587 // private? - in a new class?
17588 cleanUpPaste : function()
17590 // cleans up the whole document..
17591 Roo.log('cleanuppaste');
17593 this.cleanUpChildren(this.doc.body);
17594 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17595 if (clean != this.doc.body.innerHTML) {
17596 this.doc.body.innerHTML = clean;
17601 cleanWordChars : function(input) {// change the chars to hex code
17602 var he = Roo.HtmlEditorCore;
17604 var output = input;
17605 Roo.each(he.swapCodes, function(sw) {
17606 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17608 output = output.replace(swapper, sw[1]);
17615 cleanUpChildren : function (n)
17617 if (!n.childNodes.length) {
17620 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17621 this.cleanUpChild(n.childNodes[i]);
17628 cleanUpChild : function (node)
17631 //console.log(node);
17632 if (node.nodeName == "#text") {
17633 // clean up silly Windows -- stuff?
17636 if (node.nodeName == "#comment") {
17637 node.parentNode.removeChild(node);
17638 // clean up silly Windows -- stuff?
17641 var lcname = node.tagName.toLowerCase();
17642 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17643 // whitelist of tags..
17645 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17647 node.parentNode.removeChild(node);
17652 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17654 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17655 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17657 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17658 // remove_keep_children = true;
17661 if (remove_keep_children) {
17662 this.cleanUpChildren(node);
17663 // inserts everything just before this node...
17664 while (node.childNodes.length) {
17665 var cn = node.childNodes[0];
17666 node.removeChild(cn);
17667 node.parentNode.insertBefore(cn, node);
17669 node.parentNode.removeChild(node);
17673 if (!node.attributes || !node.attributes.length) {
17674 this.cleanUpChildren(node);
17678 function cleanAttr(n,v)
17681 if (v.match(/^\./) || v.match(/^\//)) {
17684 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17687 if (v.match(/^#/)) {
17690 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17691 node.removeAttribute(n);
17695 var cwhite = this.cwhite;
17696 var cblack = this.cblack;
17698 function cleanStyle(n,v)
17700 if (v.match(/expression/)) { //XSS?? should we even bother..
17701 node.removeAttribute(n);
17705 var parts = v.split(/;/);
17708 Roo.each(parts, function(p) {
17709 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17713 var l = p.split(':').shift().replace(/\s+/g,'');
17714 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17716 if ( cwhite.length && cblack.indexOf(l) > -1) {
17717 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17718 //node.removeAttribute(n);
17722 // only allow 'c whitelisted system attributes'
17723 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17724 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17725 //node.removeAttribute(n);
17735 if (clean.length) {
17736 node.setAttribute(n, clean.join(';'));
17738 node.removeAttribute(n);
17744 for (var i = node.attributes.length-1; i > -1 ; i--) {
17745 var a = node.attributes[i];
17748 if (a.name.toLowerCase().substr(0,2)=='on') {
17749 node.removeAttribute(a.name);
17752 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17753 node.removeAttribute(a.name);
17756 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17757 cleanAttr(a.name,a.value); // fixme..
17760 if (a.name == 'style') {
17761 cleanStyle(a.name,a.value);
17764 /// clean up MS crap..
17765 // tecnically this should be a list of valid class'es..
17768 if (a.name == 'class') {
17769 if (a.value.match(/^Mso/)) {
17770 node.className = '';
17773 if (a.value.match(/body/)) {
17774 node.className = '';
17785 this.cleanUpChildren(node);
17790 * Clean up MS wordisms...
17792 cleanWord : function(node)
17795 var cleanWordChildren = function()
17797 if (!node.childNodes.length) {
17800 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17801 _t.cleanWord(node.childNodes[i]);
17807 this.cleanWord(this.doc.body);
17810 if (node.nodeName == "#text") {
17811 // clean up silly Windows -- stuff?
17814 if (node.nodeName == "#comment") {
17815 node.parentNode.removeChild(node);
17816 // clean up silly Windows -- stuff?
17820 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17821 node.parentNode.removeChild(node);
17825 // remove - but keep children..
17826 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17827 while (node.childNodes.length) {
17828 var cn = node.childNodes[0];
17829 node.removeChild(cn);
17830 node.parentNode.insertBefore(cn, node);
17832 node.parentNode.removeChild(node);
17833 cleanWordChildren();
17837 if (node.className.length) {
17839 var cn = node.className.split(/\W+/);
17841 Roo.each(cn, function(cls) {
17842 if (cls.match(/Mso[a-zA-Z]+/)) {
17847 node.className = cna.length ? cna.join(' ') : '';
17849 node.removeAttribute("class");
17853 if (node.hasAttribute("lang")) {
17854 node.removeAttribute("lang");
17857 if (node.hasAttribute("style")) {
17859 var styles = node.getAttribute("style").split(";");
17861 Roo.each(styles, function(s) {
17862 if (!s.match(/:/)) {
17865 var kv = s.split(":");
17866 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17869 // what ever is left... we allow.
17872 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17873 if (!nstyle.length) {
17874 node.removeAttribute('style');
17878 cleanWordChildren();
17882 domToHTML : function(currentElement, depth, nopadtext) {
17884 depth = depth || 0;
17885 nopadtext = nopadtext || false;
17887 if (!currentElement) {
17888 return this.domToHTML(this.doc.body);
17891 //Roo.log(currentElement);
17893 var allText = false;
17894 var nodeName = currentElement.nodeName;
17895 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17897 if (nodeName == '#text') {
17899 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
17904 if (nodeName != 'BODY') {
17907 // Prints the node tagName, such as <A>, <IMG>, etc
17910 for(i = 0; i < currentElement.attributes.length;i++) {
17912 var aname = currentElement.attributes.item(i).name;
17913 if (!currentElement.attributes.item(i).value.length) {
17916 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17919 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17928 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17931 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17936 // Traverse the tree
17938 var currentElementChild = currentElement.childNodes.item(i);
17939 var allText = true;
17940 var innerHTML = '';
17942 while (currentElementChild) {
17943 // Formatting code (indent the tree so it looks nice on the screen)
17944 var nopad = nopadtext;
17945 if (lastnode == 'SPAN') {
17949 if (currentElementChild.nodeName == '#text') {
17950 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17951 toadd = nopadtext ? toadd : toadd.trim();
17952 if (!nopad && toadd.length > 80) {
17953 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17955 innerHTML += toadd;
17958 currentElementChild = currentElement.childNodes.item(i);
17964 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17966 // Recursively traverse the tree structure of the child node
17967 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17968 lastnode = currentElementChild.nodeName;
17970 currentElementChild=currentElement.childNodes.item(i);
17976 // The remaining code is mostly for formatting the tree
17977 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17982 ret+= "</"+tagName+">";
17988 applyBlacklists : function()
17990 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17991 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17995 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17996 if (b.indexOf(tag) > -1) {
17999 this.white.push(tag);
18003 Roo.each(w, function(tag) {
18004 if (b.indexOf(tag) > -1) {
18007 if (this.white.indexOf(tag) > -1) {
18010 this.white.push(tag);
18015 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18016 if (w.indexOf(tag) > -1) {
18019 this.black.push(tag);
18023 Roo.each(b, function(tag) {
18024 if (w.indexOf(tag) > -1) {
18027 if (this.black.indexOf(tag) > -1) {
18030 this.black.push(tag);
18035 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18036 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18040 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18041 if (b.indexOf(tag) > -1) {
18044 this.cwhite.push(tag);
18048 Roo.each(w, function(tag) {
18049 if (b.indexOf(tag) > -1) {
18052 if (this.cwhite.indexOf(tag) > -1) {
18055 this.cwhite.push(tag);
18060 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18061 if (w.indexOf(tag) > -1) {
18064 this.cblack.push(tag);
18068 Roo.each(b, function(tag) {
18069 if (w.indexOf(tag) > -1) {
18072 if (this.cblack.indexOf(tag) > -1) {
18075 this.cblack.push(tag);
18080 setStylesheets : function(stylesheets)
18082 if(typeof(stylesheets) == 'string'){
18083 Roo.get(this.iframe.contentDocument.head).createChild({
18085 rel : 'stylesheet',
18094 Roo.each(stylesheets, function(s) {
18099 Roo.get(_this.iframe.contentDocument.head).createChild({
18101 rel : 'stylesheet',
18110 removeStylesheets : function()
18114 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18119 // hide stuff that is not compatible
18133 * @event specialkey
18137 * @cfg {String} fieldClass @hide
18140 * @cfg {String} focusClass @hide
18143 * @cfg {String} autoCreate @hide
18146 * @cfg {String} inputType @hide
18149 * @cfg {String} invalidClass @hide
18152 * @cfg {String} invalidText @hide
18155 * @cfg {String} msgFx @hide
18158 * @cfg {String} validateOnBlur @hide
18162 Roo.HtmlEditorCore.white = [
18163 'area', 'br', 'img', 'input', 'hr', 'wbr',
18165 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18166 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18167 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18168 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18169 'table', 'ul', 'xmp',
18171 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18174 'dir', 'menu', 'ol', 'ul', 'dl',
18180 Roo.HtmlEditorCore.black = [
18181 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18183 'base', 'basefont', 'bgsound', 'blink', 'body',
18184 'frame', 'frameset', 'head', 'html', 'ilayer',
18185 'iframe', 'layer', 'link', 'meta', 'object',
18186 'script', 'style' ,'title', 'xml' // clean later..
18188 Roo.HtmlEditorCore.clean = [
18189 'script', 'style', 'title', 'xml'
18191 Roo.HtmlEditorCore.remove = [
18196 Roo.HtmlEditorCore.ablack = [
18200 Roo.HtmlEditorCore.aclean = [
18201 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18205 Roo.HtmlEditorCore.pwhite= [
18206 'http', 'https', 'mailto'
18209 // white listed style attributes.
18210 Roo.HtmlEditorCore.cwhite= [
18211 // 'text-align', /// default is to allow most things..
18217 // black listed style attributes.
18218 Roo.HtmlEditorCore.cblack= [
18219 // 'font-size' -- this can be set by the project
18223 Roo.HtmlEditorCore.swapCodes =[
18242 * @class Roo.bootstrap.HtmlEditor
18243 * @extends Roo.bootstrap.TextArea
18244 * Bootstrap HtmlEditor class
18247 * Create a new HtmlEditor
18248 * @param {Object} config The config object
18251 Roo.bootstrap.HtmlEditor = function(config){
18252 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18253 if (!this.toolbars) {
18254 this.toolbars = [];
18256 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18259 * @event initialize
18260 * Fires when the editor is fully initialized (including the iframe)
18261 * @param {HtmlEditor} this
18266 * Fires when the editor is first receives the focus. Any insertion must wait
18267 * until after this event.
18268 * @param {HtmlEditor} this
18272 * @event beforesync
18273 * Fires before the textarea is updated with content from the editor iframe. Return false
18274 * to cancel the sync.
18275 * @param {HtmlEditor} this
18276 * @param {String} html
18280 * @event beforepush
18281 * Fires before the iframe editor is updated with content from the textarea. Return false
18282 * to cancel the push.
18283 * @param {HtmlEditor} this
18284 * @param {String} html
18289 * Fires when the textarea is updated with content from the editor iframe.
18290 * @param {HtmlEditor} this
18291 * @param {String} html
18296 * Fires when the iframe editor is updated with content from the textarea.
18297 * @param {HtmlEditor} this
18298 * @param {String} html
18302 * @event editmodechange
18303 * Fires when the editor switches edit modes
18304 * @param {HtmlEditor} this
18305 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18307 editmodechange: true,
18309 * @event editorevent
18310 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18311 * @param {HtmlEditor} this
18315 * @event firstfocus
18316 * Fires when on first focus - needed by toolbars..
18317 * @param {HtmlEditor} this
18322 * Auto save the htmlEditor value as a file into Events
18323 * @param {HtmlEditor} this
18327 * @event savedpreview
18328 * preview the saved version of htmlEditor
18329 * @param {HtmlEditor} this
18336 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18340 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18345 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18350 * @cfg {Number} height (in pixels)
18354 * @cfg {Number} width (in pixels)
18359 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18362 stylesheets: false,
18367 // private properties
18368 validationEvent : false,
18370 initialized : false,
18373 onFocus : Roo.emptyFn,
18375 hideMode:'offsets',
18378 tbContainer : false,
18380 toolbarContainer :function() {
18381 return this.wrap.select('.x-html-editor-tb',true).first();
18385 * Protected method that will not generally be called directly. It
18386 * is called when the editor creates its toolbar. Override this method if you need to
18387 * add custom toolbar buttons.
18388 * @param {HtmlEditor} editor
18390 createToolbar : function(){
18392 Roo.log("create toolbars");
18394 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18395 this.toolbars[0].render(this.toolbarContainer());
18399 // if (!editor.toolbars || !editor.toolbars.length) {
18400 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18403 // for (var i =0 ; i < editor.toolbars.length;i++) {
18404 // editor.toolbars[i] = Roo.factory(
18405 // typeof(editor.toolbars[i]) == 'string' ?
18406 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18407 // Roo.bootstrap.HtmlEditor);
18408 // editor.toolbars[i].init(editor);
18414 onRender : function(ct, position)
18416 // Roo.log("Call onRender: " + this.xtype);
18418 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18420 this.wrap = this.inputEl().wrap({
18421 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18424 this.editorcore.onRender(ct, position);
18426 if (this.resizable) {
18427 this.resizeEl = new Roo.Resizable(this.wrap, {
18431 minHeight : this.height,
18432 height: this.height,
18433 handles : this.resizable,
18436 resize : function(r, w, h) {
18437 _t.onResize(w,h); // -something
18443 this.createToolbar(this);
18446 if(!this.width && this.resizable){
18447 this.setSize(this.wrap.getSize());
18449 if (this.resizeEl) {
18450 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18451 // should trigger onReize..
18457 onResize : function(w, h)
18459 Roo.log('resize: ' +w + ',' + h );
18460 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18464 if(this.inputEl() ){
18465 if(typeof w == 'number'){
18466 var aw = w - this.wrap.getFrameWidth('lr');
18467 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18470 if(typeof h == 'number'){
18471 var tbh = -11; // fixme it needs to tool bar size!
18472 for (var i =0; i < this.toolbars.length;i++) {
18473 // fixme - ask toolbars for heights?
18474 tbh += this.toolbars[i].el.getHeight();
18475 //if (this.toolbars[i].footer) {
18476 // tbh += this.toolbars[i].footer.el.getHeight();
18484 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18485 ah -= 5; // knock a few pixes off for look..
18486 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18490 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18491 this.editorcore.onResize(ew,eh);
18496 * Toggles the editor between standard and source edit mode.
18497 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18499 toggleSourceEdit : function(sourceEditMode)
18501 this.editorcore.toggleSourceEdit(sourceEditMode);
18503 if(this.editorcore.sourceEditMode){
18504 Roo.log('editor - showing textarea');
18507 // Roo.log(this.syncValue());
18509 this.inputEl().removeClass(['hide', 'x-hidden']);
18510 this.inputEl().dom.removeAttribute('tabIndex');
18511 this.inputEl().focus();
18513 Roo.log('editor - hiding textarea');
18515 // Roo.log(this.pushValue());
18518 this.inputEl().addClass(['hide', 'x-hidden']);
18519 this.inputEl().dom.setAttribute('tabIndex', -1);
18520 //this.deferFocus();
18523 if(this.resizable){
18524 this.setSize(this.wrap.getSize());
18527 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18530 // private (for BoxComponent)
18531 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18533 // private (for BoxComponent)
18534 getResizeEl : function(){
18538 // private (for BoxComponent)
18539 getPositionEl : function(){
18544 initEvents : function(){
18545 this.originalValue = this.getValue();
18549 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18552 // markInvalid : Roo.emptyFn,
18554 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18557 // clearInvalid : Roo.emptyFn,
18559 setValue : function(v){
18560 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18561 this.editorcore.pushValue();
18566 deferFocus : function(){
18567 this.focus.defer(10, this);
18571 focus : function(){
18572 this.editorcore.focus();
18578 onDestroy : function(){
18584 for (var i =0; i < this.toolbars.length;i++) {
18585 // fixme - ask toolbars for heights?
18586 this.toolbars[i].onDestroy();
18589 this.wrap.dom.innerHTML = '';
18590 this.wrap.remove();
18595 onFirstFocus : function(){
18596 //Roo.log("onFirstFocus");
18597 this.editorcore.onFirstFocus();
18598 for (var i =0; i < this.toolbars.length;i++) {
18599 this.toolbars[i].onFirstFocus();
18605 syncValue : function()
18607 this.editorcore.syncValue();
18610 pushValue : function()
18612 this.editorcore.pushValue();
18616 // hide stuff that is not compatible
18630 * @event specialkey
18634 * @cfg {String} fieldClass @hide
18637 * @cfg {String} focusClass @hide
18640 * @cfg {String} autoCreate @hide
18643 * @cfg {String} inputType @hide
18646 * @cfg {String} invalidClass @hide
18649 * @cfg {String} invalidText @hide
18652 * @cfg {String} msgFx @hide
18655 * @cfg {String} validateOnBlur @hide
18664 Roo.namespace('Roo.bootstrap.htmleditor');
18666 * @class Roo.bootstrap.HtmlEditorToolbar1
18671 new Roo.bootstrap.HtmlEditor({
18674 new Roo.bootstrap.HtmlEditorToolbar1({
18675 disable : { fonts: 1 , format: 1, ..., ... , ...],
18681 * @cfg {Object} disable List of elements to disable..
18682 * @cfg {Array} btns List of additional buttons.
18686 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18689 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18692 Roo.apply(this, config);
18694 // default disabled, based on 'good practice'..
18695 this.disable = this.disable || {};
18696 Roo.applyIf(this.disable, {
18699 specialElements : true
18701 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18703 this.editor = config.editor;
18704 this.editorcore = config.editor.editorcore;
18706 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18708 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18709 // dont call parent... till later.
18711 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18716 editorcore : false,
18721 "h1","h2","h3","h4","h5","h6",
18723 "abbr", "acronym", "address", "cite", "samp", "var",
18727 onRender : function(ct, position)
18729 // Roo.log("Call onRender: " + this.xtype);
18731 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18733 this.el.dom.style.marginBottom = '0';
18735 var editorcore = this.editorcore;
18736 var editor= this.editor;
18739 var btn = function(id,cmd , toggle, handler){
18741 var event = toggle ? 'toggle' : 'click';
18746 xns: Roo.bootstrap,
18749 enableToggle:toggle !== false,
18751 pressed : toggle ? false : null,
18754 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18755 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18764 xns: Roo.bootstrap,
18765 glyphicon : 'font',
18769 xns: Roo.bootstrap,
18773 Roo.each(this.formats, function(f) {
18774 style.menu.items.push({
18776 xns: Roo.bootstrap,
18777 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18782 editorcore.insertTag(this.tagname);
18789 children.push(style);
18792 btn('bold',false,true);
18793 btn('italic',false,true);
18794 btn('align-left', 'justifyleft',true);
18795 btn('align-center', 'justifycenter',true);
18796 btn('align-right' , 'justifyright',true);
18797 btn('link', false, false, function(btn) {
18798 //Roo.log("create link?");
18799 var url = prompt(this.createLinkText, this.defaultLinkValue);
18800 if(url && url != 'http:/'+'/'){
18801 this.editorcore.relayCmd('createlink', url);
18804 btn('list','insertunorderedlist',true);
18805 btn('pencil', false,true, function(btn){
18808 this.toggleSourceEdit(btn.pressed);
18814 xns: Roo.bootstrap,
18819 xns: Roo.bootstrap,
18824 cog.menu.items.push({
18826 xns: Roo.bootstrap,
18827 html : Clean styles,
18832 editorcore.insertTag(this.tagname);
18841 this.xtype = 'NavSimplebar';
18843 for(var i=0;i< children.length;i++) {
18845 this.buttons.add(this.addxtypeChild(children[i]));
18849 editor.on('editorevent', this.updateToolbar, this);
18851 onBtnClick : function(id)
18853 this.editorcore.relayCmd(id);
18854 this.editorcore.focus();
18858 * Protected method that will not generally be called directly. It triggers
18859 * a toolbar update by reading the markup state of the current selection in the editor.
18861 updateToolbar: function(){
18863 if(!this.editorcore.activated){
18864 this.editor.onFirstFocus(); // is this neeed?
18868 var btns = this.buttons;
18869 var doc = this.editorcore.doc;
18870 btns.get('bold').setActive(doc.queryCommandState('bold'));
18871 btns.get('italic').setActive(doc.queryCommandState('italic'));
18872 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18874 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18875 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18876 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18878 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18879 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18882 var ans = this.editorcore.getAllAncestors();
18883 if (this.formatCombo) {
18886 var store = this.formatCombo.store;
18887 this.formatCombo.setValue("");
18888 for (var i =0; i < ans.length;i++) {
18889 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18891 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18899 // hides menus... - so this cant be on a menu...
18900 Roo.bootstrap.MenuMgr.hideAll();
18902 Roo.bootstrap.MenuMgr.hideAll();
18903 //this.editorsyncValue();
18905 onFirstFocus: function() {
18906 this.buttons.each(function(item){
18910 toggleSourceEdit : function(sourceEditMode){
18913 if(sourceEditMode){
18914 Roo.log("disabling buttons");
18915 this.buttons.each( function(item){
18916 if(item.cmd != 'pencil'){
18922 Roo.log("enabling buttons");
18923 if(this.editorcore.initialized){
18924 this.buttons.each( function(item){
18930 Roo.log("calling toggole on editor");
18931 // tell the editor that it's been pressed..
18932 this.editor.toggleSourceEdit(sourceEditMode);
18942 * @class Roo.bootstrap.Table.AbstractSelectionModel
18943 * @extends Roo.util.Observable
18944 * Abstract base class for grid SelectionModels. It provides the interface that should be
18945 * implemented by descendant classes. This class should not be directly instantiated.
18948 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18949 this.locked = false;
18950 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18954 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18955 /** @ignore Called by the grid automatically. Do not call directly. */
18956 init : function(grid){
18962 * Locks the selections.
18965 this.locked = true;
18969 * Unlocks the selections.
18971 unlock : function(){
18972 this.locked = false;
18976 * Returns true if the selections are locked.
18977 * @return {Boolean}
18979 isLocked : function(){
18980 return this.locked;
18984 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18985 * @class Roo.bootstrap.Table.RowSelectionModel
18986 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18987 * It supports multiple selections and keyboard selection/navigation.
18989 * @param {Object} config
18992 Roo.bootstrap.Table.RowSelectionModel = function(config){
18993 Roo.apply(this, config);
18994 this.selections = new Roo.util.MixedCollection(false, function(o){
18999 this.lastActive = false;
19003 * @event selectionchange
19004 * Fires when the selection changes
19005 * @param {SelectionModel} this
19007 "selectionchange" : true,
19009 * @event afterselectionchange
19010 * Fires after the selection changes (eg. by key press or clicking)
19011 * @param {SelectionModel} this
19013 "afterselectionchange" : true,
19015 * @event beforerowselect
19016 * Fires when a row is selected being selected, return false to cancel.
19017 * @param {SelectionModel} this
19018 * @param {Number} rowIndex The selected index
19019 * @param {Boolean} keepExisting False if other selections will be cleared
19021 "beforerowselect" : true,
19024 * Fires when a row is selected.
19025 * @param {SelectionModel} this
19026 * @param {Number} rowIndex The selected index
19027 * @param {Roo.data.Record} r The record
19029 "rowselect" : true,
19031 * @event rowdeselect
19032 * Fires when a row is deselected.
19033 * @param {SelectionModel} this
19034 * @param {Number} rowIndex The selected index
19036 "rowdeselect" : true
19038 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19039 this.locked = false;
19042 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19044 * @cfg {Boolean} singleSelect
19045 * True to allow selection of only one row at a time (defaults to false)
19047 singleSelect : false,
19050 initEvents : function(){
19052 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19053 this.grid.on("mousedown", this.handleMouseDown, this);
19054 }else{ // allow click to work like normal
19055 this.grid.on("rowclick", this.handleDragableRowClick, this);
19058 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19059 "up" : function(e){
19061 this.selectPrevious(e.shiftKey);
19062 }else if(this.last !== false && this.lastActive !== false){
19063 var last = this.last;
19064 this.selectRange(this.last, this.lastActive-1);
19065 this.grid.getView().focusRow(this.lastActive);
19066 if(last !== false){
19070 this.selectFirstRow();
19072 this.fireEvent("afterselectionchange", this);
19074 "down" : function(e){
19076 this.selectNext(e.shiftKey);
19077 }else if(this.last !== false && this.lastActive !== false){
19078 var last = this.last;
19079 this.selectRange(this.last, this.lastActive+1);
19080 this.grid.getView().focusRow(this.lastActive);
19081 if(last !== false){
19085 this.selectFirstRow();
19087 this.fireEvent("afterselectionchange", this);
19092 var view = this.grid.view;
19093 view.on("refresh", this.onRefresh, this);
19094 view.on("rowupdated", this.onRowUpdated, this);
19095 view.on("rowremoved", this.onRemove, this);
19099 onRefresh : function(){
19100 var ds = this.grid.dataSource, i, v = this.grid.view;
19101 var s = this.selections;
19102 s.each(function(r){
19103 if((i = ds.indexOfId(r.id)) != -1){
19112 onRemove : function(v, index, r){
19113 this.selections.remove(r);
19117 onRowUpdated : function(v, index, r){
19118 if(this.isSelected(r)){
19119 v.onRowSelect(index);
19125 * @param {Array} records The records to select
19126 * @param {Boolean} keepExisting (optional) True to keep existing selections
19128 selectRecords : function(records, keepExisting){
19130 this.clearSelections();
19132 var ds = this.grid.dataSource;
19133 for(var i = 0, len = records.length; i < len; i++){
19134 this.selectRow(ds.indexOf(records[i]), true);
19139 * Gets the number of selected rows.
19142 getCount : function(){
19143 return this.selections.length;
19147 * Selects the first row in the grid.
19149 selectFirstRow : function(){
19154 * Select the last row.
19155 * @param {Boolean} keepExisting (optional) True to keep existing selections
19157 selectLastRow : function(keepExisting){
19158 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19162 * Selects the row immediately following the last selected row.
19163 * @param {Boolean} keepExisting (optional) True to keep existing selections
19165 selectNext : function(keepExisting){
19166 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19167 this.selectRow(this.last+1, keepExisting);
19168 this.grid.getView().focusRow(this.last);
19173 * Selects the row that precedes the last selected row.
19174 * @param {Boolean} keepExisting (optional) True to keep existing selections
19176 selectPrevious : function(keepExisting){
19178 this.selectRow(this.last-1, keepExisting);
19179 this.grid.getView().focusRow(this.last);
19184 * Returns the selected records
19185 * @return {Array} Array of selected records
19187 getSelections : function(){
19188 return [].concat(this.selections.items);
19192 * Returns the first selected record.
19195 getSelected : function(){
19196 return this.selections.itemAt(0);
19201 * Clears all selections.
19203 clearSelections : function(fast){
19204 if(this.locked) return;
19206 var ds = this.grid.dataSource;
19207 var s = this.selections;
19208 s.each(function(r){
19209 this.deselectRow(ds.indexOfId(r.id));
19213 this.selections.clear();
19220 * Selects all rows.
19222 selectAll : function(){
19223 if(this.locked) return;
19224 this.selections.clear();
19225 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19226 this.selectRow(i, true);
19231 * Returns True if there is a selection.
19232 * @return {Boolean}
19234 hasSelection : function(){
19235 return this.selections.length > 0;
19239 * Returns True if the specified row is selected.
19240 * @param {Number/Record} record The record or index of the record to check
19241 * @return {Boolean}
19243 isSelected : function(index){
19244 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19245 return (r && this.selections.key(r.id) ? true : false);
19249 * Returns True if the specified record id is selected.
19250 * @param {String} id The id of record to check
19251 * @return {Boolean}
19253 isIdSelected : function(id){
19254 return (this.selections.key(id) ? true : false);
19258 handleMouseDown : function(e, t){
19259 var view = this.grid.getView(), rowIndex;
19260 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19263 if(e.shiftKey && this.last !== false){
19264 var last = this.last;
19265 this.selectRange(last, rowIndex, e.ctrlKey);
19266 this.last = last; // reset the last
19267 view.focusRow(rowIndex);
19269 var isSelected = this.isSelected(rowIndex);
19270 if(e.button !== 0 && isSelected){
19271 view.focusRow(rowIndex);
19272 }else if(e.ctrlKey && isSelected){
19273 this.deselectRow(rowIndex);
19274 }else if(!isSelected){
19275 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19276 view.focusRow(rowIndex);
19279 this.fireEvent("afterselectionchange", this);
19282 handleDragableRowClick : function(grid, rowIndex, e)
19284 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19285 this.selectRow(rowIndex, false);
19286 grid.view.focusRow(rowIndex);
19287 this.fireEvent("afterselectionchange", this);
19292 * Selects multiple rows.
19293 * @param {Array} rows Array of the indexes of the row to select
19294 * @param {Boolean} keepExisting (optional) True to keep existing selections
19296 selectRows : function(rows, keepExisting){
19298 this.clearSelections();
19300 for(var i = 0, len = rows.length; i < len; i++){
19301 this.selectRow(rows[i], true);
19306 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19307 * @param {Number} startRow The index of the first row in the range
19308 * @param {Number} endRow The index of the last row in the range
19309 * @param {Boolean} keepExisting (optional) True to retain existing selections
19311 selectRange : function(startRow, endRow, keepExisting){
19312 if(this.locked) return;
19314 this.clearSelections();
19316 if(startRow <= endRow){
19317 for(var i = startRow; i <= endRow; i++){
19318 this.selectRow(i, true);
19321 for(var i = startRow; i >= endRow; i--){
19322 this.selectRow(i, true);
19328 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19329 * @param {Number} startRow The index of the first row in the range
19330 * @param {Number} endRow The index of the last row in the range
19332 deselectRange : function(startRow, endRow, preventViewNotify){
19333 if(this.locked) return;
19334 for(var i = startRow; i <= endRow; i++){
19335 this.deselectRow(i, preventViewNotify);
19341 * @param {Number} row The index of the row to select
19342 * @param {Boolean} keepExisting (optional) True to keep existing selections
19344 selectRow : function(index, keepExisting, preventViewNotify){
19345 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19346 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19347 if(!keepExisting || this.singleSelect){
19348 this.clearSelections();
19350 var r = this.grid.dataSource.getAt(index);
19351 this.selections.add(r);
19352 this.last = this.lastActive = index;
19353 if(!preventViewNotify){
19354 this.grid.getView().onRowSelect(index);
19356 this.fireEvent("rowselect", this, index, r);
19357 this.fireEvent("selectionchange", this);
19363 * @param {Number} row The index of the row to deselect
19365 deselectRow : function(index, preventViewNotify){
19366 if(this.locked) return;
19367 if(this.last == index){
19370 if(this.lastActive == index){
19371 this.lastActive = false;
19373 var r = this.grid.dataSource.getAt(index);
19374 this.selections.remove(r);
19375 if(!preventViewNotify){
19376 this.grid.getView().onRowDeselect(index);
19378 this.fireEvent("rowdeselect", this, index);
19379 this.fireEvent("selectionchange", this);
19383 restoreLast : function(){
19385 this.last = this._last;
19390 acceptsNav : function(row, col, cm){
19391 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19395 onEditorKey : function(field, e){
19396 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19401 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19403 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19405 }else if(k == e.ENTER && !e.ctrlKey){
19409 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19411 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19413 }else if(k == e.ESC){
19417 g.startEditing(newCell[0], newCell[1]);
19422 * Ext JS Library 1.1.1
19423 * Copyright(c) 2006-2007, Ext JS, LLC.
19425 * Originally Released Under LGPL - original licence link has changed is not relivant.
19428 * <script type="text/javascript">
19432 * @class Roo.bootstrap.PagingToolbar
19434 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19436 * Create a new PagingToolbar
19437 * @param {Object} config The config object
19439 Roo.bootstrap.PagingToolbar = function(config)
19441 // old args format still supported... - xtype is prefered..
19442 // created from xtype...
19443 var ds = config.dataSource;
19444 this.toolbarItems = [];
19445 if (config.items) {
19446 this.toolbarItems = config.items;
19447 // config.items = [];
19450 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19457 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19461 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19463 * @cfg {Roo.data.Store} dataSource
19464 * The underlying data store providing the paged data
19467 * @cfg {String/HTMLElement/Element} container
19468 * container The id or element that will contain the toolbar
19471 * @cfg {Boolean} displayInfo
19472 * True to display the displayMsg (defaults to false)
19475 * @cfg {Number} pageSize
19476 * The number of records to display per page (defaults to 20)
19480 * @cfg {String} displayMsg
19481 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19483 displayMsg : 'Displaying {0} - {1} of {2}',
19485 * @cfg {String} emptyMsg
19486 * The message to display when no records are found (defaults to "No data to display")
19488 emptyMsg : 'No data to display',
19490 * Customizable piece of the default paging text (defaults to "Page")
19493 beforePageText : "Page",
19495 * Customizable piece of the default paging text (defaults to "of %0")
19498 afterPageText : "of {0}",
19500 * Customizable piece of the default paging text (defaults to "First Page")
19503 firstText : "First Page",
19505 * Customizable piece of the default paging text (defaults to "Previous Page")
19508 prevText : "Previous Page",
19510 * Customizable piece of the default paging text (defaults to "Next Page")
19513 nextText : "Next Page",
19515 * Customizable piece of the default paging text (defaults to "Last Page")
19518 lastText : "Last Page",
19520 * Customizable piece of the default paging text (defaults to "Refresh")
19523 refreshText : "Refresh",
19527 onRender : function(ct, position)
19529 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19530 this.navgroup.parentId = this.id;
19531 this.navgroup.onRender(this.el, null);
19532 // add the buttons to the navgroup
19534 if(this.displayInfo){
19535 Roo.log(this.el.select('ul.navbar-nav',true).first());
19536 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19537 this.displayEl = this.el.select('.x-paging-info', true).first();
19538 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19539 // this.displayEl = navel.el.select('span',true).first();
19545 Roo.each(_this.buttons, function(e){
19546 Roo.factory(e).onRender(_this.el, null);
19550 Roo.each(_this.toolbarItems, function(e) {
19551 _this.navgroup.addItem(e);
19554 this.first = this.navgroup.addItem({
19555 tooltip: this.firstText,
19557 icon : 'fa fa-backward',
19559 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19562 this.prev = this.navgroup.addItem({
19563 tooltip: this.prevText,
19565 icon : 'fa fa-step-backward',
19567 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19569 //this.addSeparator();
19572 var field = this.navgroup.addItem( {
19574 cls : 'x-paging-position',
19576 html : this.beforePageText +
19577 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19578 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19581 this.field = field.el.select('input', true).first();
19582 this.field.on("keydown", this.onPagingKeydown, this);
19583 this.field.on("focus", function(){this.dom.select();});
19586 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19587 //this.field.setHeight(18);
19588 //this.addSeparator();
19589 this.next = this.navgroup.addItem({
19590 tooltip: this.nextText,
19592 html : ' <i class="fa fa-step-forward">',
19594 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19596 this.last = this.navgroup.addItem({
19597 tooltip: this.lastText,
19598 icon : 'fa fa-forward',
19601 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19603 //this.addSeparator();
19604 this.loading = this.navgroup.addItem({
19605 tooltip: this.refreshText,
19606 icon: 'fa fa-refresh',
19608 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19614 updateInfo : function(){
19615 if(this.displayEl){
19616 var count = this.ds.getCount();
19617 var msg = count == 0 ?
19621 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19623 this.displayEl.update(msg);
19628 onLoad : function(ds, r, o){
19629 this.cursor = o.params ? o.params.start : 0;
19630 var d = this.getPageData(),
19634 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19635 this.field.dom.value = ap;
19636 this.first.setDisabled(ap == 1);
19637 this.prev.setDisabled(ap == 1);
19638 this.next.setDisabled(ap == ps);
19639 this.last.setDisabled(ap == ps);
19640 this.loading.enable();
19645 getPageData : function(){
19646 var total = this.ds.getTotalCount();
19649 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19650 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19655 onLoadError : function(){
19656 this.loading.enable();
19660 onPagingKeydown : function(e){
19661 var k = e.getKey();
19662 var d = this.getPageData();
19664 var v = this.field.dom.value, pageNum;
19665 if(!v || isNaN(pageNum = parseInt(v, 10))){
19666 this.field.dom.value = d.activePage;
19669 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19670 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19673 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))
19675 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19676 this.field.dom.value = pageNum;
19677 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19680 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19682 var v = this.field.dom.value, pageNum;
19683 var increment = (e.shiftKey) ? 10 : 1;
19684 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19686 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19687 this.field.dom.value = d.activePage;
19690 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19692 this.field.dom.value = parseInt(v, 10) + increment;
19693 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19694 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19701 beforeLoad : function(){
19703 this.loading.disable();
19708 onClick : function(which){
19715 ds.load({params:{start: 0, limit: this.pageSize}});
19718 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19721 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19724 var total = ds.getTotalCount();
19725 var extra = total % this.pageSize;
19726 var lastStart = extra ? (total - extra) : total-this.pageSize;
19727 ds.load({params:{start: lastStart, limit: this.pageSize}});
19730 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19736 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19737 * @param {Roo.data.Store} store The data store to unbind
19739 unbind : function(ds){
19740 ds.un("beforeload", this.beforeLoad, this);
19741 ds.un("load", this.onLoad, this);
19742 ds.un("loadexception", this.onLoadError, this);
19743 ds.un("remove", this.updateInfo, this);
19744 ds.un("add", this.updateInfo, this);
19745 this.ds = undefined;
19749 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19750 * @param {Roo.data.Store} store The data store to bind
19752 bind : function(ds){
19753 ds.on("beforeload", this.beforeLoad, this);
19754 ds.on("load", this.onLoad, this);
19755 ds.on("loadexception", this.onLoadError, this);
19756 ds.on("remove", this.updateInfo, this);
19757 ds.on("add", this.updateInfo, this);
19768 * @class Roo.bootstrap.MessageBar
19769 * @extends Roo.bootstrap.Component
19770 * Bootstrap MessageBar class
19771 * @cfg {String} html contents of the MessageBar
19772 * @cfg {String} weight (info | success | warning | danger) default info
19773 * @cfg {String} beforeClass insert the bar before the given class
19774 * @cfg {Boolean} closable (true | false) default false
19775 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19778 * Create a new Element
19779 * @param {Object} config The config object
19782 Roo.bootstrap.MessageBar = function(config){
19783 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19786 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19792 beforeClass: 'bootstrap-sticky-wrap',
19794 getAutoCreate : function(){
19798 cls: 'alert alert-dismissable alert-' + this.weight,
19803 html: this.html || ''
19809 cfg.cls += ' alert-messages-fixed';
19823 onRender : function(ct, position)
19825 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19828 var cfg = Roo.apply({}, this.getAutoCreate());
19832 cfg.cls += ' ' + this.cls;
19835 cfg.style = this.style;
19837 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19839 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19842 this.el.select('>button.close').on('click', this.hide, this);
19848 if (!this.rendered) {
19854 this.fireEvent('show', this);
19860 if (!this.rendered) {
19866 this.fireEvent('hide', this);
19869 update : function()
19871 // var e = this.el.dom.firstChild;
19873 // if(this.closable){
19874 // e = e.nextSibling;
19877 // e.data = this.html || '';
19879 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19895 * @class Roo.bootstrap.Graph
19896 * @extends Roo.bootstrap.Component
19897 * Bootstrap Graph class
19901 @cfg {String} graphtype bar | vbar | pie
19902 @cfg {number} g_x coodinator | centre x (pie)
19903 @cfg {number} g_y coodinator | centre y (pie)
19904 @cfg {number} g_r radius (pie)
19905 @cfg {number} g_height height of the chart (respected by all elements in the set)
19906 @cfg {number} g_width width of the chart (respected by all elements in the set)
19907 @cfg {Object} title The title of the chart
19910 -opts (object) options for the chart
19912 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19913 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19915 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.
19916 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19918 o stretch (boolean)
19920 -opts (object) options for the pie
19923 o startAngle (number)
19924 o endAngle (number)
19928 * Create a new Input
19929 * @param {Object} config The config object
19932 Roo.bootstrap.Graph = function(config){
19933 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19939 * The img click event for the img.
19940 * @param {Roo.EventObject} e
19946 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19957 //g_colors: this.colors,
19964 getAutoCreate : function(){
19975 onRender : function(ct,position){
19976 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19977 this.raphael = Raphael(this.el.dom);
19979 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19980 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19981 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19982 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19984 r.text(160, 10, "Single Series Chart").attr(txtattr);
19985 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19986 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19987 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19989 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19990 r.barchart(330, 10, 300, 220, data1);
19991 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19992 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19995 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19996 // r.barchart(30, 30, 560, 250, xdata, {
19997 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19998 // axis : "0 0 1 1",
19999 // axisxlabels : xdata
20000 // //yvalues : cols,
20003 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20005 // this.load(null,xdata,{
20006 // axis : "0 0 1 1",
20007 // axisxlabels : xdata
20012 load : function(graphtype,xdata,opts){
20013 this.raphael.clear();
20015 graphtype = this.graphtype;
20020 var r = this.raphael,
20021 fin = function () {
20022 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20024 fout = function () {
20025 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20027 pfin = function() {
20028 this.sector.stop();
20029 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20032 this.label[0].stop();
20033 this.label[0].attr({ r: 7.5 });
20034 this.label[1].attr({ "font-weight": 800 });
20037 pfout = function() {
20038 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20041 this.label[0].animate({ r: 5 }, 500, "bounce");
20042 this.label[1].attr({ "font-weight": 400 });
20048 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20051 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20054 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20055 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20057 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20064 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20069 setTitle: function(o)
20074 initEvents: function() {
20077 this.el.on('click', this.onClick, this);
20081 onClick : function(e)
20083 Roo.log('img onclick');
20084 this.fireEvent('click', this, e);
20096 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20099 * @class Roo.bootstrap.dash.NumberBox
20100 * @extends Roo.bootstrap.Component
20101 * Bootstrap NumberBox class
20102 * @cfg {String} headline Box headline
20103 * @cfg {String} content Box content
20104 * @cfg {String} icon Box icon
20105 * @cfg {String} footer Footer text
20106 * @cfg {String} fhref Footer href
20109 * Create a new NumberBox
20110 * @param {Object} config The config object
20114 Roo.bootstrap.dash.NumberBox = function(config){
20115 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20119 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20128 getAutoCreate : function(){
20132 cls : 'small-box ',
20140 cls : 'roo-headline',
20141 html : this.headline
20145 cls : 'roo-content',
20146 html : this.content
20160 cls : 'ion ' + this.icon
20169 cls : 'small-box-footer',
20170 href : this.fhref || '#',
20174 cfg.cn.push(footer);
20181 onRender : function(ct,position){
20182 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20189 setHeadline: function (value)
20191 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20194 setFooter: function (value, href)
20196 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20199 this.el.select('a.small-box-footer',true).first().attr('href', href);
20204 setContent: function (value)
20206 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20209 initEvents: function()
20223 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20226 * @class Roo.bootstrap.dash.TabBox
20227 * @extends Roo.bootstrap.Component
20228 * Bootstrap TabBox class
20229 * @cfg {String} title Title of the TabBox
20230 * @cfg {String} icon Icon of the TabBox
20231 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20232 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20235 * Create a new TabBox
20236 * @param {Object} config The config object
20240 Roo.bootstrap.dash.TabBox = function(config){
20241 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20246 * When a pane is added
20247 * @param {Roo.bootstrap.dash.TabPane} pane
20251 * @event activatepane
20252 * When a pane is activated
20253 * @param {Roo.bootstrap.dash.TabPane} pane
20255 "activatepane" : true
20263 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20268 tabScrollable : false,
20270 getChildContainer : function()
20272 return this.el.select('.tab-content', true).first();
20275 getAutoCreate : function(){
20279 cls: 'pull-left header',
20287 cls: 'fa ' + this.icon
20293 cls: 'nav nav-tabs pull-right',
20299 if(this.tabScrollable){
20306 cls: 'nav nav-tabs pull-right',
20317 cls: 'nav-tabs-custom',
20322 cls: 'tab-content no-padding',
20330 initEvents : function()
20332 //Roo.log('add add pane handler');
20333 this.on('addpane', this.onAddPane, this);
20336 * Updates the box title
20337 * @param {String} html to set the title to.
20339 setTitle : function(value)
20341 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20343 onAddPane : function(pane)
20345 this.panes.push(pane);
20346 //Roo.log('addpane');
20348 // tabs are rendere left to right..
20349 if(!this.showtabs){
20353 var ctr = this.el.select('.nav-tabs', true).first();
20356 var existing = ctr.select('.nav-tab',true);
20357 var qty = existing.getCount();;
20360 var tab = ctr.createChild({
20362 cls : 'nav-tab' + (qty ? '' : ' active'),
20370 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20373 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20375 pane.el.addClass('active');
20380 onTabClick : function(ev,un,ob,pane)
20382 //Roo.log('tab - prev default');
20383 ev.preventDefault();
20386 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20387 pane.tab.addClass('active');
20388 //Roo.log(pane.title);
20389 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20390 // technically we should have a deactivate event.. but maybe add later.
20391 // and it should not de-activate the selected tab...
20392 this.fireEvent('activatepane', pane);
20393 pane.el.addClass('active');
20394 pane.fireEvent('activate');
20399 getActivePane : function()
20402 Roo.each(this.panes, function(p) {
20403 if(p.el.hasClass('active')){
20424 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20426 * @class Roo.bootstrap.TabPane
20427 * @extends Roo.bootstrap.Component
20428 * Bootstrap TabPane class
20429 * @cfg {Boolean} active (false | true) Default false
20430 * @cfg {String} title title of panel
20434 * Create a new TabPane
20435 * @param {Object} config The config object
20438 Roo.bootstrap.dash.TabPane = function(config){
20439 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20445 * When a pane is activated
20446 * @param {Roo.bootstrap.dash.TabPane} pane
20453 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20458 // the tabBox that this is attached to.
20461 getAutoCreate : function()
20469 cfg.cls += ' active';
20474 initEvents : function()
20476 //Roo.log('trigger add pane handler');
20477 this.parent().fireEvent('addpane', this)
20481 * Updates the tab title
20482 * @param {String} html to set the title to.
20484 setTitle: function(str)
20490 this.tab.select('a', true).first().dom.innerHTML = str;
20507 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20510 * @class Roo.bootstrap.menu.Menu
20511 * @extends Roo.bootstrap.Component
20512 * Bootstrap Menu class - container for Menu
20513 * @cfg {String} html Text of the menu
20514 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20515 * @cfg {String} icon Font awesome icon
20516 * @cfg {String} pos Menu align to (top | bottom) default bottom
20520 * Create a new Menu
20521 * @param {Object} config The config object
20525 Roo.bootstrap.menu.Menu = function(config){
20526 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20530 * @event beforeshow
20531 * Fires before this menu is displayed
20532 * @param {Roo.bootstrap.menu.Menu} this
20536 * @event beforehide
20537 * Fires before this menu is hidden
20538 * @param {Roo.bootstrap.menu.Menu} this
20543 * Fires after this menu is displayed
20544 * @param {Roo.bootstrap.menu.Menu} this
20549 * Fires after this menu is hidden
20550 * @param {Roo.bootstrap.menu.Menu} this
20555 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20556 * @param {Roo.bootstrap.menu.Menu} this
20557 * @param {Roo.EventObject} e
20564 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20568 weight : 'default',
20573 getChildContainer : function() {
20574 if(this.isSubMenu){
20578 return this.el.select('ul.dropdown-menu', true).first();
20581 getAutoCreate : function()
20586 cls : 'roo-menu-text',
20594 cls : 'fa ' + this.icon
20605 cls : 'dropdown-button btn btn-' + this.weight,
20610 cls : 'dropdown-toggle btn btn-' + this.weight,
20620 cls : 'dropdown-menu'
20626 if(this.pos == 'top'){
20627 cfg.cls += ' dropup';
20630 if(this.isSubMenu){
20633 cls : 'dropdown-menu'
20640 onRender : function(ct, position)
20642 this.isSubMenu = ct.hasClass('dropdown-submenu');
20644 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20647 initEvents : function()
20649 if(this.isSubMenu){
20653 this.hidden = true;
20655 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20656 this.triggerEl.on('click', this.onTriggerPress, this);
20658 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20659 this.buttonEl.on('click', this.onClick, this);
20665 if(this.isSubMenu){
20669 return this.el.select('ul.dropdown-menu', true).first();
20672 onClick : function(e)
20674 this.fireEvent("click", this, e);
20677 onTriggerPress : function(e)
20679 if (this.isVisible()) {
20686 isVisible : function(){
20687 return !this.hidden;
20692 this.fireEvent("beforeshow", this);
20694 this.hidden = false;
20695 this.el.addClass('open');
20697 Roo.get(document).on("mouseup", this.onMouseUp, this);
20699 this.fireEvent("show", this);
20706 this.fireEvent("beforehide", this);
20708 this.hidden = true;
20709 this.el.removeClass('open');
20711 Roo.get(document).un("mouseup", this.onMouseUp);
20713 this.fireEvent("hide", this);
20716 onMouseUp : function()
20730 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20733 * @class Roo.bootstrap.menu.Item
20734 * @extends Roo.bootstrap.Component
20735 * Bootstrap MenuItem class
20736 * @cfg {Boolean} submenu (true | false) default false
20737 * @cfg {String} html text of the item
20738 * @cfg {String} href the link
20739 * @cfg {Boolean} disable (true | false) default false
20740 * @cfg {Boolean} preventDefault (true | false) default true
20741 * @cfg {String} icon Font awesome icon
20742 * @cfg {String} pos Submenu align to (left | right) default right
20746 * Create a new Item
20747 * @param {Object} config The config object
20751 Roo.bootstrap.menu.Item = function(config){
20752 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20756 * Fires when the mouse is hovering over this menu
20757 * @param {Roo.bootstrap.menu.Item} this
20758 * @param {Roo.EventObject} e
20763 * Fires when the mouse exits this menu
20764 * @param {Roo.bootstrap.menu.Item} this
20765 * @param {Roo.EventObject} e
20771 * The raw click event for the entire grid.
20772 * @param {Roo.EventObject} e
20778 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20783 preventDefault: true,
20788 getAutoCreate : function()
20793 cls : 'roo-menu-item-text',
20801 cls : 'fa ' + this.icon
20810 href : this.href || '#',
20817 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20821 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20823 if(this.pos == 'left'){
20824 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20831 initEvents : function()
20833 this.el.on('mouseover', this.onMouseOver, this);
20834 this.el.on('mouseout', this.onMouseOut, this);
20836 this.el.select('a', true).first().on('click', this.onClick, this);
20840 onClick : function(e)
20842 if(this.preventDefault){
20843 e.preventDefault();
20846 this.fireEvent("click", this, e);
20849 onMouseOver : function(e)
20851 if(this.submenu && this.pos == 'left'){
20852 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20855 this.fireEvent("mouseover", this, e);
20858 onMouseOut : function(e)
20860 this.fireEvent("mouseout", this, e);
20872 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20875 * @class Roo.bootstrap.menu.Separator
20876 * @extends Roo.bootstrap.Component
20877 * Bootstrap Separator class
20880 * Create a new Separator
20881 * @param {Object} config The config object
20885 Roo.bootstrap.menu.Separator = function(config){
20886 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20889 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20891 getAutoCreate : function(){
20912 * @class Roo.bootstrap.Tooltip
20913 * Bootstrap Tooltip class
20914 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20915 * to determine which dom element triggers the tooltip.
20917 * It needs to add support for additional attributes like tooltip-position
20920 * Create a new Toolti
20921 * @param {Object} config The config object
20924 Roo.bootstrap.Tooltip = function(config){
20925 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20928 Roo.apply(Roo.bootstrap.Tooltip, {
20930 * @function init initialize tooltip monitoring.
20934 currentTip : false,
20935 currentRegion : false,
20941 Roo.get(document).on('mouseover', this.enter ,this);
20942 Roo.get(document).on('mouseout', this.leave, this);
20945 this.currentTip = new Roo.bootstrap.Tooltip();
20948 enter : function(ev)
20950 var dom = ev.getTarget();
20951 //Roo.log(['enter',dom]);
20952 var el = Roo.fly(dom);
20953 if (this.currentEl) {
20955 //Roo.log(this.currentEl);
20956 //Roo.log(this.currentEl.contains(dom));
20957 if (this.currentEl == el) {
20960 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20968 if (this.currentTip.el) {
20969 this.currentTip.el.hide(); // force hiding...
20972 if (!el.attr('tooltip')) { // parents who have tip?
20975 this.currentEl = el;
20976 this.currentTip.bind(el);
20977 this.currentRegion = Roo.lib.Region.getRegion(dom);
20978 this.currentTip.enter();
20981 leave : function(ev)
20983 var dom = ev.getTarget();
20984 //Roo.log(['leave',dom]);
20985 if (!this.currentEl) {
20990 if (dom != this.currentEl.dom) {
20993 var xy = ev.getXY();
20994 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
20997 // only activate leave if mouse cursor is outside... bounding box..
21002 if (this.currentTip) {
21003 this.currentTip.leave();
21005 //Roo.log('clear currentEl');
21006 this.currentEl = false;
21011 'left' : ['r-l', [-2,0], 'right'],
21012 'right' : ['l-r', [2,0], 'left'],
21013 'bottom' : ['t-b', [0,2], 'top'],
21014 'top' : [ 'b-t', [0,-2], 'bottom']
21020 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21025 delay : null, // can be { show : 300 , hide: 500}
21029 hoverState : null, //???
21031 placement : 'bottom',
21033 getAutoCreate : function(){
21040 cls : 'tooltip-arrow'
21043 cls : 'tooltip-inner'
21050 bind : function(el)
21056 enter : function () {
21058 if (this.timeout != null) {
21059 clearTimeout(this.timeout);
21062 this.hoverState = 'in'
21063 //Roo.log("enter - show");
21064 if (!this.delay || !this.delay.show) {
21069 this.timeout = setTimeout(function () {
21070 if (_t.hoverState == 'in') {
21073 }, this.delay.show);
21077 clearTimeout(this.timeout);
21079 this.hoverState = 'out'
21080 if (!this.delay || !this.delay.hide) {
21086 this.timeout = setTimeout(function () {
21087 //Roo.log("leave - timeout");
21089 if (_t.hoverState == 'out') {
21091 Roo.bootstrap.Tooltip.currentEl = false;
21099 this.render(document.body);
21102 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21103 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21105 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21107 var placement = typeof this.placement == 'function' ?
21108 this.placement.call(this, this.el, on_el) :
21111 var autoToken = /\s?auto?\s?/i;
21112 var autoPlace = autoToken.test(placement);
21114 placement = placement.replace(autoToken, '') || 'top';
21118 //this.el.setXY([0,0]);
21120 //this.el.dom.style.display='block';
21121 this.el.addClass(placement);
21123 //this.el.appendTo(on_el);
21125 var p = this.getPosition();
21126 var box = this.el.getBox();
21131 var align = Roo.bootstrap.Tooltip.alignment[placement]
21132 this.el.alignTo(this.bindEl, align[0],align[1]);
21133 //var arrow = this.el.select('.arrow',true).first();
21134 //arrow.set(align[2],
21136 this.el.addClass('in fade');
21137 this.hoverState = null;
21139 if (this.el.hasClass('fade')) {
21150 //this.el.setXY([0,0]);
21151 this.el.removeClass('in');
21167 * @class Roo.bootstrap.LocationPicker
21168 * @extends Roo.bootstrap.Component
21169 * Bootstrap LocationPicker class
21170 * @cfg {Number} latitude Position when init default 0
21171 * @cfg {Number} longitude Position when init default 0
21172 * @cfg {Number} zoom default 15
21173 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21174 * @cfg {Boolean} mapTypeControl default false
21175 * @cfg {Boolean} disableDoubleClickZoom default false
21176 * @cfg {Boolean} scrollwheel default true
21177 * @cfg {Boolean} streetViewControl default false
21178 * @cfg {Number} radius default 0
21179 * @cfg {String} locationName
21180 * @cfg {Boolean} draggable default true
21181 * @cfg {Boolean} enableAutocomplete default false
21182 * @cfg {Boolean} enableReverseGeocode default true
21183 * @cfg {String} markerTitle
21186 * Create a new LocationPicker
21187 * @param {Object} config The config object
21191 Roo.bootstrap.LocationPicker = function(config){
21193 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21198 * Fires when the picker initialized.
21199 * @param {Roo.bootstrap.LocationPicker} this
21200 * @param {Google Location} location
21204 * @event positionchanged
21205 * Fires when the picker position changed.
21206 * @param {Roo.bootstrap.LocationPicker} this
21207 * @param {Google Location} location
21209 positionchanged : true,
21212 * Fires when the map resize.
21213 * @param {Roo.bootstrap.LocationPicker} this
21218 * Fires when the map show.
21219 * @param {Roo.bootstrap.LocationPicker} this
21224 * Fires when the map hide.
21225 * @param {Roo.bootstrap.LocationPicker} this
21232 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
21234 gMapContext: false,
21240 mapTypeControl: false,
21241 disableDoubleClickZoom: false,
21243 streetViewControl: false,
21247 enableAutocomplete: false,
21248 enableReverseGeocode: true,
21251 getAutoCreate: function()
21256 cls: 'roo-location-picker'
21262 initEvents: function(ct, position)
21264 if(!this.mapTypeId){
21265 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
21268 if(!this.el.getWidth() || this.isApplied()){
21272 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21277 initial: function()
21279 this.gMapContext = this.GMapContext();
21283 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
21284 _this.setPosition(_this.gMapContext.marker.position);
21287 this.setPosition(this.gMapContext.location);
21289 this.fireEvent('initial', this, this.gMapContext.location);
21292 isApplied: function()
21294 return this.getGmapContext() == false ? false : true;
21297 getGmapContext: function()
21299 return this.gMapContext
21302 GMapContext: function()
21304 var _map = new google.maps.Map(this.el.dom, this);
21305 var _marker = new google.maps.Marker({
21306 position: new google.maps.LatLng(this.latitude, this.longitude),
21308 title: this.markerTitle,
21309 draggable: this.draggable
21316 location: _marker.position,
21317 radius: this.radius,
21318 locationName: this.locationName,
21319 addressComponents: {
21320 formatted_address: null,
21321 addressLine1: null,
21322 addressLine2: null,
21324 streetNumber: null,
21328 stateOrProvince: null
21331 domContainer: this.el.dom,
21332 geodecoder: new google.maps.Geocoder()
21336 drawCircle: function(center, radius, options)
21338 if (this.gMapContext.circle != null) {
21339 this.gMapContext.circle.setMap(null);
21343 options = Roo.apply({}, options, {
21344 strokeColor: "#0000FF",
21345 strokeOpacity: .35,
21347 fillColor: "#0000FF",
21351 options.map = this.gMapContext.map;
21352 options.radius = radius;
21353 options.center = center;
21354 this.gMapContext.circle = new google.maps.Circle(options);
21355 return this.gMapContext.circle;
21361 setPosition: function(location)
21363 this.gMapContext.location = location;
21364 this.gMapContext.marker.setPosition(location);
21365 this.gMapContext.map.panTo(location);
21366 this.drawCircle(location, this.gMapContext.radius, {});
21370 if (this.gMapContext.settings.enableReverseGeocode) {
21371 this.gMapContext.geodecoder.geocode({
21372 latLng: this.gMapContext.location
21373 }, function(results, status) {
21375 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21376 _this.gMapContext.locationName = results[0].formatted_address;
21377 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21379 _this.fireEvent('positionchanged', this, location);
21386 this.fireEvent('positionchanged', this, location);
21391 google.maps.event.trigger(this.gMapContext.map, "resize");
21393 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
21395 this.fireEvent('resize', this);
21398 setPositionByLatLng: function(latitude, longitude)
21400 this.setPosition(new google.maps.LatLng(latitude, longitude));
21403 getCurrentPosition: function()
21406 latitude: this.gMapContext.location.lat(),
21407 longitude: this.gMapContext.location.lng()
21411 getAddressName: function()
21413 return this.gMapContext.locationName;
21416 getAddressComponents: function()
21418 return this.gMapContext.addressComponents;
21421 address_component_from_google_geocode: function(address_components)
21425 for (var i = 0; i < address_components.length; i++) {
21426 var component = address_components[i];
21427 if (component.types.indexOf("postal_code") >= 0) {
21428 result.postalCode = component.short_name;
21429 } else if (component.types.indexOf("street_number") >= 0) {
21430 result.streetNumber = component.short_name;
21431 } else if (component.types.indexOf("route") >= 0) {
21432 result.streetName = component.short_name;
21433 } else if (component.types.indexOf("neighborhood") >= 0) {
21434 result.city = component.short_name;
21435 } else if (component.types.indexOf("locality") >= 0) {
21436 result.city = component.short_name;
21437 } else if (component.types.indexOf("sublocality") >= 0) {
21438 result.district = component.short_name;
21439 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
21440 result.stateOrProvince = component.short_name;
21441 } else if (component.types.indexOf("country") >= 0) {
21442 result.country = component.short_name;
21446 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
21447 result.addressLine2 = "";
21451 setZoomLevel: function(zoom)
21453 this.gMapContext.map.setZoom(zoom);
21466 this.fireEvent('show', this);
21477 this.fireEvent('hide', this);
21489 * @class Roo.bootstrap.Alert
21490 * @extends Roo.bootstrap.Component
21491 * Bootstrap Alert class
21492 * @cfg {String} title The title of alert
21493 * @cfg {String} html The content of alert
21494 * @cfg {String} weight ( success | info | warning | danger )
21495 * @cfg {String} faicon font-awesomeicon
21498 * Create a new alert
21499 * @param {Object} config The config object
21503 Roo.bootstrap.Alert = function(config){
21504 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
21508 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
21515 getAutoCreate : function()
21524 cls : 'roo-alert-icon'
21529 cls : 'roo-alert-title',
21534 cls : 'roo-alert-text',
21541 cfg.cn[0].cls += ' fa ' + this.faicon;
21545 cfg.cls += ' alert-' + this.weight;
21551 initEvents: function()
21553 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21556 setTitle : function(str)
21558 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
21561 setText : function(str)
21563 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
21566 setWeight : function(weight)
21569 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
21572 this.weight = weight;
21574 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
21577 setIcon : function(icon)
21580 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
21585 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);