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 * Returns the id of the column at the specified index.
4457 * @param {Number} index The column index
4458 * @return {String} the id
4460 getColumnId : function(index){
4461 return this.config[index].id;
4465 * Returns the column for a specified id.
4466 * @param {String} id The column id
4467 * @return {Object} the column
4469 getColumnById : function(id){
4470 return this.lookup[id];
4475 * Returns the column for a specified dataIndex.
4476 * @param {String} dataIndex The column dataIndex
4477 * @return {Object|Boolean} the column or false if not found
4479 getColumnByDataIndex: function(dataIndex){
4480 var index = this.findColumnIndex(dataIndex);
4481 return index > -1 ? this.config[index] : false;
4485 * Returns the index for a specified column id.
4486 * @param {String} id The column id
4487 * @return {Number} the index, or -1 if not found
4489 getIndexById : function(id){
4490 for(var i = 0, len = this.config.length; i < len; i++){
4491 if(this.config[i].id == id){
4499 * Returns the index for a specified column dataIndex.
4500 * @param {String} dataIndex The column dataIndex
4501 * @return {Number} the index, or -1 if not found
4504 findColumnIndex : function(dataIndex){
4505 for(var i = 0, len = this.config.length; i < len; i++){
4506 if(this.config[i].dataIndex == dataIndex){
4514 moveColumn : function(oldIndex, newIndex){
4515 var c = this.config[oldIndex];
4516 this.config.splice(oldIndex, 1);
4517 this.config.splice(newIndex, 0, c);
4518 this.dataMap = null;
4519 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4522 isLocked : function(colIndex){
4523 return this.config[colIndex].locked === true;
4526 setLocked : function(colIndex, value, suppressEvent){
4527 if(this.isLocked(colIndex) == value){
4530 this.config[colIndex].locked = value;
4532 this.fireEvent("columnlockchange", this, colIndex, value);
4536 getTotalLockedWidth : function(){
4538 for(var i = 0; i < this.config.length; i++){
4539 if(this.isLocked(i) && !this.isHidden(i)){
4540 this.totalWidth += this.getColumnWidth(i);
4546 getLockedCount : function(){
4547 for(var i = 0, len = this.config.length; i < len; i++){
4548 if(!this.isLocked(i)){
4555 * Returns the number of columns.
4558 getColumnCount : function(visibleOnly){
4559 if(visibleOnly === true){
4561 for(var i = 0, len = this.config.length; i < len; i++){
4562 if(!this.isHidden(i)){
4568 return this.config.length;
4572 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4573 * @param {Function} fn
4574 * @param {Object} scope (optional)
4575 * @return {Array} result
4577 getColumnsBy : function(fn, scope){
4579 for(var i = 0, len = this.config.length; i < len; i++){
4580 var c = this.config[i];
4581 if(fn.call(scope||this, c, i) === true){
4589 * Returns true if the specified column is sortable.
4590 * @param {Number} col The column index
4593 isSortable : function(col){
4594 if(typeof this.config[col].sortable == "undefined"){
4595 return this.defaultSortable;
4597 return this.config[col].sortable;
4601 * Returns the rendering (formatting) function defined for the column.
4602 * @param {Number} col The column index.
4603 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4605 getRenderer : function(col){
4606 if(!this.config[col].renderer){
4607 return Roo.grid.ColumnModel.defaultRenderer;
4609 return this.config[col].renderer;
4613 * Sets the rendering (formatting) function for a column.
4614 * @param {Number} col The column index
4615 * @param {Function} fn The function to use to process the cell's raw data
4616 * to return HTML markup for the grid view. The render function is called with
4617 * the following parameters:<ul>
4618 * <li>Data value.</li>
4619 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4620 * <li>css A CSS style string to apply to the table cell.</li>
4621 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4622 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4623 * <li>Row index</li>
4624 * <li>Column index</li>
4625 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4627 setRenderer : function(col, fn){
4628 this.config[col].renderer = fn;
4632 * Returns the width for the specified column.
4633 * @param {Number} col The column index
4636 getColumnWidth : function(col){
4637 return this.config[col].width * 1 || this.defaultWidth;
4641 * Sets the width for a column.
4642 * @param {Number} col The column index
4643 * @param {Number} width The new width
4645 setColumnWidth : function(col, width, suppressEvent){
4646 this.config[col].width = width;
4647 this.totalWidth = null;
4649 this.fireEvent("widthchange", this, col, width);
4654 * Returns the total width of all columns.
4655 * @param {Boolean} includeHidden True to include hidden column widths
4658 getTotalWidth : function(includeHidden){
4659 if(!this.totalWidth){
4660 this.totalWidth = 0;
4661 for(var i = 0, len = this.config.length; i < len; i++){
4662 if(includeHidden || !this.isHidden(i)){
4663 this.totalWidth += this.getColumnWidth(i);
4667 return this.totalWidth;
4671 * Returns the header for the specified column.
4672 * @param {Number} col The column index
4675 getColumnHeader : function(col){
4676 return this.config[col].header;
4680 * Sets the header for a column.
4681 * @param {Number} col The column index
4682 * @param {String} header The new header
4684 setColumnHeader : function(col, header){
4685 this.config[col].header = header;
4686 this.fireEvent("headerchange", this, col, header);
4690 * Returns the tooltip for the specified column.
4691 * @param {Number} col The column index
4694 getColumnTooltip : function(col){
4695 return this.config[col].tooltip;
4698 * Sets the tooltip for a column.
4699 * @param {Number} col The column index
4700 * @param {String} tooltip The new tooltip
4702 setColumnTooltip : function(col, tooltip){
4703 this.config[col].tooltip = tooltip;
4707 * Returns the dataIndex for the specified column.
4708 * @param {Number} col The column index
4711 getDataIndex : function(col){
4712 return this.config[col].dataIndex;
4716 * Sets the dataIndex for a column.
4717 * @param {Number} col The column index
4718 * @param {Number} dataIndex The new dataIndex
4720 setDataIndex : function(col, dataIndex){
4721 this.config[col].dataIndex = dataIndex;
4727 * Returns true if the cell is editable.
4728 * @param {Number} colIndex The column index
4729 * @param {Number} rowIndex The row index
4732 isCellEditable : function(colIndex, rowIndex){
4733 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4737 * Returns the editor defined for the cell/column.
4738 * return false or null to disable editing.
4739 * @param {Number} colIndex The column index
4740 * @param {Number} rowIndex The row index
4743 getCellEditor : function(colIndex, rowIndex){
4744 return this.config[colIndex].editor;
4748 * Sets if a column is editable.
4749 * @param {Number} col The column index
4750 * @param {Boolean} editable True if the column is editable
4752 setEditable : function(col, editable){
4753 this.config[col].editable = editable;
4758 * Returns true if the column is hidden.
4759 * @param {Number} colIndex The column index
4762 isHidden : function(colIndex){
4763 return this.config[colIndex].hidden;
4768 * Returns true if the column width cannot be changed
4770 isFixed : function(colIndex){
4771 return this.config[colIndex].fixed;
4775 * Returns true if the column can be resized
4778 isResizable : function(colIndex){
4779 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4782 * Sets if a column is hidden.
4783 * @param {Number} colIndex The column index
4784 * @param {Boolean} hidden True if the column is hidden
4786 setHidden : function(colIndex, hidden){
4787 this.config[colIndex].hidden = hidden;
4788 this.totalWidth = null;
4789 this.fireEvent("hiddenchange", this, colIndex, hidden);
4793 * Sets the editor for a column.
4794 * @param {Number} col The column index
4795 * @param {Object} editor The editor object
4797 setEditor : function(col, editor){
4798 this.config[col].editor = editor;
4802 Roo.grid.ColumnModel.defaultRenderer = function(value){
4803 if(typeof value == "string" && value.length < 1){
4809 // Alias for backwards compatibility
4810 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4813 * Ext JS Library 1.1.1
4814 * Copyright(c) 2006-2007, Ext JS, LLC.
4816 * Originally Released Under LGPL - original licence link has changed is not relivant.
4819 * <script type="text/javascript">
4823 * @class Roo.LoadMask
4824 * A simple utility class for generically masking elements while loading data. If the element being masked has
4825 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4826 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4827 * element's UpdateManager load indicator and will be destroyed after the initial load.
4829 * Create a new LoadMask
4830 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4831 * @param {Object} config The config object
4833 Roo.LoadMask = function(el, config){
4834 this.el = Roo.get(el);
4835 Roo.apply(this, config);
4837 this.store.on('beforeload', this.onBeforeLoad, this);
4838 this.store.on('load', this.onLoad, this);
4839 this.store.on('loadexception', this.onLoadException, this);
4840 this.removeMask = false;
4842 var um = this.el.getUpdateManager();
4843 um.showLoadIndicator = false; // disable the default indicator
4844 um.on('beforeupdate', this.onBeforeLoad, this);
4845 um.on('update', this.onLoad, this);
4846 um.on('failure', this.onLoad, this);
4847 this.removeMask = true;
4851 Roo.LoadMask.prototype = {
4853 * @cfg {Boolean} removeMask
4854 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4855 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4859 * The text to display in a centered loading message box (defaults to 'Loading...')
4863 * @cfg {String} msgCls
4864 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4866 msgCls : 'x-mask-loading',
4869 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4875 * Disables the mask to prevent it from being displayed
4877 disable : function(){
4878 this.disabled = true;
4882 * Enables the mask so that it can be displayed
4884 enable : function(){
4885 this.disabled = false;
4888 onLoadException : function()
4892 if (typeof(arguments[3]) != 'undefined') {
4893 Roo.MessageBox.alert("Error loading",arguments[3]);
4897 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4898 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4907 this.el.unmask(this.removeMask);
4912 this.el.unmask(this.removeMask);
4916 onBeforeLoad : function(){
4918 this.el.mask(this.msg, this.msgCls);
4923 destroy : function(){
4925 this.store.un('beforeload', this.onBeforeLoad, this);
4926 this.store.un('load', this.onLoad, this);
4927 this.store.un('loadexception', this.onLoadException, this);
4929 var um = this.el.getUpdateManager();
4930 um.un('beforeupdate', this.onBeforeLoad, this);
4931 um.un('update', this.onLoad, this);
4932 um.un('failure', this.onLoad, this);
4943 * @class Roo.bootstrap.Table
4944 * @extends Roo.bootstrap.Component
4945 * Bootstrap Table class
4946 * @cfg {String} cls table class
4947 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4948 * @cfg {String} bgcolor Specifies the background color for a table
4949 * @cfg {Number} border Specifies whether the table cells should have borders or not
4950 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4951 * @cfg {Number} cellspacing Specifies the space between cells
4952 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4953 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4954 * @cfg {String} sortable Specifies that the table should be sortable
4955 * @cfg {String} summary Specifies a summary of the content of a table
4956 * @cfg {Number} width Specifies the width of a table
4957 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4959 * @cfg {boolean} striped Should the rows be alternative striped
4960 * @cfg {boolean} bordered Add borders to the table
4961 * @cfg {boolean} hover Add hover highlighting
4962 * @cfg {boolean} condensed Format condensed
4963 * @cfg {boolean} responsive Format condensed
4964 * @cfg {Boolean} loadMask (true|false) default false
4965 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4966 * @cfg {Boolean} thead (true|false) generate thead, default true
4967 * @cfg {Boolean} RowSelection (true|false) default false
4968 * @cfg {Boolean} CellSelection (true|false) default false
4969 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4973 * Create a new Table
4974 * @param {Object} config The config object
4977 Roo.bootstrap.Table = function(config){
4978 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4981 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4982 this.sm = this.selModel;
4983 this.sm.xmodule = this.xmodule || false;
4985 if (this.cm && typeof(this.cm.config) == 'undefined') {
4986 this.colModel = new Roo.grid.ColumnModel(this.cm);
4987 this.cm = this.colModel;
4988 this.cm.xmodule = this.xmodule || false;
4991 this.store= Roo.factory(this.store, Roo.data);
4992 this.ds = this.store;
4993 this.ds.xmodule = this.xmodule || false;
4996 if (this.footer && this.store) {
4997 this.footer.dataSource = this.ds;
4998 this.footer = Roo.factory(this.footer);
5005 * Fires when a cell is clicked
5006 * @param {Roo.bootstrap.Table} this
5007 * @param {Roo.Element} el
5008 * @param {Number} rowIndex
5009 * @param {Number} columnIndex
5010 * @param {Roo.EventObject} e
5014 * @event celldblclick
5015 * Fires when a cell is double clicked
5016 * @param {Roo.bootstrap.Table} this
5017 * @param {Roo.Element} el
5018 * @param {Number} rowIndex
5019 * @param {Number} columnIndex
5020 * @param {Roo.EventObject} e
5022 "celldblclick" : true,
5025 * Fires when a row is clicked
5026 * @param {Roo.bootstrap.Table} this
5027 * @param {Roo.Element} el
5028 * @param {Number} rowIndex
5029 * @param {Roo.EventObject} e
5033 * @event rowdblclick
5034 * Fires when a row is double clicked
5035 * @param {Roo.bootstrap.Table} this
5036 * @param {Roo.Element} el
5037 * @param {Number} rowIndex
5038 * @param {Roo.EventObject} e
5040 "rowdblclick" : true,
5043 * Fires when a mouseover occur
5044 * @param {Roo.bootstrap.Table} this
5045 * @param {Roo.Element} el
5046 * @param {Number} rowIndex
5047 * @param {Number} columnIndex
5048 * @param {Roo.EventObject} e
5053 * Fires when a mouseout occur
5054 * @param {Roo.bootstrap.Table} this
5055 * @param {Roo.Element} el
5056 * @param {Number} rowIndex
5057 * @param {Number} columnIndex
5058 * @param {Roo.EventObject} e
5063 * Fires when a row is rendered, so you can change add a style to it.
5064 * @param {Roo.bootstrap.Table} this
5065 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5072 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5096 RowSelection : false,
5097 CellSelection : false,
5100 // Roo.Element - the tbody
5103 getAutoCreate : function(){
5104 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5113 cfg.cls += ' table-striped';
5117 cfg.cls += ' table-hover';
5119 if (this.bordered) {
5120 cfg.cls += ' table-bordered';
5122 if (this.condensed) {
5123 cfg.cls += ' table-condensed';
5125 if (this.responsive) {
5126 cfg.cls += ' table-responsive';
5130 cfg.cls+= ' ' +this.cls;
5133 // this lot should be simplifed...
5136 cfg.align=this.align;
5139 cfg.bgcolor=this.bgcolor;
5142 cfg.border=this.border;
5144 if (this.cellpadding) {
5145 cfg.cellpadding=this.cellpadding;
5147 if (this.cellspacing) {
5148 cfg.cellspacing=this.cellspacing;
5151 cfg.frame=this.frame;
5154 cfg.rules=this.rules;
5156 if (this.sortable) {
5157 cfg.sortable=this.sortable;
5160 cfg.summary=this.summary;
5163 cfg.width=this.width;
5166 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5169 if(this.store || this.cm){
5171 cfg.cn.push(this.renderHeader());
5174 cfg.cn.push(this.renderBody());
5177 cfg.cn.push(this.renderFooter());
5180 cfg.cls+= ' TableGrid';
5183 return { cn : [ cfg ] };
5186 initEvents : function()
5188 if(!this.store || !this.cm){
5192 //Roo.log('initEvents with ds!!!!');
5194 this.mainBody = this.el.select('tbody', true).first();
5199 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5200 e.on('click', _this.sort, _this);
5203 this.el.on("click", this.onClick, this);
5204 this.el.on("dblclick", this.onDblClick, this);
5206 // why is this done????? = it breaks dialogs??
5207 //this.parent().el.setStyle('position', 'relative');
5211 this.footer.parentId = this.id;
5212 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5215 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5217 this.store.on('load', this.onLoad, this);
5218 this.store.on('beforeload', this.onBeforeLoad, this);
5219 this.store.on('update', this.onUpdate, this);
5220 this.store.on('add', this.onAdd, this);
5224 onMouseover : function(e, el)
5226 var cell = Roo.get(el);
5232 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5233 cell = cell.findParent('td', false, true);
5236 var row = cell.findParent('tr', false, true);
5237 var cellIndex = cell.dom.cellIndex;
5238 var rowIndex = row.dom.rowIndex - 1; // start from 0
5240 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5244 onMouseout : function(e, el)
5246 var cell = Roo.get(el);
5252 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5253 cell = cell.findParent('td', false, true);
5256 var row = cell.findParent('tr', false, true);
5257 var cellIndex = cell.dom.cellIndex;
5258 var rowIndex = row.dom.rowIndex - 1; // start from 0
5260 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5264 onClick : function(e, el)
5266 var cell = Roo.get(el);
5268 if(!cell || (!this.CellSelection && !this.RowSelection)){
5273 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5274 cell = cell.findParent('td', false, true);
5277 var row = cell.findParent('tr', false, true);
5278 var cellIndex = cell.dom.cellIndex;
5279 var rowIndex = row.dom.rowIndex - 1;
5281 if(this.CellSelection){
5282 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5285 if(this.RowSelection){
5286 this.fireEvent('rowclick', this, row, rowIndex, e);
5292 onDblClick : function(e,el)
5294 var cell = Roo.get(el);
5296 if(!cell || (!this.CellSelection && !this.RowSelection)){
5300 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5301 cell = cell.findParent('td', false, true);
5304 var row = cell.findParent('tr', false, true);
5305 var cellIndex = cell.dom.cellIndex;
5306 var rowIndex = row.dom.rowIndex - 1;
5308 if(this.CellSelection){
5309 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5312 if(this.RowSelection){
5313 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5317 sort : function(e,el)
5319 var col = Roo.get(el)
5321 if(!col.hasClass('sortable')){
5325 var sort = col.attr('sort');
5328 if(col.hasClass('glyphicon-arrow-up')){
5332 this.store.sortInfo = {field : sort, direction : dir};
5335 Roo.log("calling footer first");
5336 this.footer.onClick('first');
5339 this.store.load({ params : { start : 0 } });
5343 renderHeader : function()
5352 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5354 var config = cm.config[i];
5359 html: cm.getColumnHeader(i)
5362 if(typeof(config.hidden) != 'undefined' && config.hidden){
5363 c.style += ' display:none;';
5366 if(typeof(config.dataIndex) != 'undefined'){
5367 c.sort = config.dataIndex;
5370 if(typeof(config.sortable) != 'undefined' && config.sortable){
5374 if(typeof(config.align) != 'undefined' && config.align.length){
5375 c.style += ' text-align:' + config.align + ';';
5378 if(typeof(config.width) != 'undefined'){
5379 c.style += ' width:' + config.width + 'px;';
5388 renderBody : function()
5398 colspan : this.cm.getColumnCount()
5408 renderFooter : function()
5418 colspan : this.cm.getColumnCount()
5432 Roo.log('ds onload');
5437 var ds = this.store;
5439 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5440 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5442 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5443 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5446 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5447 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5451 var tbody = this.mainBody;
5453 if(ds.getCount() > 0){
5454 ds.data.each(function(d,rowIndex){
5455 var row = this.renderRow(cm, ds, rowIndex);
5457 tbody.createChild(row);
5461 if(row.cellObjects.length){
5462 Roo.each(row.cellObjects, function(r){
5463 _this.renderCellObject(r);
5470 Roo.each(this.el.select('tbody td', true).elements, function(e){
5471 e.on('mouseover', _this.onMouseover, _this);
5474 Roo.each(this.el.select('tbody td', true).elements, function(e){
5475 e.on('mouseout', _this.onMouseout, _this);
5478 //if(this.loadMask){
5479 // this.maskEl.hide();
5484 onUpdate : function(ds,record)
5486 this.refreshRow(record);
5488 onRemove : function(ds, record, index, isUpdate){
5489 if(isUpdate !== true){
5490 this.fireEvent("beforerowremoved", this, index, record);
5492 var bt = this.mainBody.dom;
5494 bt.removeChild(bt.rows[index]);
5497 if(isUpdate !== true){
5498 //this.stripeRows(index);
5499 //this.syncRowHeights(index, index);
5501 this.fireEvent("rowremoved", this, index, record);
5505 onAdd : function(ds, records, rowIndex)
5507 //Roo.log('on Add called');
5508 // - note this does not handle multiple adding very well..
5509 var bt = this.mainBody.dom;
5510 for (var i =0 ; i < records.length;i++) {
5511 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5512 //Roo.log(records[i]);
5513 //Roo.log(this.store.getAt(rowIndex+i));
5514 this.insertRow(this.store, rowIndex + i, false);
5521 refreshRow : function(record){
5522 var ds = this.store, index;
5523 if(typeof record == 'number'){
5525 record = ds.getAt(index);
5527 index = ds.indexOf(record);
5529 this.insertRow(ds, index, true);
5530 this.onRemove(ds, record, index+1, true);
5531 //this.syncRowHeights(index, index);
5533 this.fireEvent("rowupdated", this, index, record);
5536 insertRow : function(dm, rowIndex, isUpdate){
5539 this.fireEvent("beforerowsinserted", this, rowIndex);
5541 //var s = this.getScrollState();
5542 var row = this.renderRow(this.cm, this.store, rowIndex);
5543 // insert before rowIndex..
5544 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5548 if(row.cellObjects.length){
5549 Roo.each(row.cellObjects, function(r){
5550 _this.renderCellObject(r);
5555 this.fireEvent("rowsinserted", this, rowIndex);
5556 //this.syncRowHeights(firstRow, lastRow);
5557 //this.stripeRows(firstRow);
5564 getRowDom : function(rowIndex)
5566 // not sure if I need to check this.. but let's do it anyway..
5567 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5568 this.mainBody.dom.rows[rowIndex] : false
5570 // returns the object tree for a tr..
5573 renderRow : function(cm, ds, rowIndex) {
5575 var d = ds.getAt(rowIndex);
5582 var cellObjects = [];
5584 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5585 var config = cm.config[i];
5587 var renderer = cm.getRenderer(i);
5591 if(typeof(renderer) !== 'undefined'){
5592 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5594 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5595 // and are rendered into the cells after the row is rendered - using the id for the element.
5597 if(typeof(value) === 'object'){
5607 rowIndex : rowIndex,
5612 this.fireEvent('rowclass', this, rowcfg);
5616 cls : rowcfg.rowClass,
5618 html: (typeof(value) === 'object') ? '' : value
5625 if(typeof(config.hidden) != 'undefined' && config.hidden){
5626 td.style += ' display:none;';
5629 if(typeof(config.align) != 'undefined' && config.align.length){
5630 td.style += ' text-align:' + config.align + ';';
5633 if(typeof(config.width) != 'undefined'){
5634 td.style += ' width:' + config.width + 'px;';
5637 if(typeof(config.cursor) != 'undefined'){
5638 td.style += ' cursor:' + config.cursor + ';';
5645 row.cellObjects = cellObjects;
5653 onBeforeLoad : function()
5655 //Roo.log('ds onBeforeLoad');
5659 //if(this.loadMask){
5660 // this.maskEl.show();
5668 this.el.select('tbody', true).first().dom.innerHTML = '';
5671 * Show or hide a row.
5672 * @param {Number} rowIndex to show or hide
5673 * @param {Boolean} state hide
5675 setRowVisibility : function(rowIndex, state)
5677 var bt = this.mainBody.dom;
5678 if(typeof(bt.rows[rowIndex]) == 'undefined'){
5681 bt.rows[rowIndex].style.display = state ? '' : 'none';
5685 getSelectionModel : function(){
5687 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5689 return this.selModel;
5692 * Render the Roo.bootstrap object from renderder
5694 renderCellObject : function(r)
5698 var t = r.cfg.render(r.container);
5701 Roo.each(r.cfg.cn, function(c){
5703 container: t.getChildContainer(),
5706 _this.renderCellObject(child);
5723 * @class Roo.bootstrap.TableCell
5724 * @extends Roo.bootstrap.Component
5725 * Bootstrap TableCell class
5726 * @cfg {String} html cell contain text
5727 * @cfg {String} cls cell class
5728 * @cfg {String} tag cell tag (td|th) default td
5729 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5730 * @cfg {String} align Aligns the content in a cell
5731 * @cfg {String} axis Categorizes cells
5732 * @cfg {String} bgcolor Specifies the background color of a cell
5733 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5734 * @cfg {Number} colspan Specifies the number of columns a cell should span
5735 * @cfg {String} headers Specifies one or more header cells a cell is related to
5736 * @cfg {Number} height Sets the height of a cell
5737 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5738 * @cfg {Number} rowspan Sets the number of rows a cell should span
5739 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5740 * @cfg {String} valign Vertical aligns the content in a cell
5741 * @cfg {Number} width Specifies the width of a cell
5744 * Create a new TableCell
5745 * @param {Object} config The config object
5748 Roo.bootstrap.TableCell = function(config){
5749 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5752 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5772 getAutoCreate : function(){
5773 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5793 cfg.align=this.align
5799 cfg.bgcolor=this.bgcolor
5802 cfg.charoff=this.charoff
5805 cfg.colspan=this.colspan
5808 cfg.headers=this.headers
5811 cfg.height=this.height
5814 cfg.nowrap=this.nowrap
5817 cfg.rowspan=this.rowspan
5820 cfg.scope=this.scope
5823 cfg.valign=this.valign
5826 cfg.width=this.width
5845 * @class Roo.bootstrap.TableRow
5846 * @extends Roo.bootstrap.Component
5847 * Bootstrap TableRow class
5848 * @cfg {String} cls row class
5849 * @cfg {String} align Aligns the content in a table row
5850 * @cfg {String} bgcolor Specifies a background color for a table row
5851 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5852 * @cfg {String} valign Vertical aligns the content in a table row
5855 * Create a new TableRow
5856 * @param {Object} config The config object
5859 Roo.bootstrap.TableRow = function(config){
5860 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5863 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5871 getAutoCreate : function(){
5872 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5882 cfg.align = this.align;
5885 cfg.bgcolor = this.bgcolor;
5888 cfg.charoff = this.charoff;
5891 cfg.valign = this.valign;
5909 * @class Roo.bootstrap.TableBody
5910 * @extends Roo.bootstrap.Component
5911 * Bootstrap TableBody class
5912 * @cfg {String} cls element class
5913 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5914 * @cfg {String} align Aligns the content inside the element
5915 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5916 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5919 * Create a new TableBody
5920 * @param {Object} config The config object
5923 Roo.bootstrap.TableBody = function(config){
5924 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5927 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5935 getAutoCreate : function(){
5936 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5950 cfg.align = this.align;
5953 cfg.charoff = this.charoff;
5956 cfg.valign = this.valign;
5963 // initEvents : function()
5970 // this.store = Roo.factory(this.store, Roo.data);
5971 // this.store.on('load', this.onLoad, this);
5973 // this.store.load();
5977 // onLoad: function ()
5979 // this.fireEvent('load', this);
5989 * Ext JS Library 1.1.1
5990 * Copyright(c) 2006-2007, Ext JS, LLC.
5992 * Originally Released Under LGPL - original licence link has changed is not relivant.
5995 * <script type="text/javascript">
5998 // as we use this in bootstrap.
5999 Roo.namespace('Roo.form');
6001 * @class Roo.form.Action
6002 * Internal Class used to handle form actions
6004 * @param {Roo.form.BasicForm} el The form element or its id
6005 * @param {Object} config Configuration options
6010 // define the action interface
6011 Roo.form.Action = function(form, options){
6013 this.options = options || {};
6016 * Client Validation Failed
6019 Roo.form.Action.CLIENT_INVALID = 'client';
6021 * Server Validation Failed
6024 Roo.form.Action.SERVER_INVALID = 'server';
6026 * Connect to Server Failed
6029 Roo.form.Action.CONNECT_FAILURE = 'connect';
6031 * Reading Data from Server Failed
6034 Roo.form.Action.LOAD_FAILURE = 'load';
6036 Roo.form.Action.prototype = {
6038 failureType : undefined,
6039 response : undefined,
6043 run : function(options){
6048 success : function(response){
6053 handleResponse : function(response){
6057 // default connection failure
6058 failure : function(response){
6060 this.response = response;
6061 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6062 this.form.afterAction(this, false);
6065 processResponse : function(response){
6066 this.response = response;
6067 if(!response.responseText){
6070 this.result = this.handleResponse(response);
6074 // utility functions used internally
6075 getUrl : function(appendParams){
6076 var url = this.options.url || this.form.url || this.form.el.dom.action;
6078 var p = this.getParams();
6080 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6086 getMethod : function(){
6087 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6090 getParams : function(){
6091 var bp = this.form.baseParams;
6092 var p = this.options.params;
6094 if(typeof p == "object"){
6095 p = Roo.urlEncode(Roo.applyIf(p, bp));
6096 }else if(typeof p == 'string' && bp){
6097 p += '&' + Roo.urlEncode(bp);
6100 p = Roo.urlEncode(bp);
6105 createCallback : function(){
6107 success: this.success,
6108 failure: this.failure,
6110 timeout: (this.form.timeout*1000),
6111 upload: this.form.fileUpload ? this.success : undefined
6116 Roo.form.Action.Submit = function(form, options){
6117 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6120 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6123 haveProgress : false,
6124 uploadComplete : false,
6126 // uploadProgress indicator.
6127 uploadProgress : function()
6129 if (!this.form.progressUrl) {
6133 if (!this.haveProgress) {
6134 Roo.MessageBox.progress("Uploading", "Uploading");
6136 if (this.uploadComplete) {
6137 Roo.MessageBox.hide();
6141 this.haveProgress = true;
6143 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6145 var c = new Roo.data.Connection();
6147 url : this.form.progressUrl,
6152 success : function(req){
6153 //console.log(data);
6157 rdata = Roo.decode(req.responseText)
6159 Roo.log("Invalid data from server..");
6163 if (!rdata || !rdata.success) {
6165 Roo.MessageBox.alert(Roo.encode(rdata));
6168 var data = rdata.data;
6170 if (this.uploadComplete) {
6171 Roo.MessageBox.hide();
6176 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6177 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6180 this.uploadProgress.defer(2000,this);
6183 failure: function(data) {
6184 Roo.log('progress url failed ');
6195 // run get Values on the form, so it syncs any secondary forms.
6196 this.form.getValues();
6198 var o = this.options;
6199 var method = this.getMethod();
6200 var isPost = method == 'POST';
6201 if(o.clientValidation === false || this.form.isValid()){
6203 if (this.form.progressUrl) {
6204 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6205 (new Date() * 1) + '' + Math.random());
6210 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6211 form:this.form.el.dom,
6212 url:this.getUrl(!isPost),
6214 params:isPost ? this.getParams() : null,
6215 isUpload: this.form.fileUpload
6218 this.uploadProgress();
6220 }else if (o.clientValidation !== false){ // client validation failed
6221 this.failureType = Roo.form.Action.CLIENT_INVALID;
6222 this.form.afterAction(this, false);
6226 success : function(response)
6228 this.uploadComplete= true;
6229 if (this.haveProgress) {
6230 Roo.MessageBox.hide();
6234 var result = this.processResponse(response);
6235 if(result === true || result.success){
6236 this.form.afterAction(this, true);
6240 this.form.markInvalid(result.errors);
6241 this.failureType = Roo.form.Action.SERVER_INVALID;
6243 this.form.afterAction(this, false);
6245 failure : function(response)
6247 this.uploadComplete= true;
6248 if (this.haveProgress) {
6249 Roo.MessageBox.hide();
6252 this.response = response;
6253 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6254 this.form.afterAction(this, false);
6257 handleResponse : function(response){
6258 if(this.form.errorReader){
6259 var rs = this.form.errorReader.read(response);
6262 for(var i = 0, len = rs.records.length; i < len; i++) {
6263 var r = rs.records[i];
6267 if(errors.length < 1){
6271 success : rs.success,
6277 ret = Roo.decode(response.responseText);
6281 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6291 Roo.form.Action.Load = function(form, options){
6292 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6293 this.reader = this.form.reader;
6296 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6301 Roo.Ajax.request(Roo.apply(
6302 this.createCallback(), {
6303 method:this.getMethod(),
6304 url:this.getUrl(false),
6305 params:this.getParams()
6309 success : function(response){
6311 var result = this.processResponse(response);
6312 if(result === true || !result.success || !result.data){
6313 this.failureType = Roo.form.Action.LOAD_FAILURE;
6314 this.form.afterAction(this, false);
6317 this.form.clearInvalid();
6318 this.form.setValues(result.data);
6319 this.form.afterAction(this, true);
6322 handleResponse : function(response){
6323 if(this.form.reader){
6324 var rs = this.form.reader.read(response);
6325 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6327 success : rs.success,
6331 return Roo.decode(response.responseText);
6335 Roo.form.Action.ACTION_TYPES = {
6336 'load' : Roo.form.Action.Load,
6337 'submit' : Roo.form.Action.Submit
6346 * @class Roo.bootstrap.Form
6347 * @extends Roo.bootstrap.Component
6348 * Bootstrap Form class
6349 * @cfg {String} method GET | POST (default POST)
6350 * @cfg {String} labelAlign top | left (default top)
6351 * @cfg {String} align left | right - for navbars
6352 * @cfg {Boolean} loadMask load mask when submit (default true)
6357 * @param {Object} config The config object
6361 Roo.bootstrap.Form = function(config){
6362 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6365 * @event clientvalidation
6366 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6367 * @param {Form} this
6368 * @param {Boolean} valid true if the form has passed client-side validation
6370 clientvalidation: true,
6372 * @event beforeaction
6373 * Fires before any action is performed. Return false to cancel the action.
6374 * @param {Form} this
6375 * @param {Action} action The action to be performed
6379 * @event actionfailed
6380 * Fires when an action fails.
6381 * @param {Form} this
6382 * @param {Action} action The action that failed
6384 actionfailed : true,
6386 * @event actioncomplete
6387 * Fires when an action is completed.
6388 * @param {Form} this
6389 * @param {Action} action The action that completed
6391 actioncomplete : true
6396 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6399 * @cfg {String} method
6400 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6405 * The URL to use for form actions if one isn't supplied in the action options.
6408 * @cfg {Boolean} fileUpload
6409 * Set to true if this form is a file upload.
6413 * @cfg {Object} baseParams
6414 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6418 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6422 * @cfg {Sting} align (left|right) for navbar forms
6427 activeAction : null,
6430 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6431 * element by passing it or its id or mask the form itself by passing in true.
6434 waitMsgTarget : false,
6438 getAutoCreate : function(){
6442 method : this.method || 'POST',
6443 id : this.id || Roo.id(),
6446 if (this.parent().xtype.match(/^Nav/)) {
6447 cfg.cls = 'navbar-form navbar-' + this.align;
6451 if (this.labelAlign == 'left' ) {
6452 cfg.cls += ' form-horizontal';
6458 initEvents : function()
6460 this.el.on('submit', this.onSubmit, this);
6461 // this was added as random key presses on the form where triggering form submit.
6462 this.el.on('keypress', function(e) {
6463 if (e.getCharCode() != 13) {
6466 // we might need to allow it for textareas.. and some other items.
6467 // check e.getTarget().
6469 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6473 Roo.log("keypress blocked");
6481 onSubmit : function(e){
6486 * Returns true if client-side validation on the form is successful.
6489 isValid : function(){
6490 var items = this.getItems();
6492 items.each(function(f){
6501 * Returns true if any fields in this form have changed since their original load.
6504 isDirty : function(){
6506 var items = this.getItems();
6507 items.each(function(f){
6517 * Performs a predefined action (submit or load) or custom actions you define on this form.
6518 * @param {String} actionName The name of the action type
6519 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6520 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6521 * accept other config options):
6523 Property Type Description
6524 ---------------- --------------- ----------------------------------------------------------------------------------
6525 url String The url for the action (defaults to the form's url)
6526 method String The form method to use (defaults to the form's method, or POST if not defined)
6527 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6528 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6529 validate the form on the client (defaults to false)
6531 * @return {BasicForm} this
6533 doAction : function(action, options){
6534 if(typeof action == 'string'){
6535 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6537 if(this.fireEvent('beforeaction', this, action) !== false){
6538 this.beforeAction(action);
6539 action.run.defer(100, action);
6545 beforeAction : function(action){
6546 var o = action.options;
6549 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6551 // not really supported yet.. ??
6553 //if(this.waitMsgTarget === true){
6554 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6555 //}else if(this.waitMsgTarget){
6556 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6557 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6559 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6565 afterAction : function(action, success){
6566 this.activeAction = null;
6567 var o = action.options;
6569 //if(this.waitMsgTarget === true){
6571 //}else if(this.waitMsgTarget){
6572 // this.waitMsgTarget.unmask();
6574 // Roo.MessageBox.updateProgress(1);
6575 // Roo.MessageBox.hide();
6582 Roo.callback(o.success, o.scope, [this, action]);
6583 this.fireEvent('actioncomplete', this, action);
6587 // failure condition..
6588 // we have a scenario where updates need confirming.
6589 // eg. if a locking scenario exists..
6590 // we look for { errors : { needs_confirm : true }} in the response.
6592 (typeof(action.result) != 'undefined') &&
6593 (typeof(action.result.errors) != 'undefined') &&
6594 (typeof(action.result.errors.needs_confirm) != 'undefined')
6597 Roo.log("not supported yet");
6600 Roo.MessageBox.confirm(
6601 "Change requires confirmation",
6602 action.result.errorMsg,
6607 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6617 Roo.callback(o.failure, o.scope, [this, action]);
6618 // show an error message if no failed handler is set..
6619 if (!this.hasListener('actionfailed')) {
6620 Roo.log("need to add dialog support");
6622 Roo.MessageBox.alert("Error",
6623 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6624 action.result.errorMsg :
6625 "Saving Failed, please check your entries or try again"
6630 this.fireEvent('actionfailed', this, action);
6635 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6636 * @param {String} id The value to search for
6639 findField : function(id){
6640 var items = this.getItems();
6641 var field = items.get(id);
6643 items.each(function(f){
6644 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6651 return field || null;
6654 * Mark fields in this form invalid in bulk.
6655 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6656 * @return {BasicForm} this
6658 markInvalid : function(errors){
6659 if(errors instanceof Array){
6660 for(var i = 0, len = errors.length; i < len; i++){
6661 var fieldError = errors[i];
6662 var f = this.findField(fieldError.id);
6664 f.markInvalid(fieldError.msg);
6670 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6671 field.markInvalid(errors[id]);
6675 //Roo.each(this.childForms || [], function (f) {
6676 // f.markInvalid(errors);
6683 * Set values for fields in this form in bulk.
6684 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6685 * @return {BasicForm} this
6687 setValues : function(values){
6688 if(values instanceof Array){ // array of objects
6689 for(var i = 0, len = values.length; i < len; i++){
6691 var f = this.findField(v.id);
6693 f.setValue(v.value);
6694 if(this.trackResetOnLoad){
6695 f.originalValue = f.getValue();
6699 }else{ // object hash
6702 if(typeof values[id] != 'function' && (field = this.findField(id))){
6704 if (field.setFromData &&
6706 field.displayField &&
6707 // combos' with local stores can
6708 // be queried via setValue()
6709 // to set their value..
6710 (field.store && !field.store.isLocal)
6714 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6715 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6716 field.setFromData(sd);
6719 field.setValue(values[id]);
6723 if(this.trackResetOnLoad){
6724 field.originalValue = field.getValue();
6730 //Roo.each(this.childForms || [], function (f) {
6731 // f.setValues(values);
6738 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6739 * they are returned as an array.
6740 * @param {Boolean} asString
6743 getValues : function(asString){
6744 //if (this.childForms) {
6745 // copy values from the child forms
6746 // Roo.each(this.childForms, function (f) {
6747 // this.setValues(f.getValues());
6753 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6754 if(asString === true){
6757 return Roo.urlDecode(fs);
6761 * Returns the fields in this form as an object with key/value pairs.
6762 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6765 getFieldValues : function(with_hidden)
6767 var items = this.getItems();
6769 items.each(function(f){
6773 var v = f.getValue();
6774 if (f.inputType =='radio') {
6775 if (typeof(ret[f.getName()]) == 'undefined') {
6776 ret[f.getName()] = ''; // empty..
6779 if (!f.el.dom.checked) {
6787 // not sure if this supported any more..
6788 if ((typeof(v) == 'object') && f.getRawValue) {
6789 v = f.getRawValue() ; // dates..
6791 // combo boxes where name != hiddenName...
6792 if (f.name != f.getName()) {
6793 ret[f.name] = f.getRawValue();
6795 ret[f.getName()] = v;
6802 * Clears all invalid messages in this form.
6803 * @return {BasicForm} this
6805 clearInvalid : function(){
6806 var items = this.getItems();
6808 items.each(function(f){
6819 * @return {BasicForm} this
6822 var items = this.getItems();
6823 items.each(function(f){
6827 Roo.each(this.childForms || [], function (f) {
6834 getItems : function()
6836 var r=new Roo.util.MixedCollection(false, function(o){
6837 return o.id || (o.id = Roo.id());
6839 var iter = function(el) {
6846 Roo.each(el.items,function(e) {
6865 * Ext JS Library 1.1.1
6866 * Copyright(c) 2006-2007, Ext JS, LLC.
6868 * Originally Released Under LGPL - original licence link has changed is not relivant.
6871 * <script type="text/javascript">
6874 * @class Roo.form.VTypes
6875 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6878 Roo.form.VTypes = function(){
6879 // closure these in so they are only created once.
6880 var alpha = /^[a-zA-Z_]+$/;
6881 var alphanum = /^[a-zA-Z0-9_]+$/;
6882 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6883 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6885 // All these messages and functions are configurable
6888 * The function used to validate email addresses
6889 * @param {String} value The email address
6891 'email' : function(v){
6892 return email.test(v);
6895 * The error text to display when the email validation function returns false
6898 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6900 * The keystroke filter mask to be applied on email input
6903 'emailMask' : /[a-z0-9_\.\-@]/i,
6906 * The function used to validate URLs
6907 * @param {String} value The URL
6909 'url' : function(v){
6913 * The error text to display when the url validation function returns false
6916 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6919 * The function used to validate alpha values
6920 * @param {String} value The value
6922 'alpha' : function(v){
6923 return alpha.test(v);
6926 * The error text to display when the alpha validation function returns false
6929 'alphaText' : 'This field should only contain letters and _',
6931 * The keystroke filter mask to be applied on alpha input
6934 'alphaMask' : /[a-z_]/i,
6937 * The function used to validate alphanumeric values
6938 * @param {String} value The value
6940 'alphanum' : function(v){
6941 return alphanum.test(v);
6944 * The error text to display when the alphanumeric validation function returns false
6947 'alphanumText' : 'This field should only contain letters, numbers and _',
6949 * The keystroke filter mask to be applied on alphanumeric input
6952 'alphanumMask' : /[a-z0-9_]/i
6962 * @class Roo.bootstrap.Input
6963 * @extends Roo.bootstrap.Component
6964 * Bootstrap Input class
6965 * @cfg {Boolean} disabled is it disabled
6966 * @cfg {String} fieldLabel - the label associated
6967 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6968 * @cfg {String} name name of the input
6969 * @cfg {string} fieldLabel - the label associated
6970 * @cfg {string} inputType - input / file submit ...
6971 * @cfg {string} placeholder - placeholder to put in text.
6972 * @cfg {string} before - input group add on before
6973 * @cfg {string} after - input group add on after
6974 * @cfg {string} size - (lg|sm) or leave empty..
6975 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6976 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6977 * @cfg {Number} md colspan out of 12 for computer-sized screens
6978 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6979 * @cfg {string} value default value of the input
6980 * @cfg {Number} labelWidth set the width of label (0-12)
6981 * @cfg {String} labelAlign (top|left)
6982 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6983 * @cfg {String} align (left|center|right) Default left
6987 * Create a new Input
6988 * @param {Object} config The config object
6991 Roo.bootstrap.Input = function(config){
6992 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6997 * Fires when this field receives input focus.
6998 * @param {Roo.form.Field} this
7003 * Fires when this field loses input focus.
7004 * @param {Roo.form.Field} this
7009 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7010 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7011 * @param {Roo.form.Field} this
7012 * @param {Roo.EventObject} e The event object
7017 * Fires just before the field blurs if the field value has changed.
7018 * @param {Roo.form.Field} this
7019 * @param {Mixed} newValue The new value
7020 * @param {Mixed} oldValue The original value
7025 * Fires after the field has been marked as invalid.
7026 * @param {Roo.form.Field} this
7027 * @param {String} msg The validation message
7032 * Fires after the field has been validated with no errors.
7033 * @param {Roo.form.Field} this
7038 * Fires after the key up
7039 * @param {Roo.form.Field} this
7040 * @param {Roo.EventObject} e The event Object
7046 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7048 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7049 automatic validation (defaults to "keyup").
7051 validationEvent : "keyup",
7053 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7055 validateOnBlur : true,
7057 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7059 validationDelay : 250,
7061 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7063 focusClass : "x-form-focus", // not needed???
7067 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7069 invalidClass : "has-error",
7072 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7074 selectOnFocus : false,
7077 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7081 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7086 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7088 disableKeyFilter : false,
7091 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7095 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7099 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7101 blankText : "This field is required",
7104 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7108 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7110 maxLength : Number.MAX_VALUE,
7112 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7114 minLengthText : "The minimum length for this field is {0}",
7116 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7118 maxLengthText : "The maximum length for this field is {0}",
7122 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7123 * If available, this function will be called only after the basic validators all return true, and will be passed the
7124 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7128 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7129 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7130 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7134 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7157 formatedValue : false,
7159 parentLabelAlign : function()
7162 while (parent.parent()) {
7163 parent = parent.parent();
7164 if (typeof(parent.labelAlign) !='undefined') {
7165 return parent.labelAlign;
7172 getAutoCreate : function(){
7174 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7180 if(this.inputType != 'hidden'){
7181 cfg.cls = 'form-group' //input-group
7187 type : this.inputType,
7189 cls : 'form-control',
7190 placeholder : this.placeholder || ''
7195 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7198 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7199 input.maxLength = this.maxLength;
7202 if (this.disabled) {
7203 input.disabled=true;
7206 if (this.readOnly) {
7207 input.readonly=true;
7211 input.name = this.name;
7214 input.cls += ' input-' + this.size;
7217 ['xs','sm','md','lg'].map(function(size){
7218 if (settings[size]) {
7219 cfg.cls += ' col-' + size + '-' + settings[size];
7223 var inputblock = input;
7225 if (this.before || this.after) {
7228 cls : 'input-group',
7231 if (this.before && typeof(this.before) == 'string') {
7233 inputblock.cn.push({
7235 cls : 'roo-input-before input-group-addon',
7239 if (this.before && typeof(this.before) == 'object') {
7240 this.before = Roo.factory(this.before);
7241 Roo.log(this.before);
7242 inputblock.cn.push({
7244 cls : 'roo-input-before input-group-' +
7245 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7249 inputblock.cn.push(input);
7251 if (this.after && typeof(this.after) == 'string') {
7252 inputblock.cn.push({
7254 cls : 'roo-input-after input-group-addon',
7258 if (this.after && typeof(this.after) == 'object') {
7259 this.after = Roo.factory(this.after);
7260 Roo.log(this.after);
7261 inputblock.cn.push({
7263 cls : 'roo-input-after input-group-' +
7264 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7269 if (align ==='left' && this.fieldLabel.length) {
7270 Roo.log("left and has label");
7276 cls : 'control-label col-sm-' + this.labelWidth,
7277 html : this.fieldLabel
7281 cls : "col-sm-" + (12 - this.labelWidth),
7288 } else if ( this.fieldLabel.length) {
7294 //cls : 'input-group-addon',
7295 html : this.fieldLabel
7305 Roo.log(" no label && no align");
7314 Roo.log('input-parentType: ' + this.parentType);
7316 if (this.parentType === 'Navbar' && this.parent().bar) {
7317 cfg.cls += ' navbar-form';
7325 * return the real input element.
7327 inputEl: function ()
7329 return this.el.select('input.form-control',true).first();
7332 tooltipEl : function()
7334 return this.inputEl();
7337 setDisabled : function(v)
7339 var i = this.inputEl().dom;
7341 i.removeAttribute('disabled');
7345 i.setAttribute('disabled','true');
7347 initEvents : function()
7350 this.inputEl().on("keydown" , this.fireKey, this);
7351 this.inputEl().on("focus", this.onFocus, this);
7352 this.inputEl().on("blur", this.onBlur, this);
7354 this.inputEl().relayEvent('keyup', this);
7356 // reference to original value for reset
7357 this.originalValue = this.getValue();
7358 //Roo.form.TextField.superclass.initEvents.call(this);
7359 if(this.validationEvent == 'keyup'){
7360 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7361 this.inputEl().on('keyup', this.filterValidation, this);
7363 else if(this.validationEvent !== false){
7364 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7367 if(this.selectOnFocus){
7368 this.on("focus", this.preFocus, this);
7371 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7372 this.inputEl().on("keypress", this.filterKeys, this);
7375 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7376 this.el.on("click", this.autoSize, this);
7379 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7380 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7383 if (typeof(this.before) == 'object') {
7384 this.before.render(this.el.select('.roo-input-before',true).first());
7386 if (typeof(this.after) == 'object') {
7387 this.after.render(this.el.select('.roo-input-after',true).first());
7392 filterValidation : function(e){
7393 if(!e.isNavKeyPress()){
7394 this.validationTask.delay(this.validationDelay);
7398 * Validates the field value
7399 * @return {Boolean} True if the value is valid, else false
7401 validate : function(){
7402 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7403 if(this.disabled || this.validateValue(this.getRawValue())){
7404 this.clearInvalid();
7412 * Validates a value according to the field's validation rules and marks the field as invalid
7413 * if the validation fails
7414 * @param {Mixed} value The value to validate
7415 * @return {Boolean} True if the value is valid, else false
7417 validateValue : function(value){
7418 if(value.length < 1) { // if it's blank
7419 if(this.allowBlank){
7420 this.clearInvalid();
7423 this.markInvalid(this.blankText);
7427 if(value.length < this.minLength){
7428 this.markInvalid(String.format(this.minLengthText, this.minLength));
7431 if(value.length > this.maxLength){
7432 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7436 var vt = Roo.form.VTypes;
7437 if(!vt[this.vtype](value, this)){
7438 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7442 if(typeof this.validator == "function"){
7443 var msg = this.validator(value);
7445 this.markInvalid(msg);
7449 if(this.regex && !this.regex.test(value)){
7450 this.markInvalid(this.regexText);
7459 fireKey : function(e){
7460 //Roo.log('field ' + e.getKey());
7461 if(e.isNavKeyPress()){
7462 this.fireEvent("specialkey", this, e);
7465 focus : function (selectText){
7467 this.inputEl().focus();
7468 if(selectText === true){
7469 this.inputEl().dom.select();
7475 onFocus : function(){
7476 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7477 // this.el.addClass(this.focusClass);
7480 this.hasFocus = true;
7481 this.startValue = this.getValue();
7482 this.fireEvent("focus", this);
7486 beforeBlur : Roo.emptyFn,
7490 onBlur : function(){
7492 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7493 //this.el.removeClass(this.focusClass);
7495 this.hasFocus = false;
7496 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7499 var v = this.getValue();
7500 if(String(v) !== String(this.startValue)){
7501 this.fireEvent('change', this, v, this.startValue);
7503 this.fireEvent("blur", this);
7507 * Resets the current field value to the originally loaded value and clears any validation messages
7510 this.setValue(this.originalValue);
7511 this.clearInvalid();
7514 * Returns the name of the field
7515 * @return {Mixed} name The name field
7517 getName: function(){
7521 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7522 * @return {Mixed} value The field value
7524 getValue : function(){
7526 var v = this.inputEl().getValue();
7531 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7532 * @return {Mixed} value The field value
7534 getRawValue : function(){
7535 var v = this.inputEl().getValue();
7541 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7542 * @param {Mixed} value The value to set
7544 setRawValue : function(v){
7545 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7548 selectText : function(start, end){
7549 var v = this.getRawValue();
7551 start = start === undefined ? 0 : start;
7552 end = end === undefined ? v.length : end;
7553 var d = this.inputEl().dom;
7554 if(d.setSelectionRange){
7555 d.setSelectionRange(start, end);
7556 }else if(d.createTextRange){
7557 var range = d.createTextRange();
7558 range.moveStart("character", start);
7559 range.moveEnd("character", v.length-end);
7566 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7567 * @param {Mixed} value The value to set
7569 setValue : function(v){
7572 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7578 processValue : function(value){
7579 if(this.stripCharsRe){
7580 var newValue = value.replace(this.stripCharsRe, '');
7581 if(newValue !== value){
7582 this.setRawValue(newValue);
7589 preFocus : function(){
7591 if(this.selectOnFocus){
7592 this.inputEl().dom.select();
7595 filterKeys : function(e){
7597 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7600 var c = e.getCharCode(), cc = String.fromCharCode(c);
7601 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7604 if(!this.maskRe.test(cc)){
7609 * Clear any invalid styles/messages for this field
7611 clearInvalid : function(){
7613 if(!this.el || this.preventMark){ // not rendered
7616 this.el.removeClass(this.invalidClass);
7618 switch(this.msgTarget){
7620 this.el.dom.qtip = '';
7623 this.el.dom.title = '';
7627 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7632 this.errorIcon.dom.qtip = '';
7633 this.errorIcon.hide();
7634 this.un('resize', this.alignErrorIcon, this);
7638 var t = Roo.getDom(this.msgTarget);
7640 t.style.display = 'none';
7644 this.fireEvent('valid', this);
7647 * Mark this field as invalid
7648 * @param {String} msg The validation message
7650 markInvalid : function(msg){
7651 if(!this.el || this.preventMark){ // not rendered
7654 this.el.addClass(this.invalidClass);
7656 msg = msg || this.invalidText;
7657 switch(this.msgTarget){
7659 this.el.dom.qtip = msg;
7660 this.el.dom.qclass = 'x-form-invalid-tip';
7661 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7662 Roo.QuickTips.enable();
7666 this.el.dom.title = msg;
7670 var elp = this.el.findParent('.x-form-element', 5, true);
7671 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7672 this.errorEl.setWidth(elp.getWidth(true)-20);
7674 this.errorEl.update(msg);
7675 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7678 if(!this.errorIcon){
7679 var elp = this.el.findParent('.x-form-element', 5, true);
7680 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7682 this.alignErrorIcon();
7683 this.errorIcon.dom.qtip = msg;
7684 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7685 this.errorIcon.show();
7686 this.on('resize', this.alignErrorIcon, this);
7689 var t = Roo.getDom(this.msgTarget);
7691 t.style.display = this.msgDisplay;
7695 this.fireEvent('invalid', this, msg);
7698 SafariOnKeyDown : function(event)
7700 // this is a workaround for a password hang bug on chrome/ webkit.
7702 var isSelectAll = false;
7704 if(this.inputEl().dom.selectionEnd > 0){
7705 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7707 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7708 event.preventDefault();
7713 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7715 event.preventDefault();
7716 // this is very hacky as keydown always get's upper case.
7718 var cc = String.fromCharCode(event.getCharCode());
7719 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7723 adjustWidth : function(tag, w){
7724 tag = tag.toLowerCase();
7725 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7726 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7730 if(tag == 'textarea'){
7733 }else if(Roo.isOpera){
7737 if(tag == 'textarea'){
7756 * @class Roo.bootstrap.TextArea
7757 * @extends Roo.bootstrap.Input
7758 * Bootstrap TextArea class
7759 * @cfg {Number} cols Specifies the visible width of a text area
7760 * @cfg {Number} rows Specifies the visible number of lines in a text area
7761 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7762 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7763 * @cfg {string} html text
7766 * Create a new TextArea
7767 * @param {Object} config The config object
7770 Roo.bootstrap.TextArea = function(config){
7771 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7775 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7785 getAutoCreate : function(){
7787 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7798 value : this.value || '',
7799 html: this.html || '',
7800 cls : 'form-control',
7801 placeholder : this.placeholder || ''
7805 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7806 input.maxLength = this.maxLength;
7810 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7814 input.cols = this.cols;
7817 if (this.readOnly) {
7818 input.readonly = true;
7822 input.name = this.name;
7826 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7830 ['xs','sm','md','lg'].map(function(size){
7831 if (settings[size]) {
7832 cfg.cls += ' col-' + size + '-' + settings[size];
7836 var inputblock = input;
7838 if (this.before || this.after) {
7841 cls : 'input-group',
7845 inputblock.cn.push({
7847 cls : 'input-group-addon',
7851 inputblock.cn.push(input);
7853 inputblock.cn.push({
7855 cls : 'input-group-addon',
7862 if (align ==='left' && this.fieldLabel.length) {
7863 Roo.log("left and has label");
7869 cls : 'control-label col-sm-' + this.labelWidth,
7870 html : this.fieldLabel
7874 cls : "col-sm-" + (12 - this.labelWidth),
7881 } else if ( this.fieldLabel.length) {
7887 //cls : 'input-group-addon',
7888 html : this.fieldLabel
7898 Roo.log(" no label && no align");
7908 if (this.disabled) {
7909 input.disabled=true;
7916 * return the real textarea element.
7918 inputEl: function ()
7920 return this.el.select('textarea.form-control',true).first();
7928 * trigger field - base class for combo..
7933 * @class Roo.bootstrap.TriggerField
7934 * @extends Roo.bootstrap.Input
7935 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7936 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7937 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7938 * for which you can provide a custom implementation. For example:
7940 var trigger = new Roo.bootstrap.TriggerField();
7941 trigger.onTriggerClick = myTriggerFn;
7942 trigger.applyTo('my-field');
7945 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7946 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7947 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7948 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7949 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
7952 * Create a new TriggerField.
7953 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7954 * to the base TextField)
7956 Roo.bootstrap.TriggerField = function(config){
7957 this.mimicing = false;
7958 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7961 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7963 * @cfg {String} triggerClass A CSS class to apply to the trigger
7966 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7970 /** @cfg {Boolean} grow @hide */
7971 /** @cfg {Number} growMin @hide */
7972 /** @cfg {Number} growMax @hide */
7978 autoSize: Roo.emptyFn,
7985 actionMode : 'wrap',
7990 getAutoCreate : function(){
7992 var align = this.labelAlign || this.parentLabelAlign();
7997 cls: 'form-group' //input-group
8004 type : this.inputType,
8005 cls : 'form-control',
8006 autocomplete: 'false',
8007 placeholder : this.placeholder || ''
8011 input.name = this.name;
8014 input.cls += ' input-' + this.size;
8017 if (this.disabled) {
8018 input.disabled=true;
8021 var inputblock = input;
8023 if (this.before || this.after) {
8026 cls : 'input-group',
8030 inputblock.cn.push({
8032 cls : 'input-group-addon',
8036 inputblock.cn.push(input);
8038 inputblock.cn.push({
8040 cls : 'input-group-addon',
8053 cls: 'form-hidden-field'
8061 Roo.log('multiple');
8069 cls: 'form-hidden-field'
8073 cls: 'select2-choices',
8077 cls: 'select2-search-field',
8090 cls: 'select2-container input-group',
8095 // cls: 'typeahead typeahead-long dropdown-menu',
8096 // style: 'display:none'
8101 if(!this.multiple && this.showToggleBtn){
8107 if (this.caret != false) {
8110 cls: 'fa fa-' + this.caret
8117 cls : 'input-group-addon btn dropdown-toggle',
8122 cls: 'combobox-clear',
8136 combobox.cls += ' select2-container-multi';
8139 if (align ==='left' && this.fieldLabel.length) {
8141 Roo.log("left and has label");
8147 cls : 'control-label col-sm-' + this.labelWidth,
8148 html : this.fieldLabel
8152 cls : "col-sm-" + (12 - this.labelWidth),
8159 } else if ( this.fieldLabel.length) {
8165 //cls : 'input-group-addon',
8166 html : this.fieldLabel
8176 Roo.log(" no label && no align");
8183 ['xs','sm','md','lg'].map(function(size){
8184 if (settings[size]) {
8185 cfg.cls += ' col-' + size + '-' + settings[size];
8196 onResize : function(w, h){
8197 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8198 // if(typeof w == 'number'){
8199 // var x = w - this.trigger.getWidth();
8200 // this.inputEl().setWidth(this.adjustWidth('input', x));
8201 // this.trigger.setStyle('left', x+'px');
8206 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8209 getResizeEl : function(){
8210 return this.inputEl();
8214 getPositionEl : function(){
8215 return this.inputEl();
8219 alignErrorIcon : function(){
8220 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8224 initEvents : function(){
8228 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8229 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8230 if(!this.multiple && this.showToggleBtn){
8231 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8232 if(this.hideTrigger){
8233 this.trigger.setDisplayed(false);
8235 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8239 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8242 //this.trigger.addClassOnOver('x-form-trigger-over');
8243 //this.trigger.addClassOnClick('x-form-trigger-click');
8246 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8250 createList : function()
8252 this.list = Roo.get(document.body).createChild({
8254 cls: 'typeahead typeahead-long dropdown-menu',
8255 style: 'display:none'
8258 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8263 initTrigger : function(){
8268 onDestroy : function(){
8270 this.trigger.removeAllListeners();
8271 // this.trigger.remove();
8274 // this.wrap.remove();
8276 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8280 onFocus : function(){
8281 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8284 this.wrap.addClass('x-trigger-wrap-focus');
8285 this.mimicing = true;
8286 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8287 if(this.monitorTab){
8288 this.el.on("keydown", this.checkTab, this);
8295 checkTab : function(e){
8296 if(e.getKey() == e.TAB){
8302 onBlur : function(){
8307 mimicBlur : function(e, t){
8309 if(!this.wrap.contains(t) && this.validateBlur()){
8316 triggerBlur : function(){
8317 this.mimicing = false;
8318 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8319 if(this.monitorTab){
8320 this.el.un("keydown", this.checkTab, this);
8322 //this.wrap.removeClass('x-trigger-wrap-focus');
8323 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8327 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8328 validateBlur : function(e, t){
8333 onDisable : function(){
8334 this.inputEl().dom.disabled = true;
8335 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8337 // this.wrap.addClass('x-item-disabled');
8342 onEnable : function(){
8343 this.inputEl().dom.disabled = false;
8344 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8346 // this.el.removeClass('x-item-disabled');
8351 onShow : function(){
8352 var ae = this.getActionEl();
8355 ae.dom.style.display = '';
8356 ae.dom.style.visibility = 'visible';
8362 onHide : function(){
8363 var ae = this.getActionEl();
8364 ae.dom.style.display = 'none';
8368 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8369 * by an implementing function.
8371 * @param {EventObject} e
8373 onTriggerClick : Roo.emptyFn
8377 * Ext JS Library 1.1.1
8378 * Copyright(c) 2006-2007, Ext JS, LLC.
8380 * Originally Released Under LGPL - original licence link has changed is not relivant.
8383 * <script type="text/javascript">
8388 * @class Roo.data.SortTypes
8390 * Defines the default sorting (casting?) comparison functions used when sorting data.
8392 Roo.data.SortTypes = {
8394 * Default sort that does nothing
8395 * @param {Mixed} s The value being converted
8396 * @return {Mixed} The comparison value
8403 * The regular expression used to strip tags
8407 stripTagsRE : /<\/?[^>]+>/gi,
8410 * Strips all HTML tags to sort on text only
8411 * @param {Mixed} s The value being converted
8412 * @return {String} The comparison value
8414 asText : function(s){
8415 return String(s).replace(this.stripTagsRE, "");
8419 * Strips all HTML tags to sort on text only - Case insensitive
8420 * @param {Mixed} s The value being converted
8421 * @return {String} The comparison value
8423 asUCText : function(s){
8424 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8428 * Case insensitive string
8429 * @param {Mixed} s The value being converted
8430 * @return {String} The comparison value
8432 asUCString : function(s) {
8433 return String(s).toUpperCase();
8438 * @param {Mixed} s The value being converted
8439 * @return {Number} The comparison value
8441 asDate : function(s) {
8445 if(s instanceof Date){
8448 return Date.parse(String(s));
8453 * @param {Mixed} s The value being converted
8454 * @return {Float} The comparison value
8456 asFloat : function(s) {
8457 var val = parseFloat(String(s).replace(/,/g, ""));
8458 if(isNaN(val)) val = 0;
8464 * @param {Mixed} s The value being converted
8465 * @return {Number} The comparison value
8467 asInt : function(s) {
8468 var val = parseInt(String(s).replace(/,/g, ""));
8469 if(isNaN(val)) val = 0;
8474 * Ext JS Library 1.1.1
8475 * Copyright(c) 2006-2007, Ext JS, LLC.
8477 * Originally Released Under LGPL - original licence link has changed is not relivant.
8480 * <script type="text/javascript">
8484 * @class Roo.data.Record
8485 * Instances of this class encapsulate both record <em>definition</em> information, and record
8486 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8487 * to access Records cached in an {@link Roo.data.Store} object.<br>
8489 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8490 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8493 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8495 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8496 * {@link #create}. The parameters are the same.
8497 * @param {Array} data An associative Array of data values keyed by the field name.
8498 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8499 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8500 * not specified an integer id is generated.
8502 Roo.data.Record = function(data, id){
8503 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8508 * Generate a constructor for a specific record layout.
8509 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8510 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8511 * Each field definition object may contain the following properties: <ul>
8512 * <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,
8513 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8514 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8515 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8516 * is being used, then this is a string containing the javascript expression to reference the data relative to
8517 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8518 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8519 * this may be omitted.</p></li>
8520 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8521 * <ul><li>auto (Default, implies no conversion)</li>
8526 * <li>date</li></ul></p></li>
8527 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8528 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8529 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8530 * by the Reader into an object that will be stored in the Record. It is passed the
8531 * following parameters:<ul>
8532 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8534 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8536 * <br>usage:<br><pre><code>
8537 var TopicRecord = Roo.data.Record.create(
8538 {name: 'title', mapping: 'topic_title'},
8539 {name: 'author', mapping: 'username'},
8540 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8541 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8542 {name: 'lastPoster', mapping: 'user2'},
8543 {name: 'excerpt', mapping: 'post_text'}
8546 var myNewRecord = new TopicRecord({
8547 title: 'Do my job please',
8550 lastPost: new Date(),
8551 lastPoster: 'Animal',
8552 excerpt: 'No way dude!'
8554 myStore.add(myNewRecord);
8559 Roo.data.Record.create = function(o){
8561 f.superclass.constructor.apply(this, arguments);
8563 Roo.extend(f, Roo.data.Record);
8564 var p = f.prototype;
8565 p.fields = new Roo.util.MixedCollection(false, function(field){
8568 for(var i = 0, len = o.length; i < len; i++){
8569 p.fields.add(new Roo.data.Field(o[i]));
8571 f.getField = function(name){
8572 return p.fields.get(name);
8577 Roo.data.Record.AUTO_ID = 1000;
8578 Roo.data.Record.EDIT = 'edit';
8579 Roo.data.Record.REJECT = 'reject';
8580 Roo.data.Record.COMMIT = 'commit';
8582 Roo.data.Record.prototype = {
8584 * Readonly flag - true if this record has been modified.
8593 join : function(store){
8598 * Set the named field to the specified value.
8599 * @param {String} name The name of the field to set.
8600 * @param {Object} value The value to set the field to.
8602 set : function(name, value){
8603 if(this.data[name] == value){
8610 if(typeof this.modified[name] == 'undefined'){
8611 this.modified[name] = this.data[name];
8613 this.data[name] = value;
8614 if(!this.editing && this.store){
8615 this.store.afterEdit(this);
8620 * Get the value of the named field.
8621 * @param {String} name The name of the field to get the value of.
8622 * @return {Object} The value of the field.
8624 get : function(name){
8625 return this.data[name];
8629 beginEdit : function(){
8630 this.editing = true;
8635 cancelEdit : function(){
8636 this.editing = false;
8637 delete this.modified;
8641 endEdit : function(){
8642 this.editing = false;
8643 if(this.dirty && this.store){
8644 this.store.afterEdit(this);
8649 * Usually called by the {@link Roo.data.Store} which owns the Record.
8650 * Rejects all changes made to the Record since either creation, or the last commit operation.
8651 * Modified fields are reverted to their original values.
8653 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8654 * of reject operations.
8656 reject : function(){
8657 var m = this.modified;
8659 if(typeof m[n] != "function"){
8660 this.data[n] = m[n];
8664 delete this.modified;
8665 this.editing = false;
8667 this.store.afterReject(this);
8672 * Usually called by the {@link Roo.data.Store} which owns the Record.
8673 * Commits all changes made to the Record since either creation, or the last commit operation.
8675 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8676 * of commit operations.
8678 commit : function(){
8680 delete this.modified;
8681 this.editing = false;
8683 this.store.afterCommit(this);
8688 hasError : function(){
8689 return this.error != null;
8693 clearError : function(){
8698 * Creates a copy of this record.
8699 * @param {String} id (optional) A new record id if you don't want to use this record's id
8702 copy : function(newId) {
8703 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8707 * Ext JS Library 1.1.1
8708 * Copyright(c) 2006-2007, Ext JS, LLC.
8710 * Originally Released Under LGPL - original licence link has changed is not relivant.
8713 * <script type="text/javascript">
8719 * @class Roo.data.Store
8720 * @extends Roo.util.Observable
8721 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8722 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8724 * 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
8725 * has no knowledge of the format of the data returned by the Proxy.<br>
8727 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8728 * instances from the data object. These records are cached and made available through accessor functions.
8730 * Creates a new Store.
8731 * @param {Object} config A config object containing the objects needed for the Store to access data,
8732 * and read the data into Records.
8734 Roo.data.Store = function(config){
8735 this.data = new Roo.util.MixedCollection(false);
8736 this.data.getKey = function(o){
8739 this.baseParams = {};
8746 "multisort" : "_multisort"
8749 if(config && config.data){
8750 this.inlineData = config.data;
8754 Roo.apply(this, config);
8756 if(this.reader){ // reader passed
8757 this.reader = Roo.factory(this.reader, Roo.data);
8758 this.reader.xmodule = this.xmodule || false;
8759 if(!this.recordType){
8760 this.recordType = this.reader.recordType;
8762 if(this.reader.onMetaChange){
8763 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8767 if(this.recordType){
8768 this.fields = this.recordType.prototype.fields;
8774 * @event datachanged
8775 * Fires when the data cache has changed, and a widget which is using this Store
8776 * as a Record cache should refresh its view.
8777 * @param {Store} this
8782 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8783 * @param {Store} this
8784 * @param {Object} meta The JSON metadata
8789 * Fires when Records have been added to the Store
8790 * @param {Store} this
8791 * @param {Roo.data.Record[]} records The array of Records added
8792 * @param {Number} index The index at which the record(s) were added
8797 * Fires when a Record has been removed from the Store
8798 * @param {Store} this
8799 * @param {Roo.data.Record} record The Record that was removed
8800 * @param {Number} index The index at which the record was removed
8805 * Fires when a Record has been updated
8806 * @param {Store} this
8807 * @param {Roo.data.Record} record The Record that was updated
8808 * @param {String} operation The update operation being performed. Value may be one of:
8810 Roo.data.Record.EDIT
8811 Roo.data.Record.REJECT
8812 Roo.data.Record.COMMIT
8818 * Fires when the data cache has been cleared.
8819 * @param {Store} this
8824 * Fires before a request is made for a new data object. If the beforeload handler returns false
8825 * the load action will be canceled.
8826 * @param {Store} this
8827 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8831 * @event beforeloadadd
8832 * Fires after a new set of Records has been loaded.
8833 * @param {Store} this
8834 * @param {Roo.data.Record[]} records The Records that were loaded
8835 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8837 beforeloadadd : true,
8840 * Fires after a new set of Records has been loaded, before they are added to the store.
8841 * @param {Store} this
8842 * @param {Roo.data.Record[]} records The Records that were loaded
8843 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8844 * @params {Object} return from reader
8848 * @event loadexception
8849 * Fires if an exception occurs in the Proxy during loading.
8850 * Called with the signature of the Proxy's "loadexception" event.
8851 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8854 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8855 * @param {Object} load options
8856 * @param {Object} jsonData from your request (normally this contains the Exception)
8858 loadexception : true
8862 this.proxy = Roo.factory(this.proxy, Roo.data);
8863 this.proxy.xmodule = this.xmodule || false;
8864 this.relayEvents(this.proxy, ["loadexception"]);
8866 this.sortToggle = {};
8867 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8869 Roo.data.Store.superclass.constructor.call(this);
8871 if(this.inlineData){
8872 this.loadData(this.inlineData);
8873 delete this.inlineData;
8877 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8879 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8880 * without a remote query - used by combo/forms at present.
8884 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8887 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8890 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8891 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8894 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8895 * on any HTTP request
8898 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8901 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8905 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8906 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8911 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8912 * loaded or when a record is removed. (defaults to false).
8914 pruneModifiedRecords : false,
8920 * Add Records to the Store and fires the add event.
8921 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8923 add : function(records){
8924 records = [].concat(records);
8925 for(var i = 0, len = records.length; i < len; i++){
8926 records[i].join(this);
8928 var index = this.data.length;
8929 this.data.addAll(records);
8930 this.fireEvent("add", this, records, index);
8934 * Remove a Record from the Store and fires the remove event.
8935 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8937 remove : function(record){
8938 var index = this.data.indexOf(record);
8939 this.data.removeAt(index);
8940 if(this.pruneModifiedRecords){
8941 this.modified.remove(record);
8943 this.fireEvent("remove", this, record, index);
8947 * Remove all Records from the Store and fires the clear event.
8949 removeAll : function(){
8951 if(this.pruneModifiedRecords){
8954 this.fireEvent("clear", this);
8958 * Inserts Records to the Store at the given index and fires the add event.
8959 * @param {Number} index The start index at which to insert the passed Records.
8960 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8962 insert : function(index, records){
8963 records = [].concat(records);
8964 for(var i = 0, len = records.length; i < len; i++){
8965 this.data.insert(index, records[i]);
8966 records[i].join(this);
8968 this.fireEvent("add", this, records, index);
8972 * Get the index within the cache of the passed Record.
8973 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8974 * @return {Number} The index of the passed Record. Returns -1 if not found.
8976 indexOf : function(record){
8977 return this.data.indexOf(record);
8981 * Get the index within the cache of the Record with the passed id.
8982 * @param {String} id The id of the Record to find.
8983 * @return {Number} The index of the Record. Returns -1 if not found.
8985 indexOfId : function(id){
8986 return this.data.indexOfKey(id);
8990 * Get the Record with the specified id.
8991 * @param {String} id The id of the Record to find.
8992 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8994 getById : function(id){
8995 return this.data.key(id);
8999 * Get the Record at the specified index.
9000 * @param {Number} index The index of the Record to find.
9001 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9003 getAt : function(index){
9004 return this.data.itemAt(index);
9008 * Returns a range of Records between specified indices.
9009 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9010 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9011 * @return {Roo.data.Record[]} An array of Records
9013 getRange : function(start, end){
9014 return this.data.getRange(start, end);
9018 storeOptions : function(o){
9019 o = Roo.apply({}, o);
9022 this.lastOptions = o;
9026 * Loads the Record cache from the configured Proxy using the configured Reader.
9028 * If using remote paging, then the first load call must specify the <em>start</em>
9029 * and <em>limit</em> properties in the options.params property to establish the initial
9030 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9032 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9033 * and this call will return before the new data has been loaded. Perform any post-processing
9034 * in a callback function, or in a "load" event handler.</strong>
9036 * @param {Object} options An object containing properties which control loading options:<ul>
9037 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9038 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9039 * passed the following arguments:<ul>
9040 * <li>r : Roo.data.Record[]</li>
9041 * <li>options: Options object from the load call</li>
9042 * <li>success: Boolean success indicator</li></ul></li>
9043 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9044 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9047 load : function(options){
9048 options = options || {};
9049 if(this.fireEvent("beforeload", this, options) !== false){
9050 this.storeOptions(options);
9051 var p = Roo.apply(options.params || {}, this.baseParams);
9052 // if meta was not loaded from remote source.. try requesting it.
9053 if (!this.reader.metaFromRemote) {
9056 if(this.sortInfo && this.remoteSort){
9057 var pn = this.paramNames;
9058 p[pn["sort"]] = this.sortInfo.field;
9059 p[pn["dir"]] = this.sortInfo.direction;
9061 if (this.multiSort) {
9062 var pn = this.paramNames;
9063 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9066 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9071 * Reloads the Record cache from the configured Proxy using the configured Reader and
9072 * the options from the last load operation performed.
9073 * @param {Object} options (optional) An object containing properties which may override the options
9074 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9075 * the most recently used options are reused).
9077 reload : function(options){
9078 this.load(Roo.applyIf(options||{}, this.lastOptions));
9082 // Called as a callback by the Reader during a load operation.
9083 loadRecords : function(o, options, success){
9084 if(!o || success === false){
9085 if(success !== false){
9086 this.fireEvent("load", this, [], options, o);
9088 if(options.callback){
9089 options.callback.call(options.scope || this, [], options, false);
9093 // if data returned failure - throw an exception.
9094 if (o.success === false) {
9095 // show a message if no listener is registered.
9096 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9097 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9099 // loadmask wil be hooked into this..
9100 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9103 var r = o.records, t = o.totalRecords || r.length;
9105 this.fireEvent("beforeloadadd", this, r, options, o);
9107 if(!options || options.add !== true){
9108 if(this.pruneModifiedRecords){
9111 for(var i = 0, len = r.length; i < len; i++){
9115 this.data = this.snapshot;
9116 delete this.snapshot;
9119 this.data.addAll(r);
9120 this.totalLength = t;
9122 this.fireEvent("datachanged", this);
9124 this.totalLength = Math.max(t, this.data.length+r.length);
9127 this.fireEvent("load", this, r, options, o);
9128 if(options.callback){
9129 options.callback.call(options.scope || this, r, options, true);
9135 * Loads data from a passed data block. A Reader which understands the format of the data
9136 * must have been configured in the constructor.
9137 * @param {Object} data The data block from which to read the Records. The format of the data expected
9138 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9139 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9141 loadData : function(o, append){
9142 var r = this.reader.readRecords(o);
9143 this.loadRecords(r, {add: append}, true);
9147 * Gets the number of cached records.
9149 * <em>If using paging, this may not be the total size of the dataset. If the data object
9150 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9151 * the data set size</em>
9153 getCount : function(){
9154 return this.data.length || 0;
9158 * Gets the total number of records in the dataset as returned by the server.
9160 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9161 * the dataset size</em>
9163 getTotalCount : function(){
9164 return this.totalLength || 0;
9168 * Returns the sort state of the Store as an object with two properties:
9170 field {String} The name of the field by which the Records are sorted
9171 direction {String} The sort order, "ASC" or "DESC"
9174 getSortState : function(){
9175 return this.sortInfo;
9179 applySort : function(){
9180 if(this.sortInfo && !this.remoteSort){
9181 var s = this.sortInfo, f = s.field;
9182 var st = this.fields.get(f).sortType;
9183 var fn = function(r1, r2){
9184 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9185 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9187 this.data.sort(s.direction, fn);
9188 if(this.snapshot && this.snapshot != this.data){
9189 this.snapshot.sort(s.direction, fn);
9195 * Sets the default sort column and order to be used by the next load operation.
9196 * @param {String} fieldName The name of the field to sort by.
9197 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9199 setDefaultSort : function(field, dir){
9200 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9205 * If remote sorting is used, the sort is performed on the server, and the cache is
9206 * reloaded. If local sorting is used, the cache is sorted internally.
9207 * @param {String} fieldName The name of the field to sort by.
9208 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9210 sort : function(fieldName, dir){
9211 var f = this.fields.get(fieldName);
9213 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9215 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9216 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9221 this.sortToggle[f.name] = dir;
9222 this.sortInfo = {field: f.name, direction: dir};
9223 if(!this.remoteSort){
9225 this.fireEvent("datachanged", this);
9227 this.load(this.lastOptions);
9232 * Calls the specified function for each of the Records in the cache.
9233 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9234 * Returning <em>false</em> aborts and exits the iteration.
9235 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9237 each : function(fn, scope){
9238 this.data.each(fn, scope);
9242 * Gets all records modified since the last commit. Modified records are persisted across load operations
9243 * (e.g., during paging).
9244 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9246 getModifiedRecords : function(){
9247 return this.modified;
9251 createFilterFn : function(property, value, anyMatch){
9252 if(!value.exec){ // not a regex
9253 value = String(value);
9254 if(value.length == 0){
9257 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9260 return value.test(r.data[property]);
9265 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9266 * @param {String} property A field on your records
9267 * @param {Number} start The record index to start at (defaults to 0)
9268 * @param {Number} end The last record index to include (defaults to length - 1)
9269 * @return {Number} The sum
9271 sum : function(property, start, end){
9272 var rs = this.data.items, v = 0;
9274 end = (end || end === 0) ? end : rs.length-1;
9276 for(var i = start; i <= end; i++){
9277 v += (rs[i].data[property] || 0);
9283 * Filter the records by a specified property.
9284 * @param {String} field A field on your records
9285 * @param {String/RegExp} value Either a string that the field
9286 * should start with or a RegExp to test against the field
9287 * @param {Boolean} anyMatch True to match any part not just the beginning
9289 filter : function(property, value, anyMatch){
9290 var fn = this.createFilterFn(property, value, anyMatch);
9291 return fn ? this.filterBy(fn) : this.clearFilter();
9295 * Filter by a function. The specified function will be called with each
9296 * record in this data source. If the function returns true the record is included,
9297 * otherwise it is filtered.
9298 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9299 * @param {Object} scope (optional) The scope of the function (defaults to this)
9301 filterBy : function(fn, scope){
9302 this.snapshot = this.snapshot || this.data;
9303 this.data = this.queryBy(fn, scope||this);
9304 this.fireEvent("datachanged", this);
9308 * Query the records by a specified property.
9309 * @param {String} field A field on your records
9310 * @param {String/RegExp} value Either a string that the field
9311 * should start with or a RegExp to test against the field
9312 * @param {Boolean} anyMatch True to match any part not just the beginning
9313 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9315 query : function(property, value, anyMatch){
9316 var fn = this.createFilterFn(property, value, anyMatch);
9317 return fn ? this.queryBy(fn) : this.data.clone();
9321 * Query by a function. The specified function will be called with each
9322 * record in this data source. If the function returns true the record is included
9324 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9325 * @param {Object} scope (optional) The scope of the function (defaults to this)
9326 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9328 queryBy : function(fn, scope){
9329 var data = this.snapshot || this.data;
9330 return data.filterBy(fn, scope||this);
9334 * Collects unique values for a particular dataIndex from this store.
9335 * @param {String} dataIndex The property to collect
9336 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9337 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9338 * @return {Array} An array of the unique values
9340 collect : function(dataIndex, allowNull, bypassFilter){
9341 var d = (bypassFilter === true && this.snapshot) ?
9342 this.snapshot.items : this.data.items;
9343 var v, sv, r = [], l = {};
9344 for(var i = 0, len = d.length; i < len; i++){
9345 v = d[i].data[dataIndex];
9347 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9356 * Revert to a view of the Record cache with no filtering applied.
9357 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9359 clearFilter : function(suppressEvent){
9360 if(this.snapshot && this.snapshot != this.data){
9361 this.data = this.snapshot;
9362 delete this.snapshot;
9363 if(suppressEvent !== true){
9364 this.fireEvent("datachanged", this);
9370 afterEdit : function(record){
9371 if(this.modified.indexOf(record) == -1){
9372 this.modified.push(record);
9374 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9378 afterReject : function(record){
9379 this.modified.remove(record);
9380 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9384 afterCommit : function(record){
9385 this.modified.remove(record);
9386 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9390 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9391 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9393 commitChanges : function(){
9394 var m = this.modified.slice(0);
9396 for(var i = 0, len = m.length; i < len; i++){
9402 * Cancel outstanding changes on all changed records.
9404 rejectChanges : function(){
9405 var m = this.modified.slice(0);
9407 for(var i = 0, len = m.length; i < len; i++){
9412 onMetaChange : function(meta, rtype, o){
9413 this.recordType = rtype;
9414 this.fields = rtype.prototype.fields;
9415 delete this.snapshot;
9416 this.sortInfo = meta.sortInfo || this.sortInfo;
9418 this.fireEvent('metachange', this, this.reader.meta);
9421 moveIndex : function(data, type)
9423 var index = this.indexOf(data);
9425 var newIndex = index + type;
9429 this.insert(newIndex, data);
9434 * Ext JS Library 1.1.1
9435 * Copyright(c) 2006-2007, Ext JS, LLC.
9437 * Originally Released Under LGPL - original licence link has changed is not relivant.
9440 * <script type="text/javascript">
9444 * @class Roo.data.SimpleStore
9445 * @extends Roo.data.Store
9446 * Small helper class to make creating Stores from Array data easier.
9447 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9448 * @cfg {Array} fields An array of field definition objects, or field name strings.
9449 * @cfg {Array} data The multi-dimensional array of data
9451 * @param {Object} config
9453 Roo.data.SimpleStore = function(config){
9454 Roo.data.SimpleStore.superclass.constructor.call(this, {
9456 reader: new Roo.data.ArrayReader({
9459 Roo.data.Record.create(config.fields)
9461 proxy : new Roo.data.MemoryProxy(config.data)
9465 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9467 * Ext JS Library 1.1.1
9468 * Copyright(c) 2006-2007, Ext JS, LLC.
9470 * Originally Released Under LGPL - original licence link has changed is not relivant.
9473 * <script type="text/javascript">
9478 * @extends Roo.data.Store
9479 * @class Roo.data.JsonStore
9480 * Small helper class to make creating Stores for JSON data easier. <br/>
9482 var store = new Roo.data.JsonStore({
9483 url: 'get-images.php',
9485 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9488 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9489 * JsonReader and HttpProxy (unless inline data is provided).</b>
9490 * @cfg {Array} fields An array of field definition objects, or field name strings.
9492 * @param {Object} config
9494 Roo.data.JsonStore = function(c){
9495 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9496 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9497 reader: new Roo.data.JsonReader(c, c.fields)
9500 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9502 * Ext JS Library 1.1.1
9503 * Copyright(c) 2006-2007, Ext JS, LLC.
9505 * Originally Released Under LGPL - original licence link has changed is not relivant.
9508 * <script type="text/javascript">
9512 Roo.data.Field = function(config){
9513 if(typeof config == "string"){
9514 config = {name: config};
9516 Roo.apply(this, config);
9522 var st = Roo.data.SortTypes;
9523 // named sortTypes are supported, here we look them up
9524 if(typeof this.sortType == "string"){
9525 this.sortType = st[this.sortType];
9528 // set default sortType for strings and dates
9532 this.sortType = st.asUCString;
9535 this.sortType = st.asDate;
9538 this.sortType = st.none;
9543 var stripRe = /[\$,%]/g;
9545 // prebuilt conversion function for this field, instead of
9546 // switching every time we're reading a value
9548 var cv, dateFormat = this.dateFormat;
9553 cv = function(v){ return v; };
9556 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9560 return v !== undefined && v !== null && v !== '' ?
9561 parseInt(String(v).replace(stripRe, ""), 10) : '';
9566 return v !== undefined && v !== null && v !== '' ?
9567 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9572 cv = function(v){ return v === true || v === "true" || v == 1; };
9579 if(v instanceof Date){
9583 if(dateFormat == "timestamp"){
9584 return new Date(v*1000);
9586 return Date.parseDate(v, dateFormat);
9588 var parsed = Date.parse(v);
9589 return parsed ? new Date(parsed) : null;
9598 Roo.data.Field.prototype = {
9606 * Ext JS Library 1.1.1
9607 * Copyright(c) 2006-2007, Ext JS, LLC.
9609 * Originally Released Under LGPL - original licence link has changed is not relivant.
9612 * <script type="text/javascript">
9615 // Base class for reading structured data from a data source. This class is intended to be
9616 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9619 * @class Roo.data.DataReader
9620 * Base class for reading structured data from a data source. This class is intended to be
9621 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9624 Roo.data.DataReader = function(meta, recordType){
9628 this.recordType = recordType instanceof Array ?
9629 Roo.data.Record.create(recordType) : recordType;
9632 Roo.data.DataReader.prototype = {
9634 * Create an empty record
9635 * @param {Object} data (optional) - overlay some values
9636 * @return {Roo.data.Record} record created.
9638 newRow : function(d) {
9640 this.recordType.prototype.fields.each(function(c) {
9642 case 'int' : da[c.name] = 0; break;
9643 case 'date' : da[c.name] = new Date(); break;
9644 case 'float' : da[c.name] = 0.0; break;
9645 case 'boolean' : da[c.name] = false; break;
9646 default : da[c.name] = ""; break;
9650 return new this.recordType(Roo.apply(da, d));
9655 * Ext JS Library 1.1.1
9656 * Copyright(c) 2006-2007, Ext JS, LLC.
9658 * Originally Released Under LGPL - original licence link has changed is not relivant.
9661 * <script type="text/javascript">
9665 * @class Roo.data.DataProxy
9666 * @extends Roo.data.Observable
9667 * This class is an abstract base class for implementations which provide retrieval of
9668 * unformatted data objects.<br>
9670 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9671 * (of the appropriate type which knows how to parse the data object) to provide a block of
9672 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9674 * Custom implementations must implement the load method as described in
9675 * {@link Roo.data.HttpProxy#load}.
9677 Roo.data.DataProxy = function(){
9681 * Fires before a network request is made to retrieve a data object.
9682 * @param {Object} This DataProxy object.
9683 * @param {Object} params The params parameter to the load function.
9688 * Fires before the load method's callback is called.
9689 * @param {Object} This DataProxy object.
9690 * @param {Object} o The data object.
9691 * @param {Object} arg The callback argument object passed to the load function.
9695 * @event loadexception
9696 * Fires if an Exception occurs during data retrieval.
9697 * @param {Object} This DataProxy object.
9698 * @param {Object} o The data object.
9699 * @param {Object} arg The callback argument object passed to the load function.
9700 * @param {Object} e The Exception.
9702 loadexception : true
9704 Roo.data.DataProxy.superclass.constructor.call(this);
9707 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9710 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9714 * Ext JS Library 1.1.1
9715 * Copyright(c) 2006-2007, Ext JS, LLC.
9717 * Originally Released Under LGPL - original licence link has changed is not relivant.
9720 * <script type="text/javascript">
9723 * @class Roo.data.MemoryProxy
9724 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9725 * to the Reader when its load method is called.
9727 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9729 Roo.data.MemoryProxy = function(data){
9733 Roo.data.MemoryProxy.superclass.constructor.call(this);
9737 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9739 * Load data from the requested source (in this case an in-memory
9740 * data object passed to the constructor), read the data object into
9741 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9742 * process that block using the passed callback.
9743 * @param {Object} params This parameter is not used by the MemoryProxy class.
9744 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9745 * object into a block of Roo.data.Records.
9746 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9747 * The function must be passed <ul>
9748 * <li>The Record block object</li>
9749 * <li>The "arg" argument from the load function</li>
9750 * <li>A boolean success indicator</li>
9752 * @param {Object} scope The scope in which to call the callback
9753 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9755 load : function(params, reader, callback, scope, arg){
9756 params = params || {};
9759 result = reader.readRecords(this.data);
9761 this.fireEvent("loadexception", this, arg, null, e);
9762 callback.call(scope, null, arg, false);
9765 callback.call(scope, result, arg, true);
9769 update : function(params, records){
9774 * Ext JS Library 1.1.1
9775 * Copyright(c) 2006-2007, Ext JS, LLC.
9777 * Originally Released Under LGPL - original licence link has changed is not relivant.
9780 * <script type="text/javascript">
9783 * @class Roo.data.HttpProxy
9784 * @extends Roo.data.DataProxy
9785 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9786 * configured to reference a certain URL.<br><br>
9788 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9789 * from which the running page was served.<br><br>
9791 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9793 * Be aware that to enable the browser to parse an XML document, the server must set
9794 * the Content-Type header in the HTTP response to "text/xml".
9796 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9797 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9798 * will be used to make the request.
9800 Roo.data.HttpProxy = function(conn){
9801 Roo.data.HttpProxy.superclass.constructor.call(this);
9802 // is conn a conn config or a real conn?
9804 this.useAjax = !conn || !conn.events;
9808 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9809 // thse are take from connection...
9812 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9815 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9816 * extra parameters to each request made by this object. (defaults to undefined)
9819 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9820 * to each request made by this object. (defaults to undefined)
9823 * @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)
9826 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9829 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9835 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9839 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9840 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9841 * a finer-grained basis than the DataProxy events.
9843 getConnection : function(){
9844 return this.useAjax ? Roo.Ajax : this.conn;
9848 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9849 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9850 * process that block using the passed callback.
9851 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9852 * for the request to the remote server.
9853 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9854 * object into a block of Roo.data.Records.
9855 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9856 * The function must be passed <ul>
9857 * <li>The Record block object</li>
9858 * <li>The "arg" argument from the load function</li>
9859 * <li>A boolean success indicator</li>
9861 * @param {Object} scope The scope in which to call the callback
9862 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9864 load : function(params, reader, callback, scope, arg){
9865 if(this.fireEvent("beforeload", this, params) !== false){
9867 params : params || {},
9869 callback : callback,
9874 callback : this.loadResponse,
9878 Roo.applyIf(o, this.conn);
9879 if(this.activeRequest){
9880 Roo.Ajax.abort(this.activeRequest);
9882 this.activeRequest = Roo.Ajax.request(o);
9884 this.conn.request(o);
9887 callback.call(scope||this, null, arg, false);
9892 loadResponse : function(o, success, response){
9893 delete this.activeRequest;
9895 this.fireEvent("loadexception", this, o, response);
9896 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9901 result = o.reader.read(response);
9903 this.fireEvent("loadexception", this, o, response, e);
9904 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9908 this.fireEvent("load", this, o, o.request.arg);
9909 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9913 update : function(dataSet){
9918 updateResponse : function(dataSet){
9923 * Ext JS Library 1.1.1
9924 * Copyright(c) 2006-2007, Ext JS, LLC.
9926 * Originally Released Under LGPL - original licence link has changed is not relivant.
9929 * <script type="text/javascript">
9933 * @class Roo.data.ScriptTagProxy
9934 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9935 * other than the originating domain of the running page.<br><br>
9937 * <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
9938 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9940 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9941 * source code that is used as the source inside a <script> tag.<br><br>
9943 * In order for the browser to process the returned data, the server must wrap the data object
9944 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9945 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9946 * depending on whether the callback name was passed:
9949 boolean scriptTag = false;
9950 String cb = request.getParameter("callback");
9953 response.setContentType("text/javascript");
9955 response.setContentType("application/x-json");
9957 Writer out = response.getWriter();
9959 out.write(cb + "(");
9961 out.print(dataBlock.toJsonString());
9968 * @param {Object} config A configuration object.
9970 Roo.data.ScriptTagProxy = function(config){
9971 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9972 Roo.apply(this, config);
9973 this.head = document.getElementsByTagName("head")[0];
9976 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9978 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9980 * @cfg {String} url The URL from which to request the data object.
9983 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9987 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9988 * the server the name of the callback function set up by the load call to process the returned data object.
9989 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9990 * javascript output which calls this named function passing the data object as its only parameter.
9992 callbackParam : "callback",
9994 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9995 * name to the request.
10000 * Load data from the configured URL, read the data object into
10001 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10002 * process that block using the passed callback.
10003 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10004 * for the request to the remote server.
10005 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10006 * object into a block of Roo.data.Records.
10007 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10008 * The function must be passed <ul>
10009 * <li>The Record block object</li>
10010 * <li>The "arg" argument from the load function</li>
10011 * <li>A boolean success indicator</li>
10013 * @param {Object} scope The scope in which to call the callback
10014 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10016 load : function(params, reader, callback, scope, arg){
10017 if(this.fireEvent("beforeload", this, params) !== false){
10019 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10021 var url = this.url;
10022 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10024 url += "&_dc=" + (new Date().getTime());
10026 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10029 cb : "stcCallback"+transId,
10030 scriptId : "stcScript"+transId,
10034 callback : callback,
10040 window[trans.cb] = function(o){
10041 conn.handleResponse(o, trans);
10044 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10046 if(this.autoAbort !== false){
10050 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10052 var script = document.createElement("script");
10053 script.setAttribute("src", url);
10054 script.setAttribute("type", "text/javascript");
10055 script.setAttribute("id", trans.scriptId);
10056 this.head.appendChild(script);
10058 this.trans = trans;
10060 callback.call(scope||this, null, arg, false);
10065 isLoading : function(){
10066 return this.trans ? true : false;
10070 * Abort the current server request.
10072 abort : function(){
10073 if(this.isLoading()){
10074 this.destroyTrans(this.trans);
10079 destroyTrans : function(trans, isLoaded){
10080 this.head.removeChild(document.getElementById(trans.scriptId));
10081 clearTimeout(trans.timeoutId);
10083 window[trans.cb] = undefined;
10085 delete window[trans.cb];
10088 // if hasn't been loaded, wait for load to remove it to prevent script error
10089 window[trans.cb] = function(){
10090 window[trans.cb] = undefined;
10092 delete window[trans.cb];
10099 handleResponse : function(o, trans){
10100 this.trans = false;
10101 this.destroyTrans(trans, true);
10104 result = trans.reader.readRecords(o);
10106 this.fireEvent("loadexception", this, o, trans.arg, e);
10107 trans.callback.call(trans.scope||window, null, trans.arg, false);
10110 this.fireEvent("load", this, o, trans.arg);
10111 trans.callback.call(trans.scope||window, result, trans.arg, true);
10115 handleFailure : function(trans){
10116 this.trans = false;
10117 this.destroyTrans(trans, false);
10118 this.fireEvent("loadexception", this, null, trans.arg);
10119 trans.callback.call(trans.scope||window, null, trans.arg, false);
10123 * Ext JS Library 1.1.1
10124 * Copyright(c) 2006-2007, Ext JS, LLC.
10126 * Originally Released Under LGPL - original licence link has changed is not relivant.
10129 * <script type="text/javascript">
10133 * @class Roo.data.JsonReader
10134 * @extends Roo.data.DataReader
10135 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10136 * based on mappings in a provided Roo.data.Record constructor.
10138 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10139 * in the reply previously.
10144 var RecordDef = Roo.data.Record.create([
10145 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10146 {name: 'occupation'} // This field will use "occupation" as the mapping.
10148 var myReader = new Roo.data.JsonReader({
10149 totalProperty: "results", // The property which contains the total dataset size (optional)
10150 root: "rows", // The property which contains an Array of row objects
10151 id: "id" // The property within each row object that provides an ID for the record (optional)
10155 * This would consume a JSON file like this:
10157 { 'results': 2, 'rows': [
10158 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10159 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10162 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10163 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10164 * paged from the remote server.
10165 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10166 * @cfg {String} root name of the property which contains the Array of row objects.
10167 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10169 * Create a new JsonReader
10170 * @param {Object} meta Metadata configuration options
10171 * @param {Object} recordType Either an Array of field definition objects,
10172 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10174 Roo.data.JsonReader = function(meta, recordType){
10177 // set some defaults:
10178 Roo.applyIf(meta, {
10179 totalProperty: 'total',
10180 successProperty : 'success',
10185 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10187 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10190 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10191 * Used by Store query builder to append _requestMeta to params.
10194 metaFromRemote : false,
10196 * This method is only used by a DataProxy which has retrieved data from a remote server.
10197 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10198 * @return {Object} data A data block which is used by an Roo.data.Store object as
10199 * a cache of Roo.data.Records.
10201 read : function(response){
10202 var json = response.responseText;
10204 var o = /* eval:var:o */ eval("("+json+")");
10206 throw {message: "JsonReader.read: Json object not found"};
10212 this.metaFromRemote = true;
10213 this.meta = o.metaData;
10214 this.recordType = Roo.data.Record.create(o.metaData.fields);
10215 this.onMetaChange(this.meta, this.recordType, o);
10217 return this.readRecords(o);
10220 // private function a store will implement
10221 onMetaChange : function(meta, recordType, o){
10228 simpleAccess: function(obj, subsc) {
10235 getJsonAccessor: function(){
10237 return function(expr) {
10239 return(re.test(expr))
10240 ? new Function("obj", "return obj." + expr)
10245 return Roo.emptyFn;
10250 * Create a data block containing Roo.data.Records from an XML document.
10251 * @param {Object} o An object which contains an Array of row objects in the property specified
10252 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10253 * which contains the total size of the dataset.
10254 * @return {Object} data A data block which is used by an Roo.data.Store object as
10255 * a cache of Roo.data.Records.
10257 readRecords : function(o){
10259 * After any data loads, the raw JSON data is available for further custom processing.
10263 var s = this.meta, Record = this.recordType,
10264 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10266 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10268 if(s.totalProperty) {
10269 this.getTotal = this.getJsonAccessor(s.totalProperty);
10271 if(s.successProperty) {
10272 this.getSuccess = this.getJsonAccessor(s.successProperty);
10274 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10276 var g = this.getJsonAccessor(s.id);
10277 this.getId = function(rec) {
10279 return (r === undefined || r === "") ? null : r;
10282 this.getId = function(){return null;};
10285 for(var jj = 0; jj < fl; jj++){
10287 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10288 this.ef[jj] = this.getJsonAccessor(map);
10292 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10293 if(s.totalProperty){
10294 var vt = parseInt(this.getTotal(o), 10);
10299 if(s.successProperty){
10300 var vs = this.getSuccess(o);
10301 if(vs === false || vs === 'false'){
10306 for(var i = 0; i < c; i++){
10309 var id = this.getId(n);
10310 for(var j = 0; j < fl; j++){
10312 var v = this.ef[j](n);
10314 Roo.log('missing convert for ' + f.name);
10318 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10320 var record = new Record(values, id);
10322 records[i] = record;
10328 totalRecords : totalRecords
10333 * Ext JS Library 1.1.1
10334 * Copyright(c) 2006-2007, Ext JS, LLC.
10336 * Originally Released Under LGPL - original licence link has changed is not relivant.
10339 * <script type="text/javascript">
10343 * @class Roo.data.ArrayReader
10344 * @extends Roo.data.DataReader
10345 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10346 * Each element of that Array represents a row of data fields. The
10347 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10348 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10352 var RecordDef = Roo.data.Record.create([
10353 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10354 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10356 var myReader = new Roo.data.ArrayReader({
10357 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10361 * This would consume an Array like this:
10363 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10365 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10367 * Create a new JsonReader
10368 * @param {Object} meta Metadata configuration options.
10369 * @param {Object} recordType Either an Array of field definition objects
10370 * as specified to {@link Roo.data.Record#create},
10371 * or an {@link Roo.data.Record} object
10372 * created using {@link Roo.data.Record#create}.
10374 Roo.data.ArrayReader = function(meta, recordType){
10375 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10378 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10380 * Create a data block containing Roo.data.Records from an XML document.
10381 * @param {Object} o An Array of row objects which represents the dataset.
10382 * @return {Object} data A data block which is used by an Roo.data.Store object as
10383 * a cache of Roo.data.Records.
10385 readRecords : function(o){
10386 var sid = this.meta ? this.meta.id : null;
10387 var recordType = this.recordType, fields = recordType.prototype.fields;
10390 for(var i = 0; i < root.length; i++){
10393 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10394 for(var j = 0, jlen = fields.length; j < jlen; j++){
10395 var f = fields.items[j];
10396 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10397 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10399 values[f.name] = v;
10401 var record = new recordType(values, id);
10403 records[records.length] = record;
10407 totalRecords : records.length
10416 * @class Roo.bootstrap.ComboBox
10417 * @extends Roo.bootstrap.TriggerField
10418 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10419 * @cfg {Boolean} append (true|false) default false
10420 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10421 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10422 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10423 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10424 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10426 * Create a new ComboBox.
10427 * @param {Object} config Configuration options
10429 Roo.bootstrap.ComboBox = function(config){
10430 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10434 * Fires when the dropdown list is expanded
10435 * @param {Roo.bootstrap.ComboBox} combo This combo box
10440 * Fires when the dropdown list is collapsed
10441 * @param {Roo.bootstrap.ComboBox} combo This combo box
10445 * @event beforeselect
10446 * Fires before a list item is selected. Return false to cancel the selection.
10447 * @param {Roo.bootstrap.ComboBox} combo This combo box
10448 * @param {Roo.data.Record} record The data record returned from the underlying store
10449 * @param {Number} index The index of the selected item in the dropdown list
10451 'beforeselect' : true,
10454 * Fires when a list item is selected
10455 * @param {Roo.bootstrap.ComboBox} combo This combo box
10456 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10457 * @param {Number} index The index of the selected item in the dropdown list
10461 * @event beforequery
10462 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10463 * The event object passed has these properties:
10464 * @param {Roo.bootstrap.ComboBox} combo This combo box
10465 * @param {String} query The query
10466 * @param {Boolean} forceAll true to force "all" query
10467 * @param {Boolean} cancel true to cancel the query
10468 * @param {Object} e The query event object
10470 'beforequery': true,
10473 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10474 * @param {Roo.bootstrap.ComboBox} combo This combo box
10479 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10480 * @param {Roo.bootstrap.ComboBox} combo This combo box
10481 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10486 * Fires when the remove value from the combobox array
10487 * @param {Roo.bootstrap.ComboBox} combo This combo box
10494 this.tickItems = [];
10496 this.selectedIndex = -1;
10497 if(this.mode == 'local'){
10498 if(config.queryDelay === undefined){
10499 this.queryDelay = 10;
10501 if(config.minChars === undefined){
10507 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10510 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10511 * rendering into an Roo.Editor, defaults to false)
10514 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10515 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10518 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10521 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10522 * the dropdown list (defaults to undefined, with no header element)
10526 * @cfg {String/Roo.Template} tpl The template to use to render the output
10530 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10532 listWidth: undefined,
10534 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10535 * mode = 'remote' or 'text' if mode = 'local')
10537 displayField: undefined,
10539 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10540 * mode = 'remote' or 'value' if mode = 'local').
10541 * Note: use of a valueField requires the user make a selection
10542 * in order for a value to be mapped.
10544 valueField: undefined,
10548 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10549 * field's data value (defaults to the underlying DOM element's name)
10551 hiddenName: undefined,
10553 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10557 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10559 selectedClass: 'active',
10562 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10566 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10567 * anchor positions (defaults to 'tl-bl')
10569 listAlign: 'tl-bl?',
10571 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10575 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10576 * query specified by the allQuery config option (defaults to 'query')
10578 triggerAction: 'query',
10580 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10581 * (defaults to 4, does not apply if editable = false)
10585 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10586 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10590 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10591 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10595 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10596 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10600 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10601 * when editable = true (defaults to false)
10603 selectOnFocus:false,
10605 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10607 queryParam: 'query',
10609 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10610 * when mode = 'remote' (defaults to 'Loading...')
10612 loadingText: 'Loading...',
10614 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10618 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10622 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10623 * traditional select (defaults to true)
10627 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10631 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10635 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10636 * listWidth has a higher value)
10640 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10641 * allow the user to set arbitrary text into the field (defaults to false)
10643 forceSelection:false,
10645 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10646 * if typeAhead = true (defaults to 250)
10648 typeAheadDelay : 250,
10650 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10651 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10653 valueNotFoundText : undefined,
10655 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10657 blockFocus : false,
10660 * @cfg {Boolean} disableClear Disable showing of clear button.
10662 disableClear : false,
10664 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10666 alwaysQuery : false,
10669 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10683 btnPosition : 'right',
10684 triggerList : true,
10685 showToggleBtn : true,
10686 // element that contains real text value.. (when hidden is used..)
10688 getAutoCreate : function()
10695 if(!this.tickable){
10696 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10701 * ComboBox with tickable selections
10704 var align = this.labelAlign || this.parentLabelAlign();
10707 cls : 'form-group roo-combobox-tickable' //input-group
10713 cls : 'tickable-buttons',
10718 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10725 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10732 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10739 Roo.each(buttons.cn, function(c){
10741 c.cls += ' btn-' + _this.size;
10744 if (_this.disabled) {
10755 cls: 'form-hidden-field'
10759 cls: 'select2-choices',
10763 cls: 'select2-search-field',
10775 cls: 'select2-container input-group select2-container-multi',
10780 // cls: 'typeahead typeahead-long dropdown-menu',
10781 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10786 if (align ==='left' && this.fieldLabel.length) {
10788 Roo.log("left and has label");
10794 cls : 'control-label col-sm-' + this.labelWidth,
10795 html : this.fieldLabel
10799 cls : "col-sm-" + (12 - this.labelWidth),
10806 } else if ( this.fieldLabel.length) {
10812 //cls : 'input-group-addon',
10813 html : this.fieldLabel
10823 Roo.log(" no label && no align");
10830 ['xs','sm','md','lg'].map(function(size){
10831 if (settings[size]) {
10832 cfg.cls += ' col-' + size + '-' + settings[size];
10841 initEvents: function()
10845 throw "can not find store for combo";
10847 this.store = Roo.factory(this.store, Roo.data);
10850 this.initTickableEvents();
10854 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10856 if(this.hiddenName){
10858 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10860 this.hiddenField.dom.value =
10861 this.hiddenValue !== undefined ? this.hiddenValue :
10862 this.value !== undefined ? this.value : '';
10864 // prevent input submission
10865 this.el.dom.removeAttribute('name');
10866 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10871 // this.el.dom.setAttribute('autocomplete', 'off');
10874 var cls = 'x-combo-list';
10876 //this.list = new Roo.Layer({
10877 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10883 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10884 _this.list.setWidth(lw);
10887 this.list.on('mouseover', this.onViewOver, this);
10888 this.list.on('mousemove', this.onViewMove, this);
10890 this.list.on('scroll', this.onViewScroll, this);
10893 this.list.swallowEvent('mousewheel');
10894 this.assetHeight = 0;
10897 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10898 this.assetHeight += this.header.getHeight();
10901 this.innerList = this.list.createChild({cls:cls+'-inner'});
10902 this.innerList.on('mouseover', this.onViewOver, this);
10903 this.innerList.on('mousemove', this.onViewMove, this);
10904 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10906 if(this.allowBlank && !this.pageSize && !this.disableClear){
10907 this.footer = this.list.createChild({cls:cls+'-ft'});
10908 this.pageTb = new Roo.Toolbar(this.footer);
10912 this.footer = this.list.createChild({cls:cls+'-ft'});
10913 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10914 {pageSize: this.pageSize});
10918 if (this.pageTb && this.allowBlank && !this.disableClear) {
10920 this.pageTb.add(new Roo.Toolbar.Fill(), {
10921 cls: 'x-btn-icon x-btn-clear',
10923 handler: function()
10926 _this.clearValue();
10927 _this.onSelect(false, -1);
10932 this.assetHeight += this.footer.getHeight();
10937 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10940 this.view = new Roo.View(this.list, this.tpl, {
10941 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10943 //this.view.wrapEl.setDisplayed(false);
10944 this.view.on('click', this.onViewClick, this);
10948 this.store.on('beforeload', this.onBeforeLoad, this);
10949 this.store.on('load', this.onLoad, this);
10950 this.store.on('loadexception', this.onLoadException, this);
10952 if(this.resizable){
10953 this.resizer = new Roo.Resizable(this.list, {
10954 pinned:true, handles:'se'
10956 this.resizer.on('resize', function(r, w, h){
10957 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10958 this.listWidth = w;
10959 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10960 this.restrictHeight();
10962 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10965 if(!this.editable){
10966 this.editable = true;
10967 this.setEditable(false);
10972 if (typeof(this.events.add.listeners) != 'undefined') {
10974 this.addicon = this.wrap.createChild(
10975 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10977 this.addicon.on('click', function(e) {
10978 this.fireEvent('add', this);
10981 if (typeof(this.events.edit.listeners) != 'undefined') {
10983 this.editicon = this.wrap.createChild(
10984 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10985 if (this.addicon) {
10986 this.editicon.setStyle('margin-left', '40px');
10988 this.editicon.on('click', function(e) {
10990 // we fire even if inothing is selected..
10991 this.fireEvent('edit', this, this.lastData );
10997 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10998 "up" : function(e){
10999 this.inKeyMode = true;
11003 "down" : function(e){
11004 if(!this.isExpanded()){
11005 this.onTriggerClick();
11007 this.inKeyMode = true;
11012 "enter" : function(e){
11013 // this.onViewClick();
11017 if(this.fireEvent("specialkey", this, e)){
11018 this.onViewClick(false);
11024 "esc" : function(e){
11028 "tab" : function(e){
11031 if(this.fireEvent("specialkey", this, e)){
11032 this.onViewClick(false);
11040 doRelay : function(foo, bar, hname){
11041 if(hname == 'down' || this.scope.isExpanded()){
11042 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11051 this.queryDelay = Math.max(this.queryDelay || 10,
11052 this.mode == 'local' ? 10 : 250);
11055 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11057 if(this.typeAhead){
11058 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11060 if(this.editable !== false){
11061 this.inputEl().on("keyup", this.onKeyUp, this);
11063 if(this.forceSelection){
11064 this.inputEl().on('blur', this.doForce, this);
11068 this.choices = this.el.select('ul.select2-choices', true).first();
11069 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11073 initTickableEvents: function()
11077 if(this.hiddenName){
11079 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11081 this.hiddenField.dom.value =
11082 this.hiddenValue !== undefined ? this.hiddenValue :
11083 this.value !== undefined ? this.value : '';
11085 // prevent input submission
11086 this.el.dom.removeAttribute('name');
11087 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11092 // this.list = this.el.select('ul.dropdown-menu',true).first();
11094 this.choices = this.el.select('ul.select2-choices', true).first();
11095 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11096 if(this.triggerList){
11097 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11100 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11101 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11103 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11104 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11106 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11107 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11109 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11110 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11111 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11114 this.cancelBtn.hide();
11119 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11120 _this.list.setWidth(lw);
11123 this.list.on('mouseover', this.onViewOver, this);
11124 this.list.on('mousemove', this.onViewMove, this);
11126 this.list.on('scroll', this.onViewScroll, this);
11129 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>';
11132 this.view = new Roo.View(this.list, this.tpl, {
11133 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11136 //this.view.wrapEl.setDisplayed(false);
11137 this.view.on('click', this.onViewClick, this);
11141 this.store.on('beforeload', this.onBeforeLoad, this);
11142 this.store.on('load', this.onLoad, this);
11143 this.store.on('loadexception', this.onLoadException, this);
11145 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11146 // "up" : function(e){
11147 // this.inKeyMode = true;
11148 // this.selectPrev();
11151 // "down" : function(e){
11152 // if(!this.isExpanded()){
11153 // this.onTriggerClick();
11155 // this.inKeyMode = true;
11156 // this.selectNext();
11160 // "enter" : function(e){
11161 //// this.onViewClick();
11163 // this.collapse();
11165 // if(this.fireEvent("specialkey", this, e)){
11166 // this.onViewClick(false);
11172 // "esc" : function(e){
11173 // this.collapse();
11176 // "tab" : function(e){
11177 // this.collapse();
11179 // if(this.fireEvent("specialkey", this, e)){
11180 // this.onViewClick(false);
11188 // doRelay : function(foo, bar, hname){
11189 // if(hname == 'down' || this.scope.isExpanded()){
11190 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11195 // forceKeyDown: true
11199 this.queryDelay = Math.max(this.queryDelay || 10,
11200 this.mode == 'local' ? 10 : 250);
11203 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11205 if(this.typeAhead){
11206 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11210 onDestroy : function(){
11212 this.view.setStore(null);
11213 this.view.el.removeAllListeners();
11214 this.view.el.remove();
11215 this.view.purgeListeners();
11218 this.list.dom.innerHTML = '';
11222 this.store.un('beforeload', this.onBeforeLoad, this);
11223 this.store.un('load', this.onLoad, this);
11224 this.store.un('loadexception', this.onLoadException, this);
11226 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11230 fireKey : function(e){
11231 if(e.isNavKeyPress() && !this.list.isVisible()){
11232 this.fireEvent("specialkey", this, e);
11237 onResize: function(w, h){
11238 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11240 // if(typeof w != 'number'){
11241 // // we do not handle it!?!?
11244 // var tw = this.trigger.getWidth();
11245 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11246 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11248 // this.inputEl().setWidth( this.adjustWidth('input', x));
11250 // //this.trigger.setStyle('left', x+'px');
11252 // if(this.list && this.listWidth === undefined){
11253 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11254 // this.list.setWidth(lw);
11255 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11263 * Allow or prevent the user from directly editing the field text. If false is passed,
11264 * the user will only be able to select from the items defined in the dropdown list. This method
11265 * is the runtime equivalent of setting the 'editable' config option at config time.
11266 * @param {Boolean} value True to allow the user to directly edit the field text
11268 setEditable : function(value){
11269 if(value == this.editable){
11272 this.editable = value;
11274 this.inputEl().dom.setAttribute('readOnly', true);
11275 this.inputEl().on('mousedown', this.onTriggerClick, this);
11276 this.inputEl().addClass('x-combo-noedit');
11278 this.inputEl().dom.setAttribute('readOnly', false);
11279 this.inputEl().un('mousedown', this.onTriggerClick, this);
11280 this.inputEl().removeClass('x-combo-noedit');
11286 onBeforeLoad : function(combo,opts){
11287 if(!this.hasFocus){
11291 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11293 this.restrictHeight();
11294 this.selectedIndex = -1;
11298 onLoad : function(){
11300 this.hasQuery = false;
11302 if(!this.hasFocus){
11306 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11307 this.loading.hide();
11310 if(this.store.getCount() > 0){
11312 // this.restrictHeight();
11313 if(this.lastQuery == this.allQuery){
11314 if(this.editable && !this.tickable){
11315 this.inputEl().dom.select();
11319 !this.selectByValue(this.value, true) &&
11320 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11321 this.store.lastOptions.add != true)
11323 this.select(0, true);
11326 if(this.autoFocus){
11329 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11330 this.taTask.delay(this.typeAheadDelay);
11334 this.onEmptyResults();
11340 onLoadException : function()
11342 this.hasQuery = false;
11344 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11345 this.loading.hide();
11349 Roo.log(this.store.reader.jsonData);
11350 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11352 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11358 onTypeAhead : function(){
11359 if(this.store.getCount() > 0){
11360 var r = this.store.getAt(0);
11361 var newValue = r.data[this.displayField];
11362 var len = newValue.length;
11363 var selStart = this.getRawValue().length;
11365 if(selStart != len){
11366 this.setRawValue(newValue);
11367 this.selectText(selStart, newValue.length);
11373 onSelect : function(record, index){
11375 if(this.fireEvent('beforeselect', this, record, index) !== false){
11377 this.setFromData(index > -1 ? record.data : false);
11380 this.fireEvent('select', this, record, index);
11385 * Returns the currently selected field value or empty string if no value is set.
11386 * @return {String} value The selected value
11388 getValue : function(){
11391 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11394 if(this.valueField){
11395 return typeof this.value != 'undefined' ? this.value : '';
11397 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11402 * Clears any text/value currently set in the field
11404 clearValue : function(){
11405 if(this.hiddenField){
11406 this.hiddenField.dom.value = '';
11409 this.setRawValue('');
11410 this.lastSelectionText = '';
11415 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11416 * will be displayed in the field. If the value does not match the data value of an existing item,
11417 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11418 * Otherwise the field will be blank (although the value will still be set).
11419 * @param {String} value The value to match
11421 setValue : function(v){
11428 if(this.valueField){
11429 var r = this.findRecord(this.valueField, v);
11431 text = r.data[this.displayField];
11432 }else if(this.valueNotFoundText !== undefined){
11433 text = this.valueNotFoundText;
11436 this.lastSelectionText = text;
11437 if(this.hiddenField){
11438 this.hiddenField.dom.value = v;
11440 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11444 * @property {Object} the last set data for the element
11449 * Sets the value of the field based on a object which is related to the record format for the store.
11450 * @param {Object} value the value to set as. or false on reset?
11452 setFromData : function(o){
11459 var dv = ''; // display value
11460 var vv = ''; // value value..
11462 if (this.displayField) {
11463 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11465 // this is an error condition!!!
11466 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11469 if(this.valueField){
11470 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11473 if(this.hiddenField){
11474 this.hiddenField.dom.value = vv;
11476 this.lastSelectionText = dv;
11477 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11481 // no hidden field.. - we store the value in 'value', but still display
11482 // display field!!!!
11483 this.lastSelectionText = dv;
11484 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11490 reset : function(){
11491 // overridden so that last data is reset..
11492 this.setValue(this.originalValue);
11493 this.clearInvalid();
11494 this.lastData = false;
11496 this.view.clearSelections();
11500 findRecord : function(prop, value){
11502 if(this.store.getCount() > 0){
11503 this.store.each(function(r){
11504 if(r.data[prop] == value){
11514 getName: function()
11516 // returns hidden if it's set..
11517 if (!this.rendered) {return ''};
11518 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11522 onViewMove : function(e, t){
11523 this.inKeyMode = false;
11527 onViewOver : function(e, t){
11528 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11531 var item = this.view.findItemFromChild(t);
11534 var index = this.view.indexOf(item);
11535 this.select(index, false);
11540 onViewClick : function(view, doFocus, el, e)
11542 var index = this.view.getSelectedIndexes()[0];
11544 var r = this.store.getAt(index);
11548 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11555 Roo.each(this.tickItems, function(v,k){
11557 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11558 _this.tickItems.splice(k, 1);
11568 this.tickItems.push(r.data);
11573 this.onSelect(r, index);
11575 if(doFocus !== false && !this.blockFocus){
11576 this.inputEl().focus();
11581 restrictHeight : function(){
11582 //this.innerList.dom.style.height = '';
11583 //var inner = this.innerList.dom;
11584 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11585 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11586 //this.list.beginUpdate();
11587 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11588 this.list.alignTo(this.inputEl(), this.listAlign);
11589 this.list.alignTo(this.inputEl(), this.listAlign);
11590 //this.list.endUpdate();
11594 onEmptyResults : function(){
11599 * Returns true if the dropdown list is expanded, else false.
11601 isExpanded : function(){
11602 return this.list.isVisible();
11606 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11607 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11608 * @param {String} value The data value of the item to select
11609 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11610 * selected item if it is not currently in view (defaults to true)
11611 * @return {Boolean} True if the value matched an item in the list, else false
11613 selectByValue : function(v, scrollIntoView){
11614 if(v !== undefined && v !== null){
11615 var r = this.findRecord(this.valueField || this.displayField, v);
11617 this.select(this.store.indexOf(r), scrollIntoView);
11625 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11626 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11627 * @param {Number} index The zero-based index of the list item to select
11628 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11629 * selected item if it is not currently in view (defaults to true)
11631 select : function(index, scrollIntoView){
11632 this.selectedIndex = index;
11633 this.view.select(index);
11634 if(scrollIntoView !== false){
11635 var el = this.view.getNode(index);
11636 if(el && !this.multiple && !this.tickable){
11637 this.list.scrollChildIntoView(el, false);
11643 selectNext : function(){
11644 var ct = this.store.getCount();
11646 if(this.selectedIndex == -1){
11648 }else if(this.selectedIndex < ct-1){
11649 this.select(this.selectedIndex+1);
11655 selectPrev : function(){
11656 var ct = this.store.getCount();
11658 if(this.selectedIndex == -1){
11660 }else if(this.selectedIndex != 0){
11661 this.select(this.selectedIndex-1);
11667 onKeyUp : function(e){
11668 if(this.editable !== false && !e.isSpecialKey()){
11669 this.lastKey = e.getKey();
11670 this.dqTask.delay(this.queryDelay);
11675 validateBlur : function(){
11676 return !this.list || !this.list.isVisible();
11680 initQuery : function(){
11681 this.doQuery(this.getRawValue());
11685 doForce : function(){
11686 if(this.inputEl().dom.value.length > 0){
11687 this.inputEl().dom.value =
11688 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11694 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11695 * query allowing the query action to be canceled if needed.
11696 * @param {String} query The SQL query to execute
11697 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11698 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11699 * saved in the current store (defaults to false)
11701 doQuery : function(q, forceAll){
11703 if(q === undefined || q === null){
11708 forceAll: forceAll,
11712 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11717 forceAll = qe.forceAll;
11718 if(forceAll === true || (q.length >= this.minChars)){
11720 this.hasQuery = true;
11722 if(this.lastQuery != q || this.alwaysQuery){
11723 this.lastQuery = q;
11724 if(this.mode == 'local'){
11725 this.selectedIndex = -1;
11727 this.store.clearFilter();
11729 this.store.filter(this.displayField, q);
11733 this.store.baseParams[this.queryParam] = q;
11735 var options = {params : this.getParams(q)};
11738 options.add = true;
11739 options.params.start = this.page * this.pageSize;
11742 this.store.load(options);
11744 * this code will make the page width larger, at the beginning, the list not align correctly,
11745 * we should expand the list on onLoad
11746 * so command out it
11751 this.selectedIndex = -1;
11756 this.loadNext = false;
11760 getParams : function(q){
11762 //p[this.queryParam] = q;
11766 p.limit = this.pageSize;
11772 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11774 collapse : function(){
11775 if(!this.isExpanded()){
11783 this.cancelBtn.hide();
11784 this.trigger.show();
11787 Roo.get(document).un('mousedown', this.collapseIf, this);
11788 Roo.get(document).un('mousewheel', this.collapseIf, this);
11789 if (!this.editable) {
11790 Roo.get(document).un('keydown', this.listKeyPress, this);
11792 this.fireEvent('collapse', this);
11796 collapseIf : function(e){
11797 var in_combo = e.within(this.el);
11798 var in_list = e.within(this.list);
11799 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11801 if (in_combo || in_list || is_list) {
11802 //e.stopPropagation();
11807 this.onTickableFooterButtonClick(e, false, false);
11815 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11817 expand : function(){
11819 if(this.isExpanded() || !this.hasFocus){
11823 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11824 this.list.setWidth(lw);
11831 this.restrictHeight();
11835 this.tickItems = Roo.apply([], this.item);
11838 this.cancelBtn.show();
11839 this.trigger.hide();
11843 Roo.get(document).on('mousedown', this.collapseIf, this);
11844 Roo.get(document).on('mousewheel', this.collapseIf, this);
11845 if (!this.editable) {
11846 Roo.get(document).on('keydown', this.listKeyPress, this);
11849 this.fireEvent('expand', this);
11853 // Implements the default empty TriggerField.onTriggerClick function
11854 onTriggerClick : function(e)
11856 Roo.log('trigger click');
11858 if(this.disabled || !this.triggerList){
11863 this.loadNext = false;
11865 if(this.isExpanded()){
11867 if (!this.blockFocus) {
11868 this.inputEl().focus();
11872 this.hasFocus = true;
11873 if(this.triggerAction == 'all') {
11874 this.doQuery(this.allQuery, true);
11876 this.doQuery(this.getRawValue());
11878 if (!this.blockFocus) {
11879 this.inputEl().focus();
11884 onTickableTriggerClick : function(e)
11891 this.loadNext = false;
11892 this.hasFocus = true;
11894 if(this.triggerAction == 'all') {
11895 this.doQuery(this.allQuery, true);
11897 this.doQuery(this.getRawValue());
11901 onSearchFieldClick : function(e)
11903 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11908 this.loadNext = false;
11909 this.hasFocus = true;
11911 if(this.triggerAction == 'all') {
11912 this.doQuery(this.allQuery, true);
11914 this.doQuery(this.getRawValue());
11918 listKeyPress : function(e)
11920 //Roo.log('listkeypress');
11921 // scroll to first matching element based on key pres..
11922 if (e.isSpecialKey()) {
11925 var k = String.fromCharCode(e.getKey()).toUpperCase();
11928 var csel = this.view.getSelectedNodes();
11929 var cselitem = false;
11931 var ix = this.view.indexOf(csel[0]);
11932 cselitem = this.store.getAt(ix);
11933 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11939 this.store.each(function(v) {
11941 // start at existing selection.
11942 if (cselitem.id == v.id) {
11948 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11949 match = this.store.indexOf(v);
11955 if (match === false) {
11956 return true; // no more action?
11959 this.view.select(match);
11960 var sn = Roo.get(this.view.getSelectedNodes()[0])
11961 sn.scrollIntoView(sn.dom.parentNode, false);
11964 onViewScroll : function(e, t){
11966 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){
11970 this.hasQuery = true;
11972 this.loading = this.list.select('.loading', true).first();
11974 if(this.loading === null){
11975 this.list.createChild({
11977 cls: 'loading select2-more-results select2-active',
11978 html: 'Loading more results...'
11981 this.loading = this.list.select('.loading', true).first();
11983 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11985 this.loading.hide();
11988 this.loading.show();
11993 this.loadNext = true;
11995 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12000 addItem : function(o)
12002 var dv = ''; // display value
12004 if (this.displayField) {
12005 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12007 // this is an error condition!!!
12008 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12015 var choice = this.choices.createChild({
12017 cls: 'select2-search-choice',
12026 cls: 'select2-search-choice-close',
12031 }, this.searchField);
12033 var close = choice.select('a.select2-search-choice-close', true).first()
12035 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12043 this.inputEl().dom.value = '';
12047 onRemoveItem : function(e, _self, o)
12049 e.preventDefault();
12050 var index = this.item.indexOf(o.data) * 1;
12053 Roo.log('not this item?!');
12057 this.item.splice(index, 1);
12062 this.fireEvent('remove', this, e);
12066 syncValue : function()
12068 if(!this.item.length){
12075 Roo.each(this.item, function(i){
12076 if(_this.valueField){
12077 value.push(i[_this.valueField]);
12084 this.value = value.join(',');
12086 if(this.hiddenField){
12087 this.hiddenField.dom.value = this.value;
12091 clearItem : function()
12093 if(!this.multiple){
12099 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12106 inputEl: function ()
12109 return this.searchField;
12111 return this.el.select('input.form-control',true).first();
12115 onTickableFooterButtonClick : function(e, btn, el)
12117 e.preventDefault();
12119 if(btn && btn.name == 'cancel'){
12120 this.tickItems = Roo.apply([], this.item);
12129 Roo.each(this.tickItems, function(o){
12137 validate : function()
12139 var v = this.getRawValue();
12142 v = this.getValue();
12145 if(this.disabled || this.validateValue(v)){
12146 this.clearInvalid();
12155 * @cfg {Boolean} grow
12159 * @cfg {Number} growMin
12163 * @cfg {Number} growMax
12173 * Ext JS Library 1.1.1
12174 * Copyright(c) 2006-2007, Ext JS, LLC.
12176 * Originally Released Under LGPL - original licence link has changed is not relivant.
12179 * <script type="text/javascript">
12184 * @extends Roo.util.Observable
12185 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12186 * This class also supports single and multi selection modes. <br>
12187 * Create a data model bound view:
12189 var store = new Roo.data.Store(...);
12191 var view = new Roo.View({
12193 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12195 singleSelect: true,
12196 selectedClass: "ydataview-selected",
12200 // listen for node click?
12201 view.on("click", function(vw, index, node, e){
12202 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12206 dataModel.load("foobar.xml");
12208 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12210 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12211 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12213 * Note: old style constructor is still suported (container, template, config)
12216 * Create a new View
12217 * @param {Object} config The config object
12220 Roo.View = function(config, depreciated_tpl, depreciated_config){
12222 this.parent = false;
12224 if (typeof(depreciated_tpl) == 'undefined') {
12225 // new way.. - universal constructor.
12226 Roo.apply(this, config);
12227 this.el = Roo.get(this.el);
12230 this.el = Roo.get(config);
12231 this.tpl = depreciated_tpl;
12232 Roo.apply(this, depreciated_config);
12234 this.wrapEl = this.el.wrap().wrap();
12235 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12238 if(typeof(this.tpl) == "string"){
12239 this.tpl = new Roo.Template(this.tpl);
12241 // support xtype ctors..
12242 this.tpl = new Roo.factory(this.tpl, Roo);
12246 this.tpl.compile();
12251 * @event beforeclick
12252 * Fires before a click is processed. Returns false to cancel the default action.
12253 * @param {Roo.View} this
12254 * @param {Number} index The index of the target node
12255 * @param {HTMLElement} node The target node
12256 * @param {Roo.EventObject} e The raw event object
12258 "beforeclick" : true,
12261 * Fires when a template node is clicked.
12262 * @param {Roo.View} this
12263 * @param {Number} index The index of the target node
12264 * @param {HTMLElement} node The target node
12265 * @param {Roo.EventObject} e The raw event object
12270 * Fires when a template node is double clicked.
12271 * @param {Roo.View} this
12272 * @param {Number} index The index of the target node
12273 * @param {HTMLElement} node The target node
12274 * @param {Roo.EventObject} e The raw event object
12278 * @event contextmenu
12279 * Fires when a template node is right clicked.
12280 * @param {Roo.View} this
12281 * @param {Number} index The index of the target node
12282 * @param {HTMLElement} node The target node
12283 * @param {Roo.EventObject} e The raw event object
12285 "contextmenu" : true,
12287 * @event selectionchange
12288 * Fires when the selected nodes change.
12289 * @param {Roo.View} this
12290 * @param {Array} selections Array of the selected nodes
12292 "selectionchange" : true,
12295 * @event beforeselect
12296 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12297 * @param {Roo.View} this
12298 * @param {HTMLElement} node The node to be selected
12299 * @param {Array} selections Array of currently selected nodes
12301 "beforeselect" : true,
12303 * @event preparedata
12304 * Fires on every row to render, to allow you to change the data.
12305 * @param {Roo.View} this
12306 * @param {Object} data to be rendered (change this)
12308 "preparedata" : true
12316 "click": this.onClick,
12317 "dblclick": this.onDblClick,
12318 "contextmenu": this.onContextMenu,
12322 this.selections = [];
12324 this.cmp = new Roo.CompositeElementLite([]);
12326 this.store = Roo.factory(this.store, Roo.data);
12327 this.setStore(this.store, true);
12330 if ( this.footer && this.footer.xtype) {
12332 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12334 this.footer.dataSource = this.store
12335 this.footer.container = fctr;
12336 this.footer = Roo.factory(this.footer, Roo);
12337 fctr.insertFirst(this.el);
12339 // this is a bit insane - as the paging toolbar seems to detach the el..
12340 // dom.parentNode.parentNode.parentNode
12341 // they get detached?
12345 Roo.View.superclass.constructor.call(this);
12350 Roo.extend(Roo.View, Roo.util.Observable, {
12353 * @cfg {Roo.data.Store} store Data store to load data from.
12358 * @cfg {String|Roo.Element} el The container element.
12363 * @cfg {String|Roo.Template} tpl The template used by this View
12367 * @cfg {String} dataName the named area of the template to use as the data area
12368 * Works with domtemplates roo-name="name"
12372 * @cfg {String} selectedClass The css class to add to selected nodes
12374 selectedClass : "x-view-selected",
12376 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12381 * @cfg {String} text to display on mask (default Loading)
12385 * @cfg {Boolean} multiSelect Allow multiple selection
12387 multiSelect : false,
12389 * @cfg {Boolean} singleSelect Allow single selection
12391 singleSelect: false,
12394 * @cfg {Boolean} toggleSelect - selecting
12396 toggleSelect : false,
12399 * @cfg {Boolean} tickable - selecting
12404 * Returns the element this view is bound to.
12405 * @return {Roo.Element}
12407 getEl : function(){
12408 return this.wrapEl;
12414 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12416 refresh : function(){
12417 //Roo.log('refresh');
12420 // if we are using something like 'domtemplate', then
12421 // the what gets used is:
12422 // t.applySubtemplate(NAME, data, wrapping data..)
12423 // the outer template then get' applied with
12424 // the store 'extra data'
12425 // and the body get's added to the
12426 // roo-name="data" node?
12427 // <span class='roo-tpl-{name}'></span> ?????
12431 this.clearSelections();
12432 this.el.update("");
12434 var records = this.store.getRange();
12435 if(records.length < 1) {
12437 // is this valid?? = should it render a template??
12439 this.el.update(this.emptyText);
12443 if (this.dataName) {
12444 this.el.update(t.apply(this.store.meta)); //????
12445 el = this.el.child('.roo-tpl-' + this.dataName);
12448 for(var i = 0, len = records.length; i < len; i++){
12449 var data = this.prepareData(records[i].data, i, records[i]);
12450 this.fireEvent("preparedata", this, data, i, records[i]);
12452 var d = Roo.apply({}, data);
12455 Roo.apply(d, {'roo-id' : Roo.id()});
12459 Roo.each(this.parent.item, function(item){
12460 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12463 Roo.apply(d, {'roo-data-checked' : 'checked'});
12467 html[html.length] = Roo.util.Format.trim(
12469 t.applySubtemplate(this.dataName, d, this.store.meta) :
12476 el.update(html.join(""));
12477 this.nodes = el.dom.childNodes;
12478 this.updateIndexes(0);
12483 * Function to override to reformat the data that is sent to
12484 * the template for each node.
12485 * DEPRICATED - use the preparedata event handler.
12486 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12487 * a JSON object for an UpdateManager bound view).
12489 prepareData : function(data, index, record)
12491 this.fireEvent("preparedata", this, data, index, record);
12495 onUpdate : function(ds, record){
12496 // Roo.log('on update');
12497 this.clearSelections();
12498 var index = this.store.indexOf(record);
12499 var n = this.nodes[index];
12500 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12501 n.parentNode.removeChild(n);
12502 this.updateIndexes(index, index);
12508 onAdd : function(ds, records, index)
12510 //Roo.log(['on Add', ds, records, index] );
12511 this.clearSelections();
12512 if(this.nodes.length == 0){
12516 var n = this.nodes[index];
12517 for(var i = 0, len = records.length; i < len; i++){
12518 var d = this.prepareData(records[i].data, i, records[i]);
12520 this.tpl.insertBefore(n, d);
12523 this.tpl.append(this.el, d);
12526 this.updateIndexes(index);
12529 onRemove : function(ds, record, index){
12530 // Roo.log('onRemove');
12531 this.clearSelections();
12532 var el = this.dataName ?
12533 this.el.child('.roo-tpl-' + this.dataName) :
12536 el.dom.removeChild(this.nodes[index]);
12537 this.updateIndexes(index);
12541 * Refresh an individual node.
12542 * @param {Number} index
12544 refreshNode : function(index){
12545 this.onUpdate(this.store, this.store.getAt(index));
12548 updateIndexes : function(startIndex, endIndex){
12549 var ns = this.nodes;
12550 startIndex = startIndex || 0;
12551 endIndex = endIndex || ns.length - 1;
12552 for(var i = startIndex; i <= endIndex; i++){
12553 ns[i].nodeIndex = i;
12558 * Changes the data store this view uses and refresh the view.
12559 * @param {Store} store
12561 setStore : function(store, initial){
12562 if(!initial && this.store){
12563 this.store.un("datachanged", this.refresh);
12564 this.store.un("add", this.onAdd);
12565 this.store.un("remove", this.onRemove);
12566 this.store.un("update", this.onUpdate);
12567 this.store.un("clear", this.refresh);
12568 this.store.un("beforeload", this.onBeforeLoad);
12569 this.store.un("load", this.onLoad);
12570 this.store.un("loadexception", this.onLoad);
12574 store.on("datachanged", this.refresh, this);
12575 store.on("add", this.onAdd, this);
12576 store.on("remove", this.onRemove, this);
12577 store.on("update", this.onUpdate, this);
12578 store.on("clear", this.refresh, this);
12579 store.on("beforeload", this.onBeforeLoad, this);
12580 store.on("load", this.onLoad, this);
12581 store.on("loadexception", this.onLoad, this);
12589 * onbeforeLoad - masks the loading area.
12592 onBeforeLoad : function(store,opts)
12594 //Roo.log('onBeforeLoad');
12596 this.el.update("");
12598 this.el.mask(this.mask ? this.mask : "Loading" );
12600 onLoad : function ()
12607 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12608 * @param {HTMLElement} node
12609 * @return {HTMLElement} The template node
12611 findItemFromChild : function(node){
12612 var el = this.dataName ?
12613 this.el.child('.roo-tpl-' + this.dataName,true) :
12616 if(!node || node.parentNode == el){
12619 var p = node.parentNode;
12620 while(p && p != el){
12621 if(p.parentNode == el){
12630 onClick : function(e){
12631 var item = this.findItemFromChild(e.getTarget());
12633 var index = this.indexOf(item);
12634 if(this.onItemClick(item, index, e) !== false){
12635 this.fireEvent("click", this, index, item, e);
12638 this.clearSelections();
12643 onContextMenu : function(e){
12644 var item = this.findItemFromChild(e.getTarget());
12646 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12651 onDblClick : function(e){
12652 var item = this.findItemFromChild(e.getTarget());
12654 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12658 onItemClick : function(item, index, e)
12660 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12663 if (this.toggleSelect) {
12664 var m = this.isSelected(item) ? 'unselect' : 'select';
12667 _t[m](item, true, false);
12670 if(this.multiSelect || this.singleSelect){
12671 if(this.multiSelect && e.shiftKey && this.lastSelection){
12672 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12674 this.select(item, this.multiSelect && e.ctrlKey);
12675 this.lastSelection = item;
12678 if(!this.tickable){
12679 e.preventDefault();
12687 * Get the number of selected nodes.
12690 getSelectionCount : function(){
12691 return this.selections.length;
12695 * Get the currently selected nodes.
12696 * @return {Array} An array of HTMLElements
12698 getSelectedNodes : function(){
12699 return this.selections;
12703 * Get the indexes of the selected nodes.
12706 getSelectedIndexes : function(){
12707 var indexes = [], s = this.selections;
12708 for(var i = 0, len = s.length; i < len; i++){
12709 indexes.push(s[i].nodeIndex);
12715 * Clear all selections
12716 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12718 clearSelections : function(suppressEvent){
12719 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12720 this.cmp.elements = this.selections;
12721 this.cmp.removeClass(this.selectedClass);
12722 this.selections = [];
12723 if(!suppressEvent){
12724 this.fireEvent("selectionchange", this, this.selections);
12730 * Returns true if the passed node is selected
12731 * @param {HTMLElement/Number} node The node or node index
12732 * @return {Boolean}
12734 isSelected : function(node){
12735 var s = this.selections;
12739 node = this.getNode(node);
12740 return s.indexOf(node) !== -1;
12745 * @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
12746 * @param {Boolean} keepExisting (optional) true to keep existing selections
12747 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12749 select : function(nodeInfo, keepExisting, suppressEvent){
12750 if(nodeInfo instanceof Array){
12752 this.clearSelections(true);
12754 for(var i = 0, len = nodeInfo.length; i < len; i++){
12755 this.select(nodeInfo[i], true, true);
12759 var node = this.getNode(nodeInfo);
12760 if(!node || this.isSelected(node)){
12761 return; // already selected.
12764 this.clearSelections(true);
12767 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12768 Roo.fly(node).addClass(this.selectedClass);
12769 this.selections.push(node);
12770 if(!suppressEvent){
12771 this.fireEvent("selectionchange", this, this.selections);
12779 * @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
12780 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12781 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12783 unselect : function(nodeInfo, keepExisting, suppressEvent)
12785 if(nodeInfo instanceof Array){
12786 Roo.each(this.selections, function(s) {
12787 this.unselect(s, nodeInfo);
12791 var node = this.getNode(nodeInfo);
12792 if(!node || !this.isSelected(node)){
12793 //Roo.log("not selected");
12794 return; // not selected.
12798 Roo.each(this.selections, function(s) {
12800 Roo.fly(node).removeClass(this.selectedClass);
12807 this.selections= ns;
12808 this.fireEvent("selectionchange", this, this.selections);
12812 * Gets a template node.
12813 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12814 * @return {HTMLElement} The node or null if it wasn't found
12816 getNode : function(nodeInfo){
12817 if(typeof nodeInfo == "string"){
12818 return document.getElementById(nodeInfo);
12819 }else if(typeof nodeInfo == "number"){
12820 return this.nodes[nodeInfo];
12826 * Gets a range template nodes.
12827 * @param {Number} startIndex
12828 * @param {Number} endIndex
12829 * @return {Array} An array of nodes
12831 getNodes : function(start, end){
12832 var ns = this.nodes;
12833 start = start || 0;
12834 end = typeof end == "undefined" ? ns.length - 1 : end;
12837 for(var i = start; i <= end; i++){
12841 for(var i = start; i >= end; i--){
12849 * Finds the index of the passed node
12850 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12851 * @return {Number} The index of the node or -1
12853 indexOf : function(node){
12854 node = this.getNode(node);
12855 if(typeof node.nodeIndex == "number"){
12856 return node.nodeIndex;
12858 var ns = this.nodes;
12859 for(var i = 0, len = ns.length; i < len; i++){
12870 * based on jquery fullcalendar
12874 Roo.bootstrap = Roo.bootstrap || {};
12876 * @class Roo.bootstrap.Calendar
12877 * @extends Roo.bootstrap.Component
12878 * Bootstrap Calendar class
12879 * @cfg {Boolean} loadMask (true|false) default false
12880 * @cfg {Object} header generate the user specific header of the calendar, default false
12883 * Create a new Container
12884 * @param {Object} config The config object
12889 Roo.bootstrap.Calendar = function(config){
12890 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12894 * Fires when a date is selected
12895 * @param {DatePicker} this
12896 * @param {Date} date The selected date
12900 * @event monthchange
12901 * Fires when the displayed month changes
12902 * @param {DatePicker} this
12903 * @param {Date} date The selected month
12905 'monthchange': true,
12907 * @event evententer
12908 * Fires when mouse over an event
12909 * @param {Calendar} this
12910 * @param {event} Event
12912 'evententer': true,
12914 * @event eventleave
12915 * Fires when the mouse leaves an
12916 * @param {Calendar} this
12919 'eventleave': true,
12921 * @event eventclick
12922 * Fires when the mouse click an
12923 * @param {Calendar} this
12932 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12935 * @cfg {Number} startDay
12936 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12944 getAutoCreate : function(){
12947 var fc_button = function(name, corner, style, content ) {
12948 return Roo.apply({},{
12950 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12952 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12955 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12966 style : 'width:100%',
12973 cls : 'fc-header-left',
12975 fc_button('prev', 'left', 'arrow', '‹' ),
12976 fc_button('next', 'right', 'arrow', '›' ),
12977 { tag: 'span', cls: 'fc-header-space' },
12978 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12986 cls : 'fc-header-center',
12990 cls: 'fc-header-title',
12993 html : 'month / year'
13001 cls : 'fc-header-right',
13003 /* fc_button('month', 'left', '', 'month' ),
13004 fc_button('week', '', '', 'week' ),
13005 fc_button('day', 'right', '', 'day' )
13017 header = this.header;
13020 var cal_heads = function() {
13022 // fixme - handle this.
13024 for (var i =0; i < Date.dayNames.length; i++) {
13025 var d = Date.dayNames[i];
13028 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13029 html : d.substring(0,3)
13033 ret[0].cls += ' fc-first';
13034 ret[6].cls += ' fc-last';
13037 var cal_cell = function(n) {
13040 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13045 cls: 'fc-day-number',
13049 cls: 'fc-day-content',
13053 style: 'position: relative;' // height: 17px;
13065 var cal_rows = function() {
13068 for (var r = 0; r < 6; r++) {
13075 for (var i =0; i < Date.dayNames.length; i++) {
13076 var d = Date.dayNames[i];
13077 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13080 row.cn[0].cls+=' fc-first';
13081 row.cn[0].cn[0].style = 'min-height:90px';
13082 row.cn[6].cls+=' fc-last';
13086 ret[0].cls += ' fc-first';
13087 ret[4].cls += ' fc-prev-last';
13088 ret[5].cls += ' fc-last';
13095 cls: 'fc-border-separate',
13096 style : 'width:100%',
13104 cls : 'fc-first fc-last',
13122 cls : 'fc-content',
13123 style : "position: relative;",
13126 cls : 'fc-view fc-view-month fc-grid',
13127 style : 'position: relative',
13128 unselectable : 'on',
13131 cls : 'fc-event-container',
13132 style : 'position:absolute;z-index:8;top:0;left:0;'
13150 initEvents : function()
13153 throw "can not find store for calendar";
13159 style: "text-align:center",
13163 style: "background-color:white;width:50%;margin:250 auto",
13167 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13178 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13180 var size = this.el.select('.fc-content', true).first().getSize();
13181 this.maskEl.setSize(size.width, size.height);
13182 this.maskEl.enableDisplayMode("block");
13183 if(!this.loadMask){
13184 this.maskEl.hide();
13187 this.store = Roo.factory(this.store, Roo.data);
13188 this.store.on('load', this.onLoad, this);
13189 this.store.on('beforeload', this.onBeforeLoad, this);
13193 this.cells = this.el.select('.fc-day',true);
13194 //Roo.log(this.cells);
13195 this.textNodes = this.el.query('.fc-day-number');
13196 this.cells.addClassOnOver('fc-state-hover');
13198 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13199 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13200 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13201 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13203 this.on('monthchange', this.onMonthChange, this);
13205 this.update(new Date().clearTime());
13208 resize : function() {
13209 var sz = this.el.getSize();
13211 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13212 this.el.select('.fc-day-content div',true).setHeight(34);
13217 showPrevMonth : function(e){
13218 this.update(this.activeDate.add("mo", -1));
13220 showToday : function(e){
13221 this.update(new Date().clearTime());
13224 showNextMonth : function(e){
13225 this.update(this.activeDate.add("mo", 1));
13229 showPrevYear : function(){
13230 this.update(this.activeDate.add("y", -1));
13234 showNextYear : function(){
13235 this.update(this.activeDate.add("y", 1));
13240 update : function(date)
13242 var vd = this.activeDate;
13243 this.activeDate = date;
13244 // if(vd && this.el){
13245 // var t = date.getTime();
13246 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13247 // Roo.log('using add remove');
13249 // this.fireEvent('monthchange', this, date);
13251 // this.cells.removeClass("fc-state-highlight");
13252 // this.cells.each(function(c){
13253 // if(c.dateValue == t){
13254 // c.addClass("fc-state-highlight");
13255 // setTimeout(function(){
13256 // try{c.dom.firstChild.focus();}catch(e){}
13266 var days = date.getDaysInMonth();
13268 var firstOfMonth = date.getFirstDateOfMonth();
13269 var startingPos = firstOfMonth.getDay()-this.startDay;
13271 if(startingPos < this.startDay){
13275 var pm = date.add(Date.MONTH, -1);
13276 var prevStart = pm.getDaysInMonth()-startingPos;
13278 this.cells = this.el.select('.fc-day',true);
13279 this.textNodes = this.el.query('.fc-day-number');
13280 this.cells.addClassOnOver('fc-state-hover');
13282 var cells = this.cells.elements;
13283 var textEls = this.textNodes;
13285 Roo.each(cells, function(cell){
13286 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13289 days += startingPos;
13291 // convert everything to numbers so it's fast
13292 var day = 86400000;
13293 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13296 //Roo.log(prevStart);
13298 var today = new Date().clearTime().getTime();
13299 var sel = date.clearTime().getTime();
13300 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13301 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13302 var ddMatch = this.disabledDatesRE;
13303 var ddText = this.disabledDatesText;
13304 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13305 var ddaysText = this.disabledDaysText;
13306 var format = this.format;
13308 var setCellClass = function(cal, cell){
13312 //Roo.log('set Cell Class');
13314 var t = d.getTime();
13318 cell.dateValue = t;
13320 cell.className += " fc-today";
13321 cell.className += " fc-state-highlight";
13322 cell.title = cal.todayText;
13325 // disable highlight in other month..
13326 //cell.className += " fc-state-highlight";
13331 cell.className = " fc-state-disabled";
13332 cell.title = cal.minText;
13336 cell.className = " fc-state-disabled";
13337 cell.title = cal.maxText;
13341 if(ddays.indexOf(d.getDay()) != -1){
13342 cell.title = ddaysText;
13343 cell.className = " fc-state-disabled";
13346 if(ddMatch && format){
13347 var fvalue = d.dateFormat(format);
13348 if(ddMatch.test(fvalue)){
13349 cell.title = ddText.replace("%0", fvalue);
13350 cell.className = " fc-state-disabled";
13354 if (!cell.initialClassName) {
13355 cell.initialClassName = cell.dom.className;
13358 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13363 for(; i < startingPos; i++) {
13364 textEls[i].innerHTML = (++prevStart);
13365 d.setDate(d.getDate()+1);
13367 cells[i].className = "fc-past fc-other-month";
13368 setCellClass(this, cells[i]);
13373 for(; i < days; i++){
13374 intDay = i - startingPos + 1;
13375 textEls[i].innerHTML = (intDay);
13376 d.setDate(d.getDate()+1);
13378 cells[i].className = ''; // "x-date-active";
13379 setCellClass(this, cells[i]);
13383 for(; i < 42; i++) {
13384 textEls[i].innerHTML = (++extraDays);
13385 d.setDate(d.getDate()+1);
13387 cells[i].className = "fc-future fc-other-month";
13388 setCellClass(this, cells[i]);
13391 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13393 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13395 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13396 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13398 if(totalRows != 6){
13399 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13400 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13403 this.fireEvent('monthchange', this, date);
13407 if(!this.internalRender){
13408 var main = this.el.dom.firstChild;
13409 var w = main.offsetWidth;
13410 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13411 Roo.fly(main).setWidth(w);
13412 this.internalRender = true;
13413 // opera does not respect the auto grow header center column
13414 // then, after it gets a width opera refuses to recalculate
13415 // without a second pass
13416 if(Roo.isOpera && !this.secondPass){
13417 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13418 this.secondPass = true;
13419 this.update.defer(10, this, [date]);
13426 findCell : function(dt) {
13427 dt = dt.clearTime().getTime();
13429 this.cells.each(function(c){
13430 //Roo.log("check " +c.dateValue + '?=' + dt);
13431 if(c.dateValue == dt){
13441 findCells : function(ev) {
13442 var s = ev.start.clone().clearTime().getTime();
13444 var e= ev.end.clone().clearTime().getTime();
13447 this.cells.each(function(c){
13448 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13450 if(c.dateValue > e){
13453 if(c.dateValue < s){
13462 // findBestRow: function(cells)
13466 // for (var i =0 ; i < cells.length;i++) {
13467 // ret = Math.max(cells[i].rows || 0,ret);
13474 addItem : function(ev)
13476 // look for vertical location slot in
13477 var cells = this.findCells(ev);
13479 // ev.row = this.findBestRow(cells);
13481 // work out the location.
13485 for(var i =0; i < cells.length; i++) {
13487 cells[i].row = cells[0].row;
13490 cells[i].row = cells[i].row + 1;
13500 if (crow.start.getY() == cells[i].getY()) {
13502 crow.end = cells[i];
13519 cells[0].events.push(ev);
13521 this.calevents.push(ev);
13524 clearEvents: function() {
13526 if(!this.calevents){
13530 Roo.each(this.cells.elements, function(c){
13536 Roo.each(this.calevents, function(e) {
13537 Roo.each(e.els, function(el) {
13538 el.un('mouseenter' ,this.onEventEnter, this);
13539 el.un('mouseleave' ,this.onEventLeave, this);
13544 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13550 renderEvents: function()
13554 this.cells.each(function(c) {
13563 if(c.row != c.events.length){
13564 r = 4 - (4 - (c.row - c.events.length));
13567 c.events = ev.slice(0, r);
13568 c.more = ev.slice(r);
13570 if(c.more.length && c.more.length == 1){
13571 c.events.push(c.more.pop());
13574 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13578 this.cells.each(function(c) {
13580 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13583 for (var e = 0; e < c.events.length; e++){
13584 var ev = c.events[e];
13585 var rows = ev.rows;
13587 for(var i = 0; i < rows.length; i++) {
13589 // how many rows should it span..
13592 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13593 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13595 unselectable : "on",
13598 cls: 'fc-event-inner',
13602 // cls: 'fc-event-time',
13603 // html : cells.length > 1 ? '' : ev.time
13607 cls: 'fc-event-title',
13608 html : String.format('{0}', ev.title)
13615 cls: 'ui-resizable-handle ui-resizable-e',
13616 html : '  '
13623 cfg.cls += ' fc-event-start';
13625 if ((i+1) == rows.length) {
13626 cfg.cls += ' fc-event-end';
13629 var ctr = _this.el.select('.fc-event-container',true).first();
13630 var cg = ctr.createChild(cfg);
13632 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13633 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13635 var r = (c.more.length) ? 1 : 0;
13636 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13637 cg.setWidth(ebox.right - sbox.x -2);
13639 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13640 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13641 cg.on('click', _this.onEventClick, _this, ev);
13652 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13653 style : 'position: absolute',
13654 unselectable : "on",
13657 cls: 'fc-event-inner',
13661 cls: 'fc-event-title',
13669 cls: 'ui-resizable-handle ui-resizable-e',
13670 html : '  '
13676 var ctr = _this.el.select('.fc-event-container',true).first();
13677 var cg = ctr.createChild(cfg);
13679 var sbox = c.select('.fc-day-content',true).first().getBox();
13680 var ebox = c.select('.fc-day-content',true).first().getBox();
13682 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13683 cg.setWidth(ebox.right - sbox.x -2);
13685 cg.on('click', _this.onMoreEventClick, _this, c.more);
13695 onEventEnter: function (e, el,event,d) {
13696 this.fireEvent('evententer', this, el, event);
13699 onEventLeave: function (e, el,event,d) {
13700 this.fireEvent('eventleave', this, el, event);
13703 onEventClick: function (e, el,event,d) {
13704 this.fireEvent('eventclick', this, el, event);
13707 onMonthChange: function () {
13711 onMoreEventClick: function(e, el, more)
13715 this.calpopover.placement = 'right';
13716 this.calpopover.setTitle('More');
13718 this.calpopover.setContent('');
13720 var ctr = this.calpopover.el.select('.popover-content', true).first();
13722 Roo.each(more, function(m){
13724 cls : 'fc-event-hori fc-event-draggable',
13727 var cg = ctr.createChild(cfg);
13729 cg.on('click', _this.onEventClick, _this, m);
13732 this.calpopover.show(el);
13737 onLoad: function ()
13739 this.calevents = [];
13742 if(this.store.getCount() > 0){
13743 this.store.data.each(function(d){
13746 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13747 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13748 time : d.data.start_time,
13749 title : d.data.title,
13750 description : d.data.description,
13751 venue : d.data.venue
13756 this.renderEvents();
13758 if(this.calevents.length && this.loadMask){
13759 this.maskEl.hide();
13763 onBeforeLoad: function()
13765 this.clearEvents();
13767 this.maskEl.show();
13781 * @class Roo.bootstrap.Popover
13782 * @extends Roo.bootstrap.Component
13783 * Bootstrap Popover class
13784 * @cfg {String} html contents of the popover (or false to use children..)
13785 * @cfg {String} title of popover (or false to hide)
13786 * @cfg {String} placement how it is placed
13787 * @cfg {String} trigger click || hover (or false to trigger manually)
13788 * @cfg {String} over what (parent or false to trigger manually.)
13789 * @cfg {Number} delay - delay before showing
13792 * Create a new Popover
13793 * @param {Object} config The config object
13796 Roo.bootstrap.Popover = function(config){
13797 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13800 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13802 title: 'Fill in a title',
13805 placement : 'right',
13806 trigger : 'hover', // hover
13812 can_build_overlaid : false,
13814 getChildContainer : function()
13816 return this.el.select('.popover-content',true).first();
13819 getAutoCreate : function(){
13820 Roo.log('make popover?');
13822 cls : 'popover roo-dynamic',
13823 style: 'display:block',
13829 cls : 'popover-inner',
13833 cls: 'popover-title',
13837 cls : 'popover-content',
13848 setTitle: function(str)
13850 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13852 setContent: function(str)
13854 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13856 // as it get's added to the bottom of the page.
13857 onRender : function(ct, position)
13859 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13861 var cfg = Roo.apply({}, this.getAutoCreate());
13865 cfg.cls += ' ' + this.cls;
13868 cfg.style = this.style;
13870 Roo.log("adding to ")
13871 this.el = Roo.get(document.body).createChild(cfg, position);
13877 initEvents : function()
13879 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13880 this.el.enableDisplayMode('block');
13882 if (this.over === false) {
13885 if (this.triggers === false) {
13888 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13889 var triggers = this.trigger ? this.trigger.split(' ') : [];
13890 Roo.each(triggers, function(trigger) {
13892 if (trigger == 'click') {
13893 on_el.on('click', this.toggle, this);
13894 } else if (trigger != 'manual') {
13895 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13896 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13898 on_el.on(eventIn ,this.enter, this);
13899 on_el.on(eventOut, this.leave, this);
13910 toggle : function () {
13911 this.hoverState == 'in' ? this.leave() : this.enter();
13914 enter : function () {
13917 clearTimeout(this.timeout);
13919 this.hoverState = 'in'
13921 if (!this.delay || !this.delay.show) {
13926 this.timeout = setTimeout(function () {
13927 if (_t.hoverState == 'in') {
13930 }, this.delay.show)
13932 leave : function() {
13933 clearTimeout(this.timeout);
13935 this.hoverState = 'out'
13937 if (!this.delay || !this.delay.hide) {
13942 this.timeout = setTimeout(function () {
13943 if (_t.hoverState == 'out') {
13946 }, this.delay.hide)
13949 show : function (on_el)
13952 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13955 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13956 if (this.html !== false) {
13957 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13959 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13960 if (!this.title.length) {
13961 this.el.select('.popover-title',true).hide();
13964 var placement = typeof this.placement == 'function' ?
13965 this.placement.call(this, this.el, on_el) :
13968 var autoToken = /\s?auto?\s?/i;
13969 var autoPlace = autoToken.test(placement);
13971 placement = placement.replace(autoToken, '') || 'top';
13975 //this.el.setXY([0,0]);
13977 this.el.dom.style.display='block';
13978 this.el.addClass(placement);
13980 //this.el.appendTo(on_el);
13982 var p = this.getPosition();
13983 var box = this.el.getBox();
13988 var align = Roo.bootstrap.Popover.alignment[placement]
13989 this.el.alignTo(on_el, align[0],align[1]);
13990 //var arrow = this.el.select('.arrow',true).first();
13991 //arrow.set(align[2],
13993 this.el.addClass('in');
13994 this.hoverState = null;
13996 if (this.el.hasClass('fade')) {
14003 this.el.setXY([0,0]);
14004 this.el.removeClass('in');
14011 Roo.bootstrap.Popover.alignment = {
14012 'left' : ['r-l', [-10,0], 'right'],
14013 'right' : ['l-r', [10,0], 'left'],
14014 'bottom' : ['t-b', [0,10], 'top'],
14015 'top' : [ 'b-t', [0,-10], 'bottom']
14026 * @class Roo.bootstrap.Progress
14027 * @extends Roo.bootstrap.Component
14028 * Bootstrap Progress class
14029 * @cfg {Boolean} striped striped of the progress bar
14030 * @cfg {Boolean} active animated of the progress bar
14034 * Create a new Progress
14035 * @param {Object} config The config object
14038 Roo.bootstrap.Progress = function(config){
14039 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14042 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14047 getAutoCreate : function(){
14055 cfg.cls += ' progress-striped';
14059 cfg.cls += ' active';
14078 * @class Roo.bootstrap.ProgressBar
14079 * @extends Roo.bootstrap.Component
14080 * Bootstrap ProgressBar class
14081 * @cfg {Number} aria_valuenow aria-value now
14082 * @cfg {Number} aria_valuemin aria-value min
14083 * @cfg {Number} aria_valuemax aria-value max
14084 * @cfg {String} label label for the progress bar
14085 * @cfg {String} panel (success | info | warning | danger )
14086 * @cfg {String} role role of the progress bar
14087 * @cfg {String} sr_only text
14091 * Create a new ProgressBar
14092 * @param {Object} config The config object
14095 Roo.bootstrap.ProgressBar = function(config){
14096 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14099 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14103 aria_valuemax : 100,
14109 getAutoCreate : function()
14114 cls: 'progress-bar',
14115 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14127 cfg.role = this.role;
14130 if(this.aria_valuenow){
14131 cfg['aria-valuenow'] = this.aria_valuenow;
14134 if(this.aria_valuemin){
14135 cfg['aria-valuemin'] = this.aria_valuemin;
14138 if(this.aria_valuemax){
14139 cfg['aria-valuemax'] = this.aria_valuemax;
14142 if(this.label && !this.sr_only){
14143 cfg.html = this.label;
14147 cfg.cls += ' progress-bar-' + this.panel;
14153 update : function(aria_valuenow)
14155 this.aria_valuenow = aria_valuenow;
14157 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14172 * @class Roo.bootstrap.TabGroup
14173 * @extends Roo.bootstrap.Column
14174 * Bootstrap Column class
14175 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14176 * @cfg {Boolean} carousel true to make the group behave like a carousel
14179 * Create a new TabGroup
14180 * @param {Object} config The config object
14183 Roo.bootstrap.TabGroup = function(config){
14184 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14186 this.navId = Roo.id();
14189 Roo.bootstrap.TabGroup.register(this);
14193 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14196 transition : false,
14198 getAutoCreate : function()
14200 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14202 cfg.cls += ' tab-content';
14204 if (this.carousel) {
14205 cfg.cls += ' carousel slide';
14207 cls : 'carousel-inner'
14214 getChildContainer : function()
14216 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14220 * register a Navigation item
14221 * @param {Roo.bootstrap.NavItem} the navitem to add
14223 register : function(item)
14225 this.tabs.push( item);
14226 item.navId = this.navId; // not really needed..
14230 getActivePanel : function()
14233 Roo.each(this.tabs, function(t) {
14243 getPanelByName : function(n)
14246 Roo.each(this.tabs, function(t) {
14247 if (t.tabId == n) {
14255 indexOfPanel : function(p)
14258 Roo.each(this.tabs, function(t,i) {
14259 if (t.tabId == p.tabId) {
14268 * show a specific panel
14269 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14270 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14272 showPanel : function (pan)
14275 if (typeof(pan) == 'number') {
14276 pan = this.tabs[pan];
14278 if (typeof(pan) == 'string') {
14279 pan = this.getPanelByName(pan);
14281 if (pan.tabId == this.getActivePanel().tabId) {
14284 var cur = this.getActivePanel();
14286 if (false === cur.fireEvent('beforedeactivate')) {
14290 if (this.carousel) {
14291 this.transition = true;
14292 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14293 var lr = dir == 'next' ? 'left' : 'right';
14294 pan.el.addClass(dir); // or prev
14295 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14296 cur.el.addClass(lr); // or right
14297 pan.el.addClass(lr);
14300 cur.el.on('transitionend', function() {
14301 Roo.log("trans end?");
14303 pan.el.removeClass([lr,dir]);
14304 pan.setActive(true);
14306 cur.el.removeClass([lr]);
14307 cur.setActive(false);
14309 _this.transition = false;
14311 }, this, { single: true } );
14315 cur.setActive(false);
14316 pan.setActive(true);
14320 showPanelNext : function()
14322 var i = this.indexOfPanel(this.getActivePanel());
14323 if (i > this.tabs.length) {
14326 this.showPanel(this.tabs[i+1]);
14328 showPanelPrev : function()
14330 var i = this.indexOfPanel(this.getActivePanel());
14334 this.showPanel(this.tabs[i-1]);
14345 Roo.apply(Roo.bootstrap.TabGroup, {
14349 * register a Navigation Group
14350 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14352 register : function(navgrp)
14354 this.groups[navgrp.navId] = navgrp;
14358 * fetch a Navigation Group based on the navigation ID
14359 * if one does not exist , it will get created.
14360 * @param {string} the navgroup to add
14361 * @returns {Roo.bootstrap.NavGroup} the navgroup
14363 get: function(navId) {
14364 if (typeof(this.groups[navId]) == 'undefined') {
14365 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14367 return this.groups[navId] ;
14382 * @class Roo.bootstrap.TabPanel
14383 * @extends Roo.bootstrap.Component
14384 * Bootstrap TabPanel class
14385 * @cfg {Boolean} active panel active
14386 * @cfg {String} html panel content
14387 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14388 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14392 * Create a new TabPanel
14393 * @param {Object} config The config object
14396 Roo.bootstrap.TabPanel = function(config){
14397 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14401 * Fires when the active status changes
14402 * @param {Roo.bootstrap.TabPanel} this
14403 * @param {Boolean} state the new state
14408 * @event beforedeactivate
14409 * Fires before a tab is de-activated - can be used to do validation on a form.
14410 * @param {Roo.bootstrap.TabPanel} this
14411 * @return {Boolean} false if there is an error
14414 'beforedeactivate': true
14417 this.tabId = this.tabId || Roo.id();
14421 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14428 getAutoCreate : function(){
14431 // item is needed for carousel - not sure if it has any effect otherwise
14432 cls: 'tab-pane item',
14433 html: this.html || ''
14437 cfg.cls += ' active';
14441 cfg.tabId = this.tabId;
14448 initEvents: function()
14450 Roo.log('-------- init events on tab panel ---------');
14452 var p = this.parent();
14453 this.navId = this.navId || p.navId;
14455 if (typeof(this.navId) != 'undefined') {
14456 // not really needed.. but just in case.. parent should be a NavGroup.
14457 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14458 Roo.log(['register', tg, this]);
14464 onRender : function(ct, position)
14466 // Roo.log("Call onRender: " + this.xtype);
14468 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14476 setActive: function(state)
14478 Roo.log("panel - set active " + this.tabId + "=" + state);
14480 this.active = state;
14482 this.el.removeClass('active');
14484 } else if (!this.el.hasClass('active')) {
14485 this.el.addClass('active');
14487 this.fireEvent('changed', this, state);
14504 * @class Roo.bootstrap.DateField
14505 * @extends Roo.bootstrap.Input
14506 * Bootstrap DateField class
14507 * @cfg {Number} weekStart default 0
14508 * @cfg {String} viewMode default empty, (months|years)
14509 * @cfg {String} minViewMode default empty, (months|years)
14510 * @cfg {Number} startDate default -Infinity
14511 * @cfg {Number} endDate default Infinity
14512 * @cfg {Boolean} todayHighlight default false
14513 * @cfg {Boolean} todayBtn default false
14514 * @cfg {Boolean} calendarWeeks default false
14515 * @cfg {Object} daysOfWeekDisabled default empty
14516 * @cfg {Boolean} singleMode default false (true | false)
14518 * @cfg {Boolean} keyboardNavigation default true
14519 * @cfg {String} language default en
14522 * Create a new DateField
14523 * @param {Object} config The config object
14526 Roo.bootstrap.DateField = function(config){
14527 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14531 * Fires when this field show.
14532 * @param {Roo.bootstrap.DateField} this
14533 * @param {Mixed} date The date value
14538 * Fires when this field hide.
14539 * @param {Roo.bootstrap.DateField} this
14540 * @param {Mixed} date The date value
14545 * Fires when select a date.
14546 * @param {Roo.bootstrap.DateField} this
14547 * @param {Mixed} date The date value
14553 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14556 * @cfg {String} format
14557 * The default date format string which can be overriden for localization support. The format must be
14558 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14562 * @cfg {String} altFormats
14563 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14564 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14566 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14574 todayHighlight : false,
14580 keyboardNavigation: true,
14582 calendarWeeks: false,
14584 startDate: -Infinity,
14588 daysOfWeekDisabled: [],
14592 singleMode : false,
14594 UTCDate: function()
14596 return new Date(Date.UTC.apply(Date, arguments));
14599 UTCToday: function()
14601 var today = new Date();
14602 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14605 getDate: function() {
14606 var d = this.getUTCDate();
14607 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14610 getUTCDate: function() {
14614 setDate: function(d) {
14615 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14618 setUTCDate: function(d) {
14620 this.setValue(this.formatDate(this.date));
14623 onRender: function(ct, position)
14626 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14628 this.language = this.language || 'en';
14629 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14630 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14632 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14633 this.format = this.format || 'm/d/y';
14634 this.isInline = false;
14635 this.isInput = true;
14636 this.component = this.el.select('.add-on', true).first() || false;
14637 this.component = (this.component && this.component.length === 0) ? false : this.component;
14638 this.hasInput = this.component && this.inputEL().length;
14640 if (typeof(this.minViewMode === 'string')) {
14641 switch (this.minViewMode) {
14643 this.minViewMode = 1;
14646 this.minViewMode = 2;
14649 this.minViewMode = 0;
14654 if (typeof(this.viewMode === 'string')) {
14655 switch (this.viewMode) {
14668 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14670 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14672 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14674 this.picker().on('mousedown', this.onMousedown, this);
14675 this.picker().on('click', this.onClick, this);
14677 this.picker().addClass('datepicker-dropdown');
14679 this.startViewMode = this.viewMode;
14681 if(this.singleMode){
14682 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14683 v.setVisibilityMode(Roo.Element.DISPLAY)
14687 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14688 v.setStyle('width', '189px');
14692 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14693 if(!this.calendarWeeks){
14698 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14699 v.attr('colspan', function(i, val){
14700 return parseInt(val) + 1;
14705 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14707 this.setStartDate(this.startDate);
14708 this.setEndDate(this.endDate);
14710 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14717 if(this.isInline) {
14722 picker : function()
14724 return this.pickerEl;
14725 // return this.el.select('.datepicker', true).first();
14728 fillDow: function()
14730 var dowCnt = this.weekStart;
14739 if(this.calendarWeeks){
14747 while (dowCnt < this.weekStart + 7) {
14751 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14755 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14758 fillMonths: function()
14761 var months = this.picker().select('>.datepicker-months td', true).first();
14763 months.dom.innerHTML = '';
14769 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14772 months.createChild(month);
14779 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;
14781 if (this.date < this.startDate) {
14782 this.viewDate = new Date(this.startDate);
14783 } else if (this.date > this.endDate) {
14784 this.viewDate = new Date(this.endDate);
14786 this.viewDate = new Date(this.date);
14794 var d = new Date(this.viewDate),
14795 year = d.getUTCFullYear(),
14796 month = d.getUTCMonth(),
14797 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14798 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14799 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14800 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14801 currentDate = this.date && this.date.valueOf(),
14802 today = this.UTCToday();
14804 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14806 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14808 // this.picker.select('>tfoot th.today').
14809 // .text(dates[this.language].today)
14810 // .toggle(this.todayBtn !== false);
14812 this.updateNavArrows();
14815 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14817 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14819 prevMonth.setUTCDate(day);
14821 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14823 var nextMonth = new Date(prevMonth);
14825 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14827 nextMonth = nextMonth.valueOf();
14829 var fillMonths = false;
14831 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14833 while(prevMonth.valueOf() < nextMonth) {
14836 if (prevMonth.getUTCDay() === this.weekStart) {
14838 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14846 if(this.calendarWeeks){
14847 // ISO 8601: First week contains first thursday.
14848 // ISO also states week starts on Monday, but we can be more abstract here.
14850 // Start of current week: based on weekstart/current date
14851 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14852 // Thursday of this week
14853 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14854 // First Thursday of year, year from thursday
14855 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14856 // Calendar week: ms between thursdays, div ms per day, div 7 days
14857 calWeek = (th - yth) / 864e5 / 7 + 1;
14859 fillMonths.cn.push({
14867 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14869 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14872 if (this.todayHighlight &&
14873 prevMonth.getUTCFullYear() == today.getFullYear() &&
14874 prevMonth.getUTCMonth() == today.getMonth() &&
14875 prevMonth.getUTCDate() == today.getDate()) {
14876 clsName += ' today';
14879 if (currentDate && prevMonth.valueOf() === currentDate) {
14880 clsName += ' active';
14883 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14884 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14885 clsName += ' disabled';
14888 fillMonths.cn.push({
14890 cls: 'day ' + clsName,
14891 html: prevMonth.getDate()
14894 prevMonth.setDate(prevMonth.getDate()+1);
14897 var currentYear = this.date && this.date.getUTCFullYear();
14898 var currentMonth = this.date && this.date.getUTCMonth();
14900 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14902 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14903 v.removeClass('active');
14905 if(currentYear === year && k === currentMonth){
14906 v.addClass('active');
14909 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14910 v.addClass('disabled');
14916 year = parseInt(year/10, 10) * 10;
14918 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14920 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14923 for (var i = -1; i < 11; i++) {
14924 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14926 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14934 showMode: function(dir)
14937 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14940 Roo.each(this.picker().select('>div',true).elements, function(v){
14941 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14944 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14949 if(this.isInline) return;
14951 this.picker().removeClass(['bottom', 'top']);
14953 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14955 * place to the top of element!
14959 this.picker().addClass('top');
14960 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14965 this.picker().addClass('bottom');
14967 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14970 parseDate : function(value)
14972 if(!value || value instanceof Date){
14975 var v = Date.parseDate(value, this.format);
14976 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
14977 v = Date.parseDate(value, 'Y-m-d');
14979 if(!v && this.altFormats){
14980 if(!this.altFormatsArray){
14981 this.altFormatsArray = this.altFormats.split("|");
14983 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14984 v = Date.parseDate(value, this.altFormatsArray[i]);
14990 formatDate : function(date, fmt)
14992 return (!date || !(date instanceof Date)) ?
14993 date : date.dateFormat(fmt || this.format);
14996 onFocus : function()
14998 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15002 onBlur : function()
15004 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15006 var d = this.inputEl().getValue();
15015 this.picker().show();
15019 this.fireEvent('show', this, this.date);
15024 if(this.isInline) return;
15025 this.picker().hide();
15026 this.viewMode = this.startViewMode;
15029 this.fireEvent('hide', this, this.date);
15033 onMousedown: function(e)
15035 e.stopPropagation();
15036 e.preventDefault();
15041 Roo.bootstrap.DateField.superclass.keyup.call(this);
15045 setValue: function(v)
15048 // v can be a string or a date..
15051 var d = new Date(this.parseDate(v) ).clearTime();
15053 if(isNaN(d.getTime())){
15054 this.date = this.viewDate = '';
15055 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15059 v = this.formatDate(d);
15061 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15063 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15067 this.fireEvent('select', this, this.date);
15071 getValue: function()
15073 return this.formatDate(this.date);
15076 fireKey: function(e)
15078 if (!this.picker().isVisible()){
15079 if (e.keyCode == 27) // allow escape to hide and re-show picker
15084 var dateChanged = false,
15086 newDate, newViewDate;
15091 e.preventDefault();
15095 if (!this.keyboardNavigation) break;
15096 dir = e.keyCode == 37 ? -1 : 1;
15099 newDate = this.moveYear(this.date, dir);
15100 newViewDate = this.moveYear(this.viewDate, dir);
15101 } else if (e.shiftKey){
15102 newDate = this.moveMonth(this.date, dir);
15103 newViewDate = this.moveMonth(this.viewDate, dir);
15105 newDate = new Date(this.date);
15106 newDate.setUTCDate(this.date.getUTCDate() + dir);
15107 newViewDate = new Date(this.viewDate);
15108 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15110 if (this.dateWithinRange(newDate)){
15111 this.date = newDate;
15112 this.viewDate = newViewDate;
15113 this.setValue(this.formatDate(this.date));
15115 e.preventDefault();
15116 dateChanged = true;
15121 if (!this.keyboardNavigation) break;
15122 dir = e.keyCode == 38 ? -1 : 1;
15124 newDate = this.moveYear(this.date, dir);
15125 newViewDate = this.moveYear(this.viewDate, dir);
15126 } else if (e.shiftKey){
15127 newDate = this.moveMonth(this.date, dir);
15128 newViewDate = this.moveMonth(this.viewDate, dir);
15130 newDate = new Date(this.date);
15131 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15132 newViewDate = new Date(this.viewDate);
15133 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15135 if (this.dateWithinRange(newDate)){
15136 this.date = newDate;
15137 this.viewDate = newViewDate;
15138 this.setValue(this.formatDate(this.date));
15140 e.preventDefault();
15141 dateChanged = true;
15145 this.setValue(this.formatDate(this.date));
15147 e.preventDefault();
15150 this.setValue(this.formatDate(this.date));
15164 onClick: function(e)
15166 e.stopPropagation();
15167 e.preventDefault();
15169 var target = e.getTarget();
15171 if(target.nodeName.toLowerCase() === 'i'){
15172 target = Roo.get(target).dom.parentNode;
15175 var nodeName = target.nodeName;
15176 var className = target.className;
15177 var html = target.innerHTML;
15178 //Roo.log(nodeName);
15180 switch(nodeName.toLowerCase()) {
15182 switch(className) {
15188 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15189 switch(this.viewMode){
15191 this.viewDate = this.moveMonth(this.viewDate, dir);
15195 this.viewDate = this.moveYear(this.viewDate, dir);
15201 var date = new Date();
15202 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15204 this.setValue(this.formatDate(this.date));
15211 if (className.indexOf('disabled') < 0) {
15212 this.viewDate.setUTCDate(1);
15213 if (className.indexOf('month') > -1) {
15214 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15216 var year = parseInt(html, 10) || 0;
15217 this.viewDate.setUTCFullYear(year);
15221 if(this.singleMode){
15222 this.setValue(this.formatDate(this.viewDate));
15233 //Roo.log(className);
15234 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15235 var day = parseInt(html, 10) || 1;
15236 var year = this.viewDate.getUTCFullYear(),
15237 month = this.viewDate.getUTCMonth();
15239 if (className.indexOf('old') > -1) {
15246 } else if (className.indexOf('new') > -1) {
15254 //Roo.log([year,month,day]);
15255 this.date = this.UTCDate(year, month, day,0,0,0,0);
15256 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15258 //Roo.log(this.formatDate(this.date));
15259 this.setValue(this.formatDate(this.date));
15266 setStartDate: function(startDate)
15268 this.startDate = startDate || -Infinity;
15269 if (this.startDate !== -Infinity) {
15270 this.startDate = this.parseDate(this.startDate);
15273 this.updateNavArrows();
15276 setEndDate: function(endDate)
15278 this.endDate = endDate || Infinity;
15279 if (this.endDate !== Infinity) {
15280 this.endDate = this.parseDate(this.endDate);
15283 this.updateNavArrows();
15286 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15288 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15289 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15290 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15292 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15293 return parseInt(d, 10);
15296 this.updateNavArrows();
15299 updateNavArrows: function()
15301 if(this.singleMode){
15305 var d = new Date(this.viewDate),
15306 year = d.getUTCFullYear(),
15307 month = d.getUTCMonth();
15309 Roo.each(this.picker().select('.prev', true).elements, function(v){
15311 switch (this.viewMode) {
15314 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15320 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15327 Roo.each(this.picker().select('.next', true).elements, function(v){
15329 switch (this.viewMode) {
15332 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15338 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15346 moveMonth: function(date, dir)
15348 if (!dir) return date;
15349 var new_date = new Date(date.valueOf()),
15350 day = new_date.getUTCDate(),
15351 month = new_date.getUTCMonth(),
15352 mag = Math.abs(dir),
15354 dir = dir > 0 ? 1 : -1;
15357 // If going back one month, make sure month is not current month
15358 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15360 return new_date.getUTCMonth() == month;
15362 // If going forward one month, make sure month is as expected
15363 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15365 return new_date.getUTCMonth() != new_month;
15367 new_month = month + dir;
15368 new_date.setUTCMonth(new_month);
15369 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15370 if (new_month < 0 || new_month > 11)
15371 new_month = (new_month + 12) % 12;
15373 // For magnitudes >1, move one month at a time...
15374 for (var i=0; i<mag; i++)
15375 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15376 new_date = this.moveMonth(new_date, dir);
15377 // ...then reset the day, keeping it in the new month
15378 new_month = new_date.getUTCMonth();
15379 new_date.setUTCDate(day);
15381 return new_month != new_date.getUTCMonth();
15384 // Common date-resetting loop -- if date is beyond end of month, make it
15387 new_date.setUTCDate(--day);
15388 new_date.setUTCMonth(new_month);
15393 moveYear: function(date, dir)
15395 return this.moveMonth(date, dir*12);
15398 dateWithinRange: function(date)
15400 return date >= this.startDate && date <= this.endDate;
15406 this.picker().remove();
15411 Roo.apply(Roo.bootstrap.DateField, {
15422 html: '<i class="fa fa-arrow-left"/>'
15432 html: '<i class="fa fa-arrow-right"/>'
15474 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15475 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15476 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15477 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15478 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15491 navFnc: 'FullYear',
15496 navFnc: 'FullYear',
15501 Roo.apply(Roo.bootstrap.DateField, {
15505 cls: 'datepicker dropdown-menu roo-dynamic',
15509 cls: 'datepicker-days',
15513 cls: 'table-condensed',
15515 Roo.bootstrap.DateField.head,
15519 Roo.bootstrap.DateField.footer
15526 cls: 'datepicker-months',
15530 cls: 'table-condensed',
15532 Roo.bootstrap.DateField.head,
15533 Roo.bootstrap.DateField.content,
15534 Roo.bootstrap.DateField.footer
15541 cls: 'datepicker-years',
15545 cls: 'table-condensed',
15547 Roo.bootstrap.DateField.head,
15548 Roo.bootstrap.DateField.content,
15549 Roo.bootstrap.DateField.footer
15568 * @class Roo.bootstrap.TimeField
15569 * @extends Roo.bootstrap.Input
15570 * Bootstrap DateField class
15574 * Create a new TimeField
15575 * @param {Object} config The config object
15578 Roo.bootstrap.TimeField = function(config){
15579 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15583 * Fires when this field show.
15584 * @param {Roo.bootstrap.DateField} this
15585 * @param {Mixed} date The date value
15590 * Fires when this field hide.
15591 * @param {Roo.bootstrap.DateField} this
15592 * @param {Mixed} date The date value
15597 * Fires when select a date.
15598 * @param {Roo.bootstrap.DateField} this
15599 * @param {Mixed} date The date value
15605 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15608 * @cfg {String} format
15609 * The default time format string which can be overriden for localization support. The format must be
15610 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15614 onRender: function(ct, position)
15617 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15619 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15621 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15623 this.pop = this.picker().select('>.datepicker-time',true).first();
15624 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15626 this.picker().on('mousedown', this.onMousedown, this);
15627 this.picker().on('click', this.onClick, this);
15629 this.picker().addClass('datepicker-dropdown');
15634 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15635 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15636 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15637 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15638 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15639 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15643 fireKey: function(e){
15644 if (!this.picker().isVisible()){
15645 if (e.keyCode == 27) // allow escape to hide and re-show picker
15650 e.preventDefault();
15658 this.onTogglePeriod();
15661 this.onIncrementMinutes();
15664 this.onDecrementMinutes();
15673 onClick: function(e) {
15674 e.stopPropagation();
15675 e.preventDefault();
15678 picker : function()
15680 return this.el.select('.datepicker', true).first();
15683 fillTime: function()
15685 var time = this.pop.select('tbody', true).first();
15687 time.dom.innerHTML = '';
15702 cls: 'hours-up glyphicon glyphicon-chevron-up'
15722 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15743 cls: 'timepicker-hour',
15758 cls: 'timepicker-minute',
15773 cls: 'btn btn-primary period',
15795 cls: 'hours-down glyphicon glyphicon-chevron-down'
15815 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15833 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15840 var hours = this.time.getHours();
15841 var minutes = this.time.getMinutes();
15854 hours = hours - 12;
15858 hours = '0' + hours;
15862 minutes = '0' + minutes;
15865 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15866 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15867 this.pop.select('button', true).first().dom.innerHTML = period;
15873 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15875 var cls = ['bottom'];
15877 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15884 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15889 this.picker().addClass(cls.join('-'));
15893 Roo.each(cls, function(c){
15895 _this.picker().setTop(_this.inputEl().getHeight());
15899 _this.picker().setTop(0 - _this.picker().getHeight());
15904 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15908 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15915 onFocus : function()
15917 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15921 onBlur : function()
15923 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15929 this.picker().show();
15934 this.fireEvent('show', this, this.date);
15939 this.picker().hide();
15942 this.fireEvent('hide', this, this.date);
15945 setTime : function()
15948 this.setValue(this.time.format(this.format));
15950 this.fireEvent('select', this, this.date);
15955 onMousedown: function(e){
15956 e.stopPropagation();
15957 e.preventDefault();
15960 onIncrementHours: function()
15962 Roo.log('onIncrementHours');
15963 this.time = this.time.add(Date.HOUR, 1);
15968 onDecrementHours: function()
15970 Roo.log('onDecrementHours');
15971 this.time = this.time.add(Date.HOUR, -1);
15975 onIncrementMinutes: function()
15977 Roo.log('onIncrementMinutes');
15978 this.time = this.time.add(Date.MINUTE, 1);
15982 onDecrementMinutes: function()
15984 Roo.log('onDecrementMinutes');
15985 this.time = this.time.add(Date.MINUTE, -1);
15989 onTogglePeriod: function()
15991 Roo.log('onTogglePeriod');
15992 this.time = this.time.add(Date.HOUR, 12);
15999 Roo.apply(Roo.bootstrap.TimeField, {
16029 cls: 'btn btn-info ok',
16041 Roo.apply(Roo.bootstrap.TimeField, {
16045 cls: 'datepicker dropdown-menu',
16049 cls: 'datepicker-time',
16053 cls: 'table-condensed',
16055 Roo.bootstrap.TimeField.content,
16056 Roo.bootstrap.TimeField.footer
16075 * @class Roo.bootstrap.CheckBox
16076 * @extends Roo.bootstrap.Input
16077 * Bootstrap CheckBox class
16079 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16080 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16081 * @cfg {String} boxLabel The text that appears beside the checkbox
16082 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16083 * @cfg {Boolean} checked initnal the element
16084 * @cfg {Boolean} inline inline the element (default false)
16087 * Create a new CheckBox
16088 * @param {Object} config The config object
16091 Roo.bootstrap.CheckBox = function(config){
16092 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16097 * Fires when the element is checked or unchecked.
16098 * @param {Roo.bootstrap.CheckBox} this This input
16099 * @param {Boolean} checked The new checked value
16105 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16107 inputType: 'checkbox',
16115 getAutoCreate : function()
16117 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16123 cfg.cls = 'form-group ' + this.inputType //input-group
16126 cfg.cls += ' ' + this.inputType + '-inline';
16132 type : this.inputType,
16133 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16134 cls : 'roo-' + this.inputType, //'form-box',
16135 placeholder : this.placeholder || ''
16139 if (this.weight) { // Validity check?
16140 cfg.cls += " " + this.inputType + "-" + this.weight;
16143 if (this.disabled) {
16144 input.disabled=true;
16148 input.checked = this.checked;
16152 input.name = this.name;
16156 input.cls += ' input-' + this.size;
16160 ['xs','sm','md','lg'].map(function(size){
16161 if (settings[size]) {
16162 cfg.cls += ' col-' + size + '-' + settings[size];
16168 var inputblock = input;
16173 if (this.before || this.after) {
16176 cls : 'input-group',
16180 inputblock.cn.push({
16182 cls : 'input-group-addon',
16186 inputblock.cn.push(input);
16188 inputblock.cn.push({
16190 cls : 'input-group-addon',
16197 if (align ==='left' && this.fieldLabel.length) {
16198 Roo.log("left and has label");
16204 cls : 'control-label col-md-' + this.labelWidth,
16205 html : this.fieldLabel
16209 cls : "col-md-" + (12 - this.labelWidth),
16216 } else if ( this.fieldLabel.length) {
16221 tag: this.boxLabel ? 'span' : 'label',
16223 cls: 'control-label box-input-label',
16224 //cls : 'input-group-addon',
16225 html : this.fieldLabel
16235 Roo.log(" no label && no align");
16236 cfg.cn = [ inputblock ] ;
16241 var boxLabelCfg = {
16243 //'for': id, // box label is handled by onclick - so no for...
16245 html: this.boxLabel
16249 boxLabelCfg.tooltip = this.tooltip;
16252 cfg.cn.push(boxLabelCfg);
16262 * return the real input element.
16264 inputEl: function ()
16266 return this.el.select('input.roo-' + this.inputType,true).first();
16269 labelEl: function()
16271 return this.el.select('label.control-label',true).first();
16273 /* depricated... */
16277 return this.labelEl();
16280 initEvents : function()
16282 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16284 this.inputEl().on('click', this.onClick, this);
16285 if (this.boxLabel) {
16286 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
16291 onClick : function()
16293 this.setChecked(!this.checked);
16296 setChecked : function(state,suppressEvent)
16298 if(this.inputType == 'radio'){
16300 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16301 e.dom.checked = false;
16304 this.inputEl().dom.checked = true;
16306 if(suppressEvent !== true){
16307 this.fireEvent('check', this, true);
16310 this.inputEl().dom.value = this.inputValue;
16315 this.checked = state;
16317 if(suppressEvent !== true){
16318 this.fireEvent('check', this, state);
16321 this.inputEl().dom.checked = state;
16323 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16327 getValue : function()
16329 if(this.inputType == 'radio'){
16330 return this.getGroupValue();
16333 return this.inputEl().getValue();
16337 getGroupValue : function()
16339 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16342 setValue : function(v,suppressEvent)
16344 if(this.inputType == 'radio'){
16345 this.setGroupValue(v, suppressEvent);
16349 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16352 setGroupValue : function(v, suppressEvent)
16354 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16355 e.dom.checked = false;
16357 if(e.dom.value == v){
16358 e.dom.checked = true;
16362 if(suppressEvent !== true){
16363 this.fireEvent('check', this, true);
16380 * @class Roo.bootstrap.Radio
16381 * @extends Roo.bootstrap.CheckBox
16382 * Bootstrap Radio class
16385 * Create a new Radio
16386 * @param {Object} config The config object
16389 Roo.bootstrap.Radio = function(config){
16390 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16394 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16396 inputType: 'radio',
16400 getAutoCreate : function()
16402 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16408 cfg.cls = 'form-group radio' //input-group
16413 type : this.inputType,
16414 //value : (!this.checked) ? this.valueOff : this.inputValue,
16415 value : this.inputValue,
16417 placeholder : this.placeholder || ''
16420 if (this.weight) { // Validity check?
16421 cfg.cls += " radio-" + this.weight;
16423 if (this.disabled) {
16424 input.disabled=true;
16428 input.checked = this.checked;
16432 input.name = this.name;
16436 input.cls += ' input-' + this.size;
16440 ['xs','sm','md','lg'].map(function(size){
16441 if (settings[size]) {
16442 cfg.cls += ' col-' + size + '-' + settings[size];
16446 var inputblock = input;
16448 if (this.before || this.after) {
16451 cls : 'input-group',
16455 inputblock.cn.push({
16457 cls : 'input-group-addon',
16461 inputblock.cn.push(input);
16463 inputblock.cn.push({
16465 cls : 'input-group-addon',
16472 if (align ==='left' && this.fieldLabel.length) {
16473 Roo.log("left and has label");
16479 cls : 'control-label col-md-' + this.labelWidth,
16480 html : this.fieldLabel
16484 cls : "col-md-" + (12 - this.labelWidth),
16491 } else if ( this.fieldLabel.length) {
16498 cls: 'control-label box-input-label',
16499 //cls : 'input-group-addon',
16500 html : this.fieldLabel
16510 Roo.log(" no label && no align");
16525 html: this.boxLabel
16532 inputEl: function ()
16534 return this.el.select('input.roo-radio',true).first();
16536 onClick : function()
16540 this.setChecked(true);
16543 setChecked : function(state,suppressEvent)
16546 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16547 v.dom.checked = false;
16551 this.checked = state;
16552 this.inputEl().dom.checked = state;
16554 if(suppressEvent !== true){
16555 this.fireEvent('check', this, state);
16558 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16562 getGroupValue : function()
16565 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16566 if(v.dom.checked == true){
16567 value = v.dom.value;
16575 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16576 * @return {Mixed} value The field value
16578 getValue : function(){
16579 return this.getGroupValue();
16585 //<script type="text/javascript">
16588 * Based Ext JS Library 1.1.1
16589 * Copyright(c) 2006-2007, Ext JS, LLC.
16595 * @class Roo.HtmlEditorCore
16596 * @extends Roo.Component
16597 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16599 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16602 Roo.HtmlEditorCore = function(config){
16605 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16610 * @event initialize
16611 * Fires when the editor is fully initialized (including the iframe)
16612 * @param {Roo.HtmlEditorCore} this
16617 * Fires when the editor is first receives the focus. Any insertion must wait
16618 * until after this event.
16619 * @param {Roo.HtmlEditorCore} this
16623 * @event beforesync
16624 * Fires before the textarea is updated with content from the editor iframe. Return false
16625 * to cancel the sync.
16626 * @param {Roo.HtmlEditorCore} this
16627 * @param {String} html
16631 * @event beforepush
16632 * Fires before the iframe editor is updated with content from the textarea. Return false
16633 * to cancel the push.
16634 * @param {Roo.HtmlEditorCore} this
16635 * @param {String} html
16640 * Fires when the textarea is updated with content from the editor iframe.
16641 * @param {Roo.HtmlEditorCore} this
16642 * @param {String} html
16647 * Fires when the iframe editor is updated with content from the textarea.
16648 * @param {Roo.HtmlEditorCore} this
16649 * @param {String} html
16654 * @event editorevent
16655 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16656 * @param {Roo.HtmlEditorCore} this
16662 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16664 // defaults : white / black...
16665 this.applyBlacklists();
16672 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16676 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16682 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16687 * @cfg {Number} height (in pixels)
16691 * @cfg {Number} width (in pixels)
16696 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16699 stylesheets: false,
16704 // private properties
16705 validationEvent : false,
16707 initialized : false,
16709 sourceEditMode : false,
16710 onFocus : Roo.emptyFn,
16712 hideMode:'offsets',
16716 // blacklist + whitelisted elements..
16723 * Protected method that will not generally be called directly. It
16724 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16725 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16727 getDocMarkup : function(){
16731 // inherit styels from page...??
16732 if (this.stylesheets === false) {
16734 Roo.get(document.head).select('style').each(function(node) {
16735 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16738 Roo.get(document.head).select('link').each(function(node) {
16739 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16742 } else if (!this.stylesheets.length) {
16744 st = '<style type="text/css">' +
16745 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16751 st += '<style type="text/css">' +
16752 'IMG { cursor: pointer } ' +
16756 return '<html><head>' + st +
16757 //<style type="text/css">' +
16758 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16760 ' </head><body class="roo-htmleditor-body"></body></html>';
16764 onRender : function(ct, position)
16767 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16768 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16771 this.el.dom.style.border = '0 none';
16772 this.el.dom.setAttribute('tabIndex', -1);
16773 this.el.addClass('x-hidden hide');
16777 if(Roo.isIE){ // fix IE 1px bogus margin
16778 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16782 this.frameId = Roo.id();
16786 var iframe = this.owner.wrap.createChild({
16788 cls: 'form-control', // bootstrap..
16790 name: this.frameId,
16791 frameBorder : 'no',
16792 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16797 this.iframe = iframe.dom;
16799 this.assignDocWin();
16801 this.doc.designMode = 'on';
16804 this.doc.write(this.getDocMarkup());
16808 var task = { // must defer to wait for browser to be ready
16810 //console.log("run task?" + this.doc.readyState);
16811 this.assignDocWin();
16812 if(this.doc.body || this.doc.readyState == 'complete'){
16814 this.doc.designMode="on";
16818 Roo.TaskMgr.stop(task);
16819 this.initEditor.defer(10, this);
16826 Roo.TaskMgr.start(task);
16831 onResize : function(w, h)
16833 Roo.log('resize: ' +w + ',' + h );
16834 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16838 if(typeof w == 'number'){
16840 this.iframe.style.width = w + 'px';
16842 if(typeof h == 'number'){
16844 this.iframe.style.height = h + 'px';
16846 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16853 * Toggles the editor between standard and source edit mode.
16854 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16856 toggleSourceEdit : function(sourceEditMode){
16858 this.sourceEditMode = sourceEditMode === true;
16860 if(this.sourceEditMode){
16862 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16865 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16866 //this.iframe.className = '';
16869 //this.setSize(this.owner.wrap.getSize());
16870 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16877 * Protected method that will not generally be called directly. If you need/want
16878 * custom HTML cleanup, this is the method you should override.
16879 * @param {String} html The HTML to be cleaned
16880 * return {String} The cleaned HTML
16882 cleanHtml : function(html){
16883 html = String(html);
16884 if(html.length > 5){
16885 if(Roo.isSafari){ // strip safari nonsense
16886 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16889 if(html == ' '){
16896 * HTML Editor -> Textarea
16897 * Protected method that will not generally be called directly. Syncs the contents
16898 * of the editor iframe with the textarea.
16900 syncValue : function(){
16901 if(this.initialized){
16902 var bd = (this.doc.body || this.doc.documentElement);
16903 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16904 var html = bd.innerHTML;
16906 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16907 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16909 html = '<div style="'+m[0]+'">' + html + '</div>';
16912 html = this.cleanHtml(html);
16913 // fix up the special chars.. normaly like back quotes in word...
16914 // however we do not want to do this with chinese..
16915 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16916 var cc = b.charCodeAt();
16918 (cc >= 0x4E00 && cc < 0xA000 ) ||
16919 (cc >= 0x3400 && cc < 0x4E00 ) ||
16920 (cc >= 0xf900 && cc < 0xfb00 )
16926 if(this.owner.fireEvent('beforesync', this, html) !== false){
16927 this.el.dom.value = html;
16928 this.owner.fireEvent('sync', this, html);
16934 * Protected method that will not generally be called directly. Pushes the value of the textarea
16935 * into the iframe editor.
16937 pushValue : function(){
16938 if(this.initialized){
16939 var v = this.el.dom.value.trim();
16941 // if(v.length < 1){
16945 if(this.owner.fireEvent('beforepush', this, v) !== false){
16946 var d = (this.doc.body || this.doc.documentElement);
16948 this.cleanUpPaste();
16949 this.el.dom.value = d.innerHTML;
16950 this.owner.fireEvent('push', this, v);
16956 deferFocus : function(){
16957 this.focus.defer(10, this);
16961 focus : function(){
16962 if(this.win && !this.sourceEditMode){
16969 assignDocWin: function()
16971 var iframe = this.iframe;
16974 this.doc = iframe.contentWindow.document;
16975 this.win = iframe.contentWindow;
16977 // if (!Roo.get(this.frameId)) {
16980 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16981 // this.win = Roo.get(this.frameId).dom.contentWindow;
16983 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16987 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16988 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16993 initEditor : function(){
16994 //console.log("INIT EDITOR");
16995 this.assignDocWin();
16999 this.doc.designMode="on";
17001 this.doc.write(this.getDocMarkup());
17004 var dbody = (this.doc.body || this.doc.documentElement);
17005 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17006 // this copies styles from the containing element into thsi one..
17007 // not sure why we need all of this..
17008 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17010 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17011 //ss['background-attachment'] = 'fixed'; // w3c
17012 dbody.bgProperties = 'fixed'; // ie
17013 //Roo.DomHelper.applyStyles(dbody, ss);
17014 Roo.EventManager.on(this.doc, {
17015 //'mousedown': this.onEditorEvent,
17016 'mouseup': this.onEditorEvent,
17017 'dblclick': this.onEditorEvent,
17018 'click': this.onEditorEvent,
17019 'keyup': this.onEditorEvent,
17024 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17026 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17027 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17029 this.initialized = true;
17031 this.owner.fireEvent('initialize', this);
17036 onDestroy : function(){
17042 //for (var i =0; i < this.toolbars.length;i++) {
17043 // // fixme - ask toolbars for heights?
17044 // this.toolbars[i].onDestroy();
17047 //this.wrap.dom.innerHTML = '';
17048 //this.wrap.remove();
17053 onFirstFocus : function(){
17055 this.assignDocWin();
17058 this.activated = true;
17061 if(Roo.isGecko){ // prevent silly gecko errors
17063 var s = this.win.getSelection();
17064 if(!s.focusNode || s.focusNode.nodeType != 3){
17065 var r = s.getRangeAt(0);
17066 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17071 this.execCmd('useCSS', true);
17072 this.execCmd('styleWithCSS', false);
17075 this.owner.fireEvent('activate', this);
17079 adjustFont: function(btn){
17080 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17081 //if(Roo.isSafari){ // safari
17084 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17085 if(Roo.isSafari){ // safari
17086 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17087 v = (v < 10) ? 10 : v;
17088 v = (v > 48) ? 48 : v;
17089 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17094 v = Math.max(1, v+adjust);
17096 this.execCmd('FontSize', v );
17099 onEditorEvent : function(e){
17100 this.owner.fireEvent('editorevent', this, e);
17101 // this.updateToolbar();
17102 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17105 insertTag : function(tg)
17107 // could be a bit smarter... -> wrap the current selected tRoo..
17108 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17110 range = this.createRange(this.getSelection());
17111 var wrappingNode = this.doc.createElement(tg.toLowerCase());
17112 wrappingNode.appendChild(range.extractContents());
17113 range.insertNode(wrappingNode);
17120 this.execCmd("formatblock", tg);
17124 insertText : function(txt)
17128 var range = this.createRange();
17129 range.deleteContents();
17130 //alert(Sender.getAttribute('label'));
17132 range.insertNode(this.doc.createTextNode(txt));
17138 * Executes a Midas editor command on the editor document and performs necessary focus and
17139 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17140 * @param {String} cmd The Midas command
17141 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17143 relayCmd : function(cmd, value){
17145 this.execCmd(cmd, value);
17146 this.owner.fireEvent('editorevent', this);
17147 //this.updateToolbar();
17148 this.owner.deferFocus();
17152 * Executes a Midas editor command directly on the editor document.
17153 * For visual commands, you should use {@link #relayCmd} instead.
17154 * <b>This should only be called after the editor is initialized.</b>
17155 * @param {String} cmd The Midas command
17156 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17158 execCmd : function(cmd, value){
17159 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17166 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17168 * @param {String} text | dom node..
17170 insertAtCursor : function(text)
17175 if(!this.activated){
17181 var r = this.doc.selection.createRange();
17192 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17196 // from jquery ui (MIT licenced)
17198 var win = this.win;
17200 if (win.getSelection && win.getSelection().getRangeAt) {
17201 range = win.getSelection().getRangeAt(0);
17202 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17203 range.insertNode(node);
17204 } else if (win.document.selection && win.document.selection.createRange) {
17205 // no firefox support
17206 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17207 win.document.selection.createRange().pasteHTML(txt);
17209 // no firefox support
17210 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17211 this.execCmd('InsertHTML', txt);
17220 mozKeyPress : function(e){
17222 var c = e.getCharCode(), cmd;
17225 c = String.fromCharCode(c).toLowerCase();
17239 this.cleanUpPaste.defer(100, this);
17247 e.preventDefault();
17255 fixKeys : function(){ // load time branching for fastest keydown performance
17257 return function(e){
17258 var k = e.getKey(), r;
17261 r = this.doc.selection.createRange();
17264 r.pasteHTML('    ');
17271 r = this.doc.selection.createRange();
17273 var target = r.parentElement();
17274 if(!target || target.tagName.toLowerCase() != 'li'){
17276 r.pasteHTML('<br />');
17282 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17283 this.cleanUpPaste.defer(100, this);
17289 }else if(Roo.isOpera){
17290 return function(e){
17291 var k = e.getKey();
17295 this.execCmd('InsertHTML','    ');
17298 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17299 this.cleanUpPaste.defer(100, this);
17304 }else if(Roo.isSafari){
17305 return function(e){
17306 var k = e.getKey();
17310 this.execCmd('InsertText','\t');
17314 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17315 this.cleanUpPaste.defer(100, this);
17323 getAllAncestors: function()
17325 var p = this.getSelectedNode();
17328 a.push(p); // push blank onto stack..
17329 p = this.getParentElement();
17333 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17337 a.push(this.doc.body);
17341 lastSelNode : false,
17344 getSelection : function()
17346 this.assignDocWin();
17347 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17350 getSelectedNode: function()
17352 // this may only work on Gecko!!!
17354 // should we cache this!!!!
17359 var range = this.createRange(this.getSelection()).cloneRange();
17362 var parent = range.parentElement();
17364 var testRange = range.duplicate();
17365 testRange.moveToElementText(parent);
17366 if (testRange.inRange(range)) {
17369 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17372 parent = parent.parentElement;
17377 // is ancestor a text element.
17378 var ac = range.commonAncestorContainer;
17379 if (ac.nodeType == 3) {
17380 ac = ac.parentNode;
17383 var ar = ac.childNodes;
17386 var other_nodes = [];
17387 var has_other_nodes = false;
17388 for (var i=0;i<ar.length;i++) {
17389 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17392 // fullly contained node.
17394 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17399 // probably selected..
17400 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17401 other_nodes.push(ar[i]);
17405 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17410 has_other_nodes = true;
17412 if (!nodes.length && other_nodes.length) {
17413 nodes= other_nodes;
17415 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17421 createRange: function(sel)
17423 // this has strange effects when using with
17424 // top toolbar - not sure if it's a great idea.
17425 //this.editor.contentWindow.focus();
17426 if (typeof sel != "undefined") {
17428 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17430 return this.doc.createRange();
17433 return this.doc.createRange();
17436 getParentElement: function()
17439 this.assignDocWin();
17440 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17442 var range = this.createRange(sel);
17445 var p = range.commonAncestorContainer;
17446 while (p.nodeType == 3) { // text node
17457 * Range intersection.. the hard stuff...
17461 * [ -- selected range --- ]
17465 * if end is before start or hits it. fail.
17466 * if start is after end or hits it fail.
17468 * if either hits (but other is outside. - then it's not
17474 // @see http://www.thismuchiknow.co.uk/?p=64.
17475 rangeIntersectsNode : function(range, node)
17477 var nodeRange = node.ownerDocument.createRange();
17479 nodeRange.selectNode(node);
17481 nodeRange.selectNodeContents(node);
17484 var rangeStartRange = range.cloneRange();
17485 rangeStartRange.collapse(true);
17487 var rangeEndRange = range.cloneRange();
17488 rangeEndRange.collapse(false);
17490 var nodeStartRange = nodeRange.cloneRange();
17491 nodeStartRange.collapse(true);
17493 var nodeEndRange = nodeRange.cloneRange();
17494 nodeEndRange.collapse(false);
17496 return rangeStartRange.compareBoundaryPoints(
17497 Range.START_TO_START, nodeEndRange) == -1 &&
17498 rangeEndRange.compareBoundaryPoints(
17499 Range.START_TO_START, nodeStartRange) == 1;
17503 rangeCompareNode : function(range, node)
17505 var nodeRange = node.ownerDocument.createRange();
17507 nodeRange.selectNode(node);
17509 nodeRange.selectNodeContents(node);
17513 range.collapse(true);
17515 nodeRange.collapse(true);
17517 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17518 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17520 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17522 var nodeIsBefore = ss == 1;
17523 var nodeIsAfter = ee == -1;
17525 if (nodeIsBefore && nodeIsAfter)
17527 if (!nodeIsBefore && nodeIsAfter)
17528 return 1; //right trailed.
17530 if (nodeIsBefore && !nodeIsAfter)
17531 return 2; // left trailed.
17536 // private? - in a new class?
17537 cleanUpPaste : function()
17539 // cleans up the whole document..
17540 Roo.log('cleanuppaste');
17542 this.cleanUpChildren(this.doc.body);
17543 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17544 if (clean != this.doc.body.innerHTML) {
17545 this.doc.body.innerHTML = clean;
17550 cleanWordChars : function(input) {// change the chars to hex code
17551 var he = Roo.HtmlEditorCore;
17553 var output = input;
17554 Roo.each(he.swapCodes, function(sw) {
17555 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17557 output = output.replace(swapper, sw[1]);
17564 cleanUpChildren : function (n)
17566 if (!n.childNodes.length) {
17569 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17570 this.cleanUpChild(n.childNodes[i]);
17577 cleanUpChild : function (node)
17580 //console.log(node);
17581 if (node.nodeName == "#text") {
17582 // clean up silly Windows -- stuff?
17585 if (node.nodeName == "#comment") {
17586 node.parentNode.removeChild(node);
17587 // clean up silly Windows -- stuff?
17590 var lcname = node.tagName.toLowerCase();
17591 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17592 // whitelist of tags..
17594 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17596 node.parentNode.removeChild(node);
17601 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17603 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17604 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17606 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17607 // remove_keep_children = true;
17610 if (remove_keep_children) {
17611 this.cleanUpChildren(node);
17612 // inserts everything just before this node...
17613 while (node.childNodes.length) {
17614 var cn = node.childNodes[0];
17615 node.removeChild(cn);
17616 node.parentNode.insertBefore(cn, node);
17618 node.parentNode.removeChild(node);
17622 if (!node.attributes || !node.attributes.length) {
17623 this.cleanUpChildren(node);
17627 function cleanAttr(n,v)
17630 if (v.match(/^\./) || v.match(/^\//)) {
17633 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17636 if (v.match(/^#/)) {
17639 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17640 node.removeAttribute(n);
17644 var cwhite = this.cwhite;
17645 var cblack = this.cblack;
17647 function cleanStyle(n,v)
17649 if (v.match(/expression/)) { //XSS?? should we even bother..
17650 node.removeAttribute(n);
17654 var parts = v.split(/;/);
17657 Roo.each(parts, function(p) {
17658 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17662 var l = p.split(':').shift().replace(/\s+/g,'');
17663 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17665 if ( cwhite.length && cblack.indexOf(l) > -1) {
17666 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17667 //node.removeAttribute(n);
17671 // only allow 'c whitelisted system attributes'
17672 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17673 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17674 //node.removeAttribute(n);
17684 if (clean.length) {
17685 node.setAttribute(n, clean.join(';'));
17687 node.removeAttribute(n);
17693 for (var i = node.attributes.length-1; i > -1 ; i--) {
17694 var a = node.attributes[i];
17697 if (a.name.toLowerCase().substr(0,2)=='on') {
17698 node.removeAttribute(a.name);
17701 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17702 node.removeAttribute(a.name);
17705 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17706 cleanAttr(a.name,a.value); // fixme..
17709 if (a.name == 'style') {
17710 cleanStyle(a.name,a.value);
17713 /// clean up MS crap..
17714 // tecnically this should be a list of valid class'es..
17717 if (a.name == 'class') {
17718 if (a.value.match(/^Mso/)) {
17719 node.className = '';
17722 if (a.value.match(/body/)) {
17723 node.className = '';
17734 this.cleanUpChildren(node);
17739 * Clean up MS wordisms...
17741 cleanWord : function(node)
17744 var cleanWordChildren = function()
17746 if (!node.childNodes.length) {
17749 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17750 _t.cleanWord(node.childNodes[i]);
17756 this.cleanWord(this.doc.body);
17759 if (node.nodeName == "#text") {
17760 // clean up silly Windows -- stuff?
17763 if (node.nodeName == "#comment") {
17764 node.parentNode.removeChild(node);
17765 // clean up silly Windows -- stuff?
17769 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17770 node.parentNode.removeChild(node);
17774 // remove - but keep children..
17775 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17776 while (node.childNodes.length) {
17777 var cn = node.childNodes[0];
17778 node.removeChild(cn);
17779 node.parentNode.insertBefore(cn, node);
17781 node.parentNode.removeChild(node);
17782 cleanWordChildren();
17786 if (node.className.length) {
17788 var cn = node.className.split(/\W+/);
17790 Roo.each(cn, function(cls) {
17791 if (cls.match(/Mso[a-zA-Z]+/)) {
17796 node.className = cna.length ? cna.join(' ') : '';
17798 node.removeAttribute("class");
17802 if (node.hasAttribute("lang")) {
17803 node.removeAttribute("lang");
17806 if (node.hasAttribute("style")) {
17808 var styles = node.getAttribute("style").split(";");
17810 Roo.each(styles, function(s) {
17811 if (!s.match(/:/)) {
17814 var kv = s.split(":");
17815 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17818 // what ever is left... we allow.
17821 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17822 if (!nstyle.length) {
17823 node.removeAttribute('style');
17827 cleanWordChildren();
17831 domToHTML : function(currentElement, depth, nopadtext) {
17833 depth = depth || 0;
17834 nopadtext = nopadtext || false;
17836 if (!currentElement) {
17837 return this.domToHTML(this.doc.body);
17840 //Roo.log(currentElement);
17842 var allText = false;
17843 var nodeName = currentElement.nodeName;
17844 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17846 if (nodeName == '#text') {
17848 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
17853 if (nodeName != 'BODY') {
17856 // Prints the node tagName, such as <A>, <IMG>, etc
17859 for(i = 0; i < currentElement.attributes.length;i++) {
17861 var aname = currentElement.attributes.item(i).name;
17862 if (!currentElement.attributes.item(i).value.length) {
17865 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17868 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17877 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17880 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17885 // Traverse the tree
17887 var currentElementChild = currentElement.childNodes.item(i);
17888 var allText = true;
17889 var innerHTML = '';
17891 while (currentElementChild) {
17892 // Formatting code (indent the tree so it looks nice on the screen)
17893 var nopad = nopadtext;
17894 if (lastnode == 'SPAN') {
17898 if (currentElementChild.nodeName == '#text') {
17899 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17900 toadd = nopadtext ? toadd : toadd.trim();
17901 if (!nopad && toadd.length > 80) {
17902 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17904 innerHTML += toadd;
17907 currentElementChild = currentElement.childNodes.item(i);
17913 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17915 // Recursively traverse the tree structure of the child node
17916 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17917 lastnode = currentElementChild.nodeName;
17919 currentElementChild=currentElement.childNodes.item(i);
17925 // The remaining code is mostly for formatting the tree
17926 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17931 ret+= "</"+tagName+">";
17937 applyBlacklists : function()
17939 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17940 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17944 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17945 if (b.indexOf(tag) > -1) {
17948 this.white.push(tag);
17952 Roo.each(w, function(tag) {
17953 if (b.indexOf(tag) > -1) {
17956 if (this.white.indexOf(tag) > -1) {
17959 this.white.push(tag);
17964 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17965 if (w.indexOf(tag) > -1) {
17968 this.black.push(tag);
17972 Roo.each(b, function(tag) {
17973 if (w.indexOf(tag) > -1) {
17976 if (this.black.indexOf(tag) > -1) {
17979 this.black.push(tag);
17984 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
17985 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
17989 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17990 if (b.indexOf(tag) > -1) {
17993 this.cwhite.push(tag);
17997 Roo.each(w, function(tag) {
17998 if (b.indexOf(tag) > -1) {
18001 if (this.cwhite.indexOf(tag) > -1) {
18004 this.cwhite.push(tag);
18009 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18010 if (w.indexOf(tag) > -1) {
18013 this.cblack.push(tag);
18017 Roo.each(b, function(tag) {
18018 if (w.indexOf(tag) > -1) {
18021 if (this.cblack.indexOf(tag) > -1) {
18024 this.cblack.push(tag);
18029 setStylesheets : function(stylesheets)
18031 if(typeof(stylesheets) == 'string'){
18032 Roo.get(this.iframe.contentDocument.head).createChild({
18034 rel : 'stylesheet',
18043 Roo.each(stylesheets, function(s) {
18048 Roo.get(_this.iframe.contentDocument.head).createChild({
18050 rel : 'stylesheet',
18059 removeStylesheets : function()
18063 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18068 // hide stuff that is not compatible
18082 * @event specialkey
18086 * @cfg {String} fieldClass @hide
18089 * @cfg {String} focusClass @hide
18092 * @cfg {String} autoCreate @hide
18095 * @cfg {String} inputType @hide
18098 * @cfg {String} invalidClass @hide
18101 * @cfg {String} invalidText @hide
18104 * @cfg {String} msgFx @hide
18107 * @cfg {String} validateOnBlur @hide
18111 Roo.HtmlEditorCore.white = [
18112 'area', 'br', 'img', 'input', 'hr', 'wbr',
18114 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
18115 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
18116 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
18117 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
18118 'table', 'ul', 'xmp',
18120 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
18123 'dir', 'menu', 'ol', 'ul', 'dl',
18129 Roo.HtmlEditorCore.black = [
18130 // 'embed', 'object', // enable - backend responsiblity to clean thiese
18132 'base', 'basefont', 'bgsound', 'blink', 'body',
18133 'frame', 'frameset', 'head', 'html', 'ilayer',
18134 'iframe', 'layer', 'link', 'meta', 'object',
18135 'script', 'style' ,'title', 'xml' // clean later..
18137 Roo.HtmlEditorCore.clean = [
18138 'script', 'style', 'title', 'xml'
18140 Roo.HtmlEditorCore.remove = [
18145 Roo.HtmlEditorCore.ablack = [
18149 Roo.HtmlEditorCore.aclean = [
18150 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
18154 Roo.HtmlEditorCore.pwhite= [
18155 'http', 'https', 'mailto'
18158 // white listed style attributes.
18159 Roo.HtmlEditorCore.cwhite= [
18160 // 'text-align', /// default is to allow most things..
18166 // black listed style attributes.
18167 Roo.HtmlEditorCore.cblack= [
18168 // 'font-size' -- this can be set by the project
18172 Roo.HtmlEditorCore.swapCodes =[
18191 * @class Roo.bootstrap.HtmlEditor
18192 * @extends Roo.bootstrap.TextArea
18193 * Bootstrap HtmlEditor class
18196 * Create a new HtmlEditor
18197 * @param {Object} config The config object
18200 Roo.bootstrap.HtmlEditor = function(config){
18201 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18202 if (!this.toolbars) {
18203 this.toolbars = [];
18205 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18208 * @event initialize
18209 * Fires when the editor is fully initialized (including the iframe)
18210 * @param {HtmlEditor} this
18215 * Fires when the editor is first receives the focus. Any insertion must wait
18216 * until after this event.
18217 * @param {HtmlEditor} this
18221 * @event beforesync
18222 * Fires before the textarea is updated with content from the editor iframe. Return false
18223 * to cancel the sync.
18224 * @param {HtmlEditor} this
18225 * @param {String} html
18229 * @event beforepush
18230 * Fires before the iframe editor is updated with content from the textarea. Return false
18231 * to cancel the push.
18232 * @param {HtmlEditor} this
18233 * @param {String} html
18238 * Fires when the textarea is updated with content from the editor iframe.
18239 * @param {HtmlEditor} this
18240 * @param {String} html
18245 * Fires when the iframe editor is updated with content from the textarea.
18246 * @param {HtmlEditor} this
18247 * @param {String} html
18251 * @event editmodechange
18252 * Fires when the editor switches edit modes
18253 * @param {HtmlEditor} this
18254 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18256 editmodechange: true,
18258 * @event editorevent
18259 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18260 * @param {HtmlEditor} this
18264 * @event firstfocus
18265 * Fires when on first focus - needed by toolbars..
18266 * @param {HtmlEditor} this
18271 * Auto save the htmlEditor value as a file into Events
18272 * @param {HtmlEditor} this
18276 * @event savedpreview
18277 * preview the saved version of htmlEditor
18278 * @param {HtmlEditor} this
18285 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18289 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18294 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18299 * @cfg {Number} height (in pixels)
18303 * @cfg {Number} width (in pixels)
18308 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18311 stylesheets: false,
18316 // private properties
18317 validationEvent : false,
18319 initialized : false,
18322 onFocus : Roo.emptyFn,
18324 hideMode:'offsets',
18327 tbContainer : false,
18329 toolbarContainer :function() {
18330 return this.wrap.select('.x-html-editor-tb',true).first();
18334 * Protected method that will not generally be called directly. It
18335 * is called when the editor creates its toolbar. Override this method if you need to
18336 * add custom toolbar buttons.
18337 * @param {HtmlEditor} editor
18339 createToolbar : function(){
18341 Roo.log("create toolbars");
18343 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18344 this.toolbars[0].render(this.toolbarContainer());
18348 // if (!editor.toolbars || !editor.toolbars.length) {
18349 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18352 // for (var i =0 ; i < editor.toolbars.length;i++) {
18353 // editor.toolbars[i] = Roo.factory(
18354 // typeof(editor.toolbars[i]) == 'string' ?
18355 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18356 // Roo.bootstrap.HtmlEditor);
18357 // editor.toolbars[i].init(editor);
18363 onRender : function(ct, position)
18365 // Roo.log("Call onRender: " + this.xtype);
18367 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18369 this.wrap = this.inputEl().wrap({
18370 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18373 this.editorcore.onRender(ct, position);
18375 if (this.resizable) {
18376 this.resizeEl = new Roo.Resizable(this.wrap, {
18380 minHeight : this.height,
18381 height: this.height,
18382 handles : this.resizable,
18385 resize : function(r, w, h) {
18386 _t.onResize(w,h); // -something
18392 this.createToolbar(this);
18395 if(!this.width && this.resizable){
18396 this.setSize(this.wrap.getSize());
18398 if (this.resizeEl) {
18399 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18400 // should trigger onReize..
18406 onResize : function(w, h)
18408 Roo.log('resize: ' +w + ',' + h );
18409 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18413 if(this.inputEl() ){
18414 if(typeof w == 'number'){
18415 var aw = w - this.wrap.getFrameWidth('lr');
18416 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18419 if(typeof h == 'number'){
18420 var tbh = -11; // fixme it needs to tool bar size!
18421 for (var i =0; i < this.toolbars.length;i++) {
18422 // fixme - ask toolbars for heights?
18423 tbh += this.toolbars[i].el.getHeight();
18424 //if (this.toolbars[i].footer) {
18425 // tbh += this.toolbars[i].footer.el.getHeight();
18433 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18434 ah -= 5; // knock a few pixes off for look..
18435 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18439 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18440 this.editorcore.onResize(ew,eh);
18445 * Toggles the editor between standard and source edit mode.
18446 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18448 toggleSourceEdit : function(sourceEditMode)
18450 this.editorcore.toggleSourceEdit(sourceEditMode);
18452 if(this.editorcore.sourceEditMode){
18453 Roo.log('editor - showing textarea');
18456 // Roo.log(this.syncValue());
18458 this.inputEl().removeClass(['hide', 'x-hidden']);
18459 this.inputEl().dom.removeAttribute('tabIndex');
18460 this.inputEl().focus();
18462 Roo.log('editor - hiding textarea');
18464 // Roo.log(this.pushValue());
18467 this.inputEl().addClass(['hide', 'x-hidden']);
18468 this.inputEl().dom.setAttribute('tabIndex', -1);
18469 //this.deferFocus();
18472 if(this.resizable){
18473 this.setSize(this.wrap.getSize());
18476 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18479 // private (for BoxComponent)
18480 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18482 // private (for BoxComponent)
18483 getResizeEl : function(){
18487 // private (for BoxComponent)
18488 getPositionEl : function(){
18493 initEvents : function(){
18494 this.originalValue = this.getValue();
18498 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18501 // markInvalid : Roo.emptyFn,
18503 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18506 // clearInvalid : Roo.emptyFn,
18508 setValue : function(v){
18509 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18510 this.editorcore.pushValue();
18515 deferFocus : function(){
18516 this.focus.defer(10, this);
18520 focus : function(){
18521 this.editorcore.focus();
18527 onDestroy : function(){
18533 for (var i =0; i < this.toolbars.length;i++) {
18534 // fixme - ask toolbars for heights?
18535 this.toolbars[i].onDestroy();
18538 this.wrap.dom.innerHTML = '';
18539 this.wrap.remove();
18544 onFirstFocus : function(){
18545 //Roo.log("onFirstFocus");
18546 this.editorcore.onFirstFocus();
18547 for (var i =0; i < this.toolbars.length;i++) {
18548 this.toolbars[i].onFirstFocus();
18554 syncValue : function()
18556 this.editorcore.syncValue();
18559 pushValue : function()
18561 this.editorcore.pushValue();
18565 // hide stuff that is not compatible
18579 * @event specialkey
18583 * @cfg {String} fieldClass @hide
18586 * @cfg {String} focusClass @hide
18589 * @cfg {String} autoCreate @hide
18592 * @cfg {String} inputType @hide
18595 * @cfg {String} invalidClass @hide
18598 * @cfg {String} invalidText @hide
18601 * @cfg {String} msgFx @hide
18604 * @cfg {String} validateOnBlur @hide
18613 Roo.namespace('Roo.bootstrap.htmleditor');
18615 * @class Roo.bootstrap.HtmlEditorToolbar1
18620 new Roo.bootstrap.HtmlEditor({
18623 new Roo.bootstrap.HtmlEditorToolbar1({
18624 disable : { fonts: 1 , format: 1, ..., ... , ...],
18630 * @cfg {Object} disable List of elements to disable..
18631 * @cfg {Array} btns List of additional buttons.
18635 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18638 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18641 Roo.apply(this, config);
18643 // default disabled, based on 'good practice'..
18644 this.disable = this.disable || {};
18645 Roo.applyIf(this.disable, {
18648 specialElements : true
18650 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18652 this.editor = config.editor;
18653 this.editorcore = config.editor.editorcore;
18655 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18657 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18658 // dont call parent... till later.
18660 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18665 editorcore : false,
18670 "h1","h2","h3","h4","h5","h6",
18672 "abbr", "acronym", "address", "cite", "samp", "var",
18676 onRender : function(ct, position)
18678 // Roo.log("Call onRender: " + this.xtype);
18680 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18682 this.el.dom.style.marginBottom = '0';
18684 var editorcore = this.editorcore;
18685 var editor= this.editor;
18688 var btn = function(id,cmd , toggle, handler){
18690 var event = toggle ? 'toggle' : 'click';
18695 xns: Roo.bootstrap,
18698 enableToggle:toggle !== false,
18700 pressed : toggle ? false : null,
18703 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18704 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18713 xns: Roo.bootstrap,
18714 glyphicon : 'font',
18718 xns: Roo.bootstrap,
18722 Roo.each(this.formats, function(f) {
18723 style.menu.items.push({
18725 xns: Roo.bootstrap,
18726 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18731 editorcore.insertTag(this.tagname);
18738 children.push(style);
18741 btn('bold',false,true);
18742 btn('italic',false,true);
18743 btn('align-left', 'justifyleft',true);
18744 btn('align-center', 'justifycenter',true);
18745 btn('align-right' , 'justifyright',true);
18746 btn('link', false, false, function(btn) {
18747 //Roo.log("create link?");
18748 var url = prompt(this.createLinkText, this.defaultLinkValue);
18749 if(url && url != 'http:/'+'/'){
18750 this.editorcore.relayCmd('createlink', url);
18753 btn('list','insertunorderedlist',true);
18754 btn('pencil', false,true, function(btn){
18757 this.toggleSourceEdit(btn.pressed);
18763 xns: Roo.bootstrap,
18768 xns: Roo.bootstrap,
18773 cog.menu.items.push({
18775 xns: Roo.bootstrap,
18776 html : Clean styles,
18781 editorcore.insertTag(this.tagname);
18790 this.xtype = 'NavSimplebar';
18792 for(var i=0;i< children.length;i++) {
18794 this.buttons.add(this.addxtypeChild(children[i]));
18798 editor.on('editorevent', this.updateToolbar, this);
18800 onBtnClick : function(id)
18802 this.editorcore.relayCmd(id);
18803 this.editorcore.focus();
18807 * Protected method that will not generally be called directly. It triggers
18808 * a toolbar update by reading the markup state of the current selection in the editor.
18810 updateToolbar: function(){
18812 if(!this.editorcore.activated){
18813 this.editor.onFirstFocus(); // is this neeed?
18817 var btns = this.buttons;
18818 var doc = this.editorcore.doc;
18819 btns.get('bold').setActive(doc.queryCommandState('bold'));
18820 btns.get('italic').setActive(doc.queryCommandState('italic'));
18821 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18823 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18824 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18825 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18827 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18828 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18831 var ans = this.editorcore.getAllAncestors();
18832 if (this.formatCombo) {
18835 var store = this.formatCombo.store;
18836 this.formatCombo.setValue("");
18837 for (var i =0; i < ans.length;i++) {
18838 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18840 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18848 // hides menus... - so this cant be on a menu...
18849 Roo.bootstrap.MenuMgr.hideAll();
18851 Roo.bootstrap.MenuMgr.hideAll();
18852 //this.editorsyncValue();
18854 onFirstFocus: function() {
18855 this.buttons.each(function(item){
18859 toggleSourceEdit : function(sourceEditMode){
18862 if(sourceEditMode){
18863 Roo.log("disabling buttons");
18864 this.buttons.each( function(item){
18865 if(item.cmd != 'pencil'){
18871 Roo.log("enabling buttons");
18872 if(this.editorcore.initialized){
18873 this.buttons.each( function(item){
18879 Roo.log("calling toggole on editor");
18880 // tell the editor that it's been pressed..
18881 this.editor.toggleSourceEdit(sourceEditMode);
18891 * @class Roo.bootstrap.Table.AbstractSelectionModel
18892 * @extends Roo.util.Observable
18893 * Abstract base class for grid SelectionModels. It provides the interface that should be
18894 * implemented by descendant classes. This class should not be directly instantiated.
18897 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18898 this.locked = false;
18899 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18903 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18904 /** @ignore Called by the grid automatically. Do not call directly. */
18905 init : function(grid){
18911 * Locks the selections.
18914 this.locked = true;
18918 * Unlocks the selections.
18920 unlock : function(){
18921 this.locked = false;
18925 * Returns true if the selections are locked.
18926 * @return {Boolean}
18928 isLocked : function(){
18929 return this.locked;
18933 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18934 * @class Roo.bootstrap.Table.RowSelectionModel
18935 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18936 * It supports multiple selections and keyboard selection/navigation.
18938 * @param {Object} config
18941 Roo.bootstrap.Table.RowSelectionModel = function(config){
18942 Roo.apply(this, config);
18943 this.selections = new Roo.util.MixedCollection(false, function(o){
18948 this.lastActive = false;
18952 * @event selectionchange
18953 * Fires when the selection changes
18954 * @param {SelectionModel} this
18956 "selectionchange" : true,
18958 * @event afterselectionchange
18959 * Fires after the selection changes (eg. by key press or clicking)
18960 * @param {SelectionModel} this
18962 "afterselectionchange" : true,
18964 * @event beforerowselect
18965 * Fires when a row is selected being selected, return false to cancel.
18966 * @param {SelectionModel} this
18967 * @param {Number} rowIndex The selected index
18968 * @param {Boolean} keepExisting False if other selections will be cleared
18970 "beforerowselect" : true,
18973 * Fires when a row is selected.
18974 * @param {SelectionModel} this
18975 * @param {Number} rowIndex The selected index
18976 * @param {Roo.data.Record} r The record
18978 "rowselect" : true,
18980 * @event rowdeselect
18981 * Fires when a row is deselected.
18982 * @param {SelectionModel} this
18983 * @param {Number} rowIndex The selected index
18985 "rowdeselect" : true
18987 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18988 this.locked = false;
18991 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18993 * @cfg {Boolean} singleSelect
18994 * True to allow selection of only one row at a time (defaults to false)
18996 singleSelect : false,
18999 initEvents : function(){
19001 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19002 this.grid.on("mousedown", this.handleMouseDown, this);
19003 }else{ // allow click to work like normal
19004 this.grid.on("rowclick", this.handleDragableRowClick, this);
19007 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19008 "up" : function(e){
19010 this.selectPrevious(e.shiftKey);
19011 }else if(this.last !== false && this.lastActive !== false){
19012 var last = this.last;
19013 this.selectRange(this.last, this.lastActive-1);
19014 this.grid.getView().focusRow(this.lastActive);
19015 if(last !== false){
19019 this.selectFirstRow();
19021 this.fireEvent("afterselectionchange", this);
19023 "down" : function(e){
19025 this.selectNext(e.shiftKey);
19026 }else if(this.last !== false && this.lastActive !== false){
19027 var last = this.last;
19028 this.selectRange(this.last, this.lastActive+1);
19029 this.grid.getView().focusRow(this.lastActive);
19030 if(last !== false){
19034 this.selectFirstRow();
19036 this.fireEvent("afterselectionchange", this);
19041 var view = this.grid.view;
19042 view.on("refresh", this.onRefresh, this);
19043 view.on("rowupdated", this.onRowUpdated, this);
19044 view.on("rowremoved", this.onRemove, this);
19048 onRefresh : function(){
19049 var ds = this.grid.dataSource, i, v = this.grid.view;
19050 var s = this.selections;
19051 s.each(function(r){
19052 if((i = ds.indexOfId(r.id)) != -1){
19061 onRemove : function(v, index, r){
19062 this.selections.remove(r);
19066 onRowUpdated : function(v, index, r){
19067 if(this.isSelected(r)){
19068 v.onRowSelect(index);
19074 * @param {Array} records The records to select
19075 * @param {Boolean} keepExisting (optional) True to keep existing selections
19077 selectRecords : function(records, keepExisting){
19079 this.clearSelections();
19081 var ds = this.grid.dataSource;
19082 for(var i = 0, len = records.length; i < len; i++){
19083 this.selectRow(ds.indexOf(records[i]), true);
19088 * Gets the number of selected rows.
19091 getCount : function(){
19092 return this.selections.length;
19096 * Selects the first row in the grid.
19098 selectFirstRow : function(){
19103 * Select the last row.
19104 * @param {Boolean} keepExisting (optional) True to keep existing selections
19106 selectLastRow : function(keepExisting){
19107 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19111 * Selects the row immediately following the last selected row.
19112 * @param {Boolean} keepExisting (optional) True to keep existing selections
19114 selectNext : function(keepExisting){
19115 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19116 this.selectRow(this.last+1, keepExisting);
19117 this.grid.getView().focusRow(this.last);
19122 * Selects the row that precedes the last selected row.
19123 * @param {Boolean} keepExisting (optional) True to keep existing selections
19125 selectPrevious : function(keepExisting){
19127 this.selectRow(this.last-1, keepExisting);
19128 this.grid.getView().focusRow(this.last);
19133 * Returns the selected records
19134 * @return {Array} Array of selected records
19136 getSelections : function(){
19137 return [].concat(this.selections.items);
19141 * Returns the first selected record.
19144 getSelected : function(){
19145 return this.selections.itemAt(0);
19150 * Clears all selections.
19152 clearSelections : function(fast){
19153 if(this.locked) return;
19155 var ds = this.grid.dataSource;
19156 var s = this.selections;
19157 s.each(function(r){
19158 this.deselectRow(ds.indexOfId(r.id));
19162 this.selections.clear();
19169 * Selects all rows.
19171 selectAll : function(){
19172 if(this.locked) return;
19173 this.selections.clear();
19174 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19175 this.selectRow(i, true);
19180 * Returns True if there is a selection.
19181 * @return {Boolean}
19183 hasSelection : function(){
19184 return this.selections.length > 0;
19188 * Returns True if the specified row is selected.
19189 * @param {Number/Record} record The record or index of the record to check
19190 * @return {Boolean}
19192 isSelected : function(index){
19193 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19194 return (r && this.selections.key(r.id) ? true : false);
19198 * Returns True if the specified record id is selected.
19199 * @param {String} id The id of record to check
19200 * @return {Boolean}
19202 isIdSelected : function(id){
19203 return (this.selections.key(id) ? true : false);
19207 handleMouseDown : function(e, t){
19208 var view = this.grid.getView(), rowIndex;
19209 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19212 if(e.shiftKey && this.last !== false){
19213 var last = this.last;
19214 this.selectRange(last, rowIndex, e.ctrlKey);
19215 this.last = last; // reset the last
19216 view.focusRow(rowIndex);
19218 var isSelected = this.isSelected(rowIndex);
19219 if(e.button !== 0 && isSelected){
19220 view.focusRow(rowIndex);
19221 }else if(e.ctrlKey && isSelected){
19222 this.deselectRow(rowIndex);
19223 }else if(!isSelected){
19224 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19225 view.focusRow(rowIndex);
19228 this.fireEvent("afterselectionchange", this);
19231 handleDragableRowClick : function(grid, rowIndex, e)
19233 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19234 this.selectRow(rowIndex, false);
19235 grid.view.focusRow(rowIndex);
19236 this.fireEvent("afterselectionchange", this);
19241 * Selects multiple rows.
19242 * @param {Array} rows Array of the indexes of the row to select
19243 * @param {Boolean} keepExisting (optional) True to keep existing selections
19245 selectRows : function(rows, keepExisting){
19247 this.clearSelections();
19249 for(var i = 0, len = rows.length; i < len; i++){
19250 this.selectRow(rows[i], true);
19255 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19256 * @param {Number} startRow The index of the first row in the range
19257 * @param {Number} endRow The index of the last row in the range
19258 * @param {Boolean} keepExisting (optional) True to retain existing selections
19260 selectRange : function(startRow, endRow, keepExisting){
19261 if(this.locked) return;
19263 this.clearSelections();
19265 if(startRow <= endRow){
19266 for(var i = startRow; i <= endRow; i++){
19267 this.selectRow(i, true);
19270 for(var i = startRow; i >= endRow; i--){
19271 this.selectRow(i, true);
19277 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19278 * @param {Number} startRow The index of the first row in the range
19279 * @param {Number} endRow The index of the last row in the range
19281 deselectRange : function(startRow, endRow, preventViewNotify){
19282 if(this.locked) return;
19283 for(var i = startRow; i <= endRow; i++){
19284 this.deselectRow(i, preventViewNotify);
19290 * @param {Number} row The index of the row to select
19291 * @param {Boolean} keepExisting (optional) True to keep existing selections
19293 selectRow : function(index, keepExisting, preventViewNotify){
19294 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19295 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19296 if(!keepExisting || this.singleSelect){
19297 this.clearSelections();
19299 var r = this.grid.dataSource.getAt(index);
19300 this.selections.add(r);
19301 this.last = this.lastActive = index;
19302 if(!preventViewNotify){
19303 this.grid.getView().onRowSelect(index);
19305 this.fireEvent("rowselect", this, index, r);
19306 this.fireEvent("selectionchange", this);
19312 * @param {Number} row The index of the row to deselect
19314 deselectRow : function(index, preventViewNotify){
19315 if(this.locked) return;
19316 if(this.last == index){
19319 if(this.lastActive == index){
19320 this.lastActive = false;
19322 var r = this.grid.dataSource.getAt(index);
19323 this.selections.remove(r);
19324 if(!preventViewNotify){
19325 this.grid.getView().onRowDeselect(index);
19327 this.fireEvent("rowdeselect", this, index);
19328 this.fireEvent("selectionchange", this);
19332 restoreLast : function(){
19334 this.last = this._last;
19339 acceptsNav : function(row, col, cm){
19340 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19344 onEditorKey : function(field, e){
19345 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19350 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19352 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19354 }else if(k == e.ENTER && !e.ctrlKey){
19358 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19360 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19362 }else if(k == e.ESC){
19366 g.startEditing(newCell[0], newCell[1]);
19371 * Ext JS Library 1.1.1
19372 * Copyright(c) 2006-2007, Ext JS, LLC.
19374 * Originally Released Under LGPL - original licence link has changed is not relivant.
19377 * <script type="text/javascript">
19381 * @class Roo.bootstrap.PagingToolbar
19383 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19385 * Create a new PagingToolbar
19386 * @param {Object} config The config object
19388 Roo.bootstrap.PagingToolbar = function(config)
19390 // old args format still supported... - xtype is prefered..
19391 // created from xtype...
19392 var ds = config.dataSource;
19393 this.toolbarItems = [];
19394 if (config.items) {
19395 this.toolbarItems = config.items;
19396 // config.items = [];
19399 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19406 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19410 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19412 * @cfg {Roo.data.Store} dataSource
19413 * The underlying data store providing the paged data
19416 * @cfg {String/HTMLElement/Element} container
19417 * container The id or element that will contain the toolbar
19420 * @cfg {Boolean} displayInfo
19421 * True to display the displayMsg (defaults to false)
19424 * @cfg {Number} pageSize
19425 * The number of records to display per page (defaults to 20)
19429 * @cfg {String} displayMsg
19430 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19432 displayMsg : 'Displaying {0} - {1} of {2}',
19434 * @cfg {String} emptyMsg
19435 * The message to display when no records are found (defaults to "No data to display")
19437 emptyMsg : 'No data to display',
19439 * Customizable piece of the default paging text (defaults to "Page")
19442 beforePageText : "Page",
19444 * Customizable piece of the default paging text (defaults to "of %0")
19447 afterPageText : "of {0}",
19449 * Customizable piece of the default paging text (defaults to "First Page")
19452 firstText : "First Page",
19454 * Customizable piece of the default paging text (defaults to "Previous Page")
19457 prevText : "Previous Page",
19459 * Customizable piece of the default paging text (defaults to "Next Page")
19462 nextText : "Next Page",
19464 * Customizable piece of the default paging text (defaults to "Last Page")
19467 lastText : "Last Page",
19469 * Customizable piece of the default paging text (defaults to "Refresh")
19472 refreshText : "Refresh",
19476 onRender : function(ct, position)
19478 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19479 this.navgroup.parentId = this.id;
19480 this.navgroup.onRender(this.el, null);
19481 // add the buttons to the navgroup
19483 if(this.displayInfo){
19484 Roo.log(this.el.select('ul.navbar-nav',true).first());
19485 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19486 this.displayEl = this.el.select('.x-paging-info', true).first();
19487 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19488 // this.displayEl = navel.el.select('span',true).first();
19494 Roo.each(_this.buttons, function(e){
19495 Roo.factory(e).onRender(_this.el, null);
19499 Roo.each(_this.toolbarItems, function(e) {
19500 _this.navgroup.addItem(e);
19503 this.first = this.navgroup.addItem({
19504 tooltip: this.firstText,
19506 icon : 'fa fa-backward',
19508 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19511 this.prev = this.navgroup.addItem({
19512 tooltip: this.prevText,
19514 icon : 'fa fa-step-backward',
19516 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19518 //this.addSeparator();
19521 var field = this.navgroup.addItem( {
19523 cls : 'x-paging-position',
19525 html : this.beforePageText +
19526 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19527 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19530 this.field = field.el.select('input', true).first();
19531 this.field.on("keydown", this.onPagingKeydown, this);
19532 this.field.on("focus", function(){this.dom.select();});
19535 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19536 //this.field.setHeight(18);
19537 //this.addSeparator();
19538 this.next = this.navgroup.addItem({
19539 tooltip: this.nextText,
19541 html : ' <i class="fa fa-step-forward">',
19543 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19545 this.last = this.navgroup.addItem({
19546 tooltip: this.lastText,
19547 icon : 'fa fa-forward',
19550 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19552 //this.addSeparator();
19553 this.loading = this.navgroup.addItem({
19554 tooltip: this.refreshText,
19555 icon: 'fa fa-refresh',
19557 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19563 updateInfo : function(){
19564 if(this.displayEl){
19565 var count = this.ds.getCount();
19566 var msg = count == 0 ?
19570 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19572 this.displayEl.update(msg);
19577 onLoad : function(ds, r, o){
19578 this.cursor = o.params ? o.params.start : 0;
19579 var d = this.getPageData(),
19583 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19584 this.field.dom.value = ap;
19585 this.first.setDisabled(ap == 1);
19586 this.prev.setDisabled(ap == 1);
19587 this.next.setDisabled(ap == ps);
19588 this.last.setDisabled(ap == ps);
19589 this.loading.enable();
19594 getPageData : function(){
19595 var total = this.ds.getTotalCount();
19598 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19599 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19604 onLoadError : function(){
19605 this.loading.enable();
19609 onPagingKeydown : function(e){
19610 var k = e.getKey();
19611 var d = this.getPageData();
19613 var v = this.field.dom.value, pageNum;
19614 if(!v || isNaN(pageNum = parseInt(v, 10))){
19615 this.field.dom.value = d.activePage;
19618 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19619 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19622 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))
19624 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19625 this.field.dom.value = pageNum;
19626 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19629 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19631 var v = this.field.dom.value, pageNum;
19632 var increment = (e.shiftKey) ? 10 : 1;
19633 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19635 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19636 this.field.dom.value = d.activePage;
19639 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19641 this.field.dom.value = parseInt(v, 10) + increment;
19642 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19643 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19650 beforeLoad : function(){
19652 this.loading.disable();
19657 onClick : function(which){
19664 ds.load({params:{start: 0, limit: this.pageSize}});
19667 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19670 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19673 var total = ds.getTotalCount();
19674 var extra = total % this.pageSize;
19675 var lastStart = extra ? (total - extra) : total-this.pageSize;
19676 ds.load({params:{start: lastStart, limit: this.pageSize}});
19679 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19685 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19686 * @param {Roo.data.Store} store The data store to unbind
19688 unbind : function(ds){
19689 ds.un("beforeload", this.beforeLoad, this);
19690 ds.un("load", this.onLoad, this);
19691 ds.un("loadexception", this.onLoadError, this);
19692 ds.un("remove", this.updateInfo, this);
19693 ds.un("add", this.updateInfo, this);
19694 this.ds = undefined;
19698 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19699 * @param {Roo.data.Store} store The data store to bind
19701 bind : function(ds){
19702 ds.on("beforeload", this.beforeLoad, this);
19703 ds.on("load", this.onLoad, this);
19704 ds.on("loadexception", this.onLoadError, this);
19705 ds.on("remove", this.updateInfo, this);
19706 ds.on("add", this.updateInfo, this);
19717 * @class Roo.bootstrap.MessageBar
19718 * @extends Roo.bootstrap.Component
19719 * Bootstrap MessageBar class
19720 * @cfg {String} html contents of the MessageBar
19721 * @cfg {String} weight (info | success | warning | danger) default info
19722 * @cfg {String} beforeClass insert the bar before the given class
19723 * @cfg {Boolean} closable (true | false) default false
19724 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19727 * Create a new Element
19728 * @param {Object} config The config object
19731 Roo.bootstrap.MessageBar = function(config){
19732 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19735 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19741 beforeClass: 'bootstrap-sticky-wrap',
19743 getAutoCreate : function(){
19747 cls: 'alert alert-dismissable alert-' + this.weight,
19752 html: this.html || ''
19758 cfg.cls += ' alert-messages-fixed';
19772 onRender : function(ct, position)
19774 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19777 var cfg = Roo.apply({}, this.getAutoCreate());
19781 cfg.cls += ' ' + this.cls;
19784 cfg.style = this.style;
19786 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19788 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19791 this.el.select('>button.close').on('click', this.hide, this);
19797 if (!this.rendered) {
19803 this.fireEvent('show', this);
19809 if (!this.rendered) {
19815 this.fireEvent('hide', this);
19818 update : function()
19820 // var e = this.el.dom.firstChild;
19822 // if(this.closable){
19823 // e = e.nextSibling;
19826 // e.data = this.html || '';
19828 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19844 * @class Roo.bootstrap.Graph
19845 * @extends Roo.bootstrap.Component
19846 * Bootstrap Graph class
19850 @cfg {String} graphtype bar | vbar | pie
19851 @cfg {number} g_x coodinator | centre x (pie)
19852 @cfg {number} g_y coodinator | centre y (pie)
19853 @cfg {number} g_r radius (pie)
19854 @cfg {number} g_height height of the chart (respected by all elements in the set)
19855 @cfg {number} g_width width of the chart (respected by all elements in the set)
19856 @cfg {Object} title The title of the chart
19859 -opts (object) options for the chart
19861 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19862 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19864 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.
19865 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19867 o stretch (boolean)
19869 -opts (object) options for the pie
19872 o startAngle (number)
19873 o endAngle (number)
19877 * Create a new Input
19878 * @param {Object} config The config object
19881 Roo.bootstrap.Graph = function(config){
19882 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19888 * The img click event for the img.
19889 * @param {Roo.EventObject} e
19895 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19906 //g_colors: this.colors,
19913 getAutoCreate : function(){
19924 onRender : function(ct,position){
19925 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19926 this.raphael = Raphael(this.el.dom);
19928 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19929 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19930 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19931 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19933 r.text(160, 10, "Single Series Chart").attr(txtattr);
19934 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19935 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19936 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19938 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19939 r.barchart(330, 10, 300, 220, data1);
19940 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19941 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19944 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19945 // r.barchart(30, 30, 560, 250, xdata, {
19946 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19947 // axis : "0 0 1 1",
19948 // axisxlabels : xdata
19949 // //yvalues : cols,
19952 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19954 // this.load(null,xdata,{
19955 // axis : "0 0 1 1",
19956 // axisxlabels : xdata
19961 load : function(graphtype,xdata,opts){
19962 this.raphael.clear();
19964 graphtype = this.graphtype;
19969 var r = this.raphael,
19970 fin = function () {
19971 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19973 fout = function () {
19974 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19976 pfin = function() {
19977 this.sector.stop();
19978 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19981 this.label[0].stop();
19982 this.label[0].attr({ r: 7.5 });
19983 this.label[1].attr({ "font-weight": 800 });
19986 pfout = function() {
19987 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19990 this.label[0].animate({ r: 5 }, 500, "bounce");
19991 this.label[1].attr({ "font-weight": 400 });
19997 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20000 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20003 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20004 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20006 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20013 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20018 setTitle: function(o)
20023 initEvents: function() {
20026 this.el.on('click', this.onClick, this);
20030 onClick : function(e)
20032 Roo.log('img onclick');
20033 this.fireEvent('click', this, e);
20045 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20048 * @class Roo.bootstrap.dash.NumberBox
20049 * @extends Roo.bootstrap.Component
20050 * Bootstrap NumberBox class
20051 * @cfg {String} headline Box headline
20052 * @cfg {String} content Box content
20053 * @cfg {String} icon Box icon
20054 * @cfg {String} footer Footer text
20055 * @cfg {String} fhref Footer href
20058 * Create a new NumberBox
20059 * @param {Object} config The config object
20063 Roo.bootstrap.dash.NumberBox = function(config){
20064 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20068 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
20077 getAutoCreate : function(){
20081 cls : 'small-box ',
20089 cls : 'roo-headline',
20090 html : this.headline
20094 cls : 'roo-content',
20095 html : this.content
20109 cls : 'ion ' + this.icon
20118 cls : 'small-box-footer',
20119 href : this.fhref || '#',
20123 cfg.cn.push(footer);
20130 onRender : function(ct,position){
20131 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20138 setHeadline: function (value)
20140 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20143 setFooter: function (value, href)
20145 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20148 this.el.select('a.small-box-footer',true).first().attr('href', href);
20153 setContent: function (value)
20155 this.el.select('.roo-content',true).first().dom.innerHTML = value;
20158 initEvents: function()
20172 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20175 * @class Roo.bootstrap.dash.TabBox
20176 * @extends Roo.bootstrap.Component
20177 * Bootstrap TabBox class
20178 * @cfg {String} title Title of the TabBox
20179 * @cfg {String} icon Icon of the TabBox
20180 * @cfg {Boolean} showtabs (true|false) show the tabs default true
20181 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20184 * Create a new TabBox
20185 * @param {Object} config The config object
20189 Roo.bootstrap.dash.TabBox = function(config){
20190 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20195 * When a pane is added
20196 * @param {Roo.bootstrap.dash.TabPane} pane
20200 * @event activatepane
20201 * When a pane is activated
20202 * @param {Roo.bootstrap.dash.TabPane} pane
20204 "activatepane" : true
20212 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20217 tabScrollable : false,
20219 getChildContainer : function()
20221 return this.el.select('.tab-content', true).first();
20224 getAutoCreate : function(){
20228 cls: 'pull-left header',
20236 cls: 'fa ' + this.icon
20242 cls: 'nav nav-tabs pull-right',
20248 if(this.tabScrollable){
20255 cls: 'nav nav-tabs pull-right',
20266 cls: 'nav-tabs-custom',
20271 cls: 'tab-content no-padding',
20279 initEvents : function()
20281 //Roo.log('add add pane handler');
20282 this.on('addpane', this.onAddPane, this);
20285 * Updates the box title
20286 * @param {String} html to set the title to.
20288 setTitle : function(value)
20290 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20292 onAddPane : function(pane)
20294 this.panes.push(pane);
20295 //Roo.log('addpane');
20297 // tabs are rendere left to right..
20298 if(!this.showtabs){
20302 var ctr = this.el.select('.nav-tabs', true).first();
20305 var existing = ctr.select('.nav-tab',true);
20306 var qty = existing.getCount();;
20309 var tab = ctr.createChild({
20311 cls : 'nav-tab' + (qty ? '' : ' active'),
20319 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20322 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20324 pane.el.addClass('active');
20329 onTabClick : function(ev,un,ob,pane)
20331 //Roo.log('tab - prev default');
20332 ev.preventDefault();
20335 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20336 pane.tab.addClass('active');
20337 //Roo.log(pane.title);
20338 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20339 // technically we should have a deactivate event.. but maybe add later.
20340 // and it should not de-activate the selected tab...
20341 this.fireEvent('activatepane', pane);
20342 pane.el.addClass('active');
20343 pane.fireEvent('activate');
20348 getActivePane : function()
20351 Roo.each(this.panes, function(p) {
20352 if(p.el.hasClass('active')){
20373 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20375 * @class Roo.bootstrap.TabPane
20376 * @extends Roo.bootstrap.Component
20377 * Bootstrap TabPane class
20378 * @cfg {Boolean} active (false | true) Default false
20379 * @cfg {String} title title of panel
20383 * Create a new TabPane
20384 * @param {Object} config The config object
20387 Roo.bootstrap.dash.TabPane = function(config){
20388 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20394 * When a pane is activated
20395 * @param {Roo.bootstrap.dash.TabPane} pane
20402 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20407 // the tabBox that this is attached to.
20410 getAutoCreate : function()
20418 cfg.cls += ' active';
20423 initEvents : function()
20425 //Roo.log('trigger add pane handler');
20426 this.parent().fireEvent('addpane', this)
20430 * Updates the tab title
20431 * @param {String} html to set the title to.
20433 setTitle: function(str)
20439 this.tab.select('a', true).first().dom.innerHTML = str;
20456 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20459 * @class Roo.bootstrap.menu.Menu
20460 * @extends Roo.bootstrap.Component
20461 * Bootstrap Menu class - container for Menu
20462 * @cfg {String} html Text of the menu
20463 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20464 * @cfg {String} icon Font awesome icon
20465 * @cfg {String} pos Menu align to (top | bottom) default bottom
20469 * Create a new Menu
20470 * @param {Object} config The config object
20474 Roo.bootstrap.menu.Menu = function(config){
20475 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20479 * @event beforeshow
20480 * Fires before this menu is displayed
20481 * @param {Roo.bootstrap.menu.Menu} this
20485 * @event beforehide
20486 * Fires before this menu is hidden
20487 * @param {Roo.bootstrap.menu.Menu} this
20492 * Fires after this menu is displayed
20493 * @param {Roo.bootstrap.menu.Menu} this
20498 * Fires after this menu is hidden
20499 * @param {Roo.bootstrap.menu.Menu} this
20504 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20505 * @param {Roo.bootstrap.menu.Menu} this
20506 * @param {Roo.EventObject} e
20513 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20517 weight : 'default',
20522 getChildContainer : function() {
20523 if(this.isSubMenu){
20527 return this.el.select('ul.dropdown-menu', true).first();
20530 getAutoCreate : function()
20535 cls : 'roo-menu-text',
20543 cls : 'fa ' + this.icon
20554 cls : 'dropdown-button btn btn-' + this.weight,
20559 cls : 'dropdown-toggle btn btn-' + this.weight,
20569 cls : 'dropdown-menu'
20575 if(this.pos == 'top'){
20576 cfg.cls += ' dropup';
20579 if(this.isSubMenu){
20582 cls : 'dropdown-menu'
20589 onRender : function(ct, position)
20591 this.isSubMenu = ct.hasClass('dropdown-submenu');
20593 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20596 initEvents : function()
20598 if(this.isSubMenu){
20602 this.hidden = true;
20604 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20605 this.triggerEl.on('click', this.onTriggerPress, this);
20607 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20608 this.buttonEl.on('click', this.onClick, this);
20614 if(this.isSubMenu){
20618 return this.el.select('ul.dropdown-menu', true).first();
20621 onClick : function(e)
20623 this.fireEvent("click", this, e);
20626 onTriggerPress : function(e)
20628 if (this.isVisible()) {
20635 isVisible : function(){
20636 return !this.hidden;
20641 this.fireEvent("beforeshow", this);
20643 this.hidden = false;
20644 this.el.addClass('open');
20646 Roo.get(document).on("mouseup", this.onMouseUp, this);
20648 this.fireEvent("show", this);
20655 this.fireEvent("beforehide", this);
20657 this.hidden = true;
20658 this.el.removeClass('open');
20660 Roo.get(document).un("mouseup", this.onMouseUp);
20662 this.fireEvent("hide", this);
20665 onMouseUp : function()
20679 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20682 * @class Roo.bootstrap.menu.Item
20683 * @extends Roo.bootstrap.Component
20684 * Bootstrap MenuItem class
20685 * @cfg {Boolean} submenu (true | false) default false
20686 * @cfg {String} html text of the item
20687 * @cfg {String} href the link
20688 * @cfg {Boolean} disable (true | false) default false
20689 * @cfg {Boolean} preventDefault (true | false) default true
20690 * @cfg {String} icon Font awesome icon
20691 * @cfg {String} pos Submenu align to (left | right) default right
20695 * Create a new Item
20696 * @param {Object} config The config object
20700 Roo.bootstrap.menu.Item = function(config){
20701 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20705 * Fires when the mouse is hovering over this menu
20706 * @param {Roo.bootstrap.menu.Item} this
20707 * @param {Roo.EventObject} e
20712 * Fires when the mouse exits this menu
20713 * @param {Roo.bootstrap.menu.Item} this
20714 * @param {Roo.EventObject} e
20720 * The raw click event for the entire grid.
20721 * @param {Roo.EventObject} e
20727 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20732 preventDefault: true,
20737 getAutoCreate : function()
20742 cls : 'roo-menu-item-text',
20750 cls : 'fa ' + this.icon
20759 href : this.href || '#',
20766 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20770 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20772 if(this.pos == 'left'){
20773 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20780 initEvents : function()
20782 this.el.on('mouseover', this.onMouseOver, this);
20783 this.el.on('mouseout', this.onMouseOut, this);
20785 this.el.select('a', true).first().on('click', this.onClick, this);
20789 onClick : function(e)
20791 if(this.preventDefault){
20792 e.preventDefault();
20795 this.fireEvent("click", this, e);
20798 onMouseOver : function(e)
20800 if(this.submenu && this.pos == 'left'){
20801 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20804 this.fireEvent("mouseover", this, e);
20807 onMouseOut : function(e)
20809 this.fireEvent("mouseout", this, e);
20821 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20824 * @class Roo.bootstrap.menu.Separator
20825 * @extends Roo.bootstrap.Component
20826 * Bootstrap Separator class
20829 * Create a new Separator
20830 * @param {Object} config The config object
20834 Roo.bootstrap.menu.Separator = function(config){
20835 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20838 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20840 getAutoCreate : function(){
20861 * @class Roo.bootstrap.Tooltip
20862 * Bootstrap Tooltip class
20863 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20864 * to determine which dom element triggers the tooltip.
20866 * It needs to add support for additional attributes like tooltip-position
20869 * Create a new Toolti
20870 * @param {Object} config The config object
20873 Roo.bootstrap.Tooltip = function(config){
20874 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20877 Roo.apply(Roo.bootstrap.Tooltip, {
20879 * @function init initialize tooltip monitoring.
20883 currentTip : false,
20884 currentRegion : false,
20890 Roo.get(document).on('mouseover', this.enter ,this);
20891 Roo.get(document).on('mouseout', this.leave, this);
20894 this.currentTip = new Roo.bootstrap.Tooltip();
20897 enter : function(ev)
20899 var dom = ev.getTarget();
20900 //Roo.log(['enter',dom]);
20901 var el = Roo.fly(dom);
20902 if (this.currentEl) {
20904 //Roo.log(this.currentEl);
20905 //Roo.log(this.currentEl.contains(dom));
20906 if (this.currentEl == el) {
20909 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20917 if (this.currentTip.el) {
20918 this.currentTip.el.hide(); // force hiding...
20921 if (!el.attr('tooltip')) { // parents who have tip?
20924 this.currentEl = el;
20925 this.currentTip.bind(el);
20926 this.currentRegion = Roo.lib.Region.getRegion(dom);
20927 this.currentTip.enter();
20930 leave : function(ev)
20932 var dom = ev.getTarget();
20933 //Roo.log(['leave',dom]);
20934 if (!this.currentEl) {
20939 if (dom != this.currentEl.dom) {
20942 var xy = ev.getXY();
20943 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
20946 // only activate leave if mouse cursor is outside... bounding box..
20951 if (this.currentTip) {
20952 this.currentTip.leave();
20954 //Roo.log('clear currentEl');
20955 this.currentEl = false;
20960 'left' : ['r-l', [-2,0], 'right'],
20961 'right' : ['l-r', [2,0], 'left'],
20962 'bottom' : ['t-b', [0,2], 'top'],
20963 'top' : [ 'b-t', [0,-2], 'bottom']
20969 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
20974 delay : null, // can be { show : 300 , hide: 500}
20978 hoverState : null, //???
20980 placement : 'bottom',
20982 getAutoCreate : function(){
20989 cls : 'tooltip-arrow'
20992 cls : 'tooltip-inner'
20999 bind : function(el)
21005 enter : function () {
21007 if (this.timeout != null) {
21008 clearTimeout(this.timeout);
21011 this.hoverState = 'in'
21012 //Roo.log("enter - show");
21013 if (!this.delay || !this.delay.show) {
21018 this.timeout = setTimeout(function () {
21019 if (_t.hoverState == 'in') {
21022 }, this.delay.show);
21026 clearTimeout(this.timeout);
21028 this.hoverState = 'out'
21029 if (!this.delay || !this.delay.hide) {
21035 this.timeout = setTimeout(function () {
21036 //Roo.log("leave - timeout");
21038 if (_t.hoverState == 'out') {
21040 Roo.bootstrap.Tooltip.currentEl = false;
21048 this.render(document.body);
21051 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21052 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21054 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21056 var placement = typeof this.placement == 'function' ?
21057 this.placement.call(this, this.el, on_el) :
21060 var autoToken = /\s?auto?\s?/i;
21061 var autoPlace = autoToken.test(placement);
21063 placement = placement.replace(autoToken, '') || 'top';
21067 //this.el.setXY([0,0]);
21069 //this.el.dom.style.display='block';
21070 this.el.addClass(placement);
21072 //this.el.appendTo(on_el);
21074 var p = this.getPosition();
21075 var box = this.el.getBox();
21080 var align = Roo.bootstrap.Tooltip.alignment[placement]
21081 this.el.alignTo(this.bindEl, align[0],align[1]);
21082 //var arrow = this.el.select('.arrow',true).first();
21083 //arrow.set(align[2],
21085 this.el.addClass('in fade');
21086 this.hoverState = null;
21088 if (this.el.hasClass('fade')) {
21099 //this.el.setXY([0,0]);
21100 this.el.removeClass('in');
21116 * @class Roo.bootstrap.LocationPicker
21117 * @extends Roo.bootstrap.Component
21118 * Bootstrap LocationPicker class
21119 * @cfg {Number} latitude Position when init default 0
21120 * @cfg {Number} longitude Position when init default 0
21121 * @cfg {Number} zoom default 15
21122 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21123 * @cfg {Boolean} mapTypeControl default false
21124 * @cfg {Boolean} disableDoubleClickZoom default false
21125 * @cfg {Boolean} scrollwheel default true
21126 * @cfg {Boolean} streetViewControl default false
21127 * @cfg {Number} radius default 0
21128 * @cfg {String} locationName
21129 * @cfg {Boolean} draggable default true
21130 * @cfg {Boolean} enableAutocomplete default false
21131 * @cfg {Boolean} enableReverseGeocode default true
21132 * @cfg {String} markerTitle
21135 * Create a new LocationPicker
21136 * @param {Object} config The config object
21140 Roo.bootstrap.LocationPicker = function(config){
21142 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21147 * Fires when the picker initialized.
21148 * @param {Roo.bootstrap.LocationPicker} this
21149 * @param {Google Location} location
21153 * @event positionchanged
21154 * Fires when the picker position changed.
21155 * @param {Roo.bootstrap.LocationPicker} this
21156 * @param {Google Location} location
21158 positionchanged : true,
21161 * Fires when the map resize.
21162 * @param {Roo.bootstrap.LocationPicker} this
21167 * Fires when the map show.
21168 * @param {Roo.bootstrap.LocationPicker} this
21173 * Fires when the map hide.
21174 * @param {Roo.bootstrap.LocationPicker} this
21181 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
21183 gMapContext: false,
21189 mapTypeControl: false,
21190 disableDoubleClickZoom: false,
21192 streetViewControl: false,
21196 enableAutocomplete: false,
21197 enableReverseGeocode: true,
21200 getAutoCreate: function()
21205 cls: 'roo-location-picker'
21211 initEvents: function(ct, position)
21213 if(!this.mapTypeId){
21214 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
21217 if(!this.el.getWidth() || this.isApplied()){
21221 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21226 initial: function()
21228 this.gMapContext = this.GMapContext();
21232 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
21233 _this.setPosition(_this.gMapContext.marker.position);
21236 this.setPosition(this.gMapContext.location);
21238 this.fireEvent('initial', this, this.gMapContext.location);
21241 isApplied: function()
21243 return this.getGmapContext() == false ? false : true;
21246 getGmapContext: function()
21248 return this.gMapContext
21251 GMapContext: function()
21253 var _map = new google.maps.Map(this.el.dom, this);
21254 var _marker = new google.maps.Marker({
21255 position: new google.maps.LatLng(this.latitude, this.longitude),
21257 title: this.markerTitle,
21258 draggable: this.draggable
21265 location: _marker.position,
21266 radius: this.radius,
21267 locationName: this.locationName,
21268 addressComponents: {
21269 formatted_address: null,
21270 addressLine1: null,
21271 addressLine2: null,
21273 streetNumber: null,
21277 stateOrProvince: null
21280 domContainer: this.el.dom,
21281 geodecoder: new google.maps.Geocoder()
21285 drawCircle: function(center, radius, options)
21287 if (this.gMapContext.circle != null) {
21288 this.gMapContext.circle.setMap(null);
21292 options = Roo.apply({}, options, {
21293 strokeColor: "#0000FF",
21294 strokeOpacity: .35,
21296 fillColor: "#0000FF",
21300 options.map = this.gMapContext.map;
21301 options.radius = radius;
21302 options.center = center;
21303 this.gMapContext.circle = new google.maps.Circle(options);
21304 return this.gMapContext.circle;
21310 setPosition: function(location)
21312 this.gMapContext.location = location;
21313 this.gMapContext.marker.setPosition(location);
21314 this.gMapContext.map.panTo(location);
21315 this.drawCircle(location, this.gMapContext.radius, {});
21319 if (this.gMapContext.settings.enableReverseGeocode) {
21320 this.gMapContext.geodecoder.geocode({
21321 latLng: this.gMapContext.location
21322 }, function(results, status) {
21324 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21325 _this.gMapContext.locationName = results[0].formatted_address;
21326 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21328 _this.fireEvent('positionchanged', this, location);
21335 this.fireEvent('positionchanged', this, location);
21340 google.maps.event.trigger(this.gMapContext.map, "resize");
21342 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
21344 this.fireEvent('resize', this);
21347 setPositionByLatLng: function(latitude, longitude)
21349 this.setPosition(new google.maps.LatLng(latitude, longitude));
21352 getCurrentPosition: function()
21355 latitude: this.gMapContext.location.lat(),
21356 longitude: this.gMapContext.location.lng()
21360 getAddressName: function()
21362 return this.gMapContext.locationName;
21365 getAddressComponents: function()
21367 return this.gMapContext.addressComponents;
21370 address_component_from_google_geocode: function(address_components)
21374 for (var i = 0; i < address_components.length; i++) {
21375 var component = address_components[i];
21376 if (component.types.indexOf("postal_code") >= 0) {
21377 result.postalCode = component.short_name;
21378 } else if (component.types.indexOf("street_number") >= 0) {
21379 result.streetNumber = component.short_name;
21380 } else if (component.types.indexOf("route") >= 0) {
21381 result.streetName = component.short_name;
21382 } else if (component.types.indexOf("neighborhood") >= 0) {
21383 result.city = component.short_name;
21384 } else if (component.types.indexOf("locality") >= 0) {
21385 result.city = component.short_name;
21386 } else if (component.types.indexOf("sublocality") >= 0) {
21387 result.district = component.short_name;
21388 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
21389 result.stateOrProvince = component.short_name;
21390 } else if (component.types.indexOf("country") >= 0) {
21391 result.country = component.short_name;
21395 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
21396 result.addressLine2 = "";
21400 setZoomLevel: function(zoom)
21402 this.gMapContext.map.setZoom(zoom);
21415 this.fireEvent('show', this);
21426 this.fireEvent('hide', this);
21438 * @class Roo.bootstrap.Alert
21439 * @extends Roo.bootstrap.Component
21440 * Bootstrap Alert class
21441 * @cfg {String} title The title of alert
21442 * @cfg {String} html The content of alert
21443 * @cfg {String} weight ( success | info | warning | danger )
21444 * @cfg {String} faicon font-awesomeicon
21447 * Create a new alert
21448 * @param {Object} config The config object
21452 Roo.bootstrap.Alert = function(config){
21453 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
21457 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
21464 getAutoCreate : function()
21473 cls : 'roo-alert-icon'
21478 cls : 'roo-alert-title',
21483 cls : 'roo-alert-text',
21490 cfg.cn[0].cls += ' fa ' + this.faicon;
21494 cfg.cls += ' alert-' + this.weight;
21500 initEvents: function()
21502 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21505 setTitle : function(str)
21507 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
21510 setText : function(str)
21512 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
21515 setWeight : function(weight)
21518 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
21521 this.weight = weight;
21523 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
21526 setIcon : function(icon)
21529 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
21534 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);