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
22 * Do not use directly - it does not do anything..
23 * @param {Object} config The config object
28 Roo.bootstrap.Component = function(config){
29 Roo.bootstrap.Component.superclass.constructor.call(this, config);
32 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
35 allowDomMove : false, // to stop relocations in parent onRender...
45 * Initialize Events for the element
47 initEvents : function() { },
53 can_build_overlaid : true,
60 // returns the parent component..
61 return Roo.ComponentMgr.get(this.parentId)
67 onRender : function(ct, position)
69 // Roo.log("Call onRender: " + this.xtype);
71 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
74 if (this.el.attr('xtype')) {
75 this.el.attr('xtypex', this.el.attr('xtype'));
76 this.el.dom.removeAttribute('xtype');
86 var cfg = Roo.apply({}, this.getAutoCreate());
89 // fill in the extra attributes
90 if (this.xattr && typeof(this.xattr) =='object') {
91 for (var i in this.xattr) {
92 cfg[i] = this.xattr[i];
97 cfg.dataId = this.dataId;
101 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
104 if (this.style) { // fixme needs to support more complex style data.
105 cfg.style = this.style;
109 cfg.name = this.name;
114 this.el = ct.createChild(cfg, position);
117 this.tooltipEl().attr('tooltip', this.tooltip);
120 if(this.tabIndex !== undefined){
121 this.el.dom.setAttribute('tabIndex', this.tabIndex);
128 * Fetch the element to add children to
129 * @return {Roo.Element} defaults to this.el
131 getChildContainer : function()
136 * Fetch the element to display the tooltip on.
137 * @return {Roo.Element} defaults to this.el
139 tooltipEl : function()
144 addxtype : function(tree,cntr)
148 cn = Roo.factory(tree);
150 cn.parentType = this.xtype; //??
151 cn.parentId = this.id;
153 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
155 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
157 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
159 var build_from_html = Roo.XComponent.build_from_html;
161 var is_body = (tree.xtype == 'Body') ;
163 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
165 var self_cntr_el = Roo.get(this[cntr](false));
167 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
168 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
169 return this.addxtypeChild(tree,cntr);
172 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
175 return this.addxtypeChild(Roo.apply({}, tree),cntr);
178 Roo.log('skipping render');
186 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
192 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
196 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
201 addxtypeChild : function (tree, cntr)
203 Roo.debug && Roo.log('addxtypeChild:' + cntr);
205 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
208 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
209 (typeof(tree['flexy:foreach']) != 'undefined');
213 skip_children = false;
214 // render the element if it's not BODY.
215 if (tree.xtype != 'Body') {
217 cn = Roo.factory(tree);
219 cn.parentType = this.xtype; //??
220 cn.parentId = this.id;
222 var build_from_html = Roo.XComponent.build_from_html;
225 // does the container contain child eleemnts with 'xtype' attributes.
226 // that match this xtype..
227 // note - when we render we create these as well..
228 // so we should check to see if body has xtype set.
229 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
231 var self_cntr_el = Roo.get(this[cntr](false));
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
235 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
236 // and are not displayed -this causes this to use up the wrong element when matching.
237 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
240 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
241 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
247 //echild.dom.removeAttribute('xtype');
249 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
250 Roo.debug && Roo.log(self_cntr_el);
251 Roo.debug && Roo.log(echild);
252 Roo.debug && Roo.log(cn);
258 // if object has flexy:if - then it may or may not be rendered.
259 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
260 // skip a flexy if element.
261 Roo.debug && Roo.log('skipping render');
262 Roo.debug && Roo.log(tree);
264 Roo.debug && Roo.log('skipping all children');
265 skip_children = true;
270 // actually if flexy:foreach is found, we really want to create
271 // multiple copies here...
273 //Roo.log(this[cntr]());
274 cn.render(this[cntr](true));
276 // then add the element..
284 if (typeof (tree.menu) != 'undefined') {
285 tree.menu.parentType = cn.xtype;
286 tree.menu.triggerEl = cn.el;
287 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
291 if (!tree.items || !tree.items.length) {
295 var items = tree.items;
298 //Roo.log(items.length);
300 if (!skip_children) {
301 for(var i =0;i < items.length;i++) {
302 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
324 * @class Roo.bootstrap.Body
325 * @extends Roo.bootstrap.Component
326 * Bootstrap Body class
330 * @param {Object} config The config object
333 Roo.bootstrap.Body = function(config){
334 Roo.bootstrap.Body.superclass.constructor.call(this, config);
335 this.el = Roo.get(document.body);
336 if (this.cls && this.cls.length) {
337 Roo.get(document.body).addClass(this.cls);
341 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
346 onRender : function(ct, position)
348 /* Roo.log("Roo.bootstrap.Body - onRender");
349 if (this.cls && this.cls.length) {
350 Roo.get(document.body).addClass(this.cls);
370 * @class Roo.bootstrap.ButtonGroup
371 * @extends Roo.bootstrap.Component
372 * Bootstrap ButtonGroup class
373 * @cfg {String} size lg | sm | xs (default empty normal)
374 * @cfg {String} align vertical | justified (default none)
375 * @cfg {String} direction up | down (default down)
376 * @cfg {Boolean} toolbar false | true
377 * @cfg {Boolean} btn true | false
382 * @param {Object} config The config object
385 Roo.bootstrap.ButtonGroup = function(config){
386 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
389 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
397 getAutoCreate : function(){
403 cfg.html = this.html || cfg.html;
414 if (['vertical','justified'].indexOf(this.align)!==-1) {
415 cfg.cls = 'btn-group-' + this.align;
417 if (this.align == 'justified') {
418 console.log(this.items);
422 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
423 cfg.cls += ' btn-group-' + this.size;
426 if (this.direction == 'up') {
427 cfg.cls += ' dropup' ;
443 * @class Roo.bootstrap.Button
444 * @extends Roo.bootstrap.Component
445 * Bootstrap Button class
446 * @cfg {String} html The button content
447 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
448 * @cfg {String} size empty | lg | sm | xs
449 * @cfg {String} tag empty | a | input | submit
450 * @cfg {String} href empty or href
451 * @cfg {Boolean} disabled false | true
452 * @cfg {Boolean} isClose false | true
453 * @cfg {String} glyphicon empty | 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
454 * @cfg {String} badge text for badge
455 * @cfg {String} theme default (or empty) | glow
456 * @cfg {Boolean} inverse false | true
457 * @cfg {Boolean} toggle false | true
458 * @cfg {String} ontext text for on toggle state
459 * @cfg {String} offtext text for off toggle state
460 * @cfg {Boolean} defaulton true | false
461 * @cfg {Boolean} preventDefault (true | false) default true
462 * @cfg {Boolean} removeClass true | false remove the standard class..
463 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
466 * Create a new button
467 * @param {Object} config The config object
471 Roo.bootstrap.Button = function(config){
472 Roo.bootstrap.Button.superclass.constructor.call(this, config);
477 * When a butotn is pressed
478 * @param {Roo.EventObject} e
483 * After the button has been toggles
484 * @param {Roo.EventObject} e
485 * @param {boolean} pressed (also available as button.pressed)
491 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
509 preventDefault: true,
518 getAutoCreate : function(){
526 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
527 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
532 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
534 if (this.toggle == true) {
537 cls: 'slider-frame roo-button',
542 'data-off-text':'OFF',
543 cls: 'slider-button',
549 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
550 cfg.cls += ' '+this.weight;
559 cfg["aria-hidden"] = true;
561 cfg.html = "×";
567 if (this.theme==='default') {
568 cfg.cls = 'btn roo-button';
570 //if (this.parentType != 'Navbar') {
571 this.weight = this.weight.length ? this.weight : 'default';
573 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
575 cfg.cls += ' btn-' + this.weight;
577 } else if (this.theme==='glow') {
580 cfg.cls = 'btn-glow roo-button';
582 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
584 cfg.cls += ' ' + this.weight;
590 this.cls += ' inverse';
595 cfg.cls += ' active';
599 cfg.disabled = 'disabled';
603 Roo.log('changing to ul' );
605 this.glyphicon = 'caret';
608 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
610 //gsRoo.log(this.parentType);
611 if (this.parentType === 'Navbar' && !this.parent().bar) {
612 Roo.log('changing to li?');
621 href : this.href || '#'
624 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
625 cfg.cls += ' dropdown';
632 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
634 if (this.glyphicon) {
635 cfg.html = ' ' + cfg.html;
640 cls: 'glyphicon glyphicon-' + this.glyphicon
650 // cfg.cls='btn roo-button';
654 var value = cfg.html;
659 cls: 'glyphicon glyphicon-' + this.glyphicon,
678 cfg.cls += ' dropdown';
679 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
682 if (cfg.tag !== 'a' && this.href !== '') {
683 throw "Tag must be a to set href.";
684 } else if (this.href.length > 0) {
685 cfg.href = this.href;
688 if(this.removeClass){
693 cfg.target = this.target;
698 initEvents: function() {
699 // Roo.log('init events?');
700 // Roo.log(this.el.dom);
703 if (typeof (this.menu) != 'undefined') {
704 this.menu.parentType = this.xtype;
705 this.menu.triggerEl = this.el;
706 this.addxtype(Roo.apply({}, this.menu));
710 if (this.el.hasClass('roo-button')) {
711 this.el.on('click', this.onClick, this);
713 this.el.select('.roo-button').on('click', this.onClick, this);
716 if(this.removeClass){
717 this.el.on('click', this.onClick, this);
720 this.el.enableDisplayMode();
723 onClick : function(e)
729 Roo.log('button on click ');
730 if(this.preventDefault){
733 if (this.pressed === true || this.pressed === false) {
734 this.pressed = !this.pressed;
735 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
736 this.fireEvent('toggle', this, e, this.pressed);
740 this.fireEvent('click', this, e);
744 * Enables this button
748 this.disabled = false;
749 this.el.removeClass('disabled');
753 * Disable this button
757 this.disabled = true;
758 this.el.addClass('disabled');
761 * sets the active state on/off,
762 * @param {Boolean} state (optional) Force a particular state
764 setActive : function(v) {
766 this.el[v ? 'addClass' : 'removeClass']('active');
769 * toggles the current active state
771 toggleActive : function()
773 var active = this.el.hasClass('active');
774 this.setActive(!active);
778 setText : function(str)
780 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
784 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
807 * @class Roo.bootstrap.Column
808 * @extends Roo.bootstrap.Component
809 * Bootstrap Column class
810 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
811 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
812 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
813 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
814 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
815 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
816 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
817 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
820 * @cfg {Boolean} hidden (true|false) hide the element
821 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
822 * @cfg {String} fa (ban|check|...) font awesome icon
823 * @cfg {Number} fasize (1|2|....) font awsome size
825 * @cfg {String} icon (info-sign|check|...) glyphicon name
827 * @cfg {String} html content of column.
830 * Create a new Column
831 * @param {Object} config The config object
834 Roo.bootstrap.Column = function(config){
835 Roo.bootstrap.Column.superclass.constructor.call(this, config);
838 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
856 getAutoCreate : function(){
857 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
865 ['xs','sm','md','lg'].map(function(size){
866 //Roo.log( size + ':' + settings[size]);
868 if (settings[size+'off'] !== false) {
869 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
872 if (settings[size] === false) {
875 Roo.log(settings[size]);
876 if (!settings[size]) { // 0 = hidden
877 cfg.cls += ' hidden-' + size;
880 cfg.cls += ' col-' + size + '-' + settings[size];
885 cfg.cls += ' hidden';
888 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
889 cfg.cls +=' alert alert-' + this.alert;
893 if (this.html.length) {
894 cfg.html = this.html;
898 if (this.fasize > 1) {
899 fasize = ' fa-' + this.fasize + 'x';
901 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
906 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
925 * @class Roo.bootstrap.Container
926 * @extends Roo.bootstrap.Component
927 * Bootstrap Container class
928 * @cfg {Boolean} jumbotron is it a jumbotron element
929 * @cfg {String} html content of element
930 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
931 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
932 * @cfg {String} header content of header (for panel)
933 * @cfg {String} footer content of footer (for panel)
934 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
935 * @cfg {String} tag (header|aside|section) type of HTML tag.
936 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
937 * @cfg {String} fa (ban|check|...) font awesome icon
938 * @cfg {String} icon (info-sign|check|...) glyphicon name
939 * @cfg {Boolean} hidden (true|false) hide the element
943 * Create a new Container
944 * @param {Object} config The config object
947 Roo.bootstrap.Container = function(config){
948 Roo.bootstrap.Container.superclass.constructor.call(this, config);
951 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
965 getChildContainer : function() {
971 if (this.panel.length) {
972 return this.el.select('.panel-body',true).first();
979 getAutoCreate : function(){
982 tag : this.tag || 'div',
986 if (this.jumbotron) {
987 cfg.cls = 'jumbotron';
992 // - this is applied by the parent..
994 // cfg.cls = this.cls + '';
997 if (this.sticky.length) {
999 var bd = Roo.get(document.body);
1000 if (!bd.hasClass('bootstrap-sticky')) {
1001 bd.addClass('bootstrap-sticky');
1002 Roo.select('html',true).setStyle('height', '100%');
1005 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1009 if (this.well.length) {
1010 switch (this.well) {
1013 cfg.cls +=' well well-' +this.well;
1022 cfg.cls += ' hidden';
1026 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1027 cfg.cls +=' alert alert-' + this.alert;
1032 if (this.panel.length) {
1033 cfg.cls += ' panel panel-' + this.panel;
1035 if (this.header.length) {
1038 cls : 'panel-heading',
1041 cls : 'panel-title',
1054 if (this.footer.length) {
1056 cls : 'panel-footer',
1065 body.html = this.html || cfg.html;
1066 // prefix with the icons..
1068 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1071 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1076 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1077 cfg.cls = 'container';
1083 titleEl : function()
1085 if(!this.el || !this.panel.length || !this.header.length){
1089 return this.el.select('.panel-title',true).first();
1092 setTitle : function(v)
1094 var titleEl = this.titleEl();
1100 titleEl.dom.innerHTML = v;
1103 getTitle : function()
1106 var titleEl = this.titleEl();
1112 return titleEl.dom.innerHTML;
1126 * @class Roo.bootstrap.Img
1127 * @extends Roo.bootstrap.Component
1128 * Bootstrap Img class
1129 * @cfg {Boolean} imgResponsive false | true
1130 * @cfg {String} border rounded | circle | thumbnail
1131 * @cfg {String} src image source
1132 * @cfg {String} alt image alternative text
1133 * @cfg {String} href a tag href
1134 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1137 * Create a new Input
1138 * @param {Object} config The config object
1141 Roo.bootstrap.Img = function(config){
1142 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1148 * The img click event for the img.
1149 * @param {Roo.EventObject} e
1155 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1157 imgResponsive: true,
1163 getAutoCreate : function(){
1167 cls: (this.imgResponsive) ? 'img-responsive' : '',
1171 cfg.html = this.html || cfg.html;
1173 cfg.src = this.src || cfg.src;
1175 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1176 cfg.cls += ' img-' + this.border;
1193 a.target = this.target;
1199 return (this.href) ? a : cfg;
1202 initEvents: function() {
1205 this.el.on('click', this.onClick, this);
1209 onClick : function(e)
1211 Roo.log('img onclick');
1212 this.fireEvent('click', this, e);
1226 * @class Roo.bootstrap.Link
1227 * @extends Roo.bootstrap.Component
1228 * Bootstrap Link Class
1229 * @cfg {String} alt image alternative text
1230 * @cfg {String} href a tag href
1231 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1232 * @cfg {String} html the content of the link.
1233 * @cfg {String} anchor name for the anchor link
1235 * @cfg {Boolean} preventDefault (true | false) default false
1239 * Create a new Input
1240 * @param {Object} config The config object
1243 Roo.bootstrap.Link = function(config){
1244 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1250 * The img click event for the img.
1251 * @param {Roo.EventObject} e
1257 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1261 preventDefault: false,
1265 getAutoCreate : function()
1271 // anchor's do not require html/href...
1272 if (this.anchor === false) {
1273 cfg.html = this.html || 'html-missing';
1274 cfg.href = this.href || '#';
1276 cfg.name = this.anchor;
1277 if (this.html !== false) {
1278 cfg.html = this.html;
1280 if (this.href !== false) {
1281 cfg.href = this.href;
1285 if(this.alt !== false){
1290 if(this.target !== false) {
1291 cfg.target = this.target;
1297 initEvents: function() {
1299 if(!this.href || this.preventDefault){
1300 this.el.on('click', this.onClick, this);
1304 onClick : function(e)
1306 if(this.preventDefault){
1309 //Roo.log('img onclick');
1310 this.fireEvent('click', this, e);
1323 * @class Roo.bootstrap.Header
1324 * @extends Roo.bootstrap.Component
1325 * Bootstrap Header class
1326 * @cfg {String} html content of header
1327 * @cfg {Number} level (1|2|3|4|5|6) default 1
1330 * Create a new Header
1331 * @param {Object} config The config object
1335 Roo.bootstrap.Header = function(config){
1336 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1339 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1347 getAutoCreate : function(){
1350 tag: 'h' + (1 *this.level),
1351 html: this.html || 'fill in html'
1363 * Ext JS Library 1.1.1
1364 * Copyright(c) 2006-2007, Ext JS, LLC.
1366 * Originally Released Under LGPL - original licence link has changed is not relivant.
1369 * <script type="text/javascript">
1373 * @class Roo.bootstrap.MenuMgr
1374 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1377 Roo.bootstrap.MenuMgr = function(){
1378 var menus, active, groups = {}, attached = false, lastShow = new Date();
1380 // private - called when first menu is created
1383 active = new Roo.util.MixedCollection();
1384 Roo.get(document).addKeyListener(27, function(){
1385 if(active.length > 0){
1393 if(active && active.length > 0){
1394 var c = active.clone();
1404 if(active.length < 1){
1405 Roo.get(document).un("mouseup", onMouseDown);
1413 var last = active.last();
1414 lastShow = new Date();
1417 Roo.get(document).on("mouseup", onMouseDown);
1422 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1423 m.parentMenu.activeChild = m;
1424 }else if(last && last.isVisible()){
1425 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1430 function onBeforeHide(m){
1432 m.activeChild.hide();
1434 if(m.autoHideTimer){
1435 clearTimeout(m.autoHideTimer);
1436 delete m.autoHideTimer;
1441 function onBeforeShow(m){
1442 var pm = m.parentMenu;
1443 if(!pm && !m.allowOtherMenus){
1445 }else if(pm && pm.activeChild && active != m){
1446 pm.activeChild.hide();
1451 function onMouseDown(e){
1452 Roo.log("on MouseDown");
1453 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1461 function onBeforeCheck(mi, state){
1463 var g = groups[mi.group];
1464 for(var i = 0, l = g.length; i < l; i++){
1466 g[i].setChecked(false);
1475 * Hides all menus that are currently visible
1477 hideAll : function(){
1482 register : function(menu){
1486 menus[menu.id] = menu;
1487 menu.on("beforehide", onBeforeHide);
1488 menu.on("hide", onHide);
1489 menu.on("beforeshow", onBeforeShow);
1490 menu.on("show", onShow);
1492 if(g && menu.events["checkchange"]){
1496 groups[g].push(menu);
1497 menu.on("checkchange", onCheck);
1502 * Returns a {@link Roo.menu.Menu} object
1503 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1504 * be used to generate and return a new Menu instance.
1506 get : function(menu){
1507 if(typeof menu == "string"){ // menu id
1509 }else if(menu.events){ // menu instance
1512 /*else if(typeof menu.length == 'number'){ // array of menu items?
1513 return new Roo.bootstrap.Menu({items:menu});
1514 }else{ // otherwise, must be a config
1515 return new Roo.bootstrap.Menu(menu);
1522 unregister : function(menu){
1523 delete menus[menu.id];
1524 menu.un("beforehide", onBeforeHide);
1525 menu.un("hide", onHide);
1526 menu.un("beforeshow", onBeforeShow);
1527 menu.un("show", onShow);
1529 if(g && menu.events["checkchange"]){
1530 groups[g].remove(menu);
1531 menu.un("checkchange", onCheck);
1536 registerCheckable : function(menuItem){
1537 var g = menuItem.group;
1542 groups[g].push(menuItem);
1543 menuItem.on("beforecheckchange", onBeforeCheck);
1548 unregisterCheckable : function(menuItem){
1549 var g = menuItem.group;
1551 groups[g].remove(menuItem);
1552 menuItem.un("beforecheckchange", onBeforeCheck);
1564 * @class Roo.bootstrap.Menu
1565 * @extends Roo.bootstrap.Component
1566 * Bootstrap Menu class - container for MenuItems
1567 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1571 * @param {Object} config The config object
1575 Roo.bootstrap.Menu = function(config){
1576 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1577 if (this.registerMenu) {
1578 Roo.bootstrap.MenuMgr.register(this);
1583 * Fires before this menu is displayed
1584 * @param {Roo.menu.Menu} this
1589 * Fires before this menu is hidden
1590 * @param {Roo.menu.Menu} this
1595 * Fires after this menu is displayed
1596 * @param {Roo.menu.Menu} this
1601 * Fires after this menu is hidden
1602 * @param {Roo.menu.Menu} this
1607 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1608 * @param {Roo.menu.Menu} this
1609 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1610 * @param {Roo.EventObject} e
1615 * Fires when the mouse is hovering over this menu
1616 * @param {Roo.menu.Menu} this
1617 * @param {Roo.EventObject} e
1618 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1623 * Fires when the mouse exits this menu
1624 * @param {Roo.menu.Menu} this
1625 * @param {Roo.EventObject} e
1626 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1631 * Fires when a menu item contained in this menu is clicked
1632 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1633 * @param {Roo.EventObject} e
1637 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1640 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1644 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1647 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1649 registerMenu : true,
1651 menuItems :false, // stores the menu items..
1657 getChildContainer : function() {
1661 getAutoCreate : function(){
1663 //if (['right'].indexOf(this.align)!==-1) {
1664 // cfg.cn[1].cls += ' pull-right'
1670 cls : 'dropdown-menu' ,
1671 style : 'z-index:1000'
1675 if (this.type === 'submenu') {
1676 cfg.cls = 'submenu active';
1678 if (this.type === 'treeview') {
1679 cfg.cls = 'treeview-menu';
1684 initEvents : function() {
1686 // Roo.log("ADD event");
1687 // Roo.log(this.triggerEl.dom);
1688 this.triggerEl.on('click', this.onTriggerPress, this);
1689 this.triggerEl.addClass('dropdown-toggle');
1690 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1692 this.el.on("mouseover", this.onMouseOver, this);
1693 this.el.on("mouseout", this.onMouseOut, this);
1697 findTargetItem : function(e){
1698 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1702 //Roo.log(t); Roo.log(t.id);
1704 //Roo.log(this.menuitems);
1705 return this.menuitems.get(t.id);
1707 //return this.items.get(t.menuItemId);
1712 onClick : function(e){
1713 Roo.log("menu.onClick");
1714 var t = this.findTargetItem(e);
1715 if(!t || t.isContainer){
1720 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1721 if(t == this.activeItem && t.shouldDeactivate(e)){
1722 this.activeItem.deactivate();
1723 delete this.activeItem;
1727 this.setActiveItem(t, true);
1735 Roo.log('pass click event');
1739 this.fireEvent("click", this, t, e);
1743 onMouseOver : function(e){
1744 var t = this.findTargetItem(e);
1747 // if(t.canActivate && !t.disabled){
1748 // this.setActiveItem(t, true);
1752 this.fireEvent("mouseover", this, e, t);
1754 isVisible : function(){
1755 return !this.hidden;
1757 onMouseOut : function(e){
1758 var t = this.findTargetItem(e);
1761 // if(t == this.activeItem && t.shouldDeactivate(e)){
1762 // this.activeItem.deactivate();
1763 // delete this.activeItem;
1766 this.fireEvent("mouseout", this, e, t);
1771 * Displays this menu relative to another element
1772 * @param {String/HTMLElement/Roo.Element} element The element to align to
1773 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1774 * the element (defaults to this.defaultAlign)
1775 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1777 show : function(el, pos, parentMenu){
1778 this.parentMenu = parentMenu;
1782 this.fireEvent("beforeshow", this);
1783 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1786 * Displays this menu at a specific xy position
1787 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1788 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1790 showAt : function(xy, parentMenu, /* private: */_e){
1791 this.parentMenu = parentMenu;
1796 this.fireEvent("beforeshow", this);
1798 //xy = this.el.adjustForConstraints(xy);
1800 //this.el.setXY(xy);
1802 this.hideMenuItems();
1803 this.hidden = false;
1804 this.triggerEl.addClass('open');
1806 this.fireEvent("show", this);
1812 this.doFocus.defer(50, this);
1816 doFocus : function(){
1818 this.focusEl.focus();
1823 * Hides this menu and optionally all parent menus
1824 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1826 hide : function(deep){
1828 this.hideMenuItems();
1829 if(this.el && this.isVisible()){
1830 this.fireEvent("beforehide", this);
1831 if(this.activeItem){
1832 this.activeItem.deactivate();
1833 this.activeItem = null;
1835 this.triggerEl.removeClass('open');;
1837 this.fireEvent("hide", this);
1839 if(deep === true && this.parentMenu){
1840 this.parentMenu.hide(true);
1844 onTriggerPress : function(e)
1847 Roo.log('trigger press');
1848 //Roo.log(e.getTarget());
1849 // Roo.log(this.triggerEl.dom);
1850 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1853 if (this.isVisible()) {
1857 this.show(this.triggerEl, false, false);
1866 hideMenuItems : function()
1868 //$(backdrop).remove()
1869 Roo.select('.open',true).each(function(aa) {
1871 aa.removeClass('open');
1872 //var parent = getParent($(this))
1873 //var relatedTarget = { relatedTarget: this }
1875 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1876 //if (e.isDefaultPrevented()) return
1877 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1880 addxtypeChild : function (tree, cntr) {
1881 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1883 this.menuitems.add(comp);
1904 * @class Roo.bootstrap.MenuItem
1905 * @extends Roo.bootstrap.Component
1906 * Bootstrap MenuItem class
1907 * @cfg {String} html the menu label
1908 * @cfg {String} href the link
1909 * @cfg {Boolean} preventDefault (true | false) default true
1910 * @cfg {Boolean} isContainer (true | false) default false
1914 * Create a new MenuItem
1915 * @param {Object} config The config object
1919 Roo.bootstrap.MenuItem = function(config){
1920 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1925 * The raw click event for the entire grid.
1926 * @param {Roo.EventObject} e
1932 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1936 preventDefault: true,
1937 isContainer : false,
1939 getAutoCreate : function(){
1941 if(this.isContainer){
1944 cls: 'dropdown-menu-item'
1950 cls: 'dropdown-menu-item',
1959 if (this.parent().type == 'treeview') {
1960 cfg.cls = 'treeview-menu';
1963 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1964 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1968 initEvents: function() {
1970 //this.el.select('a').on('click', this.onClick, this);
1973 onClick : function(e)
1975 Roo.log('item on click ');
1976 //if(this.preventDefault){
1977 // e.preventDefault();
1979 //this.parent().hideMenuItems();
1981 this.fireEvent('click', this, e);
2000 * @class Roo.bootstrap.MenuSeparator
2001 * @extends Roo.bootstrap.Component
2002 * Bootstrap MenuSeparator class
2005 * Create a new MenuItem
2006 * @param {Object} config The config object
2010 Roo.bootstrap.MenuSeparator = function(config){
2011 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2014 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2016 getAutoCreate : function(){
2031 <div class="modal fade">
2032 <div class="modal-dialog">
2033 <div class="modal-content">
2034 <div class="modal-header">
2035 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
2036 <h4 class="modal-title">Modal title</h4>
2038 <div class="modal-body">
2039 <p>One fine body…</p>
2041 <div class="modal-footer">
2042 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2043 <button type="button" class="btn btn-primary">Save changes</button>
2045 </div><!-- /.modal-content -->
2046 </div><!-- /.modal-dialog -->
2047 </div><!-- /.modal -->
2057 * @class Roo.bootstrap.Modal
2058 * @extends Roo.bootstrap.Component
2059 * Bootstrap Modal class
2060 * @cfg {String} title Title of dialog
2061 * @cfg {Boolean} specificTitle (true|false) default false
2062 * @cfg {Array} buttons Array of buttons or standard button set..
2063 * @cfg {String} buttonPosition (left|right|center) default right
2064 * @cfg {Boolean} animate (true | false) default true
2067 * Create a new Modal Dialog
2068 * @param {Object} config The config object
2071 Roo.bootstrap.Modal = function(config){
2072 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2077 * The raw btnclick event for the button
2078 * @param {Roo.EventObject} e
2082 this.buttons = this.buttons || [];
2085 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2087 title : 'test dialog',
2094 specificTitle: false,
2096 buttonPosition: 'right',
2100 onRender : function(ct, position)
2102 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2105 var cfg = Roo.apply({}, this.getAutoCreate());
2108 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2110 //if (!cfg.name.length) {
2114 cfg.cls += ' ' + this.cls;
2117 cfg.style = this.style;
2119 this.el = Roo.get(document.body).createChild(cfg, position);
2121 //var type = this.el.dom.type;
2123 if(this.tabIndex !== undefined){
2124 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2129 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2130 this.maskEl.enableDisplayMode("block");
2132 //this.el.addClass("x-dlg-modal");
2134 if (this.buttons.length) {
2135 Roo.each(this.buttons, function(bb) {
2136 b = Roo.apply({}, bb);
2137 b.xns = b.xns || Roo.bootstrap;
2138 b.xtype = b.xtype || 'Button';
2139 if (typeof(b.listeners) == 'undefined') {
2140 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2143 var btn = Roo.factory(b);
2145 btn.onRender(this.el.select('.modal-footer div').first());
2149 // render the children.
2152 if(typeof(this.items) != 'undefined'){
2153 var items = this.items;
2156 for(var i =0;i < items.length;i++) {
2157 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2161 this.items = nitems;
2163 this.body = this.el.select('.modal-body',true).first();
2164 this.close = this.el.select('.modal-header .close', true).first();
2165 this.footer = this.el.select('.modal-footer',true).first();
2167 //this.el.addClass([this.fieldClass, this.cls]);
2170 getAutoCreate : function(){
2175 html : this.html || ''
2180 cls : 'modal-title',
2184 if(this.specificTitle){
2190 style : 'display: none',
2193 cls: "modal-dialog",
2196 cls : "modal-content",
2199 cls : 'modal-header',
2211 cls : 'modal-footer',
2215 cls: 'btn-' + this.buttonPosition
2232 modal.cls += ' fade';
2238 getChildContainer : function() {
2240 return this.el.select('.modal-body',true).first();
2243 getButtonContainer : function() {
2244 return this.el.select('.modal-footer div',true).first();
2247 initEvents : function()
2249 this.el.select('.modal-header .close').on('click', this.hide, this);
2251 // this.addxtype(this);
2255 if (!this.rendered) {
2259 this.el.setStyle('display', 'block');
2263 (function(){ _this.el.addClass('in'); }).defer(50);
2265 this.el.addClass('in');
2268 Roo.get(document.body).addClass("x-body-masked");
2269 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2271 this.el.setStyle('zIndex', '10001');
2272 this.fireEvent('show', this);
2279 Roo.get(document.body).removeClass("x-body-masked");
2280 this.el.removeClass('in');
2284 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2286 this.el.setStyle('display', 'none');
2289 this.fireEvent('hide', this);
2292 addButton : function(str, cb)
2296 var b = Roo.apply({}, { html : str } );
2297 b.xns = b.xns || Roo.bootstrap;
2298 b.xtype = b.xtype || 'Button';
2299 if (typeof(b.listeners) == 'undefined') {
2300 b.listeners = { click : cb.createDelegate(this) };
2303 var btn = Roo.factory(b);
2305 btn.onRender(this.el.select('.modal-footer div').first());
2311 setDefaultButton : function(btn)
2313 //this.el.select('.modal-footer').()
2315 resizeTo: function(w,h)
2319 setContentSize : function(w, h)
2323 onButtonClick: function(btn,e)
2326 this.fireEvent('btnclick', btn.name, e);
2328 setTitle: function(str) {
2329 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2335 Roo.apply(Roo.bootstrap.Modal, {
2337 * Button config that displays a single OK button
2346 * Button config that displays Yes and No buttons
2362 * Button config that displays OK and Cancel buttons
2377 * Button config that displays Yes, No and Cancel buttons
2399 * messagebox - can be used as a replace
2403 * @class Roo.MessageBox
2404 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2408 Roo.Msg.alert('Status', 'Changes saved successfully.');
2410 // Prompt for user data:
2411 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2413 // process text value...
2417 // Show a dialog using config options:
2419 title:'Save Changes?',
2420 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2421 buttons: Roo.Msg.YESNOCANCEL,
2428 Roo.bootstrap.MessageBox = function(){
2429 var dlg, opt, mask, waitTimer;
2430 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2431 var buttons, activeTextEl, bwidth;
2435 var handleButton = function(button){
2437 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2441 var handleHide = function(){
2443 dlg.el.removeClass(opt.cls);
2446 // Roo.TaskMgr.stop(waitTimer);
2447 // waitTimer = null;
2452 var updateButtons = function(b){
2455 buttons["ok"].hide();
2456 buttons["cancel"].hide();
2457 buttons["yes"].hide();
2458 buttons["no"].hide();
2459 //dlg.footer.dom.style.display = 'none';
2462 dlg.footer.dom.style.display = '';
2463 for(var k in buttons){
2464 if(typeof buttons[k] != "function"){
2467 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2468 width += buttons[k].el.getWidth()+15;
2478 var handleEsc = function(d, k, e){
2479 if(opt && opt.closable !== false){
2489 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2490 * @return {Roo.BasicDialog} The BasicDialog element
2492 getDialog : function(){
2494 dlg = new Roo.bootstrap.Modal( {
2497 //constraintoviewport:false,
2499 //collapsible : false,
2504 //buttonAlign:"center",
2505 closeClick : function(){
2506 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2509 handleButton("cancel");
2514 dlg.on("hide", handleHide);
2516 //dlg.addKeyListener(27, handleEsc);
2518 this.buttons = buttons;
2519 var bt = this.buttonText;
2520 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2521 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2522 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2523 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2525 bodyEl = dlg.body.createChild({
2527 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2528 '<textarea class="roo-mb-textarea"></textarea>' +
2529 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2531 msgEl = bodyEl.dom.firstChild;
2532 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2533 textboxEl.enableDisplayMode();
2534 textboxEl.addKeyListener([10,13], function(){
2535 if(dlg.isVisible() && opt && opt.buttons){
2538 }else if(opt.buttons.yes){
2539 handleButton("yes");
2543 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2544 textareaEl.enableDisplayMode();
2545 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2546 progressEl.enableDisplayMode();
2547 var pf = progressEl.dom.firstChild;
2549 pp = Roo.get(pf.firstChild);
2550 pp.setHeight(pf.offsetHeight);
2558 * Updates the message box body text
2559 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2560 * the XHTML-compliant non-breaking space character '&#160;')
2561 * @return {Roo.MessageBox} This message box
2563 updateText : function(text){
2564 if(!dlg.isVisible() && !opt.width){
2565 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2567 msgEl.innerHTML = text || ' ';
2569 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2570 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2572 Math.min(opt.width || cw , this.maxWidth),
2573 Math.max(opt.minWidth || this.minWidth, bwidth)
2576 activeTextEl.setWidth(w);
2578 if(dlg.isVisible()){
2579 dlg.fixedcenter = false;
2581 // to big, make it scroll. = But as usual stupid IE does not support
2584 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2585 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2586 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2588 bodyEl.dom.style.height = '';
2589 bodyEl.dom.style.overflowY = '';
2592 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2594 bodyEl.dom.style.overflowX = '';
2597 dlg.setContentSize(w, bodyEl.getHeight());
2598 if(dlg.isVisible()){
2599 dlg.fixedcenter = true;
2605 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2606 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2607 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2608 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2609 * @return {Roo.MessageBox} This message box
2611 updateProgress : function(value, text){
2613 this.updateText(text);
2615 if (pp) { // weird bug on my firefox - for some reason this is not defined
2616 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2622 * Returns true if the message box is currently displayed
2623 * @return {Boolean} True if the message box is visible, else false
2625 isVisible : function(){
2626 return dlg && dlg.isVisible();
2630 * Hides the message box if it is displayed
2633 if(this.isVisible()){
2639 * Displays a new message box, or reinitializes an existing message box, based on the config options
2640 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2641 * The following config object properties are supported:
2643 Property Type Description
2644 ---------- --------------- ------------------------------------------------------------------------------------
2645 animEl String/Element An id or Element from which the message box should animate as it opens and
2646 closes (defaults to undefined)
2647 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2648 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2649 closable Boolean False to hide the top-right close button (defaults to true). Note that
2650 progress and wait dialogs will ignore this property and always hide the
2651 close button as they can only be closed programmatically.
2652 cls String A custom CSS class to apply to the message box element
2653 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2654 displayed (defaults to 75)
2655 fn Function A callback function to execute after closing the dialog. The arguments to the
2656 function will be btn (the name of the button that was clicked, if applicable,
2657 e.g. "ok"), and text (the value of the active text field, if applicable).
2658 Progress and wait dialogs will ignore this option since they do not respond to
2659 user actions and can only be closed programmatically, so any required function
2660 should be called by the same code after it closes the dialog.
2661 icon String A CSS class that provides a background image to be used as an icon for
2662 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2663 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2664 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2665 modal Boolean False to allow user interaction with the page while the message box is
2666 displayed (defaults to true)
2667 msg String A string that will replace the existing message box body text (defaults
2668 to the XHTML-compliant non-breaking space character ' ')
2669 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2670 progress Boolean True to display a progress bar (defaults to false)
2671 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2672 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2673 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2674 title String The title text
2675 value String The string value to set into the active textbox element if displayed
2676 wait Boolean True to display a progress bar (defaults to false)
2677 width Number The width of the dialog in pixels
2684 msg: 'Please enter your address:',
2686 buttons: Roo.MessageBox.OKCANCEL,
2689 animEl: 'addAddressBtn'
2692 * @param {Object} config Configuration options
2693 * @return {Roo.MessageBox} This message box
2695 show : function(options)
2698 // this causes nightmares if you show one dialog after another
2699 // especially on callbacks..
2701 if(this.isVisible()){
2704 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2705 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2706 Roo.log("New Dialog Message:" + options.msg )
2707 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2708 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2711 var d = this.getDialog();
2713 d.setTitle(opt.title || " ");
2714 d.close.setDisplayed(opt.closable !== false);
2715 activeTextEl = textboxEl;
2716 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2721 textareaEl.setHeight(typeof opt.multiline == "number" ?
2722 opt.multiline : this.defaultTextHeight);
2723 activeTextEl = textareaEl;
2732 progressEl.setDisplayed(opt.progress === true);
2733 this.updateProgress(0);
2734 activeTextEl.dom.value = opt.value || "";
2736 dlg.setDefaultButton(activeTextEl);
2738 var bs = opt.buttons;
2742 }else if(bs && bs.yes){
2743 db = buttons["yes"];
2745 dlg.setDefaultButton(db);
2747 bwidth = updateButtons(opt.buttons);
2748 this.updateText(opt.msg);
2750 d.el.addClass(opt.cls);
2752 d.proxyDrag = opt.proxyDrag === true;
2753 d.modal = opt.modal !== false;
2754 d.mask = opt.modal !== false ? mask : false;
2756 // force it to the end of the z-index stack so it gets a cursor in FF
2757 document.body.appendChild(dlg.el.dom);
2758 d.animateTarget = null;
2759 d.show(options.animEl);
2765 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2766 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2767 * and closing the message box when the process is complete.
2768 * @param {String} title The title bar text
2769 * @param {String} msg The message box body text
2770 * @return {Roo.MessageBox} This message box
2772 progress : function(title, msg){
2779 minWidth: this.minProgressWidth,
2786 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2787 * If a callback function is passed it will be called after the user clicks the button, and the
2788 * id of the button that was clicked will be passed as the only parameter to the callback
2789 * (could also be the top-right close button).
2790 * @param {String} title The title bar text
2791 * @param {String} msg The message box body text
2792 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2793 * @param {Object} scope (optional) The scope of the callback function
2794 * @return {Roo.MessageBox} This message box
2796 alert : function(title, msg, fn, scope){
2809 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2810 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2811 * You are responsible for closing the message box when the process is complete.
2812 * @param {String} msg The message box body text
2813 * @param {String} title (optional) The title bar text
2814 * @return {Roo.MessageBox} This message box
2816 wait : function(msg, title){
2827 waitTimer = Roo.TaskMgr.start({
2829 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2837 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2838 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2839 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2840 * @param {String} title The title bar text
2841 * @param {String} msg The message box body text
2842 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2843 * @param {Object} scope (optional) The scope of the callback function
2844 * @return {Roo.MessageBox} This message box
2846 confirm : function(title, msg, fn, scope){
2850 buttons: this.YESNO,
2859 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2860 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2861 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2862 * (could also be the top-right close button) and the text that was entered will be passed as the two
2863 * parameters to the callback.
2864 * @param {String} title The title bar text
2865 * @param {String} msg The message box body text
2866 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2867 * @param {Object} scope (optional) The scope of the callback function
2868 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2869 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2870 * @return {Roo.MessageBox} This message box
2872 prompt : function(title, msg, fn, scope, multiline){
2876 buttons: this.OKCANCEL,
2881 multiline: multiline,
2888 * Button config that displays a single OK button
2893 * Button config that displays Yes and No buttons
2896 YESNO : {yes:true, no:true},
2898 * Button config that displays OK and Cancel buttons
2901 OKCANCEL : {ok:true, cancel:true},
2903 * Button config that displays Yes, No and Cancel buttons
2906 YESNOCANCEL : {yes:true, no:true, cancel:true},
2909 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2912 defaultTextHeight : 75,
2914 * The maximum width in pixels of the message box (defaults to 600)
2919 * The minimum width in pixels of the message box (defaults to 100)
2924 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2925 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2928 minProgressWidth : 250,
2930 * An object containing the default button text strings that can be overriden for localized language support.
2931 * Supported properties are: ok, cancel, yes and no.
2932 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2945 * Shorthand for {@link Roo.MessageBox}
2947 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2948 Roo.Msg = Roo.Msg || Roo.MessageBox;
2957 * @class Roo.bootstrap.Navbar
2958 * @extends Roo.bootstrap.Component
2959 * Bootstrap Navbar class
2962 * Create a new Navbar
2963 * @param {Object} config The config object
2967 Roo.bootstrap.Navbar = function(config){
2968 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2972 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2981 getAutoCreate : function(){
2984 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2988 initEvents :function ()
2990 //Roo.log(this.el.select('.navbar-toggle',true));
2991 this.el.select('.navbar-toggle',true).on('click', function() {
2992 // Roo.log('click');
2993 this.el.select('.navbar-collapse',true).toggleClass('in');
3001 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3003 var size = this.el.getSize();
3004 this.maskEl.setSize(size.width, size.height);
3005 this.maskEl.enableDisplayMode("block");
3014 getChildContainer : function()
3016 if (this.el.select('.collapse').getCount()) {
3017 return this.el.select('.collapse',true).first();
3050 * @class Roo.bootstrap.NavSimplebar
3051 * @extends Roo.bootstrap.Navbar
3052 * Bootstrap Sidebar class
3054 * @cfg {Boolean} inverse is inverted color
3056 * @cfg {String} type (nav | pills | tabs)
3057 * @cfg {Boolean} arrangement stacked | justified
3058 * @cfg {String} align (left | right) alignment
3060 * @cfg {Boolean} main (true|false) main nav bar? default false
3061 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3063 * @cfg {String} tag (header|footer|nav|div) default is nav
3069 * Create a new Sidebar
3070 * @param {Object} config The config object
3074 Roo.bootstrap.NavSimplebar = function(config){
3075 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3078 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3094 getAutoCreate : function(){
3098 tag : this.tag || 'div',
3111 this.type = this.type || 'nav';
3112 if (['tabs','pills'].indexOf(this.type)!==-1) {
3113 cfg.cn[0].cls += ' nav-' + this.type
3117 if (this.type!=='nav') {
3118 Roo.log('nav type must be nav/tabs/pills')
3120 cfg.cn[0].cls += ' navbar-nav'
3126 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3127 cfg.cn[0].cls += ' nav-' + this.arrangement;
3131 if (this.align === 'right') {
3132 cfg.cn[0].cls += ' navbar-right';
3136 cfg.cls += ' navbar-inverse';
3163 * @class Roo.bootstrap.NavHeaderbar
3164 * @extends Roo.bootstrap.NavSimplebar
3165 * Bootstrap Sidebar class
3167 * @cfg {String} brand what is brand
3168 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3169 * @cfg {String} brand_href href of the brand
3170 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3171 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3174 * Create a new Sidebar
3175 * @param {Object} config The config object
3179 Roo.bootstrap.NavHeaderbar = function(config){
3180 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3183 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3191 getAutoCreate : function(){
3194 tag: this.nav || 'nav',
3203 cls: 'navbar-header',
3208 cls: 'navbar-toggle',
3209 'data-toggle': 'collapse',
3214 html: 'Toggle navigation'
3236 cls: 'collapse navbar-collapse',
3240 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3242 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3243 cfg.cls += ' navbar-' + this.position;
3245 // tag can override this..
3247 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3250 if (this.brand !== '') {
3253 href: this.brand_href ? this.brand_href : '#',
3254 cls: 'navbar-brand',
3262 cfg.cls += ' main-nav';
3270 initEvents : function()
3272 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3274 if (this.autohide) {
3279 Roo.get(document).on('scroll',function(e) {
3280 var ns = Roo.get(document).getScroll().top;
3281 var os = prevScroll;
3285 ft.removeClass('slideDown');
3286 ft.addClass('slideUp');
3289 ft.removeClass('slideUp');
3290 ft.addClass('slideDown');
3314 * @class Roo.bootstrap.NavSidebar
3315 * @extends Roo.bootstrap.Navbar
3316 * Bootstrap Sidebar class
3319 * Create a new Sidebar
3320 * @param {Object} config The config object
3324 Roo.bootstrap.NavSidebar = function(config){
3325 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3328 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3330 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3332 getAutoCreate : function(){
3337 cls: 'sidebar sidebar-nav'
3359 * @class Roo.bootstrap.NavGroup
3360 * @extends Roo.bootstrap.Component
3361 * Bootstrap NavGroup class
3362 * @cfg {String} align left | right
3363 * @cfg {Boolean} inverse false | true
3364 * @cfg {String} type (nav|pills|tab) default nav
3365 * @cfg {String} navId - reference Id for navbar.
3369 * Create a new nav group
3370 * @param {Object} config The config object
3373 Roo.bootstrap.NavGroup = function(config){
3374 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3377 Roo.bootstrap.NavGroup.register(this);
3381 * Fires when the active item changes
3382 * @param {Roo.bootstrap.NavGroup} this
3383 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3384 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3391 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3402 getAutoCreate : function()
3404 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3411 if (['tabs','pills'].indexOf(this.type)!==-1) {
3412 cfg.cls += ' nav-' + this.type
3414 if (this.type!=='nav') {
3415 Roo.log('nav type must be nav/tabs/pills')
3417 cfg.cls += ' navbar-nav'
3420 if (this.parent().sidebar) {
3423 cls: 'dashboard-menu sidebar-menu'
3429 if (this.form === true) {
3435 if (this.align === 'right') {
3436 cfg.cls += ' navbar-right';
3438 cfg.cls += ' navbar-left';
3442 if (this.align === 'right') {
3443 cfg.cls += ' navbar-right';
3447 cfg.cls += ' navbar-inverse';
3455 * sets the active Navigation item
3456 * @param {Roo.bootstrap.NavItem} the new current navitem
3458 setActiveItem : function(item)
3461 Roo.each(this.navItems, function(v){
3466 v.setActive(false, true);
3473 item.setActive(true, true);
3474 this.fireEvent('changed', this, item, prev);
3479 * gets the active Navigation item
3480 * @return {Roo.bootstrap.NavItem} the current navitem
3482 getActive : function()
3486 Roo.each(this.navItems, function(v){
3497 indexOfNav : function()
3501 Roo.each(this.navItems, function(v,i){
3512 * adds a Navigation item
3513 * @param {Roo.bootstrap.NavItem} the navitem to add
3515 addItem : function(cfg)
3517 var cn = new Roo.bootstrap.NavItem(cfg);
3519 cn.parentId = this.id;
3520 cn.onRender(this.el, null);
3524 * register a Navigation item
3525 * @param {Roo.bootstrap.NavItem} the navitem to add
3527 register : function(item)
3529 this.navItems.push( item);
3530 item.navId = this.navId;
3535 * clear all the Navigation item
3538 clearAll : function()
3541 this.el.dom.innerHTML = '';
3544 getNavItem: function(tabId)
3547 Roo.each(this.navItems, function(e) {
3548 if (e.tabId == tabId) {
3558 setActiveNext : function()
3560 var i = this.indexOfNav(this.getActive());
3561 if (i > this.navItems.length) {
3564 this.setActiveItem(this.navItems[i+1]);
3566 setActivePrev : function()
3568 var i = this.indexOfNav(this.getActive());
3572 this.setActiveItem(this.navItems[i-1]);
3574 clearWasActive : function(except) {
3575 Roo.each(this.navItems, function(e) {
3576 if (e.tabId != except.tabId && e.was_active) {
3577 e.was_active = false;
3584 getWasActive : function ()
3587 Roo.each(this.navItems, function(e) {
3602 Roo.apply(Roo.bootstrap.NavGroup, {
3606 * register a Navigation Group
3607 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3609 register : function(navgrp)
3611 this.groups[navgrp.navId] = navgrp;
3615 * fetch a Navigation Group based on the navigation ID
3616 * @param {string} the navgroup to add
3617 * @returns {Roo.bootstrap.NavGroup} the navgroup
3619 get: function(navId) {
3620 if (typeof(this.groups[navId]) == 'undefined') {
3622 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3624 return this.groups[navId] ;
3639 * @class Roo.bootstrap.NavItem
3640 * @extends Roo.bootstrap.Component
3641 * Bootstrap Navbar.NavItem class
3642 * @cfg {String} href link to
3643 * @cfg {String} html content of button
3644 * @cfg {String} badge text inside badge
3645 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3646 * @cfg {String} glyphicon name of glyphicon
3647 * @cfg {String} icon name of font awesome icon
3648 * @cfg {Boolean} active Is item active
3649 * @cfg {Boolean} disabled Is item disabled
3651 * @cfg {Boolean} preventDefault (true | false) default false
3652 * @cfg {String} tabId the tab that this item activates.
3653 * @cfg {String} tagtype (a|span) render as a href or span?
3656 * Create a new Navbar Item
3657 * @param {Object} config The config object
3659 Roo.bootstrap.NavItem = function(config){
3660 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3665 * The raw click event for the entire grid.
3666 * @param {Roo.EventObject} e
3671 * Fires when the active item active state changes
3672 * @param {Roo.bootstrap.NavItem} this
3673 * @param {boolean} state the new state
3681 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3689 preventDefault : false,
3696 getAutoCreate : function(){
3704 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3706 if (this.disabled) {
3707 cfg.cls += ' disabled';
3710 if (this.href || this.html || this.glyphicon || this.icon) {
3714 href : this.href || "#",
3715 html: this.html || ''
3720 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3723 if(this.glyphicon) {
3724 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3729 cfg.cn[0].html += " <span class='caret'></span>";
3733 if (this.badge !== '') {
3735 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3743 initEvents: function()
3745 if (typeof (this.menu) != 'undefined') {
3746 this.menu.parentType = this.xtype;
3747 this.menu.triggerEl = this.el;
3748 this.addxtype(Roo.apply({}, this.menu));
3751 this.el.select('a',true).on('click', this.onClick, this);
3753 if(this.tagtype == 'span'){
3754 this.el.select('span',true).on('click', this.onClick, this);
3757 // at this point parent should be available..
3758 this.parent().register(this);
3761 onClick : function(e)
3764 if(this.preventDefault){
3767 if (this.disabled) {
3771 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3772 if (tg && tg.transition) {
3773 Roo.log("waiting for the transitionend");
3777 Roo.log("fire event clicked");
3778 if(this.fireEvent('click', this, e) === false){
3782 if(this.tagtype == 'span'){
3786 var p = this.parent();
3787 if (['tabs','pills'].indexOf(p.type)!==-1) {
3788 if (typeof(p.setActiveItem) !== 'undefined') {
3789 p.setActiveItem(this);
3792 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3793 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3794 // remove the collapsed menu expand...
3795 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3800 isActive: function () {
3803 setActive : function(state, fire, is_was_active)
3805 if (this.active && !state & this.navId) {
3806 this.was_active = true;
3807 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3809 nv.clearWasActive(this);
3813 this.active = state;
3816 this.el.removeClass('active');
3817 } else if (!this.el.hasClass('active')) {
3818 this.el.addClass('active');
3821 this.fireEvent('changed', this, state);
3824 // show a panel if it's registered and related..
3826 if (!this.navId || !this.tabId || !state || is_was_active) {
3830 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3834 var pan = tg.getPanelByName(this.tabId);
3838 // if we can not flip to new panel - go back to old nav highlight..
3839 if (false == tg.showPanel(pan)) {
3840 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3842 var onav = nv.getWasActive();
3844 onav.setActive(true, false, true);
3853 // this should not be here...
3854 setDisabled : function(state)
3856 this.disabled = state;
3858 this.el.removeClass('disabled');
3859 } else if (!this.el.hasClass('disabled')) {
3860 this.el.addClass('disabled');
3873 * <span> icon </span>
3874 * <span> text </span>
3875 * <span>badge </span>
3879 * @class Roo.bootstrap.NavSidebarItem
3880 * @extends Roo.bootstrap.NavItem
3881 * Bootstrap Navbar.NavSidebarItem class
3883 * Create a new Navbar Button
3884 * @param {Object} config The config object
3886 Roo.bootstrap.NavSidebarItem = function(config){
3887 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3892 * The raw click event for the entire grid.
3893 * @param {Roo.EventObject} e
3898 * Fires when the active item active state changes
3899 * @param {Roo.bootstrap.NavSidebarItem} this
3900 * @param {boolean} state the new state
3908 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3911 getAutoCreate : function(){
3916 href : this.href || '#',
3928 html : this.html || ''
3933 cfg.cls += ' active';
3937 if (this.glyphicon || this.icon) {
3938 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3939 a.cn.push({ tag : 'i', cls : c }) ;
3944 if (this.badge !== '') {
3945 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3949 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3950 a.cls += 'dropdown-toggle treeview' ;
3974 * @class Roo.bootstrap.Row
3975 * @extends Roo.bootstrap.Component
3976 * Bootstrap Row class (contains columns...)
3980 * @param {Object} config The config object
3983 Roo.bootstrap.Row = function(config){
3984 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3987 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3989 getAutoCreate : function(){
4008 * @class Roo.bootstrap.Element
4009 * @extends Roo.bootstrap.Component
4010 * Bootstrap Element class
4011 * @cfg {String} html contents of the element
4012 * @cfg {String} tag tag of the element
4013 * @cfg {String} cls class of the element
4016 * Create a new Element
4017 * @param {Object} config The config object
4020 Roo.bootstrap.Element = function(config){
4021 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4024 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4031 getAutoCreate : function(){
4056 * @class Roo.bootstrap.Pagination
4057 * @extends Roo.bootstrap.Component
4058 * Bootstrap Pagination class
4059 * @cfg {String} size xs | sm | md | lg
4060 * @cfg {Boolean} inverse false | true
4063 * Create a new Pagination
4064 * @param {Object} config The config object
4067 Roo.bootstrap.Pagination = function(config){
4068 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4071 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4077 getAutoCreate : function(){
4083 cfg.cls += ' inverse';
4089 cfg.cls += " " + this.cls;
4107 * @class Roo.bootstrap.PaginationItem
4108 * @extends Roo.bootstrap.Component
4109 * Bootstrap PaginationItem class
4110 * @cfg {String} html text
4111 * @cfg {String} href the link
4112 * @cfg {Boolean} preventDefault (true | false) default true
4113 * @cfg {Boolean} active (true | false) default false
4117 * Create a new PaginationItem
4118 * @param {Object} config The config object
4122 Roo.bootstrap.PaginationItem = function(config){
4123 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4128 * The raw click event for the entire grid.
4129 * @param {Roo.EventObject} e
4135 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4139 preventDefault: true,
4143 getAutoCreate : function(){
4149 href : this.href ? this.href : '#',
4150 html : this.html ? this.html : ''
4160 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4166 initEvents: function() {
4168 this.el.on('click', this.onClick, this);
4171 onClick : function(e)
4173 Roo.log('PaginationItem on click ');
4174 if(this.preventDefault){
4178 this.fireEvent('click', this, e);
4194 * @class Roo.bootstrap.Slider
4195 * @extends Roo.bootstrap.Component
4196 * Bootstrap Slider class
4199 * Create a new Slider
4200 * @param {Object} config The config object
4203 Roo.bootstrap.Slider = function(config){
4204 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4207 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4209 getAutoCreate : function(){
4213 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4217 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4229 * Ext JS Library 1.1.1
4230 * Copyright(c) 2006-2007, Ext JS, LLC.
4232 * Originally Released Under LGPL - original licence link has changed is not relivant.
4235 * <script type="text/javascript">
4240 * @class Roo.grid.ColumnModel
4241 * @extends Roo.util.Observable
4242 * This is the default implementation of a ColumnModel used by the Grid. It defines
4243 * the columns in the grid.
4246 var colModel = new Roo.grid.ColumnModel([
4247 {header: "Ticker", width: 60, sortable: true, locked: true},
4248 {header: "Company Name", width: 150, sortable: true},
4249 {header: "Market Cap.", width: 100, sortable: true},
4250 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4251 {header: "Employees", width: 100, sortable: true, resizable: false}
4256 * The config options listed for this class are options which may appear in each
4257 * individual column definition.
4258 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4260 * @param {Object} config An Array of column config objects. See this class's
4261 * config objects for details.
4263 Roo.grid.ColumnModel = function(config){
4265 * The config passed into the constructor
4267 this.config = config;
4270 // if no id, create one
4271 // if the column does not have a dataIndex mapping,
4272 // map it to the order it is in the config
4273 for(var i = 0, len = config.length; i < len; i++){
4275 if(typeof c.dataIndex == "undefined"){
4278 if(typeof c.renderer == "string"){
4279 c.renderer = Roo.util.Format[c.renderer];
4281 if(typeof c.id == "undefined"){
4284 if(c.editor && c.editor.xtype){
4285 c.editor = Roo.factory(c.editor, Roo.grid);
4287 if(c.editor && c.editor.isFormField){
4288 c.editor = new Roo.grid.GridEditor(c.editor);
4290 this.lookup[c.id] = c;
4294 * The width of columns which have no width specified (defaults to 100)
4297 this.defaultWidth = 100;
4300 * Default sortable of columns which have no sortable specified (defaults to false)
4303 this.defaultSortable = false;
4307 * @event widthchange
4308 * Fires when the width of a column changes.
4309 * @param {ColumnModel} this
4310 * @param {Number} columnIndex The column index
4311 * @param {Number} newWidth The new width
4313 "widthchange": true,
4315 * @event headerchange
4316 * Fires when the text of a header changes.
4317 * @param {ColumnModel} this
4318 * @param {Number} columnIndex The column index
4319 * @param {Number} newText The new header text
4321 "headerchange": true,
4323 * @event hiddenchange
4324 * Fires when a column is hidden or "unhidden".
4325 * @param {ColumnModel} this
4326 * @param {Number} columnIndex The column index
4327 * @param {Boolean} hidden true if hidden, false otherwise
4329 "hiddenchange": true,
4331 * @event columnmoved
4332 * Fires when a column is moved.
4333 * @param {ColumnModel} this
4334 * @param {Number} oldIndex
4335 * @param {Number} newIndex
4337 "columnmoved" : true,
4339 * @event columlockchange
4340 * Fires when a column's locked state is changed
4341 * @param {ColumnModel} this
4342 * @param {Number} colIndex
4343 * @param {Boolean} locked true if locked
4345 "columnlockchange" : true
4347 Roo.grid.ColumnModel.superclass.constructor.call(this);
4349 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4351 * @cfg {String} header The header text to display in the Grid view.
4354 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4355 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4356 * specified, the column's index is used as an index into the Record's data Array.
4359 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4360 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4363 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4364 * Defaults to the value of the {@link #defaultSortable} property.
4365 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4368 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4371 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4374 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4377 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4380 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4381 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4382 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4383 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4386 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4389 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4393 * Returns the id of the column at the specified index.
4394 * @param {Number} index The column index
4395 * @return {String} the id
4397 getColumnId : function(index){
4398 return this.config[index].id;
4402 * Returns the column for a specified id.
4403 * @param {String} id The column id
4404 * @return {Object} the column
4406 getColumnById : function(id){
4407 return this.lookup[id];
4412 * Returns the column for a specified dataIndex.
4413 * @param {String} dataIndex The column dataIndex
4414 * @return {Object|Boolean} the column or false if not found
4416 getColumnByDataIndex: function(dataIndex){
4417 var index = this.findColumnIndex(dataIndex);
4418 return index > -1 ? this.config[index] : false;
4422 * Returns the index for a specified column id.
4423 * @param {String} id The column id
4424 * @return {Number} the index, or -1 if not found
4426 getIndexById : function(id){
4427 for(var i = 0, len = this.config.length; i < len; i++){
4428 if(this.config[i].id == id){
4436 * Returns the index for a specified column dataIndex.
4437 * @param {String} dataIndex The column dataIndex
4438 * @return {Number} the index, or -1 if not found
4441 findColumnIndex : function(dataIndex){
4442 for(var i = 0, len = this.config.length; i < len; i++){
4443 if(this.config[i].dataIndex == dataIndex){
4451 moveColumn : function(oldIndex, newIndex){
4452 var c = this.config[oldIndex];
4453 this.config.splice(oldIndex, 1);
4454 this.config.splice(newIndex, 0, c);
4455 this.dataMap = null;
4456 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4459 isLocked : function(colIndex){
4460 return this.config[colIndex].locked === true;
4463 setLocked : function(colIndex, value, suppressEvent){
4464 if(this.isLocked(colIndex) == value){
4467 this.config[colIndex].locked = value;
4469 this.fireEvent("columnlockchange", this, colIndex, value);
4473 getTotalLockedWidth : function(){
4475 for(var i = 0; i < this.config.length; i++){
4476 if(this.isLocked(i) && !this.isHidden(i)){
4477 this.totalWidth += this.getColumnWidth(i);
4483 getLockedCount : function(){
4484 for(var i = 0, len = this.config.length; i < len; i++){
4485 if(!this.isLocked(i)){
4492 * Returns the number of columns.
4495 getColumnCount : function(visibleOnly){
4496 if(visibleOnly === true){
4498 for(var i = 0, len = this.config.length; i < len; i++){
4499 if(!this.isHidden(i)){
4505 return this.config.length;
4509 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4510 * @param {Function} fn
4511 * @param {Object} scope (optional)
4512 * @return {Array} result
4514 getColumnsBy : function(fn, scope){
4516 for(var i = 0, len = this.config.length; i < len; i++){
4517 var c = this.config[i];
4518 if(fn.call(scope||this, c, i) === true){
4526 * Returns true if the specified column is sortable.
4527 * @param {Number} col The column index
4530 isSortable : function(col){
4531 if(typeof this.config[col].sortable == "undefined"){
4532 return this.defaultSortable;
4534 return this.config[col].sortable;
4538 * Returns the rendering (formatting) function defined for the column.
4539 * @param {Number} col The column index.
4540 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4542 getRenderer : function(col){
4543 if(!this.config[col].renderer){
4544 return Roo.grid.ColumnModel.defaultRenderer;
4546 return this.config[col].renderer;
4550 * Sets the rendering (formatting) function for a column.
4551 * @param {Number} col The column index
4552 * @param {Function} fn The function to use to process the cell's raw data
4553 * to return HTML markup for the grid view. The render function is called with
4554 * the following parameters:<ul>
4555 * <li>Data value.</li>
4556 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4557 * <li>css A CSS style string to apply to the table cell.</li>
4558 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4559 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4560 * <li>Row index</li>
4561 * <li>Column index</li>
4562 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4564 setRenderer : function(col, fn){
4565 this.config[col].renderer = fn;
4569 * Returns the width for the specified column.
4570 * @param {Number} col The column index
4573 getColumnWidth : function(col){
4574 return this.config[col].width * 1 || this.defaultWidth;
4578 * Sets the width for a column.
4579 * @param {Number} col The column index
4580 * @param {Number} width The new width
4582 setColumnWidth : function(col, width, suppressEvent){
4583 this.config[col].width = width;
4584 this.totalWidth = null;
4586 this.fireEvent("widthchange", this, col, width);
4591 * Returns the total width of all columns.
4592 * @param {Boolean} includeHidden True to include hidden column widths
4595 getTotalWidth : function(includeHidden){
4596 if(!this.totalWidth){
4597 this.totalWidth = 0;
4598 for(var i = 0, len = this.config.length; i < len; i++){
4599 if(includeHidden || !this.isHidden(i)){
4600 this.totalWidth += this.getColumnWidth(i);
4604 return this.totalWidth;
4608 * Returns the header for the specified column.
4609 * @param {Number} col The column index
4612 getColumnHeader : function(col){
4613 return this.config[col].header;
4617 * Sets the header for a column.
4618 * @param {Number} col The column index
4619 * @param {String} header The new header
4621 setColumnHeader : function(col, header){
4622 this.config[col].header = header;
4623 this.fireEvent("headerchange", this, col, header);
4627 * Returns the tooltip for the specified column.
4628 * @param {Number} col The column index
4631 getColumnTooltip : function(col){
4632 return this.config[col].tooltip;
4635 * Sets the tooltip for a column.
4636 * @param {Number} col The column index
4637 * @param {String} tooltip The new tooltip
4639 setColumnTooltip : function(col, tooltip){
4640 this.config[col].tooltip = tooltip;
4644 * Returns the dataIndex for the specified column.
4645 * @param {Number} col The column index
4648 getDataIndex : function(col){
4649 return this.config[col].dataIndex;
4653 * Sets the dataIndex for a column.
4654 * @param {Number} col The column index
4655 * @param {Number} dataIndex The new dataIndex
4657 setDataIndex : function(col, dataIndex){
4658 this.config[col].dataIndex = dataIndex;
4664 * Returns true if the cell is editable.
4665 * @param {Number} colIndex The column index
4666 * @param {Number} rowIndex The row index
4669 isCellEditable : function(colIndex, rowIndex){
4670 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4674 * Returns the editor defined for the cell/column.
4675 * return false or null to disable editing.
4676 * @param {Number} colIndex The column index
4677 * @param {Number} rowIndex The row index
4680 getCellEditor : function(colIndex, rowIndex){
4681 return this.config[colIndex].editor;
4685 * Sets if a column is editable.
4686 * @param {Number} col The column index
4687 * @param {Boolean} editable True if the column is editable
4689 setEditable : function(col, editable){
4690 this.config[col].editable = editable;
4695 * Returns true if the column is hidden.
4696 * @param {Number} colIndex The column index
4699 isHidden : function(colIndex){
4700 return this.config[colIndex].hidden;
4705 * Returns true if the column width cannot be changed
4707 isFixed : function(colIndex){
4708 return this.config[colIndex].fixed;
4712 * Returns true if the column can be resized
4715 isResizable : function(colIndex){
4716 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4719 * Sets if a column is hidden.
4720 * @param {Number} colIndex The column index
4721 * @param {Boolean} hidden True if the column is hidden
4723 setHidden : function(colIndex, hidden){
4724 this.config[colIndex].hidden = hidden;
4725 this.totalWidth = null;
4726 this.fireEvent("hiddenchange", this, colIndex, hidden);
4730 * Sets the editor for a column.
4731 * @param {Number} col The column index
4732 * @param {Object} editor The editor object
4734 setEditor : function(col, editor){
4735 this.config[col].editor = editor;
4739 Roo.grid.ColumnModel.defaultRenderer = function(value){
4740 if(typeof value == "string" && value.length < 1){
4746 // Alias for backwards compatibility
4747 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4750 * Ext JS Library 1.1.1
4751 * Copyright(c) 2006-2007, Ext JS, LLC.
4753 * Originally Released Under LGPL - original licence link has changed is not relivant.
4756 * <script type="text/javascript">
4760 * @class Roo.LoadMask
4761 * A simple utility class for generically masking elements while loading data. If the element being masked has
4762 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4763 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4764 * element's UpdateManager load indicator and will be destroyed after the initial load.
4766 * Create a new LoadMask
4767 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4768 * @param {Object} config The config object
4770 Roo.LoadMask = function(el, config){
4771 this.el = Roo.get(el);
4772 Roo.apply(this, config);
4774 this.store.on('beforeload', this.onBeforeLoad, this);
4775 this.store.on('load', this.onLoad, this);
4776 this.store.on('loadexception', this.onLoadException, this);
4777 this.removeMask = false;
4779 var um = this.el.getUpdateManager();
4780 um.showLoadIndicator = false; // disable the default indicator
4781 um.on('beforeupdate', this.onBeforeLoad, this);
4782 um.on('update', this.onLoad, this);
4783 um.on('failure', this.onLoad, this);
4784 this.removeMask = true;
4788 Roo.LoadMask.prototype = {
4790 * @cfg {Boolean} removeMask
4791 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4792 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4796 * The text to display in a centered loading message box (defaults to 'Loading...')
4800 * @cfg {String} msgCls
4801 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4803 msgCls : 'x-mask-loading',
4806 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4812 * Disables the mask to prevent it from being displayed
4814 disable : function(){
4815 this.disabled = true;
4819 * Enables the mask so that it can be displayed
4821 enable : function(){
4822 this.disabled = false;
4825 onLoadException : function()
4829 if (typeof(arguments[3]) != 'undefined') {
4830 Roo.MessageBox.alert("Error loading",arguments[3]);
4834 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4835 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4844 this.el.unmask(this.removeMask);
4849 this.el.unmask(this.removeMask);
4853 onBeforeLoad : function(){
4855 this.el.mask(this.msg, this.msgCls);
4860 destroy : function(){
4862 this.store.un('beforeload', this.onBeforeLoad, this);
4863 this.store.un('load', this.onLoad, this);
4864 this.store.un('loadexception', this.onLoadException, this);
4866 var um = this.el.getUpdateManager();
4867 um.un('beforeupdate', this.onBeforeLoad, this);
4868 um.un('update', this.onLoad, this);
4869 um.un('failure', this.onLoad, this);
4880 * @class Roo.bootstrap.Table
4881 * @extends Roo.bootstrap.Component
4882 * Bootstrap Table class
4883 * @cfg {String} cls table class
4884 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4885 * @cfg {String} bgcolor Specifies the background color for a table
4886 * @cfg {Number} border Specifies whether the table cells should have borders or not
4887 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4888 * @cfg {Number} cellspacing Specifies the space between cells
4889 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4890 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4891 * @cfg {String} sortable Specifies that the table should be sortable
4892 * @cfg {String} summary Specifies a summary of the content of a table
4893 * @cfg {Number} width Specifies the width of a table
4894 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4896 * @cfg {boolean} striped Should the rows be alternative striped
4897 * @cfg {boolean} bordered Add borders to the table
4898 * @cfg {boolean} hover Add hover highlighting
4899 * @cfg {boolean} condensed Format condensed
4900 * @cfg {boolean} responsive Format condensed
4901 * @cfg {Boolean} loadMask (true|false) default false
4902 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4903 * @cfg {Boolean} thead (true|false) generate thead, default true
4904 * @cfg {Boolean} RowSelection (true|false) default false
4905 * @cfg {Boolean} CellSelection (true|false) default false
4907 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4911 * Create a new Table
4912 * @param {Object} config The config object
4915 Roo.bootstrap.Table = function(config){
4916 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4919 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4920 this.sm = this.selModel;
4921 this.sm.xmodule = this.xmodule || false;
4923 if (this.cm && typeof(this.cm.config) == 'undefined') {
4924 this.colModel = new Roo.grid.ColumnModel(this.cm);
4925 this.cm = this.colModel;
4926 this.cm.xmodule = this.xmodule || false;
4929 this.store= Roo.factory(this.store, Roo.data);
4930 this.ds = this.store;
4931 this.ds.xmodule = this.xmodule || false;
4934 if (this.footer && this.store) {
4935 this.footer.dataSource = this.ds;
4936 this.footer = Roo.factory(this.footer);
4943 * Fires when a cell is clicked
4944 * @param {Roo.bootstrap.Table} this
4945 * @param {Roo.Element} el
4946 * @param {Number} rowIndex
4947 * @param {Number} columnIndex
4948 * @param {Roo.EventObject} e
4952 * @event celldblclick
4953 * Fires when a cell is double clicked
4954 * @param {Roo.bootstrap.Table} this
4955 * @param {Roo.Element} el
4956 * @param {Number} rowIndex
4957 * @param {Number} columnIndex
4958 * @param {Roo.EventObject} e
4960 "celldblclick" : true,
4963 * Fires when a row is clicked
4964 * @param {Roo.bootstrap.Table} this
4965 * @param {Roo.Element} el
4966 * @param {Number} rowIndex
4967 * @param {Roo.EventObject} e
4971 * @event rowdblclick
4972 * Fires when a row is double clicked
4973 * @param {Roo.bootstrap.Table} this
4974 * @param {Roo.Element} el
4975 * @param {Number} rowIndex
4976 * @param {Roo.EventObject} e
4978 "rowdblclick" : true,
4981 * Fires when a mouseover occur
4982 * @param {Roo.bootstrap.Table} this
4983 * @param {Roo.Element} el
4984 * @param {Number} rowIndex
4985 * @param {Number} columnIndex
4986 * @param {Roo.EventObject} e
4991 * Fires when a mouseout occur
4992 * @param {Roo.bootstrap.Table} this
4993 * @param {Roo.Element} el
4994 * @param {Number} rowIndex
4995 * @param {Number} columnIndex
4996 * @param {Roo.EventObject} e
5001 * Fires when a row is rendered, so you can change add a style to it.
5002 * @param {Roo.bootstrap.Table} this
5003 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5010 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5034 RowSelection : false,
5035 CellSelection : false,
5038 // Roo.Element - the tbody
5041 getAutoCreate : function(){
5042 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5051 cfg.cls += ' table-striped';
5055 cfg.cls += ' table-hover';
5057 if (this.bordered) {
5058 cfg.cls += ' table-bordered';
5060 if (this.condensed) {
5061 cfg.cls += ' table-condensed';
5063 if (this.responsive) {
5064 cfg.cls += ' table-responsive';
5068 cfg.cls+= ' ' +this.cls;
5071 // this lot should be simplifed...
5074 cfg.align=this.align;
5077 cfg.bgcolor=this.bgcolor;
5080 cfg.border=this.border;
5082 if (this.cellpadding) {
5083 cfg.cellpadding=this.cellpadding;
5085 if (this.cellspacing) {
5086 cfg.cellspacing=this.cellspacing;
5089 cfg.frame=this.frame;
5092 cfg.rules=this.rules;
5094 if (this.sortable) {
5095 cfg.sortable=this.sortable;
5098 cfg.summary=this.summary;
5101 cfg.width=this.width;
5104 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5107 if(this.store || this.cm){
5109 cfg.cn.push(this.renderHeader());
5112 cfg.cn.push(this.renderBody());
5115 cfg.cn.push(this.renderFooter());
5118 cfg.cls+= ' TableGrid';
5121 return { cn : [ cfg ] };
5124 initEvents : function()
5126 if(!this.store || !this.cm){
5130 //Roo.log('initEvents with ds!!!!');
5132 this.mainBody = this.el.select('tbody', true).first();
5137 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5138 e.on('click', _this.sort, _this);
5141 this.el.on("click", this.onClick, this);
5142 this.el.on("dblclick", this.onDblClick, this);
5144 this.parent().el.setStyle('position', 'relative');
5146 this.footer.parentId = this.id;
5147 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5150 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5152 this.store.on('load', this.onLoad, this);
5153 this.store.on('beforeload', this.onBeforeLoad, this);
5154 this.store.on('update', this.onUpdate, this);
5158 onMouseover : function(e, el)
5160 var cell = Roo.get(el);
5166 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5167 cell = cell.findParent('td', false, true);
5170 var row = cell.findParent('tr', false, true);
5171 var cellIndex = cell.dom.cellIndex;
5172 var rowIndex = row.dom.rowIndex - 1; // start from 0
5174 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5178 onMouseout : function(e, el)
5180 var cell = Roo.get(el);
5186 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5187 cell = cell.findParent('td', false, true);
5190 var row = cell.findParent('tr', false, true);
5191 var cellIndex = cell.dom.cellIndex;
5192 var rowIndex = row.dom.rowIndex - 1; // start from 0
5194 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5198 onClick : function(e, el)
5200 var cell = Roo.get(el);
5202 if(!cell || (!this.CellSelection && !this.RowSelection)){
5207 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5208 cell = cell.findParent('td', false, true);
5211 var row = cell.findParent('tr', false, true);
5212 var cellIndex = cell.dom.cellIndex;
5213 var rowIndex = row.dom.rowIndex - 1;
5215 if(this.CellSelection){
5216 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5219 if(this.RowSelection){
5220 this.fireEvent('rowclick', this, row, rowIndex, e);
5226 onDblClick : function(e,el)
5228 var cell = Roo.get(el);
5230 if(!cell || (!this.CellSelection && !this.RowSelection)){
5234 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5235 cell = cell.findParent('td', false, true);
5238 var row = cell.findParent('tr', false, true);
5239 var cellIndex = cell.dom.cellIndex;
5240 var rowIndex = row.dom.rowIndex - 1;
5242 if(this.CellSelection){
5243 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5246 if(this.RowSelection){
5247 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5251 sort : function(e,el)
5253 var col = Roo.get(el)
5255 if(!col.hasClass('sortable')){
5259 var sort = col.attr('sort');
5262 if(col.hasClass('glyphicon-arrow-up')){
5266 this.store.sortInfo = {field : sort, direction : dir};
5269 Roo.log("calling footer first");
5270 this.footer.onClick('first');
5273 this.store.load({ params : { start : 0 } });
5277 renderHeader : function()
5286 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5288 var config = cm.config[i];
5293 html: cm.getColumnHeader(i)
5296 if(typeof(config.hidden) != 'undefined' && config.hidden){
5297 c.style += ' display:none;';
5300 if(typeof(config.dataIndex) != 'undefined'){
5301 c.sort = config.dataIndex;
5304 if(typeof(config.sortable) != 'undefined' && config.sortable){
5308 if(typeof(config.align) != 'undefined' && config.align.length){
5309 c.style += ' text-align:' + config.align + ';';
5312 if(typeof(config.width) != 'undefined'){
5313 c.style += ' width:' + config.width + 'px;';
5322 renderBody : function()
5332 colspan : this.cm.getColumnCount()
5342 renderFooter : function()
5352 colspan : this.cm.getColumnCount()
5366 Roo.log('ds onload');
5371 var ds = this.store;
5373 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5374 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5376 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5377 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5380 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5381 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5385 var tbody = this.mainBody;
5387 if(ds.getCount() > 0){
5388 ds.data.each(function(d,rowIndex){
5389 var row = this.renderRow(cm, ds, rowIndex);
5391 tbody.createChild(row);
5395 if(row.cellObjects.length){
5396 Roo.each(row.cellObjects, function(r){
5397 _this.renderCellObject(r);
5404 Roo.each(this.el.select('tbody td', true).elements, function(e){
5405 e.on('mouseover', _this.onMouseover, _this);
5408 Roo.each(this.el.select('tbody td', true).elements, function(e){
5409 e.on('mouseout', _this.onMouseout, _this);
5412 //if(this.loadMask){
5413 // this.maskEl.hide();
5418 onUpdate : function(ds,record)
5420 this.refreshRow(record);
5422 onRemove : function(ds, record, index, isUpdate){
5423 if(isUpdate !== true){
5424 this.fireEvent("beforerowremoved", this, index, record);
5426 var bt = this.mainBody.dom;
5428 bt.removeChild(bt.rows[index]);
5431 if(isUpdate !== true){
5432 //this.stripeRows(index);
5433 //this.syncRowHeights(index, index);
5435 this.fireEvent("rowremoved", this, index, record);
5440 refreshRow : function(record){
5441 var ds = this.store, index;
5442 if(typeof record == 'number'){
5444 record = ds.getAt(index);
5446 index = ds.indexOf(record);
5448 this.insertRow(ds, index, true);
5449 this.onRemove(ds, record, index+1, true);
5450 //this.syncRowHeights(index, index);
5452 this.fireEvent("rowupdated", this, index, record);
5455 insertRow : function(dm, rowIndex, isUpdate){
5458 this.fireEvent("beforerowsinserted", this, rowIndex);
5460 //var s = this.getScrollState();
5461 var row = this.renderRow(this.cm, this.store, rowIndex);
5462 // insert before rowIndex..
5463 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5467 if(row.cellObjects.length){
5468 Roo.each(row.cellObjects, function(r){
5469 _this.renderCellObject(r);
5474 this.fireEvent("rowsinserted", this, rowIndex);
5475 //this.syncRowHeights(firstRow, lastRow);
5476 //this.stripeRows(firstRow);
5483 getRowDom : function(rowIndex)
5485 // not sure if I need to check this.. but let's do it anyway..
5486 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5487 this.mainBody.dom.rows[rowIndex] : false
5489 // returns the object tree for a tr..
5492 renderRow : function(cm, ds, rowIndex) {
5494 var d = ds.getAt(rowIndex);
5501 var cellObjects = [];
5503 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5504 var config = cm.config[i];
5506 var renderer = cm.getRenderer(i);
5510 if(typeof(renderer) !== 'undefined'){
5511 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5513 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5514 // and are rendered into the cells after the row is rendered - using the id for the element.
5516 if(typeof(value) === 'object'){
5526 rowIndex : rowIndex,
5531 this.fireEvent('rowclass', this, rowcfg);
5535 cls : rowcfg.rowClass,
5537 html: (typeof(value) === 'object') ? '' : value
5544 if(typeof(config.hidden) != 'undefined' && config.hidden){
5545 td.style += ' display:none;';
5548 if(typeof(config.align) != 'undefined' && config.align.length){
5549 td.style += ' text-align:' + config.align + ';';
5552 if(typeof(config.width) != 'undefined'){
5553 td.style += ' width:' + config.width + 'px;';
5560 row.cellObjects = cellObjects;
5568 onBeforeLoad : function()
5570 //Roo.log('ds onBeforeLoad');
5574 //if(this.loadMask){
5575 // this.maskEl.show();
5581 this.el.select('tbody', true).first().dom.innerHTML = '';
5584 getSelectionModel : function(){
5586 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5588 return this.selModel;
5591 * Render the Roo.bootstrap object from renderder
5593 renderCellObject : function(r)
5597 var t = r.cfg.render(r.container);
5600 Roo.each(r.cfg.cn, function(c){
5602 container: t.getChildContainer(),
5605 _this.renderCellObject(child);
5622 * @class Roo.bootstrap.TableCell
5623 * @extends Roo.bootstrap.Component
5624 * Bootstrap TableCell class
5625 * @cfg {String} html cell contain text
5626 * @cfg {String} cls cell class
5627 * @cfg {String} tag cell tag (td|th) default td
5628 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5629 * @cfg {String} align Aligns the content in a cell
5630 * @cfg {String} axis Categorizes cells
5631 * @cfg {String} bgcolor Specifies the background color of a cell
5632 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5633 * @cfg {Number} colspan Specifies the number of columns a cell should span
5634 * @cfg {String} headers Specifies one or more header cells a cell is related to
5635 * @cfg {Number} height Sets the height of a cell
5636 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5637 * @cfg {Number} rowspan Sets the number of rows a cell should span
5638 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5639 * @cfg {String} valign Vertical aligns the content in a cell
5640 * @cfg {Number} width Specifies the width of a cell
5643 * Create a new TableCell
5644 * @param {Object} config The config object
5647 Roo.bootstrap.TableCell = function(config){
5648 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5651 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5671 getAutoCreate : function(){
5672 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5692 cfg.align=this.align
5698 cfg.bgcolor=this.bgcolor
5701 cfg.charoff=this.charoff
5704 cfg.colspan=this.colspan
5707 cfg.headers=this.headers
5710 cfg.height=this.height
5713 cfg.nowrap=this.nowrap
5716 cfg.rowspan=this.rowspan
5719 cfg.scope=this.scope
5722 cfg.valign=this.valign
5725 cfg.width=this.width
5744 * @class Roo.bootstrap.TableRow
5745 * @extends Roo.bootstrap.Component
5746 * Bootstrap TableRow class
5747 * @cfg {String} cls row class
5748 * @cfg {String} align Aligns the content in a table row
5749 * @cfg {String} bgcolor Specifies a background color for a table row
5750 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5751 * @cfg {String} valign Vertical aligns the content in a table row
5754 * Create a new TableRow
5755 * @param {Object} config The config object
5758 Roo.bootstrap.TableRow = function(config){
5759 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5762 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5770 getAutoCreate : function(){
5771 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5781 cfg.align = this.align;
5784 cfg.bgcolor = this.bgcolor;
5787 cfg.charoff = this.charoff;
5790 cfg.valign = this.valign;
5808 * @class Roo.bootstrap.TableBody
5809 * @extends Roo.bootstrap.Component
5810 * Bootstrap TableBody class
5811 * @cfg {String} cls element class
5812 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5813 * @cfg {String} align Aligns the content inside the element
5814 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5815 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5818 * Create a new TableBody
5819 * @param {Object} config The config object
5822 Roo.bootstrap.TableBody = function(config){
5823 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5826 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5834 getAutoCreate : function(){
5835 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5849 cfg.align = this.align;
5852 cfg.charoff = this.charoff;
5855 cfg.valign = this.valign;
5862 // initEvents : function()
5869 // this.store = Roo.factory(this.store, Roo.data);
5870 // this.store.on('load', this.onLoad, this);
5872 // this.store.load();
5876 // onLoad: function ()
5878 // this.fireEvent('load', this);
5888 * Ext JS Library 1.1.1
5889 * Copyright(c) 2006-2007, Ext JS, LLC.
5891 * Originally Released Under LGPL - original licence link has changed is not relivant.
5894 * <script type="text/javascript">
5897 // as we use this in bootstrap.
5898 Roo.namespace('Roo.form');
5900 * @class Roo.form.Action
5901 * Internal Class used to handle form actions
5903 * @param {Roo.form.BasicForm} el The form element or its id
5904 * @param {Object} config Configuration options
5909 // define the action interface
5910 Roo.form.Action = function(form, options){
5912 this.options = options || {};
5915 * Client Validation Failed
5918 Roo.form.Action.CLIENT_INVALID = 'client';
5920 * Server Validation Failed
5923 Roo.form.Action.SERVER_INVALID = 'server';
5925 * Connect to Server Failed
5928 Roo.form.Action.CONNECT_FAILURE = 'connect';
5930 * Reading Data from Server Failed
5933 Roo.form.Action.LOAD_FAILURE = 'load';
5935 Roo.form.Action.prototype = {
5937 failureType : undefined,
5938 response : undefined,
5942 run : function(options){
5947 success : function(response){
5952 handleResponse : function(response){
5956 // default connection failure
5957 failure : function(response){
5959 this.response = response;
5960 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5961 this.form.afterAction(this, false);
5964 processResponse : function(response){
5965 this.response = response;
5966 if(!response.responseText){
5969 this.result = this.handleResponse(response);
5973 // utility functions used internally
5974 getUrl : function(appendParams){
5975 var url = this.options.url || this.form.url || this.form.el.dom.action;
5977 var p = this.getParams();
5979 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5985 getMethod : function(){
5986 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5989 getParams : function(){
5990 var bp = this.form.baseParams;
5991 var p = this.options.params;
5993 if(typeof p == "object"){
5994 p = Roo.urlEncode(Roo.applyIf(p, bp));
5995 }else if(typeof p == 'string' && bp){
5996 p += '&' + Roo.urlEncode(bp);
5999 p = Roo.urlEncode(bp);
6004 createCallback : function(){
6006 success: this.success,
6007 failure: this.failure,
6009 timeout: (this.form.timeout*1000),
6010 upload: this.form.fileUpload ? this.success : undefined
6015 Roo.form.Action.Submit = function(form, options){
6016 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6019 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6022 haveProgress : false,
6023 uploadComplete : false,
6025 // uploadProgress indicator.
6026 uploadProgress : function()
6028 if (!this.form.progressUrl) {
6032 if (!this.haveProgress) {
6033 Roo.MessageBox.progress("Uploading", "Uploading");
6035 if (this.uploadComplete) {
6036 Roo.MessageBox.hide();
6040 this.haveProgress = true;
6042 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6044 var c = new Roo.data.Connection();
6046 url : this.form.progressUrl,
6051 success : function(req){
6052 //console.log(data);
6056 rdata = Roo.decode(req.responseText)
6058 Roo.log("Invalid data from server..");
6062 if (!rdata || !rdata.success) {
6064 Roo.MessageBox.alert(Roo.encode(rdata));
6067 var data = rdata.data;
6069 if (this.uploadComplete) {
6070 Roo.MessageBox.hide();
6075 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6076 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6079 this.uploadProgress.defer(2000,this);
6082 failure: function(data) {
6083 Roo.log('progress url failed ');
6094 // run get Values on the form, so it syncs any secondary forms.
6095 this.form.getValues();
6097 var o = this.options;
6098 var method = this.getMethod();
6099 var isPost = method == 'POST';
6100 if(o.clientValidation === false || this.form.isValid()){
6102 if (this.form.progressUrl) {
6103 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6104 (new Date() * 1) + '' + Math.random());
6109 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6110 form:this.form.el.dom,
6111 url:this.getUrl(!isPost),
6113 params:isPost ? this.getParams() : null,
6114 isUpload: this.form.fileUpload
6117 this.uploadProgress();
6119 }else if (o.clientValidation !== false){ // client validation failed
6120 this.failureType = Roo.form.Action.CLIENT_INVALID;
6121 this.form.afterAction(this, false);
6125 success : function(response)
6127 this.uploadComplete= true;
6128 if (this.haveProgress) {
6129 Roo.MessageBox.hide();
6133 var result = this.processResponse(response);
6134 if(result === true || result.success){
6135 this.form.afterAction(this, true);
6139 this.form.markInvalid(result.errors);
6140 this.failureType = Roo.form.Action.SERVER_INVALID;
6142 this.form.afterAction(this, false);
6144 failure : function(response)
6146 this.uploadComplete= true;
6147 if (this.haveProgress) {
6148 Roo.MessageBox.hide();
6151 this.response = response;
6152 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6153 this.form.afterAction(this, false);
6156 handleResponse : function(response){
6157 if(this.form.errorReader){
6158 var rs = this.form.errorReader.read(response);
6161 for(var i = 0, len = rs.records.length; i < len; i++) {
6162 var r = rs.records[i];
6166 if(errors.length < 1){
6170 success : rs.success,
6176 ret = Roo.decode(response.responseText);
6180 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6190 Roo.form.Action.Load = function(form, options){
6191 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6192 this.reader = this.form.reader;
6195 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6200 Roo.Ajax.request(Roo.apply(
6201 this.createCallback(), {
6202 method:this.getMethod(),
6203 url:this.getUrl(false),
6204 params:this.getParams()
6208 success : function(response){
6210 var result = this.processResponse(response);
6211 if(result === true || !result.success || !result.data){
6212 this.failureType = Roo.form.Action.LOAD_FAILURE;
6213 this.form.afterAction(this, false);
6216 this.form.clearInvalid();
6217 this.form.setValues(result.data);
6218 this.form.afterAction(this, true);
6221 handleResponse : function(response){
6222 if(this.form.reader){
6223 var rs = this.form.reader.read(response);
6224 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6226 success : rs.success,
6230 return Roo.decode(response.responseText);
6234 Roo.form.Action.ACTION_TYPES = {
6235 'load' : Roo.form.Action.Load,
6236 'submit' : Roo.form.Action.Submit
6245 * @class Roo.bootstrap.Form
6246 * @extends Roo.bootstrap.Component
6247 * Bootstrap Form class
6248 * @cfg {String} method GET | POST (default POST)
6249 * @cfg {String} labelAlign top | left (default top)
6250 * @cfg {String} align left | right - for navbars
6251 * @cfg {Boolean} loadMask load mask when submit (default true)
6256 * @param {Object} config The config object
6260 Roo.bootstrap.Form = function(config){
6261 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6264 * @event clientvalidation
6265 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6266 * @param {Form} this
6267 * @param {Boolean} valid true if the form has passed client-side validation
6269 clientvalidation: true,
6271 * @event beforeaction
6272 * Fires before any action is performed. Return false to cancel the action.
6273 * @param {Form} this
6274 * @param {Action} action The action to be performed
6278 * @event actionfailed
6279 * Fires when an action fails.
6280 * @param {Form} this
6281 * @param {Action} action The action that failed
6283 actionfailed : true,
6285 * @event actioncomplete
6286 * Fires when an action is completed.
6287 * @param {Form} this
6288 * @param {Action} action The action that completed
6290 actioncomplete : true
6295 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6298 * @cfg {String} method
6299 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6304 * The URL to use for form actions if one isn't supplied in the action options.
6307 * @cfg {Boolean} fileUpload
6308 * Set to true if this form is a file upload.
6312 * @cfg {Object} baseParams
6313 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6317 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6321 * @cfg {Sting} align (left|right) for navbar forms
6326 activeAction : null,
6329 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6330 * element by passing it or its id or mask the form itself by passing in true.
6333 waitMsgTarget : false,
6337 getAutoCreate : function(){
6341 method : this.method || 'POST',
6342 id : this.id || Roo.id(),
6345 if (this.parent().xtype.match(/^Nav/)) {
6346 cfg.cls = 'navbar-form navbar-' + this.align;
6350 if (this.labelAlign == 'left' ) {
6351 cfg.cls += ' form-horizontal';
6357 initEvents : function()
6359 this.el.on('submit', this.onSubmit, this);
6360 // this was added as random key presses on the form where triggering form submit.
6361 this.el.on('keypress', function(e) {
6362 if (e.getCharCode() != 13) {
6365 // we might need to allow it for textareas.. and some other items.
6366 // check e.getTarget().
6368 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6372 Roo.log("keypress blocked");
6380 onSubmit : function(e){
6385 * Returns true if client-side validation on the form is successful.
6388 isValid : function(){
6389 var items = this.getItems();
6391 items.each(function(f){
6400 * Returns true if any fields in this form have changed since their original load.
6403 isDirty : function(){
6405 var items = this.getItems();
6406 items.each(function(f){
6416 * Performs a predefined action (submit or load) or custom actions you define on this form.
6417 * @param {String} actionName The name of the action type
6418 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6419 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6420 * accept other config options):
6422 Property Type Description
6423 ---------------- --------------- ----------------------------------------------------------------------------------
6424 url String The url for the action (defaults to the form's url)
6425 method String The form method to use (defaults to the form's method, or POST if not defined)
6426 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6427 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6428 validate the form on the client (defaults to false)
6430 * @return {BasicForm} this
6432 doAction : function(action, options){
6433 if(typeof action == 'string'){
6434 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6436 if(this.fireEvent('beforeaction', this, action) !== false){
6437 this.beforeAction(action);
6438 action.run.defer(100, action);
6444 beforeAction : function(action){
6445 var o = action.options;
6448 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6450 // not really supported yet.. ??
6452 //if(this.waitMsgTarget === true){
6453 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6454 //}else if(this.waitMsgTarget){
6455 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6456 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6458 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6464 afterAction : function(action, success){
6465 this.activeAction = null;
6466 var o = action.options;
6468 //if(this.waitMsgTarget === true){
6470 //}else if(this.waitMsgTarget){
6471 // this.waitMsgTarget.unmask();
6473 // Roo.MessageBox.updateProgress(1);
6474 // Roo.MessageBox.hide();
6481 Roo.callback(o.success, o.scope, [this, action]);
6482 this.fireEvent('actioncomplete', this, action);
6486 // failure condition..
6487 // we have a scenario where updates need confirming.
6488 // eg. if a locking scenario exists..
6489 // we look for { errors : { needs_confirm : true }} in the response.
6491 (typeof(action.result) != 'undefined') &&
6492 (typeof(action.result.errors) != 'undefined') &&
6493 (typeof(action.result.errors.needs_confirm) != 'undefined')
6496 Roo.log("not supported yet");
6499 Roo.MessageBox.confirm(
6500 "Change requires confirmation",
6501 action.result.errorMsg,
6506 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6516 Roo.callback(o.failure, o.scope, [this, action]);
6517 // show an error message if no failed handler is set..
6518 if (!this.hasListener('actionfailed')) {
6519 Roo.log("need to add dialog support");
6521 Roo.MessageBox.alert("Error",
6522 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6523 action.result.errorMsg :
6524 "Saving Failed, please check your entries or try again"
6529 this.fireEvent('actionfailed', this, action);
6534 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6535 * @param {String} id The value to search for
6538 findField : function(id){
6539 var items = this.getItems();
6540 var field = items.get(id);
6542 items.each(function(f){
6543 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6550 return field || null;
6553 * Mark fields in this form invalid in bulk.
6554 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6555 * @return {BasicForm} this
6557 markInvalid : function(errors){
6558 if(errors instanceof Array){
6559 for(var i = 0, len = errors.length; i < len; i++){
6560 var fieldError = errors[i];
6561 var f = this.findField(fieldError.id);
6563 f.markInvalid(fieldError.msg);
6569 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6570 field.markInvalid(errors[id]);
6574 //Roo.each(this.childForms || [], function (f) {
6575 // f.markInvalid(errors);
6582 * Set values for fields in this form in bulk.
6583 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6584 * @return {BasicForm} this
6586 setValues : function(values){
6587 if(values instanceof Array){ // array of objects
6588 for(var i = 0, len = values.length; i < len; i++){
6590 var f = this.findField(v.id);
6592 f.setValue(v.value);
6593 if(this.trackResetOnLoad){
6594 f.originalValue = f.getValue();
6598 }else{ // object hash
6601 if(typeof values[id] != 'function' && (field = this.findField(id))){
6603 if (field.setFromData &&
6605 field.displayField &&
6606 // combos' with local stores can
6607 // be queried via setValue()
6608 // to set their value..
6609 (field.store && !field.store.isLocal)
6613 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6614 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6615 field.setFromData(sd);
6618 field.setValue(values[id]);
6622 if(this.trackResetOnLoad){
6623 field.originalValue = field.getValue();
6629 //Roo.each(this.childForms || [], function (f) {
6630 // f.setValues(values);
6637 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6638 * they are returned as an array.
6639 * @param {Boolean} asString
6642 getValues : function(asString){
6643 //if (this.childForms) {
6644 // copy values from the child forms
6645 // Roo.each(this.childForms, function (f) {
6646 // this.setValues(f.getValues());
6652 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6653 if(asString === true){
6656 return Roo.urlDecode(fs);
6660 * Returns the fields in this form as an object with key/value pairs.
6661 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6664 getFieldValues : function(with_hidden)
6666 var items = this.getItems();
6668 items.each(function(f){
6672 var v = f.getValue();
6673 if (f.inputType =='radio') {
6674 if (typeof(ret[f.getName()]) == 'undefined') {
6675 ret[f.getName()] = ''; // empty..
6678 if (!f.el.dom.checked) {
6686 // not sure if this supported any more..
6687 if ((typeof(v) == 'object') && f.getRawValue) {
6688 v = f.getRawValue() ; // dates..
6690 // combo boxes where name != hiddenName...
6691 if (f.name != f.getName()) {
6692 ret[f.name] = f.getRawValue();
6694 ret[f.getName()] = v;
6701 * Clears all invalid messages in this form.
6702 * @return {BasicForm} this
6704 clearInvalid : function(){
6705 var items = this.getItems();
6707 items.each(function(f){
6718 * @return {BasicForm} this
6721 var items = this.getItems();
6722 items.each(function(f){
6726 Roo.each(this.childForms || [], function (f) {
6733 getItems : function()
6735 var r=new Roo.util.MixedCollection(false, function(o){
6736 return o.id || (o.id = Roo.id());
6738 var iter = function(el) {
6745 Roo.each(el.items,function(e) {
6764 * Ext JS Library 1.1.1
6765 * Copyright(c) 2006-2007, Ext JS, LLC.
6767 * Originally Released Under LGPL - original licence link has changed is not relivant.
6770 * <script type="text/javascript">
6773 * @class Roo.form.VTypes
6774 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6777 Roo.form.VTypes = function(){
6778 // closure these in so they are only created once.
6779 var alpha = /^[a-zA-Z_]+$/;
6780 var alphanum = /^[a-zA-Z0-9_]+$/;
6781 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6782 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6784 // All these messages and functions are configurable
6787 * The function used to validate email addresses
6788 * @param {String} value The email address
6790 'email' : function(v){
6791 return email.test(v);
6794 * The error text to display when the email validation function returns false
6797 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6799 * The keystroke filter mask to be applied on email input
6802 'emailMask' : /[a-z0-9_\.\-@]/i,
6805 * The function used to validate URLs
6806 * @param {String} value The URL
6808 'url' : function(v){
6812 * The error text to display when the url validation function returns false
6815 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6818 * The function used to validate alpha values
6819 * @param {String} value The value
6821 'alpha' : function(v){
6822 return alpha.test(v);
6825 * The error text to display when the alpha validation function returns false
6828 'alphaText' : 'This field should only contain letters and _',
6830 * The keystroke filter mask to be applied on alpha input
6833 'alphaMask' : /[a-z_]/i,
6836 * The function used to validate alphanumeric values
6837 * @param {String} value The value
6839 'alphanum' : function(v){
6840 return alphanum.test(v);
6843 * The error text to display when the alphanumeric validation function returns false
6846 'alphanumText' : 'This field should only contain letters, numbers and _',
6848 * The keystroke filter mask to be applied on alphanumeric input
6851 'alphanumMask' : /[a-z0-9_]/i
6861 * @class Roo.bootstrap.Input
6862 * @extends Roo.bootstrap.Component
6863 * Bootstrap Input class
6864 * @cfg {Boolean} disabled is it disabled
6865 * @cfg {String} fieldLabel - the label associated
6866 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6867 * @cfg {String} name name of the input
6868 * @cfg {string} fieldLabel - the label associated
6869 * @cfg {string} inputType - input / file submit ...
6870 * @cfg {string} placeholder - placeholder to put in text.
6871 * @cfg {string} before - input group add on before
6872 * @cfg {string} after - input group add on after
6873 * @cfg {string} size - (lg|sm) or leave empty..
6874 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6875 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6876 * @cfg {Number} md colspan out of 12 for computer-sized screens
6877 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6878 * @cfg {string} value default value of the input
6879 * @cfg {Number} labelWidth set the width of label (0-12)
6880 * @cfg {String} labelAlign (top|left)
6881 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6882 * @cfg {String} align (left|center|right) Default left
6886 * Create a new Input
6887 * @param {Object} config The config object
6890 Roo.bootstrap.Input = function(config){
6891 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6896 * Fires when this field receives input focus.
6897 * @param {Roo.form.Field} this
6902 * Fires when this field loses input focus.
6903 * @param {Roo.form.Field} this
6908 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6909 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6910 * @param {Roo.form.Field} this
6911 * @param {Roo.EventObject} e The event object
6916 * Fires just before the field blurs if the field value has changed.
6917 * @param {Roo.form.Field} this
6918 * @param {Mixed} newValue The new value
6919 * @param {Mixed} oldValue The original value
6924 * Fires after the field has been marked as invalid.
6925 * @param {Roo.form.Field} this
6926 * @param {String} msg The validation message
6931 * Fires after the field has been validated with no errors.
6932 * @param {Roo.form.Field} this
6937 * Fires after the key up
6938 * @param {Roo.form.Field} this
6939 * @param {Roo.EventObject} e The event Object
6945 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6947 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6948 automatic validation (defaults to "keyup").
6950 validationEvent : "keyup",
6952 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6954 validateOnBlur : true,
6956 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6958 validationDelay : 250,
6960 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6962 focusClass : "x-form-focus", // not needed???
6966 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6968 invalidClass : "has-error",
6971 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6973 selectOnFocus : false,
6976 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6980 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6985 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6987 disableKeyFilter : false,
6990 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6994 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6998 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7000 blankText : "This field is required",
7003 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7007 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7009 maxLength : Number.MAX_VALUE,
7011 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7013 minLengthText : "The minimum length for this field is {0}",
7015 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7017 maxLengthText : "The maximum length for this field is {0}",
7021 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7022 * If available, this function will be called only after the basic validators all return true, and will be passed the
7023 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7027 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7028 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7029 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7033 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7056 formatedValue : false,
7058 parentLabelAlign : function()
7061 while (parent.parent()) {
7062 parent = parent.parent();
7063 if (typeof(parent.labelAlign) !='undefined') {
7064 return parent.labelAlign;
7071 getAutoCreate : function(){
7073 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7079 if(this.inputType != 'hidden'){
7080 cfg.cls = 'form-group' //input-group
7086 type : this.inputType,
7088 cls : 'form-control',
7089 placeholder : this.placeholder || ''
7094 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7097 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7098 input.maxLength = this.maxLength;
7101 if (this.disabled) {
7102 input.disabled=true;
7105 if (this.readOnly) {
7106 input.readonly=true;
7110 input.name = this.name;
7113 input.cls += ' input-' + this.size;
7116 ['xs','sm','md','lg'].map(function(size){
7117 if (settings[size]) {
7118 cfg.cls += ' col-' + size + '-' + settings[size];
7122 var inputblock = input;
7124 if (this.before || this.after) {
7127 cls : 'input-group',
7130 if (this.before && typeof(this.before) == 'string') {
7132 inputblock.cn.push({
7134 cls : 'roo-input-before input-group-addon',
7138 if (this.before && typeof(this.before) == 'object') {
7139 this.before = Roo.factory(this.before);
7140 Roo.log(this.before);
7141 inputblock.cn.push({
7143 cls : 'roo-input-before input-group-' +
7144 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7148 inputblock.cn.push(input);
7150 if (this.after && typeof(this.after) == 'string') {
7151 inputblock.cn.push({
7153 cls : 'roo-input-after input-group-addon',
7157 if (this.after && typeof(this.after) == 'object') {
7158 this.after = Roo.factory(this.after);
7159 Roo.log(this.after);
7160 inputblock.cn.push({
7162 cls : 'roo-input-after input-group-' +
7163 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7168 if (align ==='left' && this.fieldLabel.length) {
7169 Roo.log("left and has label");
7175 cls : 'control-label col-sm-' + this.labelWidth,
7176 html : this.fieldLabel
7180 cls : "col-sm-" + (12 - this.labelWidth),
7187 } else if ( this.fieldLabel.length) {
7193 //cls : 'input-group-addon',
7194 html : this.fieldLabel
7204 Roo.log(" no label && no align");
7213 Roo.log('input-parentType: ' + this.parentType);
7215 if (this.parentType === 'Navbar' && this.parent().bar) {
7216 cfg.cls += ' navbar-form';
7224 * return the real input element.
7226 inputEl: function ()
7228 return this.el.select('input.form-control',true).first();
7231 tooltipEl : function()
7233 return this.inputEl();
7236 setDisabled : function(v)
7238 var i = this.inputEl().dom;
7240 i.removeAttribute('disabled');
7244 i.setAttribute('disabled','true');
7246 initEvents : function()
7249 this.inputEl().on("keydown" , this.fireKey, this);
7250 this.inputEl().on("focus", this.onFocus, this);
7251 this.inputEl().on("blur", this.onBlur, this);
7253 this.inputEl().relayEvent('keyup', this);
7255 // reference to original value for reset
7256 this.originalValue = this.getValue();
7257 //Roo.form.TextField.superclass.initEvents.call(this);
7258 if(this.validationEvent == 'keyup'){
7259 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7260 this.inputEl().on('keyup', this.filterValidation, this);
7262 else if(this.validationEvent !== false){
7263 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7266 if(this.selectOnFocus){
7267 this.on("focus", this.preFocus, this);
7270 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7271 this.inputEl().on("keypress", this.filterKeys, this);
7274 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7275 this.el.on("click", this.autoSize, this);
7278 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7279 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7282 if (typeof(this.before) == 'object') {
7283 this.before.render(this.el.select('.roo-input-before',true).first());
7285 if (typeof(this.after) == 'object') {
7286 this.after.render(this.el.select('.roo-input-after',true).first());
7291 filterValidation : function(e){
7292 if(!e.isNavKeyPress()){
7293 this.validationTask.delay(this.validationDelay);
7297 * Validates the field value
7298 * @return {Boolean} True if the value is valid, else false
7300 validate : function(){
7301 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7302 if(this.disabled || this.validateValue(this.getRawValue())){
7303 this.clearInvalid();
7311 * Validates a value according to the field's validation rules and marks the field as invalid
7312 * if the validation fails
7313 * @param {Mixed} value The value to validate
7314 * @return {Boolean} True if the value is valid, else false
7316 validateValue : function(value){
7317 if(value.length < 1) { // if it's blank
7318 if(this.allowBlank){
7319 this.clearInvalid();
7322 this.markInvalid(this.blankText);
7326 if(value.length < this.minLength){
7327 this.markInvalid(String.format(this.minLengthText, this.minLength));
7330 if(value.length > this.maxLength){
7331 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7335 var vt = Roo.form.VTypes;
7336 if(!vt[this.vtype](value, this)){
7337 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7341 if(typeof this.validator == "function"){
7342 var msg = this.validator(value);
7344 this.markInvalid(msg);
7348 if(this.regex && !this.regex.test(value)){
7349 this.markInvalid(this.regexText);
7358 fireKey : function(e){
7359 //Roo.log('field ' + e.getKey());
7360 if(e.isNavKeyPress()){
7361 this.fireEvent("specialkey", this, e);
7364 focus : function (selectText){
7366 this.inputEl().focus();
7367 if(selectText === true){
7368 this.inputEl().dom.select();
7374 onFocus : function(){
7375 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7376 // this.el.addClass(this.focusClass);
7379 this.hasFocus = true;
7380 this.startValue = this.getValue();
7381 this.fireEvent("focus", this);
7385 beforeBlur : Roo.emptyFn,
7389 onBlur : function(){
7391 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7392 //this.el.removeClass(this.focusClass);
7394 this.hasFocus = false;
7395 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7398 var v = this.getValue();
7399 if(String(v) !== String(this.startValue)){
7400 this.fireEvent('change', this, v, this.startValue);
7402 this.fireEvent("blur", this);
7406 * Resets the current field value to the originally loaded value and clears any validation messages
7409 this.setValue(this.originalValue);
7410 this.clearInvalid();
7413 * Returns the name of the field
7414 * @return {Mixed} name The name field
7416 getName: function(){
7420 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7421 * @return {Mixed} value The field value
7423 getValue : function(){
7425 var v = this.inputEl().getValue();
7430 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7431 * @return {Mixed} value The field value
7433 getRawValue : function(){
7434 var v = this.inputEl().getValue();
7440 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7441 * @param {Mixed} value The value to set
7443 setRawValue : function(v){
7444 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7447 selectText : function(start, end){
7448 var v = this.getRawValue();
7450 start = start === undefined ? 0 : start;
7451 end = end === undefined ? v.length : end;
7452 var d = this.inputEl().dom;
7453 if(d.setSelectionRange){
7454 d.setSelectionRange(start, end);
7455 }else if(d.createTextRange){
7456 var range = d.createTextRange();
7457 range.moveStart("character", start);
7458 range.moveEnd("character", v.length-end);
7465 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7466 * @param {Mixed} value The value to set
7468 setValue : function(v){
7471 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7477 processValue : function(value){
7478 if(this.stripCharsRe){
7479 var newValue = value.replace(this.stripCharsRe, '');
7480 if(newValue !== value){
7481 this.setRawValue(newValue);
7488 preFocus : function(){
7490 if(this.selectOnFocus){
7491 this.inputEl().dom.select();
7494 filterKeys : function(e){
7496 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7499 var c = e.getCharCode(), cc = String.fromCharCode(c);
7500 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7503 if(!this.maskRe.test(cc)){
7508 * Clear any invalid styles/messages for this field
7510 clearInvalid : function(){
7512 if(!this.el || this.preventMark){ // not rendered
7515 this.el.removeClass(this.invalidClass);
7517 switch(this.msgTarget){
7519 this.el.dom.qtip = '';
7522 this.el.dom.title = '';
7526 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7531 this.errorIcon.dom.qtip = '';
7532 this.errorIcon.hide();
7533 this.un('resize', this.alignErrorIcon, this);
7537 var t = Roo.getDom(this.msgTarget);
7539 t.style.display = 'none';
7543 this.fireEvent('valid', this);
7546 * Mark this field as invalid
7547 * @param {String} msg The validation message
7549 markInvalid : function(msg){
7550 if(!this.el || this.preventMark){ // not rendered
7553 this.el.addClass(this.invalidClass);
7555 msg = msg || this.invalidText;
7556 switch(this.msgTarget){
7558 this.el.dom.qtip = msg;
7559 this.el.dom.qclass = 'x-form-invalid-tip';
7560 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7561 Roo.QuickTips.enable();
7565 this.el.dom.title = msg;
7569 var elp = this.el.findParent('.x-form-element', 5, true);
7570 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7571 this.errorEl.setWidth(elp.getWidth(true)-20);
7573 this.errorEl.update(msg);
7574 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7577 if(!this.errorIcon){
7578 var elp = this.el.findParent('.x-form-element', 5, true);
7579 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7581 this.alignErrorIcon();
7582 this.errorIcon.dom.qtip = msg;
7583 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7584 this.errorIcon.show();
7585 this.on('resize', this.alignErrorIcon, this);
7588 var t = Roo.getDom(this.msgTarget);
7590 t.style.display = this.msgDisplay;
7594 this.fireEvent('invalid', this, msg);
7597 SafariOnKeyDown : function(event)
7599 // this is a workaround for a password hang bug on chrome/ webkit.
7601 var isSelectAll = false;
7603 if(this.inputEl().dom.selectionEnd > 0){
7604 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7606 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7607 event.preventDefault();
7612 if(isSelectAll){ // backspace and delete key
7614 event.preventDefault();
7615 // this is very hacky as keydown always get's upper case.
7617 var cc = String.fromCharCode(event.getCharCode());
7618 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7622 adjustWidth : function(tag, w){
7623 tag = tag.toLowerCase();
7624 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7625 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7629 if(tag == 'textarea'){
7632 }else if(Roo.isOpera){
7636 if(tag == 'textarea'){
7655 * @class Roo.bootstrap.TextArea
7656 * @extends Roo.bootstrap.Input
7657 * Bootstrap TextArea class
7658 * @cfg {Number} cols Specifies the visible width of a text area
7659 * @cfg {Number} rows Specifies the visible number of lines in a text area
7660 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7661 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7662 * @cfg {string} html text
7665 * Create a new TextArea
7666 * @param {Object} config The config object
7669 Roo.bootstrap.TextArea = function(config){
7670 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7674 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7684 getAutoCreate : function(){
7686 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7697 value : this.value || '',
7698 html: this.html || '',
7699 cls : 'form-control',
7700 placeholder : this.placeholder || ''
7704 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7705 input.maxLength = this.maxLength;
7709 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7713 input.cols = this.cols;
7716 if (this.readOnly) {
7717 input.readonly = true;
7721 input.name = this.name;
7725 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7729 ['xs','sm','md','lg'].map(function(size){
7730 if (settings[size]) {
7731 cfg.cls += ' col-' + size + '-' + settings[size];
7735 var inputblock = input;
7737 if (this.before || this.after) {
7740 cls : 'input-group',
7744 inputblock.cn.push({
7746 cls : 'input-group-addon',
7750 inputblock.cn.push(input);
7752 inputblock.cn.push({
7754 cls : 'input-group-addon',
7761 if (align ==='left' && this.fieldLabel.length) {
7762 Roo.log("left and has label");
7768 cls : 'control-label col-sm-' + this.labelWidth,
7769 html : this.fieldLabel
7773 cls : "col-sm-" + (12 - this.labelWidth),
7780 } else if ( this.fieldLabel.length) {
7786 //cls : 'input-group-addon',
7787 html : this.fieldLabel
7797 Roo.log(" no label && no align");
7807 if (this.disabled) {
7808 input.disabled=true;
7815 * return the real textarea element.
7817 inputEl: function ()
7819 return this.el.select('textarea.form-control',true).first();
7827 * trigger field - base class for combo..
7832 * @class Roo.bootstrap.TriggerField
7833 * @extends Roo.bootstrap.Input
7834 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7835 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7836 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7837 * for which you can provide a custom implementation. For example:
7839 var trigger = new Roo.bootstrap.TriggerField();
7840 trigger.onTriggerClick = myTriggerFn;
7841 trigger.applyTo('my-field');
7844 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7845 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7846 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7847 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7849 * Create a new TriggerField.
7850 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7851 * to the base TextField)
7853 Roo.bootstrap.TriggerField = function(config){
7854 this.mimicing = false;
7855 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7858 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7860 * @cfg {String} triggerClass A CSS class to apply to the trigger
7863 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7867 /** @cfg {Boolean} grow @hide */
7868 /** @cfg {Number} growMin @hide */
7869 /** @cfg {Number} growMax @hide */
7875 autoSize: Roo.emptyFn,
7882 actionMode : 'wrap',
7886 getAutoCreate : function(){
7888 var align = this.labelAlign || this.parentLabelAlign();
7893 cls: 'form-group' //input-group
7900 type : this.inputType,
7901 cls : 'form-control',
7902 autocomplete: 'off',
7903 placeholder : this.placeholder || ''
7907 input.name = this.name;
7910 input.cls += ' input-' + this.size;
7913 if (this.disabled) {
7914 input.disabled=true;
7917 var inputblock = input;
7919 if (this.before || this.after) {
7922 cls : 'input-group',
7926 inputblock.cn.push({
7928 cls : 'input-group-addon',
7932 inputblock.cn.push(input);
7934 inputblock.cn.push({
7936 cls : 'input-group-addon',
7949 cls: 'form-hidden-field'
7957 Roo.log('multiple');
7965 cls: 'form-hidden-field'
7969 cls: 'select2-choices',
7973 cls: 'select2-search-field',
7986 cls: 'select2-container input-group',
7991 // cls: 'typeahead typeahead-long dropdown-menu',
7992 // style: 'display:none'
7997 if(!this.multiple && this.showToggleBtn){
8000 cls : 'input-group-addon btn dropdown-toggle',
8008 cls: 'combobox-clear',
8022 combobox.cls += ' select2-container-multi';
8025 if (align ==='left' && this.fieldLabel.length) {
8027 Roo.log("left and has label");
8033 cls : 'control-label col-sm-' + this.labelWidth,
8034 html : this.fieldLabel
8038 cls : "col-sm-" + (12 - this.labelWidth),
8045 } else if ( this.fieldLabel.length) {
8051 //cls : 'input-group-addon',
8052 html : this.fieldLabel
8062 Roo.log(" no label && no align");
8069 ['xs','sm','md','lg'].map(function(size){
8070 if (settings[size]) {
8071 cfg.cls += ' col-' + size + '-' + settings[size];
8082 onResize : function(w, h){
8083 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8084 // if(typeof w == 'number'){
8085 // var x = w - this.trigger.getWidth();
8086 // this.inputEl().setWidth(this.adjustWidth('input', x));
8087 // this.trigger.setStyle('left', x+'px');
8092 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8095 getResizeEl : function(){
8096 return this.inputEl();
8100 getPositionEl : function(){
8101 return this.inputEl();
8105 alignErrorIcon : function(){
8106 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8110 initEvents : function(){
8114 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8115 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8116 if(!this.multiple && this.showToggleBtn){
8117 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8118 if(this.hideTrigger){
8119 this.trigger.setDisplayed(false);
8121 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8125 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8128 //this.trigger.addClassOnOver('x-form-trigger-over');
8129 //this.trigger.addClassOnClick('x-form-trigger-click');
8132 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8136 createList : function()
8138 this.list = Roo.get(document.body).createChild({
8140 cls: 'typeahead typeahead-long dropdown-menu',
8141 style: 'display:none'
8144 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8149 initTrigger : function(){
8154 onDestroy : function(){
8156 this.trigger.removeAllListeners();
8157 // this.trigger.remove();
8160 // this.wrap.remove();
8162 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8166 onFocus : function(){
8167 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8170 this.wrap.addClass('x-trigger-wrap-focus');
8171 this.mimicing = true;
8172 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8173 if(this.monitorTab){
8174 this.el.on("keydown", this.checkTab, this);
8181 checkTab : function(e){
8182 if(e.getKey() == e.TAB){
8188 onBlur : function(){
8193 mimicBlur : function(e, t){
8195 if(!this.wrap.contains(t) && this.validateBlur()){
8202 triggerBlur : function(){
8203 this.mimicing = false;
8204 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8205 if(this.monitorTab){
8206 this.el.un("keydown", this.checkTab, this);
8208 //this.wrap.removeClass('x-trigger-wrap-focus');
8209 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8213 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8214 validateBlur : function(e, t){
8219 onDisable : function(){
8220 this.inputEl().dom.disabled = true;
8221 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8223 // this.wrap.addClass('x-item-disabled');
8228 onEnable : function(){
8229 this.inputEl().dom.disabled = false;
8230 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8232 // this.el.removeClass('x-item-disabled');
8237 onShow : function(){
8238 var ae = this.getActionEl();
8241 ae.dom.style.display = '';
8242 ae.dom.style.visibility = 'visible';
8248 onHide : function(){
8249 var ae = this.getActionEl();
8250 ae.dom.style.display = 'none';
8254 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8255 * by an implementing function.
8257 * @param {EventObject} e
8259 onTriggerClick : Roo.emptyFn
8263 * Ext JS Library 1.1.1
8264 * Copyright(c) 2006-2007, Ext JS, LLC.
8266 * Originally Released Under LGPL - original licence link has changed is not relivant.
8269 * <script type="text/javascript">
8274 * @class Roo.data.SortTypes
8276 * Defines the default sorting (casting?) comparison functions used when sorting data.
8278 Roo.data.SortTypes = {
8280 * Default sort that does nothing
8281 * @param {Mixed} s The value being converted
8282 * @return {Mixed} The comparison value
8289 * The regular expression used to strip tags
8293 stripTagsRE : /<\/?[^>]+>/gi,
8296 * Strips all HTML tags to sort on text only
8297 * @param {Mixed} s The value being converted
8298 * @return {String} The comparison value
8300 asText : function(s){
8301 return String(s).replace(this.stripTagsRE, "");
8305 * Strips all HTML tags to sort on text only - Case insensitive
8306 * @param {Mixed} s The value being converted
8307 * @return {String} The comparison value
8309 asUCText : function(s){
8310 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8314 * Case insensitive string
8315 * @param {Mixed} s The value being converted
8316 * @return {String} The comparison value
8318 asUCString : function(s) {
8319 return String(s).toUpperCase();
8324 * @param {Mixed} s The value being converted
8325 * @return {Number} The comparison value
8327 asDate : function(s) {
8331 if(s instanceof Date){
8334 return Date.parse(String(s));
8339 * @param {Mixed} s The value being converted
8340 * @return {Float} The comparison value
8342 asFloat : function(s) {
8343 var val = parseFloat(String(s).replace(/,/g, ""));
8344 if(isNaN(val)) val = 0;
8350 * @param {Mixed} s The value being converted
8351 * @return {Number} The comparison value
8353 asInt : function(s) {
8354 var val = parseInt(String(s).replace(/,/g, ""));
8355 if(isNaN(val)) val = 0;
8360 * Ext JS Library 1.1.1
8361 * Copyright(c) 2006-2007, Ext JS, LLC.
8363 * Originally Released Under LGPL - original licence link has changed is not relivant.
8366 * <script type="text/javascript">
8370 * @class Roo.data.Record
8371 * Instances of this class encapsulate both record <em>definition</em> information, and record
8372 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8373 * to access Records cached in an {@link Roo.data.Store} object.<br>
8375 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8376 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8379 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8381 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8382 * {@link #create}. The parameters are the same.
8383 * @param {Array} data An associative Array of data values keyed by the field name.
8384 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8385 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8386 * not specified an integer id is generated.
8388 Roo.data.Record = function(data, id){
8389 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8394 * Generate a constructor for a specific record layout.
8395 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8396 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8397 * Each field definition object may contain the following properties: <ul>
8398 * <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,
8399 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8400 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8401 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8402 * is being used, then this is a string containing the javascript expression to reference the data relative to
8403 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8404 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8405 * this may be omitted.</p></li>
8406 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8407 * <ul><li>auto (Default, implies no conversion)</li>
8412 * <li>date</li></ul></p></li>
8413 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8414 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8415 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8416 * by the Reader into an object that will be stored in the Record. It is passed the
8417 * following parameters:<ul>
8418 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8420 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8422 * <br>usage:<br><pre><code>
8423 var TopicRecord = Roo.data.Record.create(
8424 {name: 'title', mapping: 'topic_title'},
8425 {name: 'author', mapping: 'username'},
8426 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8427 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8428 {name: 'lastPoster', mapping: 'user2'},
8429 {name: 'excerpt', mapping: 'post_text'}
8432 var myNewRecord = new TopicRecord({
8433 title: 'Do my job please',
8436 lastPost: new Date(),
8437 lastPoster: 'Animal',
8438 excerpt: 'No way dude!'
8440 myStore.add(myNewRecord);
8445 Roo.data.Record.create = function(o){
8447 f.superclass.constructor.apply(this, arguments);
8449 Roo.extend(f, Roo.data.Record);
8450 var p = f.prototype;
8451 p.fields = new Roo.util.MixedCollection(false, function(field){
8454 for(var i = 0, len = o.length; i < len; i++){
8455 p.fields.add(new Roo.data.Field(o[i]));
8457 f.getField = function(name){
8458 return p.fields.get(name);
8463 Roo.data.Record.AUTO_ID = 1000;
8464 Roo.data.Record.EDIT = 'edit';
8465 Roo.data.Record.REJECT = 'reject';
8466 Roo.data.Record.COMMIT = 'commit';
8468 Roo.data.Record.prototype = {
8470 * Readonly flag - true if this record has been modified.
8479 join : function(store){
8484 * Set the named field to the specified value.
8485 * @param {String} name The name of the field to set.
8486 * @param {Object} value The value to set the field to.
8488 set : function(name, value){
8489 if(this.data[name] == value){
8496 if(typeof this.modified[name] == 'undefined'){
8497 this.modified[name] = this.data[name];
8499 this.data[name] = value;
8500 if(!this.editing && this.store){
8501 this.store.afterEdit(this);
8506 * Get the value of the named field.
8507 * @param {String} name The name of the field to get the value of.
8508 * @return {Object} The value of the field.
8510 get : function(name){
8511 return this.data[name];
8515 beginEdit : function(){
8516 this.editing = true;
8521 cancelEdit : function(){
8522 this.editing = false;
8523 delete this.modified;
8527 endEdit : function(){
8528 this.editing = false;
8529 if(this.dirty && this.store){
8530 this.store.afterEdit(this);
8535 * Usually called by the {@link Roo.data.Store} which owns the Record.
8536 * Rejects all changes made to the Record since either creation, or the last commit operation.
8537 * Modified fields are reverted to their original values.
8539 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8540 * of reject operations.
8542 reject : function(){
8543 var m = this.modified;
8545 if(typeof m[n] != "function"){
8546 this.data[n] = m[n];
8550 delete this.modified;
8551 this.editing = false;
8553 this.store.afterReject(this);
8558 * Usually called by the {@link Roo.data.Store} which owns the Record.
8559 * Commits all changes made to the Record since either creation, or the last commit operation.
8561 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8562 * of commit operations.
8564 commit : function(){
8566 delete this.modified;
8567 this.editing = false;
8569 this.store.afterCommit(this);
8574 hasError : function(){
8575 return this.error != null;
8579 clearError : function(){
8584 * Creates a copy of this record.
8585 * @param {String} id (optional) A new record id if you don't want to use this record's id
8588 copy : function(newId) {
8589 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8593 * Ext JS Library 1.1.1
8594 * Copyright(c) 2006-2007, Ext JS, LLC.
8596 * Originally Released Under LGPL - original licence link has changed is not relivant.
8599 * <script type="text/javascript">
8605 * @class Roo.data.Store
8606 * @extends Roo.util.Observable
8607 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8608 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8610 * 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
8611 * has no knowledge of the format of the data returned by the Proxy.<br>
8613 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8614 * instances from the data object. These records are cached and made available through accessor functions.
8616 * Creates a new Store.
8617 * @param {Object} config A config object containing the objects needed for the Store to access data,
8618 * and read the data into Records.
8620 Roo.data.Store = function(config){
8621 this.data = new Roo.util.MixedCollection(false);
8622 this.data.getKey = function(o){
8625 this.baseParams = {};
8632 "multisort" : "_multisort"
8635 if(config && config.data){
8636 this.inlineData = config.data;
8640 Roo.apply(this, config);
8642 if(this.reader){ // reader passed
8643 this.reader = Roo.factory(this.reader, Roo.data);
8644 this.reader.xmodule = this.xmodule || false;
8645 if(!this.recordType){
8646 this.recordType = this.reader.recordType;
8648 if(this.reader.onMetaChange){
8649 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8653 if(this.recordType){
8654 this.fields = this.recordType.prototype.fields;
8660 * @event datachanged
8661 * Fires when the data cache has changed, and a widget which is using this Store
8662 * as a Record cache should refresh its view.
8663 * @param {Store} this
8668 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8669 * @param {Store} this
8670 * @param {Object} meta The JSON metadata
8675 * Fires when Records have been added to the Store
8676 * @param {Store} this
8677 * @param {Roo.data.Record[]} records The array of Records added
8678 * @param {Number} index The index at which the record(s) were added
8683 * Fires when a Record has been removed from the Store
8684 * @param {Store} this
8685 * @param {Roo.data.Record} record The Record that was removed
8686 * @param {Number} index The index at which the record was removed
8691 * Fires when a Record has been updated
8692 * @param {Store} this
8693 * @param {Roo.data.Record} record The Record that was updated
8694 * @param {String} operation The update operation being performed. Value may be one of:
8696 Roo.data.Record.EDIT
8697 Roo.data.Record.REJECT
8698 Roo.data.Record.COMMIT
8704 * Fires when the data cache has been cleared.
8705 * @param {Store} this
8710 * Fires before a request is made for a new data object. If the beforeload handler returns false
8711 * the load action will be canceled.
8712 * @param {Store} this
8713 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8717 * @event beforeloadadd
8718 * Fires after a new set of Records has been loaded.
8719 * @param {Store} this
8720 * @param {Roo.data.Record[]} records The Records that were loaded
8721 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8723 beforeloadadd : true,
8726 * Fires after a new set of Records has been loaded, before they are added to the store.
8727 * @param {Store} this
8728 * @param {Roo.data.Record[]} records The Records that were loaded
8729 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8730 * @params {Object} return from reader
8734 * @event loadexception
8735 * Fires if an exception occurs in the Proxy during loading.
8736 * Called with the signature of the Proxy's "loadexception" event.
8737 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8740 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8741 * @param {Object} load options
8742 * @param {Object} jsonData from your request (normally this contains the Exception)
8744 loadexception : true
8748 this.proxy = Roo.factory(this.proxy, Roo.data);
8749 this.proxy.xmodule = this.xmodule || false;
8750 this.relayEvents(this.proxy, ["loadexception"]);
8752 this.sortToggle = {};
8753 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8755 Roo.data.Store.superclass.constructor.call(this);
8757 if(this.inlineData){
8758 this.loadData(this.inlineData);
8759 delete this.inlineData;
8763 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8765 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8766 * without a remote query - used by combo/forms at present.
8770 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8773 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8776 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8777 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8780 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8781 * on any HTTP request
8784 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8787 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8791 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8792 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8797 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8798 * loaded or when a record is removed. (defaults to false).
8800 pruneModifiedRecords : false,
8806 * Add Records to the Store and fires the add event.
8807 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8809 add : function(records){
8810 records = [].concat(records);
8811 for(var i = 0, len = records.length; i < len; i++){
8812 records[i].join(this);
8814 var index = this.data.length;
8815 this.data.addAll(records);
8816 this.fireEvent("add", this, records, index);
8820 * Remove a Record from the Store and fires the remove event.
8821 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8823 remove : function(record){
8824 var index = this.data.indexOf(record);
8825 this.data.removeAt(index);
8826 if(this.pruneModifiedRecords){
8827 this.modified.remove(record);
8829 this.fireEvent("remove", this, record, index);
8833 * Remove all Records from the Store and fires the clear event.
8835 removeAll : function(){
8837 if(this.pruneModifiedRecords){
8840 this.fireEvent("clear", this);
8844 * Inserts Records to the Store at the given index and fires the add event.
8845 * @param {Number} index The start index at which to insert the passed Records.
8846 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8848 insert : function(index, records){
8849 records = [].concat(records);
8850 for(var i = 0, len = records.length; i < len; i++){
8851 this.data.insert(index, records[i]);
8852 records[i].join(this);
8854 this.fireEvent("add", this, records, index);
8858 * Get the index within the cache of the passed Record.
8859 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8860 * @return {Number} The index of the passed Record. Returns -1 if not found.
8862 indexOf : function(record){
8863 return this.data.indexOf(record);
8867 * Get the index within the cache of the Record with the passed id.
8868 * @param {String} id The id of the Record to find.
8869 * @return {Number} The index of the Record. Returns -1 if not found.
8871 indexOfId : function(id){
8872 return this.data.indexOfKey(id);
8876 * Get the Record with the specified id.
8877 * @param {String} id The id of the Record to find.
8878 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8880 getById : function(id){
8881 return this.data.key(id);
8885 * Get the Record at the specified index.
8886 * @param {Number} index The index of the Record to find.
8887 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8889 getAt : function(index){
8890 return this.data.itemAt(index);
8894 * Returns a range of Records between specified indices.
8895 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8896 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8897 * @return {Roo.data.Record[]} An array of Records
8899 getRange : function(start, end){
8900 return this.data.getRange(start, end);
8904 storeOptions : function(o){
8905 o = Roo.apply({}, o);
8908 this.lastOptions = o;
8912 * Loads the Record cache from the configured Proxy using the configured Reader.
8914 * If using remote paging, then the first load call must specify the <em>start</em>
8915 * and <em>limit</em> properties in the options.params property to establish the initial
8916 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8918 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8919 * and this call will return before the new data has been loaded. Perform any post-processing
8920 * in a callback function, or in a "load" event handler.</strong>
8922 * @param {Object} options An object containing properties which control loading options:<ul>
8923 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8924 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8925 * passed the following arguments:<ul>
8926 * <li>r : Roo.data.Record[]</li>
8927 * <li>options: Options object from the load call</li>
8928 * <li>success: Boolean success indicator</li></ul></li>
8929 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8930 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8933 load : function(options){
8934 options = options || {};
8935 if(this.fireEvent("beforeload", this, options) !== false){
8936 this.storeOptions(options);
8937 var p = Roo.apply(options.params || {}, this.baseParams);
8938 // if meta was not loaded from remote source.. try requesting it.
8939 if (!this.reader.metaFromRemote) {
8942 if(this.sortInfo && this.remoteSort){
8943 var pn = this.paramNames;
8944 p[pn["sort"]] = this.sortInfo.field;
8945 p[pn["dir"]] = this.sortInfo.direction;
8947 if (this.multiSort) {
8948 var pn = this.paramNames;
8949 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8952 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8957 * Reloads the Record cache from the configured Proxy using the configured Reader and
8958 * the options from the last load operation performed.
8959 * @param {Object} options (optional) An object containing properties which may override the options
8960 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8961 * the most recently used options are reused).
8963 reload : function(options){
8964 this.load(Roo.applyIf(options||{}, this.lastOptions));
8968 // Called as a callback by the Reader during a load operation.
8969 loadRecords : function(o, options, success){
8970 if(!o || success === false){
8971 if(success !== false){
8972 this.fireEvent("load", this, [], options, o);
8974 if(options.callback){
8975 options.callback.call(options.scope || this, [], options, false);
8979 // if data returned failure - throw an exception.
8980 if (o.success === false) {
8981 // show a message if no listener is registered.
8982 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8983 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8985 // loadmask wil be hooked into this..
8986 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8989 var r = o.records, t = o.totalRecords || r.length;
8991 this.fireEvent("beforeloadadd", this, r, options, o);
8993 if(!options || options.add !== true){
8994 if(this.pruneModifiedRecords){
8997 for(var i = 0, len = r.length; i < len; i++){
9001 this.data = this.snapshot;
9002 delete this.snapshot;
9005 this.data.addAll(r);
9006 this.totalLength = t;
9008 this.fireEvent("datachanged", this);
9010 this.totalLength = Math.max(t, this.data.length+r.length);
9013 this.fireEvent("load", this, r, options, o);
9014 if(options.callback){
9015 options.callback.call(options.scope || this, r, options, true);
9021 * Loads data from a passed data block. A Reader which understands the format of the data
9022 * must have been configured in the constructor.
9023 * @param {Object} data The data block from which to read the Records. The format of the data expected
9024 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9025 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9027 loadData : function(o, append){
9028 var r = this.reader.readRecords(o);
9029 this.loadRecords(r, {add: append}, true);
9033 * Gets the number of cached records.
9035 * <em>If using paging, this may not be the total size of the dataset. If the data object
9036 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9037 * the data set size</em>
9039 getCount : function(){
9040 return this.data.length || 0;
9044 * Gets the total number of records in the dataset as returned by the server.
9046 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9047 * the dataset size</em>
9049 getTotalCount : function(){
9050 return this.totalLength || 0;
9054 * Returns the sort state of the Store as an object with two properties:
9056 field {String} The name of the field by which the Records are sorted
9057 direction {String} The sort order, "ASC" or "DESC"
9060 getSortState : function(){
9061 return this.sortInfo;
9065 applySort : function(){
9066 if(this.sortInfo && !this.remoteSort){
9067 var s = this.sortInfo, f = s.field;
9068 var st = this.fields.get(f).sortType;
9069 var fn = function(r1, r2){
9070 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9071 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9073 this.data.sort(s.direction, fn);
9074 if(this.snapshot && this.snapshot != this.data){
9075 this.snapshot.sort(s.direction, fn);
9081 * Sets the default sort column and order to be used by the next load operation.
9082 * @param {String} fieldName The name of the field to sort by.
9083 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9085 setDefaultSort : function(field, dir){
9086 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9091 * If remote sorting is used, the sort is performed on the server, and the cache is
9092 * reloaded. If local sorting is used, the cache is sorted internally.
9093 * @param {String} fieldName The name of the field to sort by.
9094 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9096 sort : function(fieldName, dir){
9097 var f = this.fields.get(fieldName);
9099 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9101 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9102 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9107 this.sortToggle[f.name] = dir;
9108 this.sortInfo = {field: f.name, direction: dir};
9109 if(!this.remoteSort){
9111 this.fireEvent("datachanged", this);
9113 this.load(this.lastOptions);
9118 * Calls the specified function for each of the Records in the cache.
9119 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9120 * Returning <em>false</em> aborts and exits the iteration.
9121 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9123 each : function(fn, scope){
9124 this.data.each(fn, scope);
9128 * Gets all records modified since the last commit. Modified records are persisted across load operations
9129 * (e.g., during paging).
9130 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9132 getModifiedRecords : function(){
9133 return this.modified;
9137 createFilterFn : function(property, value, anyMatch){
9138 if(!value.exec){ // not a regex
9139 value = String(value);
9140 if(value.length == 0){
9143 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9146 return value.test(r.data[property]);
9151 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9152 * @param {String} property A field on your records
9153 * @param {Number} start The record index to start at (defaults to 0)
9154 * @param {Number} end The last record index to include (defaults to length - 1)
9155 * @return {Number} The sum
9157 sum : function(property, start, end){
9158 var rs = this.data.items, v = 0;
9160 end = (end || end === 0) ? end : rs.length-1;
9162 for(var i = start; i <= end; i++){
9163 v += (rs[i].data[property] || 0);
9169 * Filter the records by a specified property.
9170 * @param {String} field A field on your records
9171 * @param {String/RegExp} value Either a string that the field
9172 * should start with or a RegExp to test against the field
9173 * @param {Boolean} anyMatch True to match any part not just the beginning
9175 filter : function(property, value, anyMatch){
9176 var fn = this.createFilterFn(property, value, anyMatch);
9177 return fn ? this.filterBy(fn) : this.clearFilter();
9181 * Filter by a function. The specified function will be called with each
9182 * record in this data source. If the function returns true the record is included,
9183 * otherwise it is filtered.
9184 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9185 * @param {Object} scope (optional) The scope of the function (defaults to this)
9187 filterBy : function(fn, scope){
9188 this.snapshot = this.snapshot || this.data;
9189 this.data = this.queryBy(fn, scope||this);
9190 this.fireEvent("datachanged", this);
9194 * Query the records by a specified property.
9195 * @param {String} field A field on your records
9196 * @param {String/RegExp} value Either a string that the field
9197 * should start with or a RegExp to test against the field
9198 * @param {Boolean} anyMatch True to match any part not just the beginning
9199 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9201 query : function(property, value, anyMatch){
9202 var fn = this.createFilterFn(property, value, anyMatch);
9203 return fn ? this.queryBy(fn) : this.data.clone();
9207 * Query by a function. The specified function will be called with each
9208 * record in this data source. If the function returns true the record is included
9210 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9211 * @param {Object} scope (optional) The scope of the function (defaults to this)
9212 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9214 queryBy : function(fn, scope){
9215 var data = this.snapshot || this.data;
9216 return data.filterBy(fn, scope||this);
9220 * Collects unique values for a particular dataIndex from this store.
9221 * @param {String} dataIndex The property to collect
9222 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9223 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9224 * @return {Array} An array of the unique values
9226 collect : function(dataIndex, allowNull, bypassFilter){
9227 var d = (bypassFilter === true && this.snapshot) ?
9228 this.snapshot.items : this.data.items;
9229 var v, sv, r = [], l = {};
9230 for(var i = 0, len = d.length; i < len; i++){
9231 v = d[i].data[dataIndex];
9233 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9242 * Revert to a view of the Record cache with no filtering applied.
9243 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9245 clearFilter : function(suppressEvent){
9246 if(this.snapshot && this.snapshot != this.data){
9247 this.data = this.snapshot;
9248 delete this.snapshot;
9249 if(suppressEvent !== true){
9250 this.fireEvent("datachanged", this);
9256 afterEdit : function(record){
9257 if(this.modified.indexOf(record) == -1){
9258 this.modified.push(record);
9260 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9264 afterReject : function(record){
9265 this.modified.remove(record);
9266 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9270 afterCommit : function(record){
9271 this.modified.remove(record);
9272 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9276 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9277 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9279 commitChanges : function(){
9280 var m = this.modified.slice(0);
9282 for(var i = 0, len = m.length; i < len; i++){
9288 * Cancel outstanding changes on all changed records.
9290 rejectChanges : function(){
9291 var m = this.modified.slice(0);
9293 for(var i = 0, len = m.length; i < len; i++){
9298 onMetaChange : function(meta, rtype, o){
9299 this.recordType = rtype;
9300 this.fields = rtype.prototype.fields;
9301 delete this.snapshot;
9302 this.sortInfo = meta.sortInfo || this.sortInfo;
9304 this.fireEvent('metachange', this, this.reader.meta);
9307 moveIndex : function(data, type)
9309 var index = this.indexOf(data);
9311 var newIndex = index + type;
9315 this.insert(newIndex, data);
9320 * Ext JS Library 1.1.1
9321 * Copyright(c) 2006-2007, Ext JS, LLC.
9323 * Originally Released Under LGPL - original licence link has changed is not relivant.
9326 * <script type="text/javascript">
9330 * @class Roo.data.SimpleStore
9331 * @extends Roo.data.Store
9332 * Small helper class to make creating Stores from Array data easier.
9333 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9334 * @cfg {Array} fields An array of field definition objects, or field name strings.
9335 * @cfg {Array} data The multi-dimensional array of data
9337 * @param {Object} config
9339 Roo.data.SimpleStore = function(config){
9340 Roo.data.SimpleStore.superclass.constructor.call(this, {
9342 reader: new Roo.data.ArrayReader({
9345 Roo.data.Record.create(config.fields)
9347 proxy : new Roo.data.MemoryProxy(config.data)
9351 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9353 * Ext JS Library 1.1.1
9354 * Copyright(c) 2006-2007, Ext JS, LLC.
9356 * Originally Released Under LGPL - original licence link has changed is not relivant.
9359 * <script type="text/javascript">
9364 * @extends Roo.data.Store
9365 * @class Roo.data.JsonStore
9366 * Small helper class to make creating Stores for JSON data easier. <br/>
9368 var store = new Roo.data.JsonStore({
9369 url: 'get-images.php',
9371 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9374 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9375 * JsonReader and HttpProxy (unless inline data is provided).</b>
9376 * @cfg {Array} fields An array of field definition objects, or field name strings.
9378 * @param {Object} config
9380 Roo.data.JsonStore = function(c){
9381 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9382 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9383 reader: new Roo.data.JsonReader(c, c.fields)
9386 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9388 * Ext JS Library 1.1.1
9389 * Copyright(c) 2006-2007, Ext JS, LLC.
9391 * Originally Released Under LGPL - original licence link has changed is not relivant.
9394 * <script type="text/javascript">
9398 Roo.data.Field = function(config){
9399 if(typeof config == "string"){
9400 config = {name: config};
9402 Roo.apply(this, config);
9408 var st = Roo.data.SortTypes;
9409 // named sortTypes are supported, here we look them up
9410 if(typeof this.sortType == "string"){
9411 this.sortType = st[this.sortType];
9414 // set default sortType for strings and dates
9418 this.sortType = st.asUCString;
9421 this.sortType = st.asDate;
9424 this.sortType = st.none;
9429 var stripRe = /[\$,%]/g;
9431 // prebuilt conversion function for this field, instead of
9432 // switching every time we're reading a value
9434 var cv, dateFormat = this.dateFormat;
9439 cv = function(v){ return v; };
9442 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9446 return v !== undefined && v !== null && v !== '' ?
9447 parseInt(String(v).replace(stripRe, ""), 10) : '';
9452 return v !== undefined && v !== null && v !== '' ?
9453 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9458 cv = function(v){ return v === true || v === "true" || v == 1; };
9465 if(v instanceof Date){
9469 if(dateFormat == "timestamp"){
9470 return new Date(v*1000);
9472 return Date.parseDate(v, dateFormat);
9474 var parsed = Date.parse(v);
9475 return parsed ? new Date(parsed) : null;
9484 Roo.data.Field.prototype = {
9492 * Ext JS Library 1.1.1
9493 * Copyright(c) 2006-2007, Ext JS, LLC.
9495 * Originally Released Under LGPL - original licence link has changed is not relivant.
9498 * <script type="text/javascript">
9501 // Base class for reading structured data from a data source. This class is intended to be
9502 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9505 * @class Roo.data.DataReader
9506 * Base class for reading structured data from a data source. This class is intended to be
9507 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9510 Roo.data.DataReader = function(meta, recordType){
9514 this.recordType = recordType instanceof Array ?
9515 Roo.data.Record.create(recordType) : recordType;
9518 Roo.data.DataReader.prototype = {
9520 * Create an empty record
9521 * @param {Object} data (optional) - overlay some values
9522 * @return {Roo.data.Record} record created.
9524 newRow : function(d) {
9526 this.recordType.prototype.fields.each(function(c) {
9528 case 'int' : da[c.name] = 0; break;
9529 case 'date' : da[c.name] = new Date(); break;
9530 case 'float' : da[c.name] = 0.0; break;
9531 case 'boolean' : da[c.name] = false; break;
9532 default : da[c.name] = ""; break;
9536 return new this.recordType(Roo.apply(da, d));
9541 * Ext JS Library 1.1.1
9542 * Copyright(c) 2006-2007, Ext JS, LLC.
9544 * Originally Released Under LGPL - original licence link has changed is not relivant.
9547 * <script type="text/javascript">
9551 * @class Roo.data.DataProxy
9552 * @extends Roo.data.Observable
9553 * This class is an abstract base class for implementations which provide retrieval of
9554 * unformatted data objects.<br>
9556 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9557 * (of the appropriate type which knows how to parse the data object) to provide a block of
9558 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9560 * Custom implementations must implement the load method as described in
9561 * {@link Roo.data.HttpProxy#load}.
9563 Roo.data.DataProxy = function(){
9567 * Fires before a network request is made to retrieve a data object.
9568 * @param {Object} This DataProxy object.
9569 * @param {Object} params The params parameter to the load function.
9574 * Fires before the load method's callback is called.
9575 * @param {Object} This DataProxy object.
9576 * @param {Object} o The data object.
9577 * @param {Object} arg The callback argument object passed to the load function.
9581 * @event loadexception
9582 * Fires if an Exception occurs during data retrieval.
9583 * @param {Object} This DataProxy object.
9584 * @param {Object} o The data object.
9585 * @param {Object} arg The callback argument object passed to the load function.
9586 * @param {Object} e The Exception.
9588 loadexception : true
9590 Roo.data.DataProxy.superclass.constructor.call(this);
9593 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9596 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9600 * Ext JS Library 1.1.1
9601 * Copyright(c) 2006-2007, Ext JS, LLC.
9603 * Originally Released Under LGPL - original licence link has changed is not relivant.
9606 * <script type="text/javascript">
9609 * @class Roo.data.MemoryProxy
9610 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9611 * to the Reader when its load method is called.
9613 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9615 Roo.data.MemoryProxy = function(data){
9619 Roo.data.MemoryProxy.superclass.constructor.call(this);
9623 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9625 * Load data from the requested source (in this case an in-memory
9626 * data object passed to the constructor), read the data object into
9627 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9628 * process that block using the passed callback.
9629 * @param {Object} params This parameter is not used by the MemoryProxy class.
9630 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9631 * object into a block of Roo.data.Records.
9632 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9633 * The function must be passed <ul>
9634 * <li>The Record block object</li>
9635 * <li>The "arg" argument from the load function</li>
9636 * <li>A boolean success indicator</li>
9638 * @param {Object} scope The scope in which to call the callback
9639 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9641 load : function(params, reader, callback, scope, arg){
9642 params = params || {};
9645 result = reader.readRecords(this.data);
9647 this.fireEvent("loadexception", this, arg, null, e);
9648 callback.call(scope, null, arg, false);
9651 callback.call(scope, result, arg, true);
9655 update : function(params, records){
9660 * Ext JS Library 1.1.1
9661 * Copyright(c) 2006-2007, Ext JS, LLC.
9663 * Originally Released Under LGPL - original licence link has changed is not relivant.
9666 * <script type="text/javascript">
9669 * @class Roo.data.HttpProxy
9670 * @extends Roo.data.DataProxy
9671 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9672 * configured to reference a certain URL.<br><br>
9674 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9675 * from which the running page was served.<br><br>
9677 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9679 * Be aware that to enable the browser to parse an XML document, the server must set
9680 * the Content-Type header in the HTTP response to "text/xml".
9682 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9683 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9684 * will be used to make the request.
9686 Roo.data.HttpProxy = function(conn){
9687 Roo.data.HttpProxy.superclass.constructor.call(this);
9688 // is conn a conn config or a real conn?
9690 this.useAjax = !conn || !conn.events;
9694 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9695 // thse are take from connection...
9698 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9701 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9702 * extra parameters to each request made by this object. (defaults to undefined)
9705 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9706 * to each request made by this object. (defaults to undefined)
9709 * @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)
9712 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9715 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9721 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9725 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9726 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9727 * a finer-grained basis than the DataProxy events.
9729 getConnection : function(){
9730 return this.useAjax ? Roo.Ajax : this.conn;
9734 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9735 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9736 * process that block using the passed callback.
9737 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9738 * for the request to the remote server.
9739 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9740 * object into a block of Roo.data.Records.
9741 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9742 * The function must be passed <ul>
9743 * <li>The Record block object</li>
9744 * <li>The "arg" argument from the load function</li>
9745 * <li>A boolean success indicator</li>
9747 * @param {Object} scope The scope in which to call the callback
9748 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9750 load : function(params, reader, callback, scope, arg){
9751 if(this.fireEvent("beforeload", this, params) !== false){
9753 params : params || {},
9755 callback : callback,
9760 callback : this.loadResponse,
9764 Roo.applyIf(o, this.conn);
9765 if(this.activeRequest){
9766 Roo.Ajax.abort(this.activeRequest);
9768 this.activeRequest = Roo.Ajax.request(o);
9770 this.conn.request(o);
9773 callback.call(scope||this, null, arg, false);
9778 loadResponse : function(o, success, response){
9779 delete this.activeRequest;
9781 this.fireEvent("loadexception", this, o, response);
9782 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9787 result = o.reader.read(response);
9789 this.fireEvent("loadexception", this, o, response, e);
9790 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9794 this.fireEvent("load", this, o, o.request.arg);
9795 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9799 update : function(dataSet){
9804 updateResponse : function(dataSet){
9809 * Ext JS Library 1.1.1
9810 * Copyright(c) 2006-2007, Ext JS, LLC.
9812 * Originally Released Under LGPL - original licence link has changed is not relivant.
9815 * <script type="text/javascript">
9819 * @class Roo.data.ScriptTagProxy
9820 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9821 * other than the originating domain of the running page.<br><br>
9823 * <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
9824 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9826 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9827 * source code that is used as the source inside a <script> tag.<br><br>
9829 * In order for the browser to process the returned data, the server must wrap the data object
9830 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9831 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9832 * depending on whether the callback name was passed:
9835 boolean scriptTag = false;
9836 String cb = request.getParameter("callback");
9839 response.setContentType("text/javascript");
9841 response.setContentType("application/x-json");
9843 Writer out = response.getWriter();
9845 out.write(cb + "(");
9847 out.print(dataBlock.toJsonString());
9854 * @param {Object} config A configuration object.
9856 Roo.data.ScriptTagProxy = function(config){
9857 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9858 Roo.apply(this, config);
9859 this.head = document.getElementsByTagName("head")[0];
9862 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9864 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9866 * @cfg {String} url The URL from which to request the data object.
9869 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9873 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9874 * the server the name of the callback function set up by the load call to process the returned data object.
9875 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9876 * javascript output which calls this named function passing the data object as its only parameter.
9878 callbackParam : "callback",
9880 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9881 * name to the request.
9886 * Load data from the configured URL, read the data object into
9887 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9888 * process that block using the passed callback.
9889 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9890 * for the request to the remote server.
9891 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9892 * object into a block of Roo.data.Records.
9893 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9894 * The function must be passed <ul>
9895 * <li>The Record block object</li>
9896 * <li>The "arg" argument from the load function</li>
9897 * <li>A boolean success indicator</li>
9899 * @param {Object} scope The scope in which to call the callback
9900 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9902 load : function(params, reader, callback, scope, arg){
9903 if(this.fireEvent("beforeload", this, params) !== false){
9905 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9908 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9910 url += "&_dc=" + (new Date().getTime());
9912 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9915 cb : "stcCallback"+transId,
9916 scriptId : "stcScript"+transId,
9920 callback : callback,
9926 window[trans.cb] = function(o){
9927 conn.handleResponse(o, trans);
9930 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9932 if(this.autoAbort !== false){
9936 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9938 var script = document.createElement("script");
9939 script.setAttribute("src", url);
9940 script.setAttribute("type", "text/javascript");
9941 script.setAttribute("id", trans.scriptId);
9942 this.head.appendChild(script);
9946 callback.call(scope||this, null, arg, false);
9951 isLoading : function(){
9952 return this.trans ? true : false;
9956 * Abort the current server request.
9959 if(this.isLoading()){
9960 this.destroyTrans(this.trans);
9965 destroyTrans : function(trans, isLoaded){
9966 this.head.removeChild(document.getElementById(trans.scriptId));
9967 clearTimeout(trans.timeoutId);
9969 window[trans.cb] = undefined;
9971 delete window[trans.cb];
9974 // if hasn't been loaded, wait for load to remove it to prevent script error
9975 window[trans.cb] = function(){
9976 window[trans.cb] = undefined;
9978 delete window[trans.cb];
9985 handleResponse : function(o, trans){
9987 this.destroyTrans(trans, true);
9990 result = trans.reader.readRecords(o);
9992 this.fireEvent("loadexception", this, o, trans.arg, e);
9993 trans.callback.call(trans.scope||window, null, trans.arg, false);
9996 this.fireEvent("load", this, o, trans.arg);
9997 trans.callback.call(trans.scope||window, result, trans.arg, true);
10001 handleFailure : function(trans){
10002 this.trans = false;
10003 this.destroyTrans(trans, false);
10004 this.fireEvent("loadexception", this, null, trans.arg);
10005 trans.callback.call(trans.scope||window, null, trans.arg, false);
10009 * Ext JS Library 1.1.1
10010 * Copyright(c) 2006-2007, Ext JS, LLC.
10012 * Originally Released Under LGPL - original licence link has changed is not relivant.
10015 * <script type="text/javascript">
10019 * @class Roo.data.JsonReader
10020 * @extends Roo.data.DataReader
10021 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10022 * based on mappings in a provided Roo.data.Record constructor.
10024 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10025 * in the reply previously.
10030 var RecordDef = Roo.data.Record.create([
10031 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10032 {name: 'occupation'} // This field will use "occupation" as the mapping.
10034 var myReader = new Roo.data.JsonReader({
10035 totalProperty: "results", // The property which contains the total dataset size (optional)
10036 root: "rows", // The property which contains an Array of row objects
10037 id: "id" // The property within each row object that provides an ID for the record (optional)
10041 * This would consume a JSON file like this:
10043 { 'results': 2, 'rows': [
10044 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10045 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10048 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10049 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10050 * paged from the remote server.
10051 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10052 * @cfg {String} root name of the property which contains the Array of row objects.
10053 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10055 * Create a new JsonReader
10056 * @param {Object} meta Metadata configuration options
10057 * @param {Object} recordType Either an Array of field definition objects,
10058 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10060 Roo.data.JsonReader = function(meta, recordType){
10063 // set some defaults:
10064 Roo.applyIf(meta, {
10065 totalProperty: 'total',
10066 successProperty : 'success',
10071 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10073 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10076 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10077 * Used by Store query builder to append _requestMeta to params.
10080 metaFromRemote : false,
10082 * This method is only used by a DataProxy which has retrieved data from a remote server.
10083 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10084 * @return {Object} data A data block which is used by an Roo.data.Store object as
10085 * a cache of Roo.data.Records.
10087 read : function(response){
10088 var json = response.responseText;
10090 var o = /* eval:var:o */ eval("("+json+")");
10092 throw {message: "JsonReader.read: Json object not found"};
10098 this.metaFromRemote = true;
10099 this.meta = o.metaData;
10100 this.recordType = Roo.data.Record.create(o.metaData.fields);
10101 this.onMetaChange(this.meta, this.recordType, o);
10103 return this.readRecords(o);
10106 // private function a store will implement
10107 onMetaChange : function(meta, recordType, o){
10114 simpleAccess: function(obj, subsc) {
10121 getJsonAccessor: function(){
10123 return function(expr) {
10125 return(re.test(expr))
10126 ? new Function("obj", "return obj." + expr)
10131 return Roo.emptyFn;
10136 * Create a data block containing Roo.data.Records from an XML document.
10137 * @param {Object} o An object which contains an Array of row objects in the property specified
10138 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10139 * which contains the total size of the dataset.
10140 * @return {Object} data A data block which is used by an Roo.data.Store object as
10141 * a cache of Roo.data.Records.
10143 readRecords : function(o){
10145 * After any data loads, the raw JSON data is available for further custom processing.
10149 var s = this.meta, Record = this.recordType,
10150 f = Record.prototype.fields, fi = f.items, fl = f.length;
10152 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10154 if(s.totalProperty) {
10155 this.getTotal = this.getJsonAccessor(s.totalProperty);
10157 if(s.successProperty) {
10158 this.getSuccess = this.getJsonAccessor(s.successProperty);
10160 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10162 var g = this.getJsonAccessor(s.id);
10163 this.getId = function(rec) {
10165 return (r === undefined || r === "") ? null : r;
10168 this.getId = function(){return null;};
10171 for(var jj = 0; jj < fl; jj++){
10173 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10174 this.ef[jj] = this.getJsonAccessor(map);
10178 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10179 if(s.totalProperty){
10180 var vt = parseInt(this.getTotal(o), 10);
10185 if(s.successProperty){
10186 var vs = this.getSuccess(o);
10187 if(vs === false || vs === 'false'){
10192 for(var i = 0; i < c; i++){
10195 var id = this.getId(n);
10196 for(var j = 0; j < fl; j++){
10198 var v = this.ef[j](n);
10200 Roo.log('missing convert for ' + f.name);
10204 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10206 var record = new Record(values, id);
10208 records[i] = record;
10214 totalRecords : totalRecords
10219 * Ext JS Library 1.1.1
10220 * Copyright(c) 2006-2007, Ext JS, LLC.
10222 * Originally Released Under LGPL - original licence link has changed is not relivant.
10225 * <script type="text/javascript">
10229 * @class Roo.data.ArrayReader
10230 * @extends Roo.data.DataReader
10231 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10232 * Each element of that Array represents a row of data fields. The
10233 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10234 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10238 var RecordDef = Roo.data.Record.create([
10239 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10240 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10242 var myReader = new Roo.data.ArrayReader({
10243 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10247 * This would consume an Array like this:
10249 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10251 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10253 * Create a new JsonReader
10254 * @param {Object} meta Metadata configuration options.
10255 * @param {Object} recordType Either an Array of field definition objects
10256 * as specified to {@link Roo.data.Record#create},
10257 * or an {@link Roo.data.Record} object
10258 * created using {@link Roo.data.Record#create}.
10260 Roo.data.ArrayReader = function(meta, recordType){
10261 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10264 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10266 * Create a data block containing Roo.data.Records from an XML document.
10267 * @param {Object} o An Array of row objects which represents the dataset.
10268 * @return {Object} data A data block which is used by an Roo.data.Store object as
10269 * a cache of Roo.data.Records.
10271 readRecords : function(o){
10272 var sid = this.meta ? this.meta.id : null;
10273 var recordType = this.recordType, fields = recordType.prototype.fields;
10276 for(var i = 0; i < root.length; i++){
10279 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10280 for(var j = 0, jlen = fields.length; j < jlen; j++){
10281 var f = fields.items[j];
10282 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10283 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10285 values[f.name] = v;
10287 var record = new recordType(values, id);
10289 records[records.length] = record;
10293 totalRecords : records.length
10302 * @class Roo.bootstrap.ComboBox
10303 * @extends Roo.bootstrap.TriggerField
10304 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10305 * @cfg {Boolean} append (true|false) default false
10306 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10307 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10308 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10309 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10310 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10312 * Create a new ComboBox.
10313 * @param {Object} config Configuration options
10315 Roo.bootstrap.ComboBox = function(config){
10316 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10320 * Fires when the dropdown list is expanded
10321 * @param {Roo.bootstrap.ComboBox} combo This combo box
10326 * Fires when the dropdown list is collapsed
10327 * @param {Roo.bootstrap.ComboBox} combo This combo box
10331 * @event beforeselect
10332 * Fires before a list item is selected. Return false to cancel the selection.
10333 * @param {Roo.bootstrap.ComboBox} combo This combo box
10334 * @param {Roo.data.Record} record The data record returned from the underlying store
10335 * @param {Number} index The index of the selected item in the dropdown list
10337 'beforeselect' : true,
10340 * Fires when a list item is selected
10341 * @param {Roo.bootstrap.ComboBox} combo This combo box
10342 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10343 * @param {Number} index The index of the selected item in the dropdown list
10347 * @event beforequery
10348 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10349 * The event object passed has these properties:
10350 * @param {Roo.bootstrap.ComboBox} combo This combo box
10351 * @param {String} query The query
10352 * @param {Boolean} forceAll true to force "all" query
10353 * @param {Boolean} cancel true to cancel the query
10354 * @param {Object} e The query event object
10356 'beforequery': true,
10359 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10360 * @param {Roo.bootstrap.ComboBox} combo This combo box
10365 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10366 * @param {Roo.bootstrap.ComboBox} combo This combo box
10367 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10372 * Fires when the remove value from the combobox array
10373 * @param {Roo.bootstrap.ComboBox} combo This combo box
10380 this.tickItems = [];
10382 this.selectedIndex = -1;
10383 if(this.mode == 'local'){
10384 if(config.queryDelay === undefined){
10385 this.queryDelay = 10;
10387 if(config.minChars === undefined){
10393 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10396 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10397 * rendering into an Roo.Editor, defaults to false)
10400 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10401 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10404 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10407 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10408 * the dropdown list (defaults to undefined, with no header element)
10412 * @cfg {String/Roo.Template} tpl The template to use to render the output
10416 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10418 listWidth: undefined,
10420 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10421 * mode = 'remote' or 'text' if mode = 'local')
10423 displayField: undefined,
10425 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10426 * mode = 'remote' or 'value' if mode = 'local').
10427 * Note: use of a valueField requires the user make a selection
10428 * in order for a value to be mapped.
10430 valueField: undefined,
10434 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10435 * field's data value (defaults to the underlying DOM element's name)
10437 hiddenName: undefined,
10439 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10443 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10445 selectedClass: 'active',
10448 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10452 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10453 * anchor positions (defaults to 'tl-bl')
10455 listAlign: 'tl-bl?',
10457 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10461 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10462 * query specified by the allQuery config option (defaults to 'query')
10464 triggerAction: 'query',
10466 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10467 * (defaults to 4, does not apply if editable = false)
10471 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10472 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10476 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10477 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10481 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10482 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10486 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10487 * when editable = true (defaults to false)
10489 selectOnFocus:false,
10491 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10493 queryParam: 'query',
10495 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10496 * when mode = 'remote' (defaults to 'Loading...')
10498 loadingText: 'Loading...',
10500 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10504 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10508 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10509 * traditional select (defaults to true)
10513 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10517 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10521 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10522 * listWidth has a higher value)
10526 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10527 * allow the user to set arbitrary text into the field (defaults to false)
10529 forceSelection:false,
10531 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10532 * if typeAhead = true (defaults to 250)
10534 typeAheadDelay : 250,
10536 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10537 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10539 valueNotFoundText : undefined,
10541 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10543 blockFocus : false,
10546 * @cfg {Boolean} disableClear Disable showing of clear button.
10548 disableClear : false,
10550 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10552 alwaysQuery : false,
10555 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10569 btnPosition : 'right',
10570 triggerList : true,
10571 showToggleBtn : true,
10572 // element that contains real text value.. (when hidden is used..)
10574 getAutoCreate : function()
10581 if(!this.tickable){
10582 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10587 * ComboBox with tickable selections
10590 var align = this.labelAlign || this.parentLabelAlign();
10593 cls : 'form-group roo-combobox-tickable' //input-group
10599 cls : 'tickable-buttons',
10604 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10611 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10618 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10625 Roo.each(buttons.cn, function(c){
10627 c.cls += ' btn-' + _this.size;
10630 if (_this.disabled) {
10641 cls: 'form-hidden-field'
10645 cls: 'select2-choices',
10649 cls: 'select2-search-field',
10661 cls: 'select2-container input-group select2-container-multi',
10666 // cls: 'typeahead typeahead-long dropdown-menu',
10667 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10672 if (align ==='left' && this.fieldLabel.length) {
10674 Roo.log("left and has label");
10680 cls : 'control-label col-sm-' + this.labelWidth,
10681 html : this.fieldLabel
10685 cls : "col-sm-" + (12 - this.labelWidth),
10692 } else if ( this.fieldLabel.length) {
10698 //cls : 'input-group-addon',
10699 html : this.fieldLabel
10709 Roo.log(" no label && no align");
10716 ['xs','sm','md','lg'].map(function(size){
10717 if (settings[size]) {
10718 cfg.cls += ' col-' + size + '-' + settings[size];
10727 initEvents: function()
10731 throw "can not find store for combo";
10733 this.store = Roo.factory(this.store, Roo.data);
10736 this.initTickableEvents();
10740 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10742 if(this.hiddenName){
10744 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10746 this.hiddenField.dom.value =
10747 this.hiddenValue !== undefined ? this.hiddenValue :
10748 this.value !== undefined ? this.value : '';
10750 // prevent input submission
10751 this.el.dom.removeAttribute('name');
10752 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10757 // this.el.dom.setAttribute('autocomplete', 'off');
10760 var cls = 'x-combo-list';
10762 //this.list = new Roo.Layer({
10763 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10769 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10770 _this.list.setWidth(lw);
10773 this.list.on('mouseover', this.onViewOver, this);
10774 this.list.on('mousemove', this.onViewMove, this);
10776 this.list.on('scroll', this.onViewScroll, this);
10779 this.list.swallowEvent('mousewheel');
10780 this.assetHeight = 0;
10783 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10784 this.assetHeight += this.header.getHeight();
10787 this.innerList = this.list.createChild({cls:cls+'-inner'});
10788 this.innerList.on('mouseover', this.onViewOver, this);
10789 this.innerList.on('mousemove', this.onViewMove, this);
10790 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10792 if(this.allowBlank && !this.pageSize && !this.disableClear){
10793 this.footer = this.list.createChild({cls:cls+'-ft'});
10794 this.pageTb = new Roo.Toolbar(this.footer);
10798 this.footer = this.list.createChild({cls:cls+'-ft'});
10799 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10800 {pageSize: this.pageSize});
10804 if (this.pageTb && this.allowBlank && !this.disableClear) {
10806 this.pageTb.add(new Roo.Toolbar.Fill(), {
10807 cls: 'x-btn-icon x-btn-clear',
10809 handler: function()
10812 _this.clearValue();
10813 _this.onSelect(false, -1);
10818 this.assetHeight += this.footer.getHeight();
10823 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10826 this.view = new Roo.View(this.list, this.tpl, {
10827 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10829 //this.view.wrapEl.setDisplayed(false);
10830 this.view.on('click', this.onViewClick, this);
10834 this.store.on('beforeload', this.onBeforeLoad, this);
10835 this.store.on('load', this.onLoad, this);
10836 this.store.on('loadexception', this.onLoadException, this);
10838 if(this.resizable){
10839 this.resizer = new Roo.Resizable(this.list, {
10840 pinned:true, handles:'se'
10842 this.resizer.on('resize', function(r, w, h){
10843 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10844 this.listWidth = w;
10845 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10846 this.restrictHeight();
10848 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10851 if(!this.editable){
10852 this.editable = true;
10853 this.setEditable(false);
10858 if (typeof(this.events.add.listeners) != 'undefined') {
10860 this.addicon = this.wrap.createChild(
10861 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10863 this.addicon.on('click', function(e) {
10864 this.fireEvent('add', this);
10867 if (typeof(this.events.edit.listeners) != 'undefined') {
10869 this.editicon = this.wrap.createChild(
10870 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10871 if (this.addicon) {
10872 this.editicon.setStyle('margin-left', '40px');
10874 this.editicon.on('click', function(e) {
10876 // we fire even if inothing is selected..
10877 this.fireEvent('edit', this, this.lastData );
10883 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10884 "up" : function(e){
10885 this.inKeyMode = true;
10889 "down" : function(e){
10890 if(!this.isExpanded()){
10891 this.onTriggerClick();
10893 this.inKeyMode = true;
10898 "enter" : function(e){
10899 // this.onViewClick();
10903 if(this.fireEvent("specialkey", this, e)){
10904 this.onViewClick(false);
10910 "esc" : function(e){
10914 "tab" : function(e){
10917 if(this.fireEvent("specialkey", this, e)){
10918 this.onViewClick(false);
10926 doRelay : function(foo, bar, hname){
10927 if(hname == 'down' || this.scope.isExpanded()){
10928 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10937 this.queryDelay = Math.max(this.queryDelay || 10,
10938 this.mode == 'local' ? 10 : 250);
10941 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10943 if(this.typeAhead){
10944 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10946 if(this.editable !== false){
10947 this.inputEl().on("keyup", this.onKeyUp, this);
10949 if(this.forceSelection){
10950 this.inputEl().on('blur', this.doForce, this);
10954 this.choices = this.el.select('ul.select2-choices', true).first();
10955 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10959 initTickableEvents: function()
10963 if(this.hiddenName){
10965 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10967 this.hiddenField.dom.value =
10968 this.hiddenValue !== undefined ? this.hiddenValue :
10969 this.value !== undefined ? this.value : '';
10971 // prevent input submission
10972 this.el.dom.removeAttribute('name');
10973 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10978 // this.list = this.el.select('ul.dropdown-menu',true).first();
10980 this.choices = this.el.select('ul.select2-choices', true).first();
10981 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10982 if(this.triggerList){
10983 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10986 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10987 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10989 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10990 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10992 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10993 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10995 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10996 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10997 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11000 this.cancelBtn.hide();
11005 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11006 _this.list.setWidth(lw);
11009 this.list.on('mouseover', this.onViewOver, this);
11010 this.list.on('mousemove', this.onViewMove, this);
11012 this.list.on('scroll', this.onViewScroll, this);
11015 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>';
11018 this.view = new Roo.View(this.list, this.tpl, {
11019 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11022 //this.view.wrapEl.setDisplayed(false);
11023 this.view.on('click', this.onViewClick, this);
11027 this.store.on('beforeload', this.onBeforeLoad, this);
11028 this.store.on('load', this.onLoad, this);
11029 this.store.on('loadexception', this.onLoadException, this);
11031 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11032 // "up" : function(e){
11033 // this.inKeyMode = true;
11034 // this.selectPrev();
11037 // "down" : function(e){
11038 // if(!this.isExpanded()){
11039 // this.onTriggerClick();
11041 // this.inKeyMode = true;
11042 // this.selectNext();
11046 // "enter" : function(e){
11047 //// this.onViewClick();
11049 // this.collapse();
11051 // if(this.fireEvent("specialkey", this, e)){
11052 // this.onViewClick(false);
11058 // "esc" : function(e){
11059 // this.collapse();
11062 // "tab" : function(e){
11063 // this.collapse();
11065 // if(this.fireEvent("specialkey", this, e)){
11066 // this.onViewClick(false);
11074 // doRelay : function(foo, bar, hname){
11075 // if(hname == 'down' || this.scope.isExpanded()){
11076 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11081 // forceKeyDown: true
11085 this.queryDelay = Math.max(this.queryDelay || 10,
11086 this.mode == 'local' ? 10 : 250);
11089 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11091 if(this.typeAhead){
11092 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11096 onDestroy : function(){
11098 this.view.setStore(null);
11099 this.view.el.removeAllListeners();
11100 this.view.el.remove();
11101 this.view.purgeListeners();
11104 this.list.dom.innerHTML = '';
11108 this.store.un('beforeload', this.onBeforeLoad, this);
11109 this.store.un('load', this.onLoad, this);
11110 this.store.un('loadexception', this.onLoadException, this);
11112 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11116 fireKey : function(e){
11117 if(e.isNavKeyPress() && !this.list.isVisible()){
11118 this.fireEvent("specialkey", this, e);
11123 onResize: function(w, h){
11124 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11126 // if(typeof w != 'number'){
11127 // // we do not handle it!?!?
11130 // var tw = this.trigger.getWidth();
11131 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11132 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11134 // this.inputEl().setWidth( this.adjustWidth('input', x));
11136 // //this.trigger.setStyle('left', x+'px');
11138 // if(this.list && this.listWidth === undefined){
11139 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11140 // this.list.setWidth(lw);
11141 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11149 * Allow or prevent the user from directly editing the field text. If false is passed,
11150 * the user will only be able to select from the items defined in the dropdown list. This method
11151 * is the runtime equivalent of setting the 'editable' config option at config time.
11152 * @param {Boolean} value True to allow the user to directly edit the field text
11154 setEditable : function(value){
11155 if(value == this.editable){
11158 this.editable = value;
11160 this.inputEl().dom.setAttribute('readOnly', true);
11161 this.inputEl().on('mousedown', this.onTriggerClick, this);
11162 this.inputEl().addClass('x-combo-noedit');
11164 this.inputEl().dom.setAttribute('readOnly', false);
11165 this.inputEl().un('mousedown', this.onTriggerClick, this);
11166 this.inputEl().removeClass('x-combo-noedit');
11172 onBeforeLoad : function(combo,opts){
11173 if(!this.hasFocus){
11177 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11179 this.restrictHeight();
11180 this.selectedIndex = -1;
11184 onLoad : function(){
11186 this.hasQuery = false;
11188 if(!this.hasFocus){
11192 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11193 this.loading.hide();
11196 if(this.store.getCount() > 0){
11198 // this.restrictHeight();
11199 if(this.lastQuery == this.allQuery){
11200 if(this.editable && !this.tickable){
11201 this.inputEl().dom.select();
11205 !this.selectByValue(this.value, true) &&
11206 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11207 this.store.lastOptions.add != true)
11209 this.select(0, true);
11212 if(this.autoFocus){
11215 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11216 this.taTask.delay(this.typeAheadDelay);
11220 this.onEmptyResults();
11226 onLoadException : function()
11228 this.hasQuery = false;
11230 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11231 this.loading.hide();
11235 Roo.log(this.store.reader.jsonData);
11236 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11238 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11244 onTypeAhead : function(){
11245 if(this.store.getCount() > 0){
11246 var r = this.store.getAt(0);
11247 var newValue = r.data[this.displayField];
11248 var len = newValue.length;
11249 var selStart = this.getRawValue().length;
11251 if(selStart != len){
11252 this.setRawValue(newValue);
11253 this.selectText(selStart, newValue.length);
11259 onSelect : function(record, index){
11261 if(this.fireEvent('beforeselect', this, record, index) !== false){
11263 this.setFromData(index > -1 ? record.data : false);
11266 this.fireEvent('select', this, record, index);
11271 * Returns the currently selected field value or empty string if no value is set.
11272 * @return {String} value The selected value
11274 getValue : function(){
11277 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11280 if(this.valueField){
11281 return typeof this.value != 'undefined' ? this.value : '';
11283 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11288 * Clears any text/value currently set in the field
11290 clearValue : function(){
11291 if(this.hiddenField){
11292 this.hiddenField.dom.value = '';
11295 this.setRawValue('');
11296 this.lastSelectionText = '';
11301 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11302 * will be displayed in the field. If the value does not match the data value of an existing item,
11303 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11304 * Otherwise the field will be blank (although the value will still be set).
11305 * @param {String} value The value to match
11307 setValue : function(v){
11314 if(this.valueField){
11315 var r = this.findRecord(this.valueField, v);
11317 text = r.data[this.displayField];
11318 }else if(this.valueNotFoundText !== undefined){
11319 text = this.valueNotFoundText;
11322 this.lastSelectionText = text;
11323 if(this.hiddenField){
11324 this.hiddenField.dom.value = v;
11326 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11330 * @property {Object} the last set data for the element
11335 * Sets the value of the field based on a object which is related to the record format for the store.
11336 * @param {Object} value the value to set as. or false on reset?
11338 setFromData : function(o){
11345 var dv = ''; // display value
11346 var vv = ''; // value value..
11348 if (this.displayField) {
11349 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11351 // this is an error condition!!!
11352 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11355 if(this.valueField){
11356 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11359 if(this.hiddenField){
11360 this.hiddenField.dom.value = vv;
11362 this.lastSelectionText = dv;
11363 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11367 // no hidden field.. - we store the value in 'value', but still display
11368 // display field!!!!
11369 this.lastSelectionText = dv;
11370 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11376 reset : function(){
11377 // overridden so that last data is reset..
11378 this.setValue(this.originalValue);
11379 this.clearInvalid();
11380 this.lastData = false;
11382 this.view.clearSelections();
11386 findRecord : function(prop, value){
11388 if(this.store.getCount() > 0){
11389 this.store.each(function(r){
11390 if(r.data[prop] == value){
11400 getName: function()
11402 // returns hidden if it's set..
11403 if (!this.rendered) {return ''};
11404 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11408 onViewMove : function(e, t){
11409 this.inKeyMode = false;
11413 onViewOver : function(e, t){
11414 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11417 var item = this.view.findItemFromChild(t);
11420 var index = this.view.indexOf(item);
11421 this.select(index, false);
11426 onViewClick : function(view, doFocus, el, e)
11428 var index = this.view.getSelectedIndexes()[0];
11430 var r = this.store.getAt(index);
11434 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11441 Roo.each(this.tickItems, function(v,k){
11443 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11444 _this.tickItems.splice(k, 1);
11454 this.tickItems.push(r.data);
11459 this.onSelect(r, index);
11461 if(doFocus !== false && !this.blockFocus){
11462 this.inputEl().focus();
11467 restrictHeight : function(){
11468 //this.innerList.dom.style.height = '';
11469 //var inner = this.innerList.dom;
11470 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11471 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11472 //this.list.beginUpdate();
11473 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11474 this.list.alignTo(this.inputEl(), this.listAlign);
11475 this.list.alignTo(this.inputEl(), this.listAlign);
11476 //this.list.endUpdate();
11480 onEmptyResults : function(){
11485 * Returns true if the dropdown list is expanded, else false.
11487 isExpanded : function(){
11488 return this.list.isVisible();
11492 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11493 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11494 * @param {String} value The data value of the item to select
11495 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11496 * selected item if it is not currently in view (defaults to true)
11497 * @return {Boolean} True if the value matched an item in the list, else false
11499 selectByValue : function(v, scrollIntoView){
11500 if(v !== undefined && v !== null){
11501 var r = this.findRecord(this.valueField || this.displayField, v);
11503 this.select(this.store.indexOf(r), scrollIntoView);
11511 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11512 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11513 * @param {Number} index The zero-based index of the list item to select
11514 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11515 * selected item if it is not currently in view (defaults to true)
11517 select : function(index, scrollIntoView){
11518 this.selectedIndex = index;
11519 this.view.select(index);
11520 if(scrollIntoView !== false){
11521 var el = this.view.getNode(index);
11522 if(el && !this.multiple && !this.tickable){
11523 this.list.scrollChildIntoView(el, false);
11529 selectNext : function(){
11530 var ct = this.store.getCount();
11532 if(this.selectedIndex == -1){
11534 }else if(this.selectedIndex < ct-1){
11535 this.select(this.selectedIndex+1);
11541 selectPrev : function(){
11542 var ct = this.store.getCount();
11544 if(this.selectedIndex == -1){
11546 }else if(this.selectedIndex != 0){
11547 this.select(this.selectedIndex-1);
11553 onKeyUp : function(e){
11554 if(this.editable !== false && !e.isSpecialKey()){
11555 this.lastKey = e.getKey();
11556 this.dqTask.delay(this.queryDelay);
11561 validateBlur : function(){
11562 return !this.list || !this.list.isVisible();
11566 initQuery : function(){
11567 this.doQuery(this.getRawValue());
11571 doForce : function(){
11572 if(this.inputEl().dom.value.length > 0){
11573 this.inputEl().dom.value =
11574 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11580 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11581 * query allowing the query action to be canceled if needed.
11582 * @param {String} query The SQL query to execute
11583 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11584 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11585 * saved in the current store (defaults to false)
11587 doQuery : function(q, forceAll){
11589 if(q === undefined || q === null){
11594 forceAll: forceAll,
11598 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11603 forceAll = qe.forceAll;
11604 if(forceAll === true || (q.length >= this.minChars)){
11606 this.hasQuery = true;
11608 if(this.lastQuery != q || this.alwaysQuery){
11609 this.lastQuery = q;
11610 if(this.mode == 'local'){
11611 this.selectedIndex = -1;
11613 this.store.clearFilter();
11615 this.store.filter(this.displayField, q);
11619 this.store.baseParams[this.queryParam] = q;
11621 var options = {params : this.getParams(q)};
11624 options.add = true;
11625 options.params.start = this.page * this.pageSize;
11628 this.store.load(options);
11630 * this code will make the page width larger, at the beginning, the list not align correctly,
11631 * we should expand the list on onLoad
11632 * so command out it
11637 this.selectedIndex = -1;
11642 this.loadNext = false;
11646 getParams : function(q){
11648 //p[this.queryParam] = q;
11652 p.limit = this.pageSize;
11658 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11660 collapse : function(){
11661 if(!this.isExpanded()){
11669 this.cancelBtn.hide();
11670 this.trigger.show();
11673 Roo.get(document).un('mousedown', this.collapseIf, this);
11674 Roo.get(document).un('mousewheel', this.collapseIf, this);
11675 if (!this.editable) {
11676 Roo.get(document).un('keydown', this.listKeyPress, this);
11678 this.fireEvent('collapse', this);
11682 collapseIf : function(e){
11683 var in_combo = e.within(this.el);
11684 var in_list = e.within(this.list);
11685 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11687 if (in_combo || in_list || is_list) {
11688 //e.stopPropagation();
11693 this.onTickableFooterButtonClick(e, false, false);
11701 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11703 expand : function(){
11705 if(this.isExpanded() || !this.hasFocus){
11709 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11710 this.list.setWidth(lw);
11717 this.restrictHeight();
11721 this.tickItems = Roo.apply([], this.item);
11724 this.cancelBtn.show();
11725 this.trigger.hide();
11729 Roo.get(document).on('mousedown', this.collapseIf, this);
11730 Roo.get(document).on('mousewheel', this.collapseIf, this);
11731 if (!this.editable) {
11732 Roo.get(document).on('keydown', this.listKeyPress, this);
11735 this.fireEvent('expand', this);
11739 // Implements the default empty TriggerField.onTriggerClick function
11740 onTriggerClick : function(e)
11742 Roo.log('trigger click');
11744 if(this.disabled || !this.triggerList){
11749 this.loadNext = false;
11751 if(this.isExpanded()){
11753 if (!this.blockFocus) {
11754 this.inputEl().focus();
11758 this.hasFocus = true;
11759 if(this.triggerAction == 'all') {
11760 this.doQuery(this.allQuery, true);
11762 this.doQuery(this.getRawValue());
11764 if (!this.blockFocus) {
11765 this.inputEl().focus();
11770 onTickableTriggerClick : function(e)
11777 this.loadNext = false;
11778 this.hasFocus = true;
11780 if(this.triggerAction == 'all') {
11781 this.doQuery(this.allQuery, true);
11783 this.doQuery(this.getRawValue());
11787 onSearchFieldClick : function(e)
11789 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11794 this.loadNext = false;
11795 this.hasFocus = true;
11797 if(this.triggerAction == 'all') {
11798 this.doQuery(this.allQuery, true);
11800 this.doQuery(this.getRawValue());
11804 listKeyPress : function(e)
11806 //Roo.log('listkeypress');
11807 // scroll to first matching element based on key pres..
11808 if (e.isSpecialKey()) {
11811 var k = String.fromCharCode(e.getKey()).toUpperCase();
11814 var csel = this.view.getSelectedNodes();
11815 var cselitem = false;
11817 var ix = this.view.indexOf(csel[0]);
11818 cselitem = this.store.getAt(ix);
11819 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11825 this.store.each(function(v) {
11827 // start at existing selection.
11828 if (cselitem.id == v.id) {
11834 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11835 match = this.store.indexOf(v);
11841 if (match === false) {
11842 return true; // no more action?
11845 this.view.select(match);
11846 var sn = Roo.get(this.view.getSelectedNodes()[0])
11847 sn.scrollIntoView(sn.dom.parentNode, false);
11850 onViewScroll : function(e, t){
11852 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){
11856 this.hasQuery = true;
11858 this.loading = this.list.select('.loading', true).first();
11860 if(this.loading === null){
11861 this.list.createChild({
11863 cls: 'loading select2-more-results select2-active',
11864 html: 'Loading more results...'
11867 this.loading = this.list.select('.loading', true).first();
11869 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11871 this.loading.hide();
11874 this.loading.show();
11879 this.loadNext = true;
11881 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11886 addItem : function(o)
11888 var dv = ''; // display value
11890 if (this.displayField) {
11891 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11893 // this is an error condition!!!
11894 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11901 var choice = this.choices.createChild({
11903 cls: 'select2-search-choice',
11912 cls: 'select2-search-choice-close',
11917 }, this.searchField);
11919 var close = choice.select('a.select2-search-choice-close', true).first()
11921 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11929 this.inputEl().dom.value = '';
11933 onRemoveItem : function(e, _self, o)
11935 e.preventDefault();
11936 var index = this.item.indexOf(o.data) * 1;
11939 Roo.log('not this item?!');
11943 this.item.splice(index, 1);
11948 this.fireEvent('remove', this, e);
11952 syncValue : function()
11954 if(!this.item.length){
11961 Roo.each(this.item, function(i){
11962 if(_this.valueField){
11963 value.push(i[_this.valueField]);
11970 this.value = value.join(',');
11972 if(this.hiddenField){
11973 this.hiddenField.dom.value = this.value;
11977 clearItem : function()
11979 if(!this.multiple){
11985 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11992 inputEl: function ()
11995 return this.searchField;
11997 return this.el.select('input.form-control',true).first();
12001 onTickableFooterButtonClick : function(e, btn, el)
12003 e.preventDefault();
12005 if(btn && btn.name == 'cancel'){
12006 this.tickItems = Roo.apply([], this.item);
12015 Roo.each(this.tickItems, function(o){
12026 * @cfg {Boolean} grow
12030 * @cfg {Number} growMin
12034 * @cfg {Number} growMax
12044 * Ext JS Library 1.1.1
12045 * Copyright(c) 2006-2007, Ext JS, LLC.
12047 * Originally Released Under LGPL - original licence link has changed is not relivant.
12050 * <script type="text/javascript">
12055 * @extends Roo.util.Observable
12056 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12057 * This class also supports single and multi selection modes. <br>
12058 * Create a data model bound view:
12060 var store = new Roo.data.Store(...);
12062 var view = new Roo.View({
12064 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12066 singleSelect: true,
12067 selectedClass: "ydataview-selected",
12071 // listen for node click?
12072 view.on("click", function(vw, index, node, e){
12073 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12077 dataModel.load("foobar.xml");
12079 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12081 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12082 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12084 * Note: old style constructor is still suported (container, template, config)
12087 * Create a new View
12088 * @param {Object} config The config object
12091 Roo.View = function(config, depreciated_tpl, depreciated_config){
12093 this.parent = false;
12095 if (typeof(depreciated_tpl) == 'undefined') {
12096 // new way.. - universal constructor.
12097 Roo.apply(this, config);
12098 this.el = Roo.get(this.el);
12101 this.el = Roo.get(config);
12102 this.tpl = depreciated_tpl;
12103 Roo.apply(this, depreciated_config);
12105 this.wrapEl = this.el.wrap().wrap();
12106 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12109 if(typeof(this.tpl) == "string"){
12110 this.tpl = new Roo.Template(this.tpl);
12112 // support xtype ctors..
12113 this.tpl = new Roo.factory(this.tpl, Roo);
12117 this.tpl.compile();
12122 * @event beforeclick
12123 * Fires before a click is processed. Returns false to cancel the default action.
12124 * @param {Roo.View} this
12125 * @param {Number} index The index of the target node
12126 * @param {HTMLElement} node The target node
12127 * @param {Roo.EventObject} e The raw event object
12129 "beforeclick" : true,
12132 * Fires when a template node is clicked.
12133 * @param {Roo.View} this
12134 * @param {Number} index The index of the target node
12135 * @param {HTMLElement} node The target node
12136 * @param {Roo.EventObject} e The raw event object
12141 * Fires when a template node is double clicked.
12142 * @param {Roo.View} this
12143 * @param {Number} index The index of the target node
12144 * @param {HTMLElement} node The target node
12145 * @param {Roo.EventObject} e The raw event object
12149 * @event contextmenu
12150 * Fires when a template node is right clicked.
12151 * @param {Roo.View} this
12152 * @param {Number} index The index of the target node
12153 * @param {HTMLElement} node The target node
12154 * @param {Roo.EventObject} e The raw event object
12156 "contextmenu" : true,
12158 * @event selectionchange
12159 * Fires when the selected nodes change.
12160 * @param {Roo.View} this
12161 * @param {Array} selections Array of the selected nodes
12163 "selectionchange" : true,
12166 * @event beforeselect
12167 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12168 * @param {Roo.View} this
12169 * @param {HTMLElement} node The node to be selected
12170 * @param {Array} selections Array of currently selected nodes
12172 "beforeselect" : true,
12174 * @event preparedata
12175 * Fires on every row to render, to allow you to change the data.
12176 * @param {Roo.View} this
12177 * @param {Object} data to be rendered (change this)
12179 "preparedata" : true
12187 "click": this.onClick,
12188 "dblclick": this.onDblClick,
12189 "contextmenu": this.onContextMenu,
12193 this.selections = [];
12195 this.cmp = new Roo.CompositeElementLite([]);
12197 this.store = Roo.factory(this.store, Roo.data);
12198 this.setStore(this.store, true);
12201 if ( this.footer && this.footer.xtype) {
12203 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12205 this.footer.dataSource = this.store
12206 this.footer.container = fctr;
12207 this.footer = Roo.factory(this.footer, Roo);
12208 fctr.insertFirst(this.el);
12210 // this is a bit insane - as the paging toolbar seems to detach the el..
12211 // dom.parentNode.parentNode.parentNode
12212 // they get detached?
12216 Roo.View.superclass.constructor.call(this);
12221 Roo.extend(Roo.View, Roo.util.Observable, {
12224 * @cfg {Roo.data.Store} store Data store to load data from.
12229 * @cfg {String|Roo.Element} el The container element.
12234 * @cfg {String|Roo.Template} tpl The template used by this View
12238 * @cfg {String} dataName the named area of the template to use as the data area
12239 * Works with domtemplates roo-name="name"
12243 * @cfg {String} selectedClass The css class to add to selected nodes
12245 selectedClass : "x-view-selected",
12247 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12252 * @cfg {String} text to display on mask (default Loading)
12256 * @cfg {Boolean} multiSelect Allow multiple selection
12258 multiSelect : false,
12260 * @cfg {Boolean} singleSelect Allow single selection
12262 singleSelect: false,
12265 * @cfg {Boolean} toggleSelect - selecting
12267 toggleSelect : false,
12270 * @cfg {Boolean} tickable - selecting
12275 * Returns the element this view is bound to.
12276 * @return {Roo.Element}
12278 getEl : function(){
12279 return this.wrapEl;
12285 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12287 refresh : function(){
12288 Roo.log('refresh');
12291 // if we are using something like 'domtemplate', then
12292 // the what gets used is:
12293 // t.applySubtemplate(NAME, data, wrapping data..)
12294 // the outer template then get' applied with
12295 // the store 'extra data'
12296 // and the body get's added to the
12297 // roo-name="data" node?
12298 // <span class='roo-tpl-{name}'></span> ?????
12302 this.clearSelections();
12303 this.el.update("");
12305 var records = this.store.getRange();
12306 if(records.length < 1) {
12308 // is this valid?? = should it render a template??
12310 this.el.update(this.emptyText);
12314 if (this.dataName) {
12315 this.el.update(t.apply(this.store.meta)); //????
12316 el = this.el.child('.roo-tpl-' + this.dataName);
12319 for(var i = 0, len = records.length; i < len; i++){
12320 var data = this.prepareData(records[i].data, i, records[i]);
12321 this.fireEvent("preparedata", this, data, i, records[i]);
12323 var d = Roo.apply({}, data);
12326 Roo.apply(d, {'roo-id' : Roo.id()});
12330 Roo.each(this.parent.item, function(item){
12331 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12334 Roo.apply(d, {'roo-data-checked' : 'checked'});
12338 html[html.length] = Roo.util.Format.trim(
12340 t.applySubtemplate(this.dataName, d, this.store.meta) :
12347 el.update(html.join(""));
12348 this.nodes = el.dom.childNodes;
12349 this.updateIndexes(0);
12354 * Function to override to reformat the data that is sent to
12355 * the template for each node.
12356 * DEPRICATED - use the preparedata event handler.
12357 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12358 * a JSON object for an UpdateManager bound view).
12360 prepareData : function(data, index, record)
12362 this.fireEvent("preparedata", this, data, index, record);
12366 onUpdate : function(ds, record){
12367 Roo.log('on update');
12368 this.clearSelections();
12369 var index = this.store.indexOf(record);
12370 var n = this.nodes[index];
12371 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12372 n.parentNode.removeChild(n);
12373 this.updateIndexes(index, index);
12379 onAdd : function(ds, records, index)
12381 Roo.log(['on Add', ds, records, index] );
12382 this.clearSelections();
12383 if(this.nodes.length == 0){
12387 var n = this.nodes[index];
12388 for(var i = 0, len = records.length; i < len; i++){
12389 var d = this.prepareData(records[i].data, i, records[i]);
12391 this.tpl.insertBefore(n, d);
12394 this.tpl.append(this.el, d);
12397 this.updateIndexes(index);
12400 onRemove : function(ds, record, index){
12401 Roo.log('onRemove');
12402 this.clearSelections();
12403 var el = this.dataName ?
12404 this.el.child('.roo-tpl-' + this.dataName) :
12407 el.dom.removeChild(this.nodes[index]);
12408 this.updateIndexes(index);
12412 * Refresh an individual node.
12413 * @param {Number} index
12415 refreshNode : function(index){
12416 this.onUpdate(this.store, this.store.getAt(index));
12419 updateIndexes : function(startIndex, endIndex){
12420 var ns = this.nodes;
12421 startIndex = startIndex || 0;
12422 endIndex = endIndex || ns.length - 1;
12423 for(var i = startIndex; i <= endIndex; i++){
12424 ns[i].nodeIndex = i;
12429 * Changes the data store this view uses and refresh the view.
12430 * @param {Store} store
12432 setStore : function(store, initial){
12433 if(!initial && this.store){
12434 this.store.un("datachanged", this.refresh);
12435 this.store.un("add", this.onAdd);
12436 this.store.un("remove", this.onRemove);
12437 this.store.un("update", this.onUpdate);
12438 this.store.un("clear", this.refresh);
12439 this.store.un("beforeload", this.onBeforeLoad);
12440 this.store.un("load", this.onLoad);
12441 this.store.un("loadexception", this.onLoad);
12445 store.on("datachanged", this.refresh, this);
12446 store.on("add", this.onAdd, this);
12447 store.on("remove", this.onRemove, this);
12448 store.on("update", this.onUpdate, this);
12449 store.on("clear", this.refresh, this);
12450 store.on("beforeload", this.onBeforeLoad, this);
12451 store.on("load", this.onLoad, this);
12452 store.on("loadexception", this.onLoad, this);
12460 * onbeforeLoad - masks the loading area.
12463 onBeforeLoad : function(store,opts)
12465 Roo.log('onBeforeLoad');
12467 this.el.update("");
12469 this.el.mask(this.mask ? this.mask : "Loading" );
12471 onLoad : function ()
12478 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12479 * @param {HTMLElement} node
12480 * @return {HTMLElement} The template node
12482 findItemFromChild : function(node){
12483 var el = this.dataName ?
12484 this.el.child('.roo-tpl-' + this.dataName,true) :
12487 if(!node || node.parentNode == el){
12490 var p = node.parentNode;
12491 while(p && p != el){
12492 if(p.parentNode == el){
12501 onClick : function(e){
12502 var item = this.findItemFromChild(e.getTarget());
12504 var index = this.indexOf(item);
12505 if(this.onItemClick(item, index, e) !== false){
12506 this.fireEvent("click", this, index, item, e);
12509 this.clearSelections();
12514 onContextMenu : function(e){
12515 var item = this.findItemFromChild(e.getTarget());
12517 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12522 onDblClick : function(e){
12523 var item = this.findItemFromChild(e.getTarget());
12525 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12529 onItemClick : function(item, index, e)
12531 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12534 if (this.toggleSelect) {
12535 var m = this.isSelected(item) ? 'unselect' : 'select';
12538 _t[m](item, true, false);
12541 if(this.multiSelect || this.singleSelect){
12542 if(this.multiSelect && e.shiftKey && this.lastSelection){
12543 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12545 this.select(item, this.multiSelect && e.ctrlKey);
12546 this.lastSelection = item;
12549 if(!this.tickable){
12550 e.preventDefault();
12558 * Get the number of selected nodes.
12561 getSelectionCount : function(){
12562 return this.selections.length;
12566 * Get the currently selected nodes.
12567 * @return {Array} An array of HTMLElements
12569 getSelectedNodes : function(){
12570 return this.selections;
12574 * Get the indexes of the selected nodes.
12577 getSelectedIndexes : function(){
12578 var indexes = [], s = this.selections;
12579 for(var i = 0, len = s.length; i < len; i++){
12580 indexes.push(s[i].nodeIndex);
12586 * Clear all selections
12587 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12589 clearSelections : function(suppressEvent){
12590 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12591 this.cmp.elements = this.selections;
12592 this.cmp.removeClass(this.selectedClass);
12593 this.selections = [];
12594 if(!suppressEvent){
12595 this.fireEvent("selectionchange", this, this.selections);
12601 * Returns true if the passed node is selected
12602 * @param {HTMLElement/Number} node The node or node index
12603 * @return {Boolean}
12605 isSelected : function(node){
12606 var s = this.selections;
12610 node = this.getNode(node);
12611 return s.indexOf(node) !== -1;
12616 * @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
12617 * @param {Boolean} keepExisting (optional) true to keep existing selections
12618 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12620 select : function(nodeInfo, keepExisting, suppressEvent){
12621 if(nodeInfo instanceof Array){
12623 this.clearSelections(true);
12625 for(var i = 0, len = nodeInfo.length; i < len; i++){
12626 this.select(nodeInfo[i], true, true);
12630 var node = this.getNode(nodeInfo);
12631 if(!node || this.isSelected(node)){
12632 return; // already selected.
12635 this.clearSelections(true);
12638 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12639 Roo.fly(node).addClass(this.selectedClass);
12640 this.selections.push(node);
12641 if(!suppressEvent){
12642 this.fireEvent("selectionchange", this, this.selections);
12650 * @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
12651 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12652 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12654 unselect : function(nodeInfo, keepExisting, suppressEvent)
12656 if(nodeInfo instanceof Array){
12657 Roo.each(this.selections, function(s) {
12658 this.unselect(s, nodeInfo);
12662 var node = this.getNode(nodeInfo);
12663 if(!node || !this.isSelected(node)){
12664 Roo.log("not selected");
12665 return; // not selected.
12669 Roo.each(this.selections, function(s) {
12671 Roo.fly(node).removeClass(this.selectedClass);
12678 this.selections= ns;
12679 this.fireEvent("selectionchange", this, this.selections);
12683 * Gets a template node.
12684 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12685 * @return {HTMLElement} The node or null if it wasn't found
12687 getNode : function(nodeInfo){
12688 if(typeof nodeInfo == "string"){
12689 return document.getElementById(nodeInfo);
12690 }else if(typeof nodeInfo == "number"){
12691 return this.nodes[nodeInfo];
12697 * Gets a range template nodes.
12698 * @param {Number} startIndex
12699 * @param {Number} endIndex
12700 * @return {Array} An array of nodes
12702 getNodes : function(start, end){
12703 var ns = this.nodes;
12704 start = start || 0;
12705 end = typeof end == "undefined" ? ns.length - 1 : end;
12708 for(var i = start; i <= end; i++){
12712 for(var i = start; i >= end; i--){
12720 * Finds the index of the passed node
12721 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12722 * @return {Number} The index of the node or -1
12724 indexOf : function(node){
12725 node = this.getNode(node);
12726 if(typeof node.nodeIndex == "number"){
12727 return node.nodeIndex;
12729 var ns = this.nodes;
12730 for(var i = 0, len = ns.length; i < len; i++){
12741 * based on jquery fullcalendar
12745 Roo.bootstrap = Roo.bootstrap || {};
12747 * @class Roo.bootstrap.Calendar
12748 * @extends Roo.bootstrap.Component
12749 * Bootstrap Calendar class
12750 * @cfg {Boolean} loadMask (true|false) default false
12751 * @cfg {Object} header generate the user specific header of the calendar, default false
12754 * Create a new Container
12755 * @param {Object} config The config object
12760 Roo.bootstrap.Calendar = function(config){
12761 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12765 * Fires when a date is selected
12766 * @param {DatePicker} this
12767 * @param {Date} date The selected date
12771 * @event monthchange
12772 * Fires when the displayed month changes
12773 * @param {DatePicker} this
12774 * @param {Date} date The selected month
12776 'monthchange': true,
12778 * @event evententer
12779 * Fires when mouse over an event
12780 * @param {Calendar} this
12781 * @param {event} Event
12783 'evententer': true,
12785 * @event eventleave
12786 * Fires when the mouse leaves an
12787 * @param {Calendar} this
12790 'eventleave': true,
12792 * @event eventclick
12793 * Fires when the mouse click an
12794 * @param {Calendar} this
12803 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12806 * @cfg {Number} startDay
12807 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12815 getAutoCreate : function(){
12818 var fc_button = function(name, corner, style, content ) {
12819 return Roo.apply({},{
12821 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12823 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12826 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12837 style : 'width:100%',
12844 cls : 'fc-header-left',
12846 fc_button('prev', 'left', 'arrow', '‹' ),
12847 fc_button('next', 'right', 'arrow', '›' ),
12848 { tag: 'span', cls: 'fc-header-space' },
12849 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12857 cls : 'fc-header-center',
12861 cls: 'fc-header-title',
12864 html : 'month / year'
12872 cls : 'fc-header-right',
12874 /* fc_button('month', 'left', '', 'month' ),
12875 fc_button('week', '', '', 'week' ),
12876 fc_button('day', 'right', '', 'day' )
12888 header = this.header;
12891 var cal_heads = function() {
12893 // fixme - handle this.
12895 for (var i =0; i < Date.dayNames.length; i++) {
12896 var d = Date.dayNames[i];
12899 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12900 html : d.substring(0,3)
12904 ret[0].cls += ' fc-first';
12905 ret[6].cls += ' fc-last';
12908 var cal_cell = function(n) {
12911 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12916 cls: 'fc-day-number',
12920 cls: 'fc-day-content',
12924 style: 'position: relative;' // height: 17px;
12936 var cal_rows = function() {
12939 for (var r = 0; r < 6; r++) {
12946 for (var i =0; i < Date.dayNames.length; i++) {
12947 var d = Date.dayNames[i];
12948 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12951 row.cn[0].cls+=' fc-first';
12952 row.cn[0].cn[0].style = 'min-height:90px';
12953 row.cn[6].cls+=' fc-last';
12957 ret[0].cls += ' fc-first';
12958 ret[4].cls += ' fc-prev-last';
12959 ret[5].cls += ' fc-last';
12966 cls: 'fc-border-separate',
12967 style : 'width:100%',
12975 cls : 'fc-first fc-last',
12993 cls : 'fc-content',
12994 style : "position: relative;",
12997 cls : 'fc-view fc-view-month fc-grid',
12998 style : 'position: relative',
12999 unselectable : 'on',
13002 cls : 'fc-event-container',
13003 style : 'position:absolute;z-index:8;top:0;left:0;'
13021 initEvents : function()
13024 throw "can not find store for calendar";
13030 style: "text-align:center",
13034 style: "background-color:white;width:50%;margin:250 auto",
13038 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13049 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13051 var size = this.el.select('.fc-content', true).first().getSize();
13052 this.maskEl.setSize(size.width, size.height);
13053 this.maskEl.enableDisplayMode("block");
13054 if(!this.loadMask){
13055 this.maskEl.hide();
13058 this.store = Roo.factory(this.store, Roo.data);
13059 this.store.on('load', this.onLoad, this);
13060 this.store.on('beforeload', this.onBeforeLoad, this);
13064 this.cells = this.el.select('.fc-day',true);
13065 //Roo.log(this.cells);
13066 this.textNodes = this.el.query('.fc-day-number');
13067 this.cells.addClassOnOver('fc-state-hover');
13069 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13070 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13071 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13072 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13074 this.on('monthchange', this.onMonthChange, this);
13076 this.update(new Date().clearTime());
13079 resize : function() {
13080 var sz = this.el.getSize();
13082 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13083 this.el.select('.fc-day-content div',true).setHeight(34);
13088 showPrevMonth : function(e){
13089 this.update(this.activeDate.add("mo", -1));
13091 showToday : function(e){
13092 this.update(new Date().clearTime());
13095 showNextMonth : function(e){
13096 this.update(this.activeDate.add("mo", 1));
13100 showPrevYear : function(){
13101 this.update(this.activeDate.add("y", -1));
13105 showNextYear : function(){
13106 this.update(this.activeDate.add("y", 1));
13111 update : function(date)
13113 var vd = this.activeDate;
13114 this.activeDate = date;
13115 // if(vd && this.el){
13116 // var t = date.getTime();
13117 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13118 // Roo.log('using add remove');
13120 // this.fireEvent('monthchange', this, date);
13122 // this.cells.removeClass("fc-state-highlight");
13123 // this.cells.each(function(c){
13124 // if(c.dateValue == t){
13125 // c.addClass("fc-state-highlight");
13126 // setTimeout(function(){
13127 // try{c.dom.firstChild.focus();}catch(e){}
13137 var days = date.getDaysInMonth();
13139 var firstOfMonth = date.getFirstDateOfMonth();
13140 var startingPos = firstOfMonth.getDay()-this.startDay;
13142 if(startingPos < this.startDay){
13146 var pm = date.add(Date.MONTH, -1);
13147 var prevStart = pm.getDaysInMonth()-startingPos;
13149 this.cells = this.el.select('.fc-day',true);
13150 this.textNodes = this.el.query('.fc-day-number');
13151 this.cells.addClassOnOver('fc-state-hover');
13153 var cells = this.cells.elements;
13154 var textEls = this.textNodes;
13156 Roo.each(cells, function(cell){
13157 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13160 days += startingPos;
13162 // convert everything to numbers so it's fast
13163 var day = 86400000;
13164 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13167 //Roo.log(prevStart);
13169 var today = new Date().clearTime().getTime();
13170 var sel = date.clearTime().getTime();
13171 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13172 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13173 var ddMatch = this.disabledDatesRE;
13174 var ddText = this.disabledDatesText;
13175 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13176 var ddaysText = this.disabledDaysText;
13177 var format = this.format;
13179 var setCellClass = function(cal, cell){
13183 //Roo.log('set Cell Class');
13185 var t = d.getTime();
13189 cell.dateValue = t;
13191 cell.className += " fc-today";
13192 cell.className += " fc-state-highlight";
13193 cell.title = cal.todayText;
13196 // disable highlight in other month..
13197 //cell.className += " fc-state-highlight";
13202 cell.className = " fc-state-disabled";
13203 cell.title = cal.minText;
13207 cell.className = " fc-state-disabled";
13208 cell.title = cal.maxText;
13212 if(ddays.indexOf(d.getDay()) != -1){
13213 cell.title = ddaysText;
13214 cell.className = " fc-state-disabled";
13217 if(ddMatch && format){
13218 var fvalue = d.dateFormat(format);
13219 if(ddMatch.test(fvalue)){
13220 cell.title = ddText.replace("%0", fvalue);
13221 cell.className = " fc-state-disabled";
13225 if (!cell.initialClassName) {
13226 cell.initialClassName = cell.dom.className;
13229 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13234 for(; i < startingPos; i++) {
13235 textEls[i].innerHTML = (++prevStart);
13236 d.setDate(d.getDate()+1);
13238 cells[i].className = "fc-past fc-other-month";
13239 setCellClass(this, cells[i]);
13244 for(; i < days; i++){
13245 intDay = i - startingPos + 1;
13246 textEls[i].innerHTML = (intDay);
13247 d.setDate(d.getDate()+1);
13249 cells[i].className = ''; // "x-date-active";
13250 setCellClass(this, cells[i]);
13254 for(; i < 42; i++) {
13255 textEls[i].innerHTML = (++extraDays);
13256 d.setDate(d.getDate()+1);
13258 cells[i].className = "fc-future fc-other-month";
13259 setCellClass(this, cells[i]);
13262 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13264 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13266 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13267 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13269 if(totalRows != 6){
13270 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13271 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13274 this.fireEvent('monthchange', this, date);
13278 if(!this.internalRender){
13279 var main = this.el.dom.firstChild;
13280 var w = main.offsetWidth;
13281 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13282 Roo.fly(main).setWidth(w);
13283 this.internalRender = true;
13284 // opera does not respect the auto grow header center column
13285 // then, after it gets a width opera refuses to recalculate
13286 // without a second pass
13287 if(Roo.isOpera && !this.secondPass){
13288 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13289 this.secondPass = true;
13290 this.update.defer(10, this, [date]);
13297 findCell : function(dt) {
13298 dt = dt.clearTime().getTime();
13300 this.cells.each(function(c){
13301 //Roo.log("check " +c.dateValue + '?=' + dt);
13302 if(c.dateValue == dt){
13312 findCells : function(ev) {
13313 var s = ev.start.clone().clearTime().getTime();
13315 var e= ev.end.clone().clearTime().getTime();
13318 this.cells.each(function(c){
13319 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13321 if(c.dateValue > e){
13324 if(c.dateValue < s){
13333 // findBestRow: function(cells)
13337 // for (var i =0 ; i < cells.length;i++) {
13338 // ret = Math.max(cells[i].rows || 0,ret);
13345 addItem : function(ev)
13347 // look for vertical location slot in
13348 var cells = this.findCells(ev);
13350 // ev.row = this.findBestRow(cells);
13352 // work out the location.
13356 for(var i =0; i < cells.length; i++) {
13358 cells[i].row = cells[0].row;
13361 cells[i].row = cells[i].row + 1;
13371 if (crow.start.getY() == cells[i].getY()) {
13373 crow.end = cells[i];
13390 cells[0].events.push(ev);
13392 this.calevents.push(ev);
13395 clearEvents: function() {
13397 if(!this.calevents){
13401 Roo.each(this.cells.elements, function(c){
13407 Roo.each(this.calevents, function(e) {
13408 Roo.each(e.els, function(el) {
13409 el.un('mouseenter' ,this.onEventEnter, this);
13410 el.un('mouseleave' ,this.onEventLeave, this);
13415 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13421 renderEvents: function()
13425 this.cells.each(function(c) {
13434 if(c.row != c.events.length){
13435 r = 4 - (4 - (c.row - c.events.length));
13438 c.events = ev.slice(0, r);
13439 c.more = ev.slice(r);
13441 if(c.more.length && c.more.length == 1){
13442 c.events.push(c.more.pop());
13445 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13449 this.cells.each(function(c) {
13451 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13454 for (var e = 0; e < c.events.length; e++){
13455 var ev = c.events[e];
13456 var rows = ev.rows;
13458 for(var i = 0; i < rows.length; i++) {
13460 // how many rows should it span..
13463 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13464 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13466 unselectable : "on",
13469 cls: 'fc-event-inner',
13473 // cls: 'fc-event-time',
13474 // html : cells.length > 1 ? '' : ev.time
13478 cls: 'fc-event-title',
13479 html : String.format('{0}', ev.title)
13486 cls: 'ui-resizable-handle ui-resizable-e',
13487 html : '  '
13494 cfg.cls += ' fc-event-start';
13496 if ((i+1) == rows.length) {
13497 cfg.cls += ' fc-event-end';
13500 var ctr = _this.el.select('.fc-event-container',true).first();
13501 var cg = ctr.createChild(cfg);
13503 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13504 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13506 var r = (c.more.length) ? 1 : 0;
13507 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13508 cg.setWidth(ebox.right - sbox.x -2);
13510 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13511 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13512 cg.on('click', _this.onEventClick, _this, ev);
13523 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13524 style : 'position: absolute',
13525 unselectable : "on",
13528 cls: 'fc-event-inner',
13532 cls: 'fc-event-title',
13540 cls: 'ui-resizable-handle ui-resizable-e',
13541 html : '  '
13547 var ctr = _this.el.select('.fc-event-container',true).first();
13548 var cg = ctr.createChild(cfg);
13550 var sbox = c.select('.fc-day-content',true).first().getBox();
13551 var ebox = c.select('.fc-day-content',true).first().getBox();
13553 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13554 cg.setWidth(ebox.right - sbox.x -2);
13556 cg.on('click', _this.onMoreEventClick, _this, c.more);
13566 onEventEnter: function (e, el,event,d) {
13567 this.fireEvent('evententer', this, el, event);
13570 onEventLeave: function (e, el,event,d) {
13571 this.fireEvent('eventleave', this, el, event);
13574 onEventClick: function (e, el,event,d) {
13575 this.fireEvent('eventclick', this, el, event);
13578 onMonthChange: function () {
13582 onMoreEventClick: function(e, el, more)
13586 this.calpopover.placement = 'right';
13587 this.calpopover.setTitle('More');
13589 this.calpopover.setContent('');
13591 var ctr = this.calpopover.el.select('.popover-content', true).first();
13593 Roo.each(more, function(m){
13595 cls : 'fc-event-hori fc-event-draggable',
13598 var cg = ctr.createChild(cfg);
13600 cg.on('click', _this.onEventClick, _this, m);
13603 this.calpopover.show(el);
13608 onLoad: function ()
13610 this.calevents = [];
13613 if(this.store.getCount() > 0){
13614 this.store.data.each(function(d){
13617 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13618 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13619 time : d.data.start_time,
13620 title : d.data.title,
13621 description : d.data.description,
13622 venue : d.data.venue
13627 this.renderEvents();
13629 if(this.calevents.length && this.loadMask){
13630 this.maskEl.hide();
13634 onBeforeLoad: function()
13636 this.clearEvents();
13638 this.maskEl.show();
13652 * @class Roo.bootstrap.Popover
13653 * @extends Roo.bootstrap.Component
13654 * Bootstrap Popover class
13655 * @cfg {String} html contents of the popover (or false to use children..)
13656 * @cfg {String} title of popover (or false to hide)
13657 * @cfg {String} placement how it is placed
13658 * @cfg {String} trigger click || hover (or false to trigger manually)
13659 * @cfg {String} over what (parent or false to trigger manually.)
13660 * @cfg {Number} delay - delay before showing
13663 * Create a new Popover
13664 * @param {Object} config The config object
13667 Roo.bootstrap.Popover = function(config){
13668 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13671 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13673 title: 'Fill in a title',
13676 placement : 'right',
13677 trigger : 'hover', // hover
13683 can_build_overlaid : false,
13685 getChildContainer : function()
13687 return this.el.select('.popover-content',true).first();
13690 getAutoCreate : function(){
13691 Roo.log('make popover?');
13693 cls : 'popover roo-dynamic',
13694 style: 'display:block',
13700 cls : 'popover-inner',
13704 cls: 'popover-title',
13708 cls : 'popover-content',
13719 setTitle: function(str)
13721 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13723 setContent: function(str)
13725 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13727 // as it get's added to the bottom of the page.
13728 onRender : function(ct, position)
13730 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13732 var cfg = Roo.apply({}, this.getAutoCreate());
13736 cfg.cls += ' ' + this.cls;
13739 cfg.style = this.style;
13741 Roo.log("adding to ")
13742 this.el = Roo.get(document.body).createChild(cfg, position);
13748 initEvents : function()
13750 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13751 this.el.enableDisplayMode('block');
13753 if (this.over === false) {
13756 if (this.triggers === false) {
13759 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13760 var triggers = this.trigger ? this.trigger.split(' ') : [];
13761 Roo.each(triggers, function(trigger) {
13763 if (trigger == 'click') {
13764 on_el.on('click', this.toggle, this);
13765 } else if (trigger != 'manual') {
13766 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13767 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13769 on_el.on(eventIn ,this.enter, this);
13770 on_el.on(eventOut, this.leave, this);
13781 toggle : function () {
13782 this.hoverState == 'in' ? this.leave() : this.enter();
13785 enter : function () {
13788 clearTimeout(this.timeout);
13790 this.hoverState = 'in'
13792 if (!this.delay || !this.delay.show) {
13797 this.timeout = setTimeout(function () {
13798 if (_t.hoverState == 'in') {
13801 }, this.delay.show)
13803 leave : function() {
13804 clearTimeout(this.timeout);
13806 this.hoverState = 'out'
13808 if (!this.delay || !this.delay.hide) {
13813 this.timeout = setTimeout(function () {
13814 if (_t.hoverState == 'out') {
13817 }, this.delay.hide)
13820 show : function (on_el)
13823 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13826 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13827 if (this.html !== false) {
13828 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13830 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13831 if (!this.title.length) {
13832 this.el.select('.popover-title',true).hide();
13835 var placement = typeof this.placement == 'function' ?
13836 this.placement.call(this, this.el, on_el) :
13839 var autoToken = /\s?auto?\s?/i;
13840 var autoPlace = autoToken.test(placement);
13842 placement = placement.replace(autoToken, '') || 'top';
13846 //this.el.setXY([0,0]);
13848 this.el.dom.style.display='block';
13849 this.el.addClass(placement);
13851 //this.el.appendTo(on_el);
13853 var p = this.getPosition();
13854 var box = this.el.getBox();
13859 var align = Roo.bootstrap.Popover.alignment[placement]
13860 this.el.alignTo(on_el, align[0],align[1]);
13861 //var arrow = this.el.select('.arrow',true).first();
13862 //arrow.set(align[2],
13864 this.el.addClass('in');
13865 this.hoverState = null;
13867 if (this.el.hasClass('fade')) {
13874 this.el.setXY([0,0]);
13875 this.el.removeClass('in');
13882 Roo.bootstrap.Popover.alignment = {
13883 'left' : ['r-l', [-10,0], 'right'],
13884 'right' : ['l-r', [10,0], 'left'],
13885 'bottom' : ['t-b', [0,10], 'top'],
13886 'top' : [ 'b-t', [0,-10], 'bottom']
13897 * @class Roo.bootstrap.Progress
13898 * @extends Roo.bootstrap.Component
13899 * Bootstrap Progress class
13900 * @cfg {Boolean} striped striped of the progress bar
13901 * @cfg {Boolean} active animated of the progress bar
13905 * Create a new Progress
13906 * @param {Object} config The config object
13909 Roo.bootstrap.Progress = function(config){
13910 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13913 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13918 getAutoCreate : function(){
13926 cfg.cls += ' progress-striped';
13930 cfg.cls += ' active';
13949 * @class Roo.bootstrap.ProgressBar
13950 * @extends Roo.bootstrap.Component
13951 * Bootstrap ProgressBar class
13952 * @cfg {Number} aria_valuenow aria-value now
13953 * @cfg {Number} aria_valuemin aria-value min
13954 * @cfg {Number} aria_valuemax aria-value max
13955 * @cfg {String} label label for the progress bar
13956 * @cfg {String} panel (success | info | warning | danger )
13957 * @cfg {String} role role of the progress bar
13958 * @cfg {String} sr_only text
13962 * Create a new ProgressBar
13963 * @param {Object} config The config object
13966 Roo.bootstrap.ProgressBar = function(config){
13967 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13970 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13974 aria_valuemax : 100,
13980 getAutoCreate : function()
13985 cls: 'progress-bar',
13986 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13998 cfg.role = this.role;
14001 if(this.aria_valuenow){
14002 cfg['aria-valuenow'] = this.aria_valuenow;
14005 if(this.aria_valuemin){
14006 cfg['aria-valuemin'] = this.aria_valuemin;
14009 if(this.aria_valuemax){
14010 cfg['aria-valuemax'] = this.aria_valuemax;
14013 if(this.label && !this.sr_only){
14014 cfg.html = this.label;
14018 cfg.cls += ' progress-bar-' + this.panel;
14024 update : function(aria_valuenow)
14026 this.aria_valuenow = aria_valuenow;
14028 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14043 * @class Roo.bootstrap.TabGroup
14044 * @extends Roo.bootstrap.Column
14045 * Bootstrap Column class
14046 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14047 * @cfg {Boolean} carousel true to make the group behave like a carousel
14050 * Create a new TabGroup
14051 * @param {Object} config The config object
14054 Roo.bootstrap.TabGroup = function(config){
14055 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14057 this.navId = Roo.id();
14060 Roo.bootstrap.TabGroup.register(this);
14064 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14067 transition : false,
14069 getAutoCreate : function()
14071 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14073 cfg.cls += ' tab-content';
14075 if (this.carousel) {
14076 cfg.cls += ' carousel slide';
14078 cls : 'carousel-inner'
14085 getChildContainer : function()
14087 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14091 * register a Navigation item
14092 * @param {Roo.bootstrap.NavItem} the navitem to add
14094 register : function(item)
14096 this.tabs.push( item);
14097 item.navId = this.navId; // not really needed..
14101 getActivePanel : function()
14104 Roo.each(this.tabs, function(t) {
14114 getPanelByName : function(n)
14117 Roo.each(this.tabs, function(t) {
14118 if (t.tabId == n) {
14126 indexOfPanel : function(p)
14129 Roo.each(this.tabs, function(t,i) {
14130 if (t.tabId == p.tabId) {
14139 * show a specific panel
14140 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14141 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14143 showPanel : function (pan)
14146 if (typeof(pan) == 'number') {
14147 pan = this.tabs[pan];
14149 if (typeof(pan) == 'string') {
14150 pan = this.getPanelByName(pan);
14152 if (pan.tabId == this.getActivePanel().tabId) {
14155 var cur = this.getActivePanel();
14157 if (false === cur.fireEvent('beforedeactivate')) {
14161 if (this.carousel) {
14162 this.transition = true;
14163 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14164 var lr = dir == 'next' ? 'left' : 'right';
14165 pan.el.addClass(dir); // or prev
14166 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14167 cur.el.addClass(lr); // or right
14168 pan.el.addClass(lr);
14171 cur.el.on('transitionend', function() {
14172 Roo.log("trans end?");
14174 pan.el.removeClass([lr,dir]);
14175 pan.setActive(true);
14177 cur.el.removeClass([lr]);
14178 cur.setActive(false);
14180 _this.transition = false;
14182 }, this, { single: true } );
14186 cur.setActive(false);
14187 pan.setActive(true);
14191 showPanelNext : function()
14193 var i = this.indexOfPanel(this.getActivePanel());
14194 if (i > this.tabs.length) {
14197 this.showPanel(this.tabs[i+1]);
14199 showPanelPrev : function()
14201 var i = this.indexOfPanel(this.getActivePanel());
14205 this.showPanel(this.tabs[i-1]);
14216 Roo.apply(Roo.bootstrap.TabGroup, {
14220 * register a Navigation Group
14221 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14223 register : function(navgrp)
14225 this.groups[navgrp.navId] = navgrp;
14229 * fetch a Navigation Group based on the navigation ID
14230 * if one does not exist , it will get created.
14231 * @param {string} the navgroup to add
14232 * @returns {Roo.bootstrap.NavGroup} the navgroup
14234 get: function(navId) {
14235 if (typeof(this.groups[navId]) == 'undefined') {
14236 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14238 return this.groups[navId] ;
14253 * @class Roo.bootstrap.TabPanel
14254 * @extends Roo.bootstrap.Component
14255 * Bootstrap TabPanel class
14256 * @cfg {Boolean} active panel active
14257 * @cfg {String} html panel content
14258 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14259 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14263 * Create a new TabPanel
14264 * @param {Object} config The config object
14267 Roo.bootstrap.TabPanel = function(config){
14268 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14272 * Fires when the active status changes
14273 * @param {Roo.bootstrap.TabPanel} this
14274 * @param {Boolean} state the new state
14279 * @event beforedeactivate
14280 * Fires before a tab is de-activated - can be used to do validation on a form.
14281 * @param {Roo.bootstrap.TabPanel} this
14282 * @return {Boolean} false if there is an error
14285 'beforedeactivate': true
14288 this.tabId = this.tabId || Roo.id();
14292 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14299 getAutoCreate : function(){
14302 // item is needed for carousel - not sure if it has any effect otherwise
14303 cls: 'tab-pane item',
14304 html: this.html || ''
14308 cfg.cls += ' active';
14312 cfg.tabId = this.tabId;
14319 initEvents: function()
14321 Roo.log('-------- init events on tab panel ---------');
14323 var p = this.parent();
14324 this.navId = this.navId || p.navId;
14326 if (typeof(this.navId) != 'undefined') {
14327 // not really needed.. but just in case.. parent should be a NavGroup.
14328 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14329 Roo.log(['register', tg, this]);
14335 onRender : function(ct, position)
14337 // Roo.log("Call onRender: " + this.xtype);
14339 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14347 setActive: function(state)
14349 Roo.log("panel - set active " + this.tabId + "=" + state);
14351 this.active = state;
14353 this.el.removeClass('active');
14355 } else if (!this.el.hasClass('active')) {
14356 this.el.addClass('active');
14358 this.fireEvent('changed', this, state);
14375 * @class Roo.bootstrap.DateField
14376 * @extends Roo.bootstrap.Input
14377 * Bootstrap DateField class
14378 * @cfg {Number} weekStart default 0
14379 * @cfg {String} viewMode default empty, (months|years)
14380 * @cfg {String} minViewMode default empty, (months|years)
14381 * @cfg {Number} startDate default -Infinity
14382 * @cfg {Number} endDate default Infinity
14383 * @cfg {Boolean} todayHighlight default false
14384 * @cfg {Boolean} todayBtn default false
14385 * @cfg {Boolean} calendarWeeks default false
14386 * @cfg {Object} daysOfWeekDisabled default empty
14387 * @cfg {Boolean} singleMode default false (true | false)
14389 * @cfg {Boolean} keyboardNavigation default true
14390 * @cfg {String} language default en
14393 * Create a new DateField
14394 * @param {Object} config The config object
14397 Roo.bootstrap.DateField = function(config){
14398 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14402 * Fires when this field show.
14403 * @param {Roo.bootstrap.DateField} this
14404 * @param {Mixed} date The date value
14409 * Fires when this field hide.
14410 * @param {Roo.bootstrap.DateField} this
14411 * @param {Mixed} date The date value
14416 * Fires when select a date.
14417 * @param {Roo.bootstrap.DateField} this
14418 * @param {Mixed} date The date value
14424 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14427 * @cfg {String} format
14428 * The default date format string which can be overriden for localization support. The format must be
14429 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14433 * @cfg {String} altFormats
14434 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14435 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14437 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14445 todayHighlight : false,
14451 keyboardNavigation: true,
14453 calendarWeeks: false,
14455 startDate: -Infinity,
14459 daysOfWeekDisabled: [],
14463 singleMode : false,
14465 UTCDate: function()
14467 return new Date(Date.UTC.apply(Date, arguments));
14470 UTCToday: function()
14472 var today = new Date();
14473 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14476 getDate: function() {
14477 var d = this.getUTCDate();
14478 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14481 getUTCDate: function() {
14485 setDate: function(d) {
14486 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14489 setUTCDate: function(d) {
14491 this.setValue(this.formatDate(this.date));
14494 onRender: function(ct, position)
14497 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14499 this.language = this.language || 'en';
14500 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14501 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14503 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14504 this.format = this.format || 'm/d/y';
14505 this.isInline = false;
14506 this.isInput = true;
14507 this.component = this.el.select('.add-on', true).first() || false;
14508 this.component = (this.component && this.component.length === 0) ? false : this.component;
14509 this.hasInput = this.component && this.inputEL().length;
14511 if (typeof(this.minViewMode === 'string')) {
14512 switch (this.minViewMode) {
14514 this.minViewMode = 1;
14517 this.minViewMode = 2;
14520 this.minViewMode = 0;
14525 if (typeof(this.viewMode === 'string')) {
14526 switch (this.viewMode) {
14539 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14541 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14543 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14545 this.picker().on('mousedown', this.onMousedown, this);
14546 this.picker().on('click', this.onClick, this);
14548 this.picker().addClass('datepicker-dropdown');
14550 this.startViewMode = this.viewMode;
14552 if(this.singleMode){
14553 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14554 v.setVisibilityMode(Roo.Element.DISPLAY)
14558 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14559 v.setStyle('width', '189px');
14563 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14564 if(!this.calendarWeeks){
14569 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14570 v.attr('colspan', function(i, val){
14571 return parseInt(val) + 1;
14576 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14578 this.setStartDate(this.startDate);
14579 this.setEndDate(this.endDate);
14581 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14588 if(this.isInline) {
14593 picker : function()
14595 return this.pickerEl;
14596 // return this.el.select('.datepicker', true).first();
14599 fillDow: function()
14601 var dowCnt = this.weekStart;
14610 if(this.calendarWeeks){
14618 while (dowCnt < this.weekStart + 7) {
14622 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14626 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14629 fillMonths: function()
14632 var months = this.picker().select('>.datepicker-months td', true).first();
14634 months.dom.innerHTML = '';
14640 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14643 months.createChild(month);
14650 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;
14652 if (this.date < this.startDate) {
14653 this.viewDate = new Date(this.startDate);
14654 } else if (this.date > this.endDate) {
14655 this.viewDate = new Date(this.endDate);
14657 this.viewDate = new Date(this.date);
14665 var d = new Date(this.viewDate),
14666 year = d.getUTCFullYear(),
14667 month = d.getUTCMonth(),
14668 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14669 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14670 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14671 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14672 currentDate = this.date && this.date.valueOf(),
14673 today = this.UTCToday();
14675 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14677 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14679 // this.picker.select('>tfoot th.today').
14680 // .text(dates[this.language].today)
14681 // .toggle(this.todayBtn !== false);
14683 this.updateNavArrows();
14686 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14688 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14690 prevMonth.setUTCDate(day);
14692 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14694 var nextMonth = new Date(prevMonth);
14696 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14698 nextMonth = nextMonth.valueOf();
14700 var fillMonths = false;
14702 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14704 while(prevMonth.valueOf() < nextMonth) {
14707 if (prevMonth.getUTCDay() === this.weekStart) {
14709 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14717 if(this.calendarWeeks){
14718 // ISO 8601: First week contains first thursday.
14719 // ISO also states week starts on Monday, but we can be more abstract here.
14721 // Start of current week: based on weekstart/current date
14722 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14723 // Thursday of this week
14724 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14725 // First Thursday of year, year from thursday
14726 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14727 // Calendar week: ms between thursdays, div ms per day, div 7 days
14728 calWeek = (th - yth) / 864e5 / 7 + 1;
14730 fillMonths.cn.push({
14738 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14740 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14743 if (this.todayHighlight &&
14744 prevMonth.getUTCFullYear() == today.getFullYear() &&
14745 prevMonth.getUTCMonth() == today.getMonth() &&
14746 prevMonth.getUTCDate() == today.getDate()) {
14747 clsName += ' today';
14750 if (currentDate && prevMonth.valueOf() === currentDate) {
14751 clsName += ' active';
14754 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14755 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14756 clsName += ' disabled';
14759 fillMonths.cn.push({
14761 cls: 'day ' + clsName,
14762 html: prevMonth.getDate()
14765 prevMonth.setDate(prevMonth.getDate()+1);
14768 var currentYear = this.date && this.date.getUTCFullYear();
14769 var currentMonth = this.date && this.date.getUTCMonth();
14771 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14773 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14774 v.removeClass('active');
14776 if(currentYear === year && k === currentMonth){
14777 v.addClass('active');
14780 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14781 v.addClass('disabled');
14787 year = parseInt(year/10, 10) * 10;
14789 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14791 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14794 for (var i = -1; i < 11; i++) {
14795 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14797 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14805 showMode: function(dir)
14808 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14811 Roo.each(this.picker().select('>div',true).elements, function(v){
14812 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14815 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14820 if(this.isInline) return;
14822 this.picker().removeClass(['bottom', 'top']);
14824 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14826 * place to the top of element!
14830 this.picker().addClass('top');
14831 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14836 this.picker().addClass('bottom');
14838 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14841 parseDate : function(value)
14843 if(!value || value instanceof Date){
14846 var v = Date.parseDate(value, this.format);
14847 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
14848 v = Date.parseDate(value, 'Y-m-d');
14850 if(!v && this.altFormats){
14851 if(!this.altFormatsArray){
14852 this.altFormatsArray = this.altFormats.split("|");
14854 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14855 v = Date.parseDate(value, this.altFormatsArray[i]);
14861 formatDate : function(date, fmt)
14863 return (!date || !(date instanceof Date)) ?
14864 date : date.dateFormat(fmt || this.format);
14867 onFocus : function()
14869 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14873 onBlur : function()
14875 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14877 var d = this.inputEl().getValue();
14886 this.picker().show();
14890 this.fireEvent('show', this, this.date);
14895 if(this.isInline) return;
14896 this.picker().hide();
14897 this.viewMode = this.startViewMode;
14900 this.fireEvent('hide', this, this.date);
14904 onMousedown: function(e)
14906 e.stopPropagation();
14907 e.preventDefault();
14912 Roo.bootstrap.DateField.superclass.keyup.call(this);
14916 setValue: function(v)
14919 // v can be a string or a date..
14922 var d = new Date(this.parseDate(v) ).clearTime();
14924 if(isNaN(d.getTime())){
14925 this.date = this.viewDate = '';
14926 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14930 v = this.formatDate(d);
14932 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14934 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14938 this.fireEvent('select', this, this.date);
14942 getValue: function()
14944 return this.formatDate(this.date);
14947 fireKey: function(e)
14949 if (!this.picker().isVisible()){
14950 if (e.keyCode == 27) // allow escape to hide and re-show picker
14955 var dateChanged = false,
14957 newDate, newViewDate;
14962 e.preventDefault();
14966 if (!this.keyboardNavigation) break;
14967 dir = e.keyCode == 37 ? -1 : 1;
14970 newDate = this.moveYear(this.date, dir);
14971 newViewDate = this.moveYear(this.viewDate, dir);
14972 } else if (e.shiftKey){
14973 newDate = this.moveMonth(this.date, dir);
14974 newViewDate = this.moveMonth(this.viewDate, dir);
14976 newDate = new Date(this.date);
14977 newDate.setUTCDate(this.date.getUTCDate() + dir);
14978 newViewDate = new Date(this.viewDate);
14979 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14981 if (this.dateWithinRange(newDate)){
14982 this.date = newDate;
14983 this.viewDate = newViewDate;
14984 this.setValue(this.formatDate(this.date));
14986 e.preventDefault();
14987 dateChanged = true;
14992 if (!this.keyboardNavigation) break;
14993 dir = e.keyCode == 38 ? -1 : 1;
14995 newDate = this.moveYear(this.date, dir);
14996 newViewDate = this.moveYear(this.viewDate, dir);
14997 } else if (e.shiftKey){
14998 newDate = this.moveMonth(this.date, dir);
14999 newViewDate = this.moveMonth(this.viewDate, dir);
15001 newDate = new Date(this.date);
15002 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15003 newViewDate = new Date(this.viewDate);
15004 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15006 if (this.dateWithinRange(newDate)){
15007 this.date = newDate;
15008 this.viewDate = newViewDate;
15009 this.setValue(this.formatDate(this.date));
15011 e.preventDefault();
15012 dateChanged = true;
15016 this.setValue(this.formatDate(this.date));
15018 e.preventDefault();
15021 this.setValue(this.formatDate(this.date));
15035 onClick: function(e)
15037 e.stopPropagation();
15038 e.preventDefault();
15040 var target = e.getTarget();
15042 if(target.nodeName.toLowerCase() === 'i'){
15043 target = Roo.get(target).dom.parentNode;
15046 var nodeName = target.nodeName;
15047 var className = target.className;
15048 var html = target.innerHTML;
15049 //Roo.log(nodeName);
15051 switch(nodeName.toLowerCase()) {
15053 switch(className) {
15059 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15060 switch(this.viewMode){
15062 this.viewDate = this.moveMonth(this.viewDate, dir);
15066 this.viewDate = this.moveYear(this.viewDate, dir);
15072 var date = new Date();
15073 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15075 this.setValue(this.formatDate(this.date));
15082 if (className.indexOf('disabled') < 0) {
15083 this.viewDate.setUTCDate(1);
15084 if (className.indexOf('month') > -1) {
15085 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15087 var year = parseInt(html, 10) || 0;
15088 this.viewDate.setUTCFullYear(year);
15092 if(this.singleMode){
15093 this.setValue(this.formatDate(this.viewDate));
15104 //Roo.log(className);
15105 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15106 var day = parseInt(html, 10) || 1;
15107 var year = this.viewDate.getUTCFullYear(),
15108 month = this.viewDate.getUTCMonth();
15110 if (className.indexOf('old') > -1) {
15117 } else if (className.indexOf('new') > -1) {
15125 //Roo.log([year,month,day]);
15126 this.date = this.UTCDate(year, month, day,0,0,0,0);
15127 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15129 //Roo.log(this.formatDate(this.date));
15130 this.setValue(this.formatDate(this.date));
15137 setStartDate: function(startDate)
15139 this.startDate = startDate || -Infinity;
15140 if (this.startDate !== -Infinity) {
15141 this.startDate = this.parseDate(this.startDate);
15144 this.updateNavArrows();
15147 setEndDate: function(endDate)
15149 this.endDate = endDate || Infinity;
15150 if (this.endDate !== Infinity) {
15151 this.endDate = this.parseDate(this.endDate);
15154 this.updateNavArrows();
15157 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15159 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15160 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15161 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15163 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15164 return parseInt(d, 10);
15167 this.updateNavArrows();
15170 updateNavArrows: function()
15172 if(this.singleMode){
15176 var d = new Date(this.viewDate),
15177 year = d.getUTCFullYear(),
15178 month = d.getUTCMonth();
15180 Roo.each(this.picker().select('.prev', true).elements, function(v){
15182 switch (this.viewMode) {
15185 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15191 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15198 Roo.each(this.picker().select('.next', true).elements, function(v){
15200 switch (this.viewMode) {
15203 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15209 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15217 moveMonth: function(date, dir)
15219 if (!dir) return date;
15220 var new_date = new Date(date.valueOf()),
15221 day = new_date.getUTCDate(),
15222 month = new_date.getUTCMonth(),
15223 mag = Math.abs(dir),
15225 dir = dir > 0 ? 1 : -1;
15228 // If going back one month, make sure month is not current month
15229 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15231 return new_date.getUTCMonth() == month;
15233 // If going forward one month, make sure month is as expected
15234 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15236 return new_date.getUTCMonth() != new_month;
15238 new_month = month + dir;
15239 new_date.setUTCMonth(new_month);
15240 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15241 if (new_month < 0 || new_month > 11)
15242 new_month = (new_month + 12) % 12;
15244 // For magnitudes >1, move one month at a time...
15245 for (var i=0; i<mag; i++)
15246 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15247 new_date = this.moveMonth(new_date, dir);
15248 // ...then reset the day, keeping it in the new month
15249 new_month = new_date.getUTCMonth();
15250 new_date.setUTCDate(day);
15252 return new_month != new_date.getUTCMonth();
15255 // Common date-resetting loop -- if date is beyond end of month, make it
15258 new_date.setUTCDate(--day);
15259 new_date.setUTCMonth(new_month);
15264 moveYear: function(date, dir)
15266 return this.moveMonth(date, dir*12);
15269 dateWithinRange: function(date)
15271 return date >= this.startDate && date <= this.endDate;
15277 this.picker().remove();
15282 Roo.apply(Roo.bootstrap.DateField, {
15293 html: '<i class="fa fa-arrow-left"/>'
15303 html: '<i class="fa fa-arrow-right"/>'
15345 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15346 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15347 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15348 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15349 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15362 navFnc: 'FullYear',
15367 navFnc: 'FullYear',
15372 Roo.apply(Roo.bootstrap.DateField, {
15376 cls: 'datepicker dropdown-menu',
15380 cls: 'datepicker-days',
15384 cls: 'table-condensed',
15386 Roo.bootstrap.DateField.head,
15390 Roo.bootstrap.DateField.footer
15397 cls: 'datepicker-months',
15401 cls: 'table-condensed',
15403 Roo.bootstrap.DateField.head,
15404 Roo.bootstrap.DateField.content,
15405 Roo.bootstrap.DateField.footer
15412 cls: 'datepicker-years',
15416 cls: 'table-condensed',
15418 Roo.bootstrap.DateField.head,
15419 Roo.bootstrap.DateField.content,
15420 Roo.bootstrap.DateField.footer
15439 * @class Roo.bootstrap.TimeField
15440 * @extends Roo.bootstrap.Input
15441 * Bootstrap DateField class
15445 * Create a new TimeField
15446 * @param {Object} config The config object
15449 Roo.bootstrap.TimeField = function(config){
15450 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15454 * Fires when this field show.
15455 * @param {Roo.bootstrap.DateField} this
15456 * @param {Mixed} date The date value
15461 * Fires when this field hide.
15462 * @param {Roo.bootstrap.DateField} this
15463 * @param {Mixed} date The date value
15468 * Fires when select a date.
15469 * @param {Roo.bootstrap.DateField} this
15470 * @param {Mixed} date The date value
15476 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15479 * @cfg {String} format
15480 * The default time format string which can be overriden for localization support. The format must be
15481 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15485 onRender: function(ct, position)
15488 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15490 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15492 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15494 this.pop = this.picker().select('>.datepicker-time',true).first();
15495 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15497 this.picker().on('mousedown', this.onMousedown, this);
15498 this.picker().on('click', this.onClick, this);
15500 this.picker().addClass('datepicker-dropdown');
15505 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15506 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15507 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15508 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15509 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15510 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15514 fireKey: function(e){
15515 if (!this.picker().isVisible()){
15516 if (e.keyCode == 27) // allow escape to hide and re-show picker
15521 e.preventDefault();
15529 this.onTogglePeriod();
15532 this.onIncrementMinutes();
15535 this.onDecrementMinutes();
15544 onClick: function(e) {
15545 e.stopPropagation();
15546 e.preventDefault();
15549 picker : function()
15551 return this.el.select('.datepicker', true).first();
15554 fillTime: function()
15556 var time = this.pop.select('tbody', true).first();
15558 time.dom.innerHTML = '';
15573 cls: 'hours-up glyphicon glyphicon-chevron-up'
15593 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15614 cls: 'timepicker-hour',
15629 cls: 'timepicker-minute',
15644 cls: 'btn btn-primary period',
15666 cls: 'hours-down glyphicon glyphicon-chevron-down'
15686 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15704 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15711 var hours = this.time.getHours();
15712 var minutes = this.time.getMinutes();
15725 hours = hours - 12;
15729 hours = '0' + hours;
15733 minutes = '0' + minutes;
15736 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15737 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15738 this.pop.select('button', true).first().dom.innerHTML = period;
15744 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15746 var cls = ['bottom'];
15748 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15755 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15760 this.picker().addClass(cls.join('-'));
15764 Roo.each(cls, function(c){
15766 _this.picker().setTop(_this.inputEl().getHeight());
15770 _this.picker().setTop(0 - _this.picker().getHeight());
15775 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15779 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15786 onFocus : function()
15788 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15792 onBlur : function()
15794 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15800 this.picker().show();
15805 this.fireEvent('show', this, this.date);
15810 this.picker().hide();
15813 this.fireEvent('hide', this, this.date);
15816 setTime : function()
15819 this.setValue(this.time.format(this.format));
15821 this.fireEvent('select', this, this.date);
15826 onMousedown: function(e){
15827 e.stopPropagation();
15828 e.preventDefault();
15831 onIncrementHours: function()
15833 Roo.log('onIncrementHours');
15834 this.time = this.time.add(Date.HOUR, 1);
15839 onDecrementHours: function()
15841 Roo.log('onDecrementHours');
15842 this.time = this.time.add(Date.HOUR, -1);
15846 onIncrementMinutes: function()
15848 Roo.log('onIncrementMinutes');
15849 this.time = this.time.add(Date.MINUTE, 1);
15853 onDecrementMinutes: function()
15855 Roo.log('onDecrementMinutes');
15856 this.time = this.time.add(Date.MINUTE, -1);
15860 onTogglePeriod: function()
15862 Roo.log('onTogglePeriod');
15863 this.time = this.time.add(Date.HOUR, 12);
15870 Roo.apply(Roo.bootstrap.TimeField, {
15900 cls: 'btn btn-info ok',
15912 Roo.apply(Roo.bootstrap.TimeField, {
15916 cls: 'datepicker dropdown-menu',
15920 cls: 'datepicker-time',
15924 cls: 'table-condensed',
15926 Roo.bootstrap.TimeField.content,
15927 Roo.bootstrap.TimeField.footer
15946 * @class Roo.bootstrap.CheckBox
15947 * @extends Roo.bootstrap.Input
15948 * Bootstrap CheckBox class
15950 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15951 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15952 * @cfg {String} boxLabel The text that appears beside the checkbox
15953 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15954 * @cfg {Boolean} checked initnal the element
15958 * Create a new CheckBox
15959 * @param {Object} config The config object
15962 Roo.bootstrap.CheckBox = function(config){
15963 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15968 * Fires when the element is checked or unchecked.
15969 * @param {Roo.bootstrap.CheckBox} this This input
15970 * @param {Boolean} checked The new checked value
15976 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15978 inputType: 'checkbox',
15985 getAutoCreate : function()
15987 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15993 cfg.cls = 'form-group checkbox' //input-group
16001 type : this.inputType,
16002 value : (!this.checked) ? this.valueOff : this.inputValue,
16003 cls : 'roo-checkbox', //'form-box',
16004 placeholder : this.placeholder || ''
16008 if (this.weight) { // Validity check?
16009 cfg.cls += " checkbox-" + this.weight;
16012 if (this.disabled) {
16013 input.disabled=true;
16017 input.checked = this.checked;
16021 input.name = this.name;
16025 input.cls += ' input-' + this.size;
16029 ['xs','sm','md','lg'].map(function(size){
16030 if (settings[size]) {
16031 cfg.cls += ' col-' + size + '-' + settings[size];
16037 var inputblock = input;
16042 if (this.before || this.after) {
16045 cls : 'input-group',
16049 inputblock.cn.push({
16051 cls : 'input-group-addon',
16055 inputblock.cn.push(input);
16057 inputblock.cn.push({
16059 cls : 'input-group-addon',
16066 if (align ==='left' && this.fieldLabel.length) {
16067 Roo.log("left and has label");
16073 cls : 'control-label col-md-' + this.labelWidth,
16074 html : this.fieldLabel
16078 cls : "col-md-" + (12 - this.labelWidth),
16085 } else if ( this.fieldLabel.length) {
16090 tag: this.boxLabel ? 'span' : 'label',
16092 cls: 'control-label box-input-label',
16093 //cls : 'input-group-addon',
16094 html : this.fieldLabel
16104 Roo.log(" no label && no align");
16105 cfg.cn = [ inputblock ] ;
16114 html: this.boxLabel
16126 * return the real input element.
16128 inputEl: function ()
16130 return this.el.select('input.roo-checkbox',true).first();
16135 return this.el.select('label.control-label',true).first();
16138 initEvents : function()
16140 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16142 this.inputEl().on('click', this.onClick, this);
16146 onClick : function()
16148 this.setChecked(!this.checked);
16151 setChecked : function(state,suppressEvent)
16153 this.checked = state;
16155 this.inputEl().dom.checked = state;
16157 if(suppressEvent !== true){
16158 this.fireEvent('check', this, state);
16161 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16165 setValue : function(v,suppressEvent)
16167 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16181 * @class Roo.bootstrap.Radio
16182 * @extends Roo.bootstrap.CheckBox
16183 * Bootstrap Radio class
16186 * Create a new Radio
16187 * @param {Object} config The config object
16190 Roo.bootstrap.Radio = function(config){
16191 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16195 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16197 inputType: 'radio',
16201 getAutoCreate : function()
16203 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16209 cfg.cls = 'form-group radio' //input-group
16214 type : this.inputType,
16215 value : (!this.checked) ? this.valueOff : this.inputValue,
16217 placeholder : this.placeholder || ''
16220 if (this.weight) { // Validity check?
16221 cfg.cls += " radio-" + this.weight;
16223 if (this.disabled) {
16224 input.disabled=true;
16228 input.checked = this.checked;
16232 input.name = this.name;
16236 input.cls += ' input-' + this.size;
16240 ['xs','sm','md','lg'].map(function(size){
16241 if (settings[size]) {
16242 cfg.cls += ' col-' + size + '-' + settings[size];
16246 var inputblock = input;
16248 if (this.before || this.after) {
16251 cls : 'input-group',
16255 inputblock.cn.push({
16257 cls : 'input-group-addon',
16261 inputblock.cn.push(input);
16263 inputblock.cn.push({
16265 cls : 'input-group-addon',
16272 if (align ==='left' && this.fieldLabel.length) {
16273 Roo.log("left and has label");
16279 cls : 'control-label col-md-' + this.labelWidth,
16280 html : this.fieldLabel
16284 cls : "col-md-" + (12 - this.labelWidth),
16291 } else if ( this.fieldLabel.length) {
16298 cls: 'control-label box-input-label',
16299 //cls : 'input-group-addon',
16300 html : this.fieldLabel
16310 Roo.log(" no label && no align");
16325 html: this.boxLabel
16332 inputEl: function ()
16334 return this.el.select('input.roo-radio',true).first();
16336 onClick : function()
16338 this.setChecked(true);
16341 setChecked : function(state,suppressEvent)
16344 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16345 v.dom.checked = false;
16349 this.checked = state;
16350 this.inputEl().dom.checked = state;
16352 if(suppressEvent !== true){
16353 this.fireEvent('check', this, state);
16356 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16360 getGroupValue : function()
16363 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16364 if(v.dom.checked == true){
16365 value = v.dom.value;
16373 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16374 * @return {Mixed} value The field value
16376 getValue : function(){
16377 return this.getGroupValue();
16383 //<script type="text/javascript">
16386 * Based Ext JS Library 1.1.1
16387 * Copyright(c) 2006-2007, Ext JS, LLC.
16393 * @class Roo.HtmlEditorCore
16394 * @extends Roo.Component
16395 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16397 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16400 Roo.HtmlEditorCore = function(config){
16403 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16408 * @event initialize
16409 * Fires when the editor is fully initialized (including the iframe)
16410 * @param {Roo.HtmlEditorCore} this
16415 * Fires when the editor is first receives the focus. Any insertion must wait
16416 * until after this event.
16417 * @param {Roo.HtmlEditorCore} this
16421 * @event beforesync
16422 * Fires before the textarea is updated with content from the editor iframe. Return false
16423 * to cancel the sync.
16424 * @param {Roo.HtmlEditorCore} this
16425 * @param {String} html
16429 * @event beforepush
16430 * Fires before the iframe editor is updated with content from the textarea. Return false
16431 * to cancel the push.
16432 * @param {Roo.HtmlEditorCore} this
16433 * @param {String} html
16438 * Fires when the textarea is updated with content from the editor iframe.
16439 * @param {Roo.HtmlEditorCore} this
16440 * @param {String} html
16445 * Fires when the iframe editor is updated with content from the textarea.
16446 * @param {Roo.HtmlEditorCore} this
16447 * @param {String} html
16452 * @event editorevent
16453 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16454 * @param {Roo.HtmlEditorCore} this
16459 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16461 // defaults : white / black...
16462 this.applyBlacklists();
16469 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16473 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16479 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16484 * @cfg {Number} height (in pixels)
16488 * @cfg {Number} width (in pixels)
16493 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16496 stylesheets: false,
16501 // private properties
16502 validationEvent : false,
16504 initialized : false,
16506 sourceEditMode : false,
16507 onFocus : Roo.emptyFn,
16509 hideMode:'offsets',
16513 // blacklist + whitelisted elements..
16520 * Protected method that will not generally be called directly. It
16521 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16522 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16524 getDocMarkup : function(){
16527 Roo.log(this.stylesheets);
16529 // inherit styels from page...??
16530 if (this.stylesheets === false) {
16532 Roo.get(document.head).select('style').each(function(node) {
16533 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16536 Roo.get(document.head).select('link').each(function(node) {
16537 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16540 } else if (!this.stylesheets.length) {
16542 st = '<style type="text/css">' +
16543 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16546 Roo.each(this.stylesheets, function(s) {
16547 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16552 st += '<style type="text/css">' +
16553 'IMG { cursor: pointer } ' +
16557 return '<html><head>' + st +
16558 //<style type="text/css">' +
16559 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16561 ' </head><body class="roo-htmleditor-body"></body></html>';
16565 onRender : function(ct, position)
16568 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16569 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16572 this.el.dom.style.border = '0 none';
16573 this.el.dom.setAttribute('tabIndex', -1);
16574 this.el.addClass('x-hidden hide');
16578 if(Roo.isIE){ // fix IE 1px bogus margin
16579 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16583 this.frameId = Roo.id();
16587 var iframe = this.owner.wrap.createChild({
16589 cls: 'form-control', // bootstrap..
16591 name: this.frameId,
16592 frameBorder : 'no',
16593 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16598 this.iframe = iframe.dom;
16600 this.assignDocWin();
16602 this.doc.designMode = 'on';
16605 this.doc.write(this.getDocMarkup());
16609 var task = { // must defer to wait for browser to be ready
16611 //console.log("run task?" + this.doc.readyState);
16612 this.assignDocWin();
16613 if(this.doc.body || this.doc.readyState == 'complete'){
16615 this.doc.designMode="on";
16619 Roo.TaskMgr.stop(task);
16620 this.initEditor.defer(10, this);
16627 Roo.TaskMgr.start(task);
16634 onResize : function(w, h)
16636 Roo.log('resize: ' +w + ',' + h );
16637 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16641 if(typeof w == 'number'){
16643 this.iframe.style.width = w + 'px';
16645 if(typeof h == 'number'){
16647 this.iframe.style.height = h + 'px';
16649 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16656 * Toggles the editor between standard and source edit mode.
16657 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16659 toggleSourceEdit : function(sourceEditMode){
16661 this.sourceEditMode = sourceEditMode === true;
16663 if(this.sourceEditMode){
16665 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16668 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16669 //this.iframe.className = '';
16672 //this.setSize(this.owner.wrap.getSize());
16673 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16680 * Protected method that will not generally be called directly. If you need/want
16681 * custom HTML cleanup, this is the method you should override.
16682 * @param {String} html The HTML to be cleaned
16683 * return {String} The cleaned HTML
16685 cleanHtml : function(html){
16686 html = String(html);
16687 if(html.length > 5){
16688 if(Roo.isSafari){ // strip safari nonsense
16689 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16692 if(html == ' '){
16699 * HTML Editor -> Textarea
16700 * Protected method that will not generally be called directly. Syncs the contents
16701 * of the editor iframe with the textarea.
16703 syncValue : function(){
16704 if(this.initialized){
16705 var bd = (this.doc.body || this.doc.documentElement);
16706 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16707 var html = bd.innerHTML;
16709 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16710 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16712 html = '<div style="'+m[0]+'">' + html + '</div>';
16715 html = this.cleanHtml(html);
16716 // fix up the special chars.. normaly like back quotes in word...
16717 // however we do not want to do this with chinese..
16718 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16719 var cc = b.charCodeAt();
16721 (cc >= 0x4E00 && cc < 0xA000 ) ||
16722 (cc >= 0x3400 && cc < 0x4E00 ) ||
16723 (cc >= 0xf900 && cc < 0xfb00 )
16729 if(this.owner.fireEvent('beforesync', this, html) !== false){
16730 this.el.dom.value = html;
16731 this.owner.fireEvent('sync', this, html);
16737 * Protected method that will not generally be called directly. Pushes the value of the textarea
16738 * into the iframe editor.
16740 pushValue : function(){
16741 if(this.initialized){
16742 var v = this.el.dom.value.trim();
16744 // if(v.length < 1){
16748 if(this.owner.fireEvent('beforepush', this, v) !== false){
16749 var d = (this.doc.body || this.doc.documentElement);
16751 this.cleanUpPaste();
16752 this.el.dom.value = d.innerHTML;
16753 this.owner.fireEvent('push', this, v);
16759 deferFocus : function(){
16760 this.focus.defer(10, this);
16764 focus : function(){
16765 if(this.win && !this.sourceEditMode){
16772 assignDocWin: function()
16774 var iframe = this.iframe;
16777 this.doc = iframe.contentWindow.document;
16778 this.win = iframe.contentWindow;
16780 // if (!Roo.get(this.frameId)) {
16783 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16784 // this.win = Roo.get(this.frameId).dom.contentWindow;
16786 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16790 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16791 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16796 initEditor : function(){
16797 //console.log("INIT EDITOR");
16798 this.assignDocWin();
16802 this.doc.designMode="on";
16804 this.doc.write(this.getDocMarkup());
16807 var dbody = (this.doc.body || this.doc.documentElement);
16808 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16809 // this copies styles from the containing element into thsi one..
16810 // not sure why we need all of this..
16811 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16813 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16814 //ss['background-attachment'] = 'fixed'; // w3c
16815 dbody.bgProperties = 'fixed'; // ie
16816 //Roo.DomHelper.applyStyles(dbody, ss);
16817 Roo.EventManager.on(this.doc, {
16818 //'mousedown': this.onEditorEvent,
16819 'mouseup': this.onEditorEvent,
16820 'dblclick': this.onEditorEvent,
16821 'click': this.onEditorEvent,
16822 'keyup': this.onEditorEvent,
16827 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16829 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16830 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16832 this.initialized = true;
16834 this.owner.fireEvent('initialize', this);
16839 onDestroy : function(){
16845 //for (var i =0; i < this.toolbars.length;i++) {
16846 // // fixme - ask toolbars for heights?
16847 // this.toolbars[i].onDestroy();
16850 //this.wrap.dom.innerHTML = '';
16851 //this.wrap.remove();
16856 onFirstFocus : function(){
16858 this.assignDocWin();
16861 this.activated = true;
16864 if(Roo.isGecko){ // prevent silly gecko errors
16866 var s = this.win.getSelection();
16867 if(!s.focusNode || s.focusNode.nodeType != 3){
16868 var r = s.getRangeAt(0);
16869 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16874 this.execCmd('useCSS', true);
16875 this.execCmd('styleWithCSS', false);
16878 this.owner.fireEvent('activate', this);
16882 adjustFont: function(btn){
16883 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16884 //if(Roo.isSafari){ // safari
16887 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16888 if(Roo.isSafari){ // safari
16889 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16890 v = (v < 10) ? 10 : v;
16891 v = (v > 48) ? 48 : v;
16892 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16897 v = Math.max(1, v+adjust);
16899 this.execCmd('FontSize', v );
16902 onEditorEvent : function(e){
16903 this.owner.fireEvent('editorevent', this, e);
16904 // this.updateToolbar();
16905 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16908 insertTag : function(tg)
16910 // could be a bit smarter... -> wrap the current selected tRoo..
16911 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16913 range = this.createRange(this.getSelection());
16914 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16915 wrappingNode.appendChild(range.extractContents());
16916 range.insertNode(wrappingNode);
16923 this.execCmd("formatblock", tg);
16927 insertText : function(txt)
16931 var range = this.createRange();
16932 range.deleteContents();
16933 //alert(Sender.getAttribute('label'));
16935 range.insertNode(this.doc.createTextNode(txt));
16941 * Executes a Midas editor command on the editor document and performs necessary focus and
16942 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16943 * @param {String} cmd The Midas command
16944 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16946 relayCmd : function(cmd, value){
16948 this.execCmd(cmd, value);
16949 this.owner.fireEvent('editorevent', this);
16950 //this.updateToolbar();
16951 this.owner.deferFocus();
16955 * Executes a Midas editor command directly on the editor document.
16956 * For visual commands, you should use {@link #relayCmd} instead.
16957 * <b>This should only be called after the editor is initialized.</b>
16958 * @param {String} cmd The Midas command
16959 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16961 execCmd : function(cmd, value){
16962 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16969 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16971 * @param {String} text | dom node..
16973 insertAtCursor : function(text)
16978 if(!this.activated){
16984 var r = this.doc.selection.createRange();
16995 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16999 // from jquery ui (MIT licenced)
17001 var win = this.win;
17003 if (win.getSelection && win.getSelection().getRangeAt) {
17004 range = win.getSelection().getRangeAt(0);
17005 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17006 range.insertNode(node);
17007 } else if (win.document.selection && win.document.selection.createRange) {
17008 // no firefox support
17009 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17010 win.document.selection.createRange().pasteHTML(txt);
17012 // no firefox support
17013 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17014 this.execCmd('InsertHTML', txt);
17023 mozKeyPress : function(e){
17025 var c = e.getCharCode(), cmd;
17028 c = String.fromCharCode(c).toLowerCase();
17042 this.cleanUpPaste.defer(100, this);
17050 e.preventDefault();
17058 fixKeys : function(){ // load time branching for fastest keydown performance
17060 return function(e){
17061 var k = e.getKey(), r;
17064 r = this.doc.selection.createRange();
17067 r.pasteHTML('    ');
17074 r = this.doc.selection.createRange();
17076 var target = r.parentElement();
17077 if(!target || target.tagName.toLowerCase() != 'li'){
17079 r.pasteHTML('<br />');
17085 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17086 this.cleanUpPaste.defer(100, this);
17092 }else if(Roo.isOpera){
17093 return function(e){
17094 var k = e.getKey();
17098 this.execCmd('InsertHTML','    ');
17101 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17102 this.cleanUpPaste.defer(100, this);
17107 }else if(Roo.isSafari){
17108 return function(e){
17109 var k = e.getKey();
17113 this.execCmd('InsertText','\t');
17117 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17118 this.cleanUpPaste.defer(100, this);
17126 getAllAncestors: function()
17128 var p = this.getSelectedNode();
17131 a.push(p); // push blank onto stack..
17132 p = this.getParentElement();
17136 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17140 a.push(this.doc.body);
17144 lastSelNode : false,
17147 getSelection : function()
17149 this.assignDocWin();
17150 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17153 getSelectedNode: function()
17155 // this may only work on Gecko!!!
17157 // should we cache this!!!!
17162 var range = this.createRange(this.getSelection()).cloneRange();
17165 var parent = range.parentElement();
17167 var testRange = range.duplicate();
17168 testRange.moveToElementText(parent);
17169 if (testRange.inRange(range)) {
17172 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17175 parent = parent.parentElement;
17180 // is ancestor a text element.
17181 var ac = range.commonAncestorContainer;
17182 if (ac.nodeType == 3) {
17183 ac = ac.parentNode;
17186 var ar = ac.childNodes;
17189 var other_nodes = [];
17190 var has_other_nodes = false;
17191 for (var i=0;i<ar.length;i++) {
17192 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17195 // fullly contained node.
17197 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17202 // probably selected..
17203 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17204 other_nodes.push(ar[i]);
17208 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17213 has_other_nodes = true;
17215 if (!nodes.length && other_nodes.length) {
17216 nodes= other_nodes;
17218 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17224 createRange: function(sel)
17226 // this has strange effects when using with
17227 // top toolbar - not sure if it's a great idea.
17228 //this.editor.contentWindow.focus();
17229 if (typeof sel != "undefined") {
17231 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17233 return this.doc.createRange();
17236 return this.doc.createRange();
17239 getParentElement: function()
17242 this.assignDocWin();
17243 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17245 var range = this.createRange(sel);
17248 var p = range.commonAncestorContainer;
17249 while (p.nodeType == 3) { // text node
17260 * Range intersection.. the hard stuff...
17264 * [ -- selected range --- ]
17268 * if end is before start or hits it. fail.
17269 * if start is after end or hits it fail.
17271 * if either hits (but other is outside. - then it's not
17277 // @see http://www.thismuchiknow.co.uk/?p=64.
17278 rangeIntersectsNode : function(range, node)
17280 var nodeRange = node.ownerDocument.createRange();
17282 nodeRange.selectNode(node);
17284 nodeRange.selectNodeContents(node);
17287 var rangeStartRange = range.cloneRange();
17288 rangeStartRange.collapse(true);
17290 var rangeEndRange = range.cloneRange();
17291 rangeEndRange.collapse(false);
17293 var nodeStartRange = nodeRange.cloneRange();
17294 nodeStartRange.collapse(true);
17296 var nodeEndRange = nodeRange.cloneRange();
17297 nodeEndRange.collapse(false);
17299 return rangeStartRange.compareBoundaryPoints(
17300 Range.START_TO_START, nodeEndRange) == -1 &&
17301 rangeEndRange.compareBoundaryPoints(
17302 Range.START_TO_START, nodeStartRange) == 1;
17306 rangeCompareNode : function(range, node)
17308 var nodeRange = node.ownerDocument.createRange();
17310 nodeRange.selectNode(node);
17312 nodeRange.selectNodeContents(node);
17316 range.collapse(true);
17318 nodeRange.collapse(true);
17320 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17321 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17323 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17325 var nodeIsBefore = ss == 1;
17326 var nodeIsAfter = ee == -1;
17328 if (nodeIsBefore && nodeIsAfter)
17330 if (!nodeIsBefore && nodeIsAfter)
17331 return 1; //right trailed.
17333 if (nodeIsBefore && !nodeIsAfter)
17334 return 2; // left trailed.
17339 // private? - in a new class?
17340 cleanUpPaste : function()
17342 // cleans up the whole document..
17343 Roo.log('cleanuppaste');
17345 this.cleanUpChildren(this.doc.body);
17346 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17347 if (clean != this.doc.body.innerHTML) {
17348 this.doc.body.innerHTML = clean;
17353 cleanWordChars : function(input) {// change the chars to hex code
17354 var he = Roo.HtmlEditorCore;
17356 var output = input;
17357 Roo.each(he.swapCodes, function(sw) {
17358 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17360 output = output.replace(swapper, sw[1]);
17367 cleanUpChildren : function (n)
17369 if (!n.childNodes.length) {
17372 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17373 this.cleanUpChild(n.childNodes[i]);
17380 cleanUpChild : function (node)
17383 //console.log(node);
17384 if (node.nodeName == "#text") {
17385 // clean up silly Windows -- stuff?
17388 if (node.nodeName == "#comment") {
17389 node.parentNode.removeChild(node);
17390 // clean up silly Windows -- stuff?
17393 var lcname = node.tagName.toLowerCase();
17394 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17395 // whitelist of tags..
17397 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17399 node.parentNode.removeChild(node);
17404 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17406 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17407 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17409 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17410 // remove_keep_children = true;
17413 if (remove_keep_children) {
17414 this.cleanUpChildren(node);
17415 // inserts everything just before this node...
17416 while (node.childNodes.length) {
17417 var cn = node.childNodes[0];
17418 node.removeChild(cn);
17419 node.parentNode.insertBefore(cn, node);
17421 node.parentNode.removeChild(node);
17425 if (!node.attributes || !node.attributes.length) {
17426 this.cleanUpChildren(node);
17430 function cleanAttr(n,v)
17433 if (v.match(/^\./) || v.match(/^\//)) {
17436 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17439 if (v.match(/^#/)) {
17442 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17443 node.removeAttribute(n);
17447 var cwhite = this.cwhite;
17448 var cblack = this.cblack;
17450 function cleanStyle(n,v)
17452 if (v.match(/expression/)) { //XSS?? should we even bother..
17453 node.removeAttribute(n);
17457 var parts = v.split(/;/);
17460 Roo.each(parts, function(p) {
17461 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17465 var l = p.split(':').shift().replace(/\s+/g,'');
17466 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17468 if ( cwhite.length && cblack.indexOf(l) > -1) {
17469 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17470 //node.removeAttribute(n);
17474 // only allow 'c whitelisted system attributes'
17475 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17476 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17477 //node.removeAttribute(n);
17487 if (clean.length) {
17488 node.setAttribute(n, clean.join(';'));
17490 node.removeAttribute(n);
17496 for (var i = node.attributes.length-1; i > -1 ; i--) {
17497 var a = node.attributes[i];
17500 if (a.name.toLowerCase().substr(0,2)=='on') {
17501 node.removeAttribute(a.name);
17504 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17505 node.removeAttribute(a.name);
17508 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17509 cleanAttr(a.name,a.value); // fixme..
17512 if (a.name == 'style') {
17513 cleanStyle(a.name,a.value);
17516 /// clean up MS crap..
17517 // tecnically this should be a list of valid class'es..
17520 if (a.name == 'class') {
17521 if (a.value.match(/^Mso/)) {
17522 node.className = '';
17525 if (a.value.match(/body/)) {
17526 node.className = '';
17537 this.cleanUpChildren(node);
17542 * Clean up MS wordisms...
17544 cleanWord : function(node)
17547 var cleanWordChildren = function()
17549 if (!node.childNodes.length) {
17552 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17553 _t.cleanWord(node.childNodes[i]);
17559 this.cleanWord(this.doc.body);
17562 if (node.nodeName == "#text") {
17563 // clean up silly Windows -- stuff?
17566 if (node.nodeName == "#comment") {
17567 node.parentNode.removeChild(node);
17568 // clean up silly Windows -- stuff?
17572 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17573 node.parentNode.removeChild(node);
17577 // remove - but keep children..
17578 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17579 while (node.childNodes.length) {
17580 var cn = node.childNodes[0];
17581 node.removeChild(cn);
17582 node.parentNode.insertBefore(cn, node);
17584 node.parentNode.removeChild(node);
17585 cleanWordChildren();
17589 if (node.className.length) {
17591 var cn = node.className.split(/\W+/);
17593 Roo.each(cn, function(cls) {
17594 if (cls.match(/Mso[a-zA-Z]+/)) {
17599 node.className = cna.length ? cna.join(' ') : '';
17601 node.removeAttribute("class");
17605 if (node.hasAttribute("lang")) {
17606 node.removeAttribute("lang");
17609 if (node.hasAttribute("style")) {
17611 var styles = node.getAttribute("style").split(";");
17613 Roo.each(styles, function(s) {
17614 if (!s.match(/:/)) {
17617 var kv = s.split(":");
17618 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17621 // what ever is left... we allow.
17624 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17625 if (!nstyle.length) {
17626 node.removeAttribute('style');
17630 cleanWordChildren();
17634 domToHTML : function(currentElement, depth, nopadtext) {
17636 depth = depth || 0;
17637 nopadtext = nopadtext || false;
17639 if (!currentElement) {
17640 return this.domToHTML(this.doc.body);
17643 //Roo.log(currentElement);
17645 var allText = false;
17646 var nodeName = currentElement.nodeName;
17647 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17649 if (nodeName == '#text') {
17650 return currentElement.nodeValue;
17655 if (nodeName != 'BODY') {
17658 // Prints the node tagName, such as <A>, <IMG>, etc
17661 for(i = 0; i < currentElement.attributes.length;i++) {
17663 var aname = currentElement.attributes.item(i).name;
17664 if (!currentElement.attributes.item(i).value.length) {
17667 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17670 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17679 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17682 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17687 // Traverse the tree
17689 var currentElementChild = currentElement.childNodes.item(i);
17690 var allText = true;
17691 var innerHTML = '';
17693 while (currentElementChild) {
17694 // Formatting code (indent the tree so it looks nice on the screen)
17695 var nopad = nopadtext;
17696 if (lastnode == 'SPAN') {
17700 if (currentElementChild.nodeName == '#text') {
17701 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17702 if (!nopad && toadd.length > 80) {
17703 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17705 innerHTML += toadd;
17708 currentElementChild = currentElement.childNodes.item(i);
17714 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17716 // Recursively traverse the tree structure of the child node
17717 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17718 lastnode = currentElementChild.nodeName;
17720 currentElementChild=currentElement.childNodes.item(i);
17726 // The remaining code is mostly for formatting the tree
17727 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17732 ret+= "</"+tagName+">";
17738 applyBlacklists : function()
17740 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17741 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17745 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17746 if (b.indexOf(tag) > -1) {
17749 this.white.push(tag);
17753 Roo.each(w, function(tag) {
17754 if (b.indexOf(tag) > -1) {
17757 if (this.white.indexOf(tag) > -1) {
17760 this.white.push(tag);
17765 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17766 if (w.indexOf(tag) > -1) {
17769 this.black.push(tag);
17773 Roo.each(b, function(tag) {
17774 if (w.indexOf(tag) > -1) {
17777 if (this.black.indexOf(tag) > -1) {
17780 this.black.push(tag);
17785 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
17786 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
17790 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17791 if (b.indexOf(tag) > -1) {
17794 this.cwhite.push(tag);
17798 Roo.each(w, function(tag) {
17799 if (b.indexOf(tag) > -1) {
17802 if (this.cwhite.indexOf(tag) > -1) {
17805 this.cwhite.push(tag);
17810 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
17811 if (w.indexOf(tag) > -1) {
17814 this.cblack.push(tag);
17818 Roo.each(b, function(tag) {
17819 if (w.indexOf(tag) > -1) {
17822 if (this.cblack.indexOf(tag) > -1) {
17825 this.cblack.push(tag);
17830 // hide stuff that is not compatible
17844 * @event specialkey
17848 * @cfg {String} fieldClass @hide
17851 * @cfg {String} focusClass @hide
17854 * @cfg {String} autoCreate @hide
17857 * @cfg {String} inputType @hide
17860 * @cfg {String} invalidClass @hide
17863 * @cfg {String} invalidText @hide
17866 * @cfg {String} msgFx @hide
17869 * @cfg {String} validateOnBlur @hide
17873 Roo.HtmlEditorCore.white = [
17874 'area', 'br', 'img', 'input', 'hr', 'wbr',
17876 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17877 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17878 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17879 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17880 'table', 'ul', 'xmp',
17882 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17885 'dir', 'menu', 'ol', 'ul', 'dl',
17891 Roo.HtmlEditorCore.black = [
17892 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17894 'base', 'basefont', 'bgsound', 'blink', 'body',
17895 'frame', 'frameset', 'head', 'html', 'ilayer',
17896 'iframe', 'layer', 'link', 'meta', 'object',
17897 'script', 'style' ,'title', 'xml' // clean later..
17899 Roo.HtmlEditorCore.clean = [
17900 'script', 'style', 'title', 'xml'
17902 Roo.HtmlEditorCore.remove = [
17907 Roo.HtmlEditorCore.ablack = [
17911 Roo.HtmlEditorCore.aclean = [
17912 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17916 Roo.HtmlEditorCore.pwhite= [
17917 'http', 'https', 'mailto'
17920 // white listed style attributes.
17921 Roo.HtmlEditorCore.cwhite= [
17922 // 'text-align', /// default is to allow most things..
17928 // black listed style attributes.
17929 Roo.HtmlEditorCore.cblack= [
17930 // 'font-size' -- this can be set by the project
17934 Roo.HtmlEditorCore.swapCodes =[
17953 * @class Roo.bootstrap.HtmlEditor
17954 * @extends Roo.bootstrap.TextArea
17955 * Bootstrap HtmlEditor class
17958 * Create a new HtmlEditor
17959 * @param {Object} config The config object
17962 Roo.bootstrap.HtmlEditor = function(config){
17963 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17964 if (!this.toolbars) {
17965 this.toolbars = [];
17967 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17970 * @event initialize
17971 * Fires when the editor is fully initialized (including the iframe)
17972 * @param {HtmlEditor} this
17977 * Fires when the editor is first receives the focus. Any insertion must wait
17978 * until after this event.
17979 * @param {HtmlEditor} this
17983 * @event beforesync
17984 * Fires before the textarea is updated with content from the editor iframe. Return false
17985 * to cancel the sync.
17986 * @param {HtmlEditor} this
17987 * @param {String} html
17991 * @event beforepush
17992 * Fires before the iframe editor is updated with content from the textarea. Return false
17993 * to cancel the push.
17994 * @param {HtmlEditor} this
17995 * @param {String} html
18000 * Fires when the textarea is updated with content from the editor iframe.
18001 * @param {HtmlEditor} this
18002 * @param {String} html
18007 * Fires when the iframe editor is updated with content from the textarea.
18008 * @param {HtmlEditor} this
18009 * @param {String} html
18013 * @event editmodechange
18014 * Fires when the editor switches edit modes
18015 * @param {HtmlEditor} this
18016 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18018 editmodechange: true,
18020 * @event editorevent
18021 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18022 * @param {HtmlEditor} this
18026 * @event firstfocus
18027 * Fires when on first focus - needed by toolbars..
18028 * @param {HtmlEditor} this
18033 * Auto save the htmlEditor value as a file into Events
18034 * @param {HtmlEditor} this
18038 * @event savedpreview
18039 * preview the saved version of htmlEditor
18040 * @param {HtmlEditor} this
18047 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18051 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18056 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18061 * @cfg {Number} height (in pixels)
18065 * @cfg {Number} width (in pixels)
18070 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18073 stylesheets: false,
18078 // private properties
18079 validationEvent : false,
18081 initialized : false,
18084 onFocus : Roo.emptyFn,
18086 hideMode:'offsets',
18089 tbContainer : false,
18091 toolbarContainer :function() {
18092 return this.wrap.select('.x-html-editor-tb',true).first();
18096 * Protected method that will not generally be called directly. It
18097 * is called when the editor creates its toolbar. Override this method if you need to
18098 * add custom toolbar buttons.
18099 * @param {HtmlEditor} editor
18101 createToolbar : function(){
18103 Roo.log("create toolbars");
18105 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18106 this.toolbars[0].render(this.toolbarContainer());
18110 // if (!editor.toolbars || !editor.toolbars.length) {
18111 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18114 // for (var i =0 ; i < editor.toolbars.length;i++) {
18115 // editor.toolbars[i] = Roo.factory(
18116 // typeof(editor.toolbars[i]) == 'string' ?
18117 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18118 // Roo.bootstrap.HtmlEditor);
18119 // editor.toolbars[i].init(editor);
18125 onRender : function(ct, position)
18127 // Roo.log("Call onRender: " + this.xtype);
18129 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18131 this.wrap = this.inputEl().wrap({
18132 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18135 this.editorcore.onRender(ct, position);
18137 if (this.resizable) {
18138 this.resizeEl = new Roo.Resizable(this.wrap, {
18142 minHeight : this.height,
18143 height: this.height,
18144 handles : this.resizable,
18147 resize : function(r, w, h) {
18148 _t.onResize(w,h); // -something
18154 this.createToolbar(this);
18157 if(!this.width && this.resizable){
18158 this.setSize(this.wrap.getSize());
18160 if (this.resizeEl) {
18161 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18162 // should trigger onReize..
18168 onResize : function(w, h)
18170 Roo.log('resize: ' +w + ',' + h );
18171 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18175 if(this.inputEl() ){
18176 if(typeof w == 'number'){
18177 var aw = w - this.wrap.getFrameWidth('lr');
18178 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18181 if(typeof h == 'number'){
18182 var tbh = -11; // fixme it needs to tool bar size!
18183 for (var i =0; i < this.toolbars.length;i++) {
18184 // fixme - ask toolbars for heights?
18185 tbh += this.toolbars[i].el.getHeight();
18186 //if (this.toolbars[i].footer) {
18187 // tbh += this.toolbars[i].footer.el.getHeight();
18195 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18196 ah -= 5; // knock a few pixes off for look..
18197 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18201 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18202 this.editorcore.onResize(ew,eh);
18207 * Toggles the editor between standard and source edit mode.
18208 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18210 toggleSourceEdit : function(sourceEditMode)
18212 this.editorcore.toggleSourceEdit(sourceEditMode);
18214 if(this.editorcore.sourceEditMode){
18215 Roo.log('editor - showing textarea');
18218 // Roo.log(this.syncValue());
18220 this.inputEl().removeClass(['hide', 'x-hidden']);
18221 this.inputEl().dom.removeAttribute('tabIndex');
18222 this.inputEl().focus();
18224 Roo.log('editor - hiding textarea');
18226 // Roo.log(this.pushValue());
18229 this.inputEl().addClass(['hide', 'x-hidden']);
18230 this.inputEl().dom.setAttribute('tabIndex', -1);
18231 //this.deferFocus();
18234 if(this.resizable){
18235 this.setSize(this.wrap.getSize());
18238 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18241 // private (for BoxComponent)
18242 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18244 // private (for BoxComponent)
18245 getResizeEl : function(){
18249 // private (for BoxComponent)
18250 getPositionEl : function(){
18255 initEvents : function(){
18256 this.originalValue = this.getValue();
18260 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18263 // markInvalid : Roo.emptyFn,
18265 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18268 // clearInvalid : Roo.emptyFn,
18270 setValue : function(v){
18271 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18272 this.editorcore.pushValue();
18277 deferFocus : function(){
18278 this.focus.defer(10, this);
18282 focus : function(){
18283 this.editorcore.focus();
18289 onDestroy : function(){
18295 for (var i =0; i < this.toolbars.length;i++) {
18296 // fixme - ask toolbars for heights?
18297 this.toolbars[i].onDestroy();
18300 this.wrap.dom.innerHTML = '';
18301 this.wrap.remove();
18306 onFirstFocus : function(){
18307 //Roo.log("onFirstFocus");
18308 this.editorcore.onFirstFocus();
18309 for (var i =0; i < this.toolbars.length;i++) {
18310 this.toolbars[i].onFirstFocus();
18316 syncValue : function()
18318 this.editorcore.syncValue();
18321 pushValue : function()
18323 this.editorcore.pushValue();
18327 // hide stuff that is not compatible
18341 * @event specialkey
18345 * @cfg {String} fieldClass @hide
18348 * @cfg {String} focusClass @hide
18351 * @cfg {String} autoCreate @hide
18354 * @cfg {String} inputType @hide
18357 * @cfg {String} invalidClass @hide
18360 * @cfg {String} invalidText @hide
18363 * @cfg {String} msgFx @hide
18366 * @cfg {String} validateOnBlur @hide
18375 Roo.namespace('Roo.bootstrap.htmleditor');
18377 * @class Roo.bootstrap.HtmlEditorToolbar1
18382 new Roo.bootstrap.HtmlEditor({
18385 new Roo.bootstrap.HtmlEditorToolbar1({
18386 disable : { fonts: 1 , format: 1, ..., ... , ...],
18392 * @cfg {Object} disable List of elements to disable..
18393 * @cfg {Array} btns List of additional buttons.
18397 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18400 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18403 Roo.apply(this, config);
18405 // default disabled, based on 'good practice'..
18406 this.disable = this.disable || {};
18407 Roo.applyIf(this.disable, {
18410 specialElements : true
18412 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18414 this.editor = config.editor;
18415 this.editorcore = config.editor.editorcore;
18417 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18419 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18420 // dont call parent... till later.
18422 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18427 editorcore : false,
18432 "h1","h2","h3","h4","h5","h6",
18434 "abbr", "acronym", "address", "cite", "samp", "var",
18438 onRender : function(ct, position)
18440 // Roo.log("Call onRender: " + this.xtype);
18442 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18444 this.el.dom.style.marginBottom = '0';
18446 var editorcore = this.editorcore;
18447 var editor= this.editor;
18450 var btn = function(id,cmd , toggle, handler){
18452 var event = toggle ? 'toggle' : 'click';
18457 xns: Roo.bootstrap,
18460 enableToggle:toggle !== false,
18462 pressed : toggle ? false : null,
18465 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18466 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18475 xns: Roo.bootstrap,
18476 glyphicon : 'font',
18480 xns: Roo.bootstrap,
18484 Roo.each(this.formats, function(f) {
18485 style.menu.items.push({
18487 xns: Roo.bootstrap,
18488 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18493 editorcore.insertTag(this.tagname);
18500 children.push(style);
18503 btn('bold',false,true);
18504 btn('italic',false,true);
18505 btn('align-left', 'justifyleft',true);
18506 btn('align-center', 'justifycenter',true);
18507 btn('align-right' , 'justifyright',true);
18508 btn('link', false, false, function(btn) {
18509 //Roo.log("create link?");
18510 var url = prompt(this.createLinkText, this.defaultLinkValue);
18511 if(url && url != 'http:/'+'/'){
18512 this.editorcore.relayCmd('createlink', url);
18515 btn('list','insertunorderedlist',true);
18516 btn('pencil', false,true, function(btn){
18519 this.toggleSourceEdit(btn.pressed);
18525 xns: Roo.bootstrap,
18530 xns: Roo.bootstrap,
18535 cog.menu.items.push({
18537 xns: Roo.bootstrap,
18538 html : Clean styles,
18543 editorcore.insertTag(this.tagname);
18552 this.xtype = 'NavSimplebar';
18554 for(var i=0;i< children.length;i++) {
18556 this.buttons.add(this.addxtypeChild(children[i]));
18560 editor.on('editorevent', this.updateToolbar, this);
18562 onBtnClick : function(id)
18564 this.editorcore.relayCmd(id);
18565 this.editorcore.focus();
18569 * Protected method that will not generally be called directly. It triggers
18570 * a toolbar update by reading the markup state of the current selection in the editor.
18572 updateToolbar: function(){
18574 if(!this.editorcore.activated){
18575 this.editor.onFirstFocus(); // is this neeed?
18579 var btns = this.buttons;
18580 var doc = this.editorcore.doc;
18581 btns.get('bold').setActive(doc.queryCommandState('bold'));
18582 btns.get('italic').setActive(doc.queryCommandState('italic'));
18583 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18585 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18586 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18587 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18589 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18590 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18593 var ans = this.editorcore.getAllAncestors();
18594 if (this.formatCombo) {
18597 var store = this.formatCombo.store;
18598 this.formatCombo.setValue("");
18599 for (var i =0; i < ans.length;i++) {
18600 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18602 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18610 // hides menus... - so this cant be on a menu...
18611 Roo.bootstrap.MenuMgr.hideAll();
18613 Roo.bootstrap.MenuMgr.hideAll();
18614 //this.editorsyncValue();
18616 onFirstFocus: function() {
18617 this.buttons.each(function(item){
18621 toggleSourceEdit : function(sourceEditMode){
18624 if(sourceEditMode){
18625 Roo.log("disabling buttons");
18626 this.buttons.each( function(item){
18627 if(item.cmd != 'pencil'){
18633 Roo.log("enabling buttons");
18634 if(this.editorcore.initialized){
18635 this.buttons.each( function(item){
18641 Roo.log("calling toggole on editor");
18642 // tell the editor that it's been pressed..
18643 this.editor.toggleSourceEdit(sourceEditMode);
18653 * @class Roo.bootstrap.Table.AbstractSelectionModel
18654 * @extends Roo.util.Observable
18655 * Abstract base class for grid SelectionModels. It provides the interface that should be
18656 * implemented by descendant classes. This class should not be directly instantiated.
18659 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18660 this.locked = false;
18661 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18665 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18666 /** @ignore Called by the grid automatically. Do not call directly. */
18667 init : function(grid){
18673 * Locks the selections.
18676 this.locked = true;
18680 * Unlocks the selections.
18682 unlock : function(){
18683 this.locked = false;
18687 * Returns true if the selections are locked.
18688 * @return {Boolean}
18690 isLocked : function(){
18691 return this.locked;
18695 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18696 * @class Roo.bootstrap.Table.RowSelectionModel
18697 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18698 * It supports multiple selections and keyboard selection/navigation.
18700 * @param {Object} config
18703 Roo.bootstrap.Table.RowSelectionModel = function(config){
18704 Roo.apply(this, config);
18705 this.selections = new Roo.util.MixedCollection(false, function(o){
18710 this.lastActive = false;
18714 * @event selectionchange
18715 * Fires when the selection changes
18716 * @param {SelectionModel} this
18718 "selectionchange" : true,
18720 * @event afterselectionchange
18721 * Fires after the selection changes (eg. by key press or clicking)
18722 * @param {SelectionModel} this
18724 "afterselectionchange" : true,
18726 * @event beforerowselect
18727 * Fires when a row is selected being selected, return false to cancel.
18728 * @param {SelectionModel} this
18729 * @param {Number} rowIndex The selected index
18730 * @param {Boolean} keepExisting False if other selections will be cleared
18732 "beforerowselect" : true,
18735 * Fires when a row is selected.
18736 * @param {SelectionModel} this
18737 * @param {Number} rowIndex The selected index
18738 * @param {Roo.data.Record} r The record
18740 "rowselect" : true,
18742 * @event rowdeselect
18743 * Fires when a row is deselected.
18744 * @param {SelectionModel} this
18745 * @param {Number} rowIndex The selected index
18747 "rowdeselect" : true
18749 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18750 this.locked = false;
18753 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18755 * @cfg {Boolean} singleSelect
18756 * True to allow selection of only one row at a time (defaults to false)
18758 singleSelect : false,
18761 initEvents : function(){
18763 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18764 this.grid.on("mousedown", this.handleMouseDown, this);
18765 }else{ // allow click to work like normal
18766 this.grid.on("rowclick", this.handleDragableRowClick, this);
18769 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18770 "up" : function(e){
18772 this.selectPrevious(e.shiftKey);
18773 }else if(this.last !== false && this.lastActive !== false){
18774 var last = this.last;
18775 this.selectRange(this.last, this.lastActive-1);
18776 this.grid.getView().focusRow(this.lastActive);
18777 if(last !== false){
18781 this.selectFirstRow();
18783 this.fireEvent("afterselectionchange", this);
18785 "down" : function(e){
18787 this.selectNext(e.shiftKey);
18788 }else if(this.last !== false && this.lastActive !== false){
18789 var last = this.last;
18790 this.selectRange(this.last, this.lastActive+1);
18791 this.grid.getView().focusRow(this.lastActive);
18792 if(last !== false){
18796 this.selectFirstRow();
18798 this.fireEvent("afterselectionchange", this);
18803 var view = this.grid.view;
18804 view.on("refresh", this.onRefresh, this);
18805 view.on("rowupdated", this.onRowUpdated, this);
18806 view.on("rowremoved", this.onRemove, this);
18810 onRefresh : function(){
18811 var ds = this.grid.dataSource, i, v = this.grid.view;
18812 var s = this.selections;
18813 s.each(function(r){
18814 if((i = ds.indexOfId(r.id)) != -1){
18823 onRemove : function(v, index, r){
18824 this.selections.remove(r);
18828 onRowUpdated : function(v, index, r){
18829 if(this.isSelected(r)){
18830 v.onRowSelect(index);
18836 * @param {Array} records The records to select
18837 * @param {Boolean} keepExisting (optional) True to keep existing selections
18839 selectRecords : function(records, keepExisting){
18841 this.clearSelections();
18843 var ds = this.grid.dataSource;
18844 for(var i = 0, len = records.length; i < len; i++){
18845 this.selectRow(ds.indexOf(records[i]), true);
18850 * Gets the number of selected rows.
18853 getCount : function(){
18854 return this.selections.length;
18858 * Selects the first row in the grid.
18860 selectFirstRow : function(){
18865 * Select the last row.
18866 * @param {Boolean} keepExisting (optional) True to keep existing selections
18868 selectLastRow : function(keepExisting){
18869 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18873 * Selects the row immediately following the last selected row.
18874 * @param {Boolean} keepExisting (optional) True to keep existing selections
18876 selectNext : function(keepExisting){
18877 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18878 this.selectRow(this.last+1, keepExisting);
18879 this.grid.getView().focusRow(this.last);
18884 * Selects the row that precedes the last selected row.
18885 * @param {Boolean} keepExisting (optional) True to keep existing selections
18887 selectPrevious : function(keepExisting){
18889 this.selectRow(this.last-1, keepExisting);
18890 this.grid.getView().focusRow(this.last);
18895 * Returns the selected records
18896 * @return {Array} Array of selected records
18898 getSelections : function(){
18899 return [].concat(this.selections.items);
18903 * Returns the first selected record.
18906 getSelected : function(){
18907 return this.selections.itemAt(0);
18912 * Clears all selections.
18914 clearSelections : function(fast){
18915 if(this.locked) return;
18917 var ds = this.grid.dataSource;
18918 var s = this.selections;
18919 s.each(function(r){
18920 this.deselectRow(ds.indexOfId(r.id));
18924 this.selections.clear();
18931 * Selects all rows.
18933 selectAll : function(){
18934 if(this.locked) return;
18935 this.selections.clear();
18936 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18937 this.selectRow(i, true);
18942 * Returns True if there is a selection.
18943 * @return {Boolean}
18945 hasSelection : function(){
18946 return this.selections.length > 0;
18950 * Returns True if the specified row is selected.
18951 * @param {Number/Record} record The record or index of the record to check
18952 * @return {Boolean}
18954 isSelected : function(index){
18955 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18956 return (r && this.selections.key(r.id) ? true : false);
18960 * Returns True if the specified record id is selected.
18961 * @param {String} id The id of record to check
18962 * @return {Boolean}
18964 isIdSelected : function(id){
18965 return (this.selections.key(id) ? true : false);
18969 handleMouseDown : function(e, t){
18970 var view = this.grid.getView(), rowIndex;
18971 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18974 if(e.shiftKey && this.last !== false){
18975 var last = this.last;
18976 this.selectRange(last, rowIndex, e.ctrlKey);
18977 this.last = last; // reset the last
18978 view.focusRow(rowIndex);
18980 var isSelected = this.isSelected(rowIndex);
18981 if(e.button !== 0 && isSelected){
18982 view.focusRow(rowIndex);
18983 }else if(e.ctrlKey && isSelected){
18984 this.deselectRow(rowIndex);
18985 }else if(!isSelected){
18986 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18987 view.focusRow(rowIndex);
18990 this.fireEvent("afterselectionchange", this);
18993 handleDragableRowClick : function(grid, rowIndex, e)
18995 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18996 this.selectRow(rowIndex, false);
18997 grid.view.focusRow(rowIndex);
18998 this.fireEvent("afterselectionchange", this);
19003 * Selects multiple rows.
19004 * @param {Array} rows Array of the indexes of the row to select
19005 * @param {Boolean} keepExisting (optional) True to keep existing selections
19007 selectRows : function(rows, keepExisting){
19009 this.clearSelections();
19011 for(var i = 0, len = rows.length; i < len; i++){
19012 this.selectRow(rows[i], true);
19017 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19018 * @param {Number} startRow The index of the first row in the range
19019 * @param {Number} endRow The index of the last row in the range
19020 * @param {Boolean} keepExisting (optional) True to retain existing selections
19022 selectRange : function(startRow, endRow, keepExisting){
19023 if(this.locked) return;
19025 this.clearSelections();
19027 if(startRow <= endRow){
19028 for(var i = startRow; i <= endRow; i++){
19029 this.selectRow(i, true);
19032 for(var i = startRow; i >= endRow; i--){
19033 this.selectRow(i, true);
19039 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19040 * @param {Number} startRow The index of the first row in the range
19041 * @param {Number} endRow The index of the last row in the range
19043 deselectRange : function(startRow, endRow, preventViewNotify){
19044 if(this.locked) return;
19045 for(var i = startRow; i <= endRow; i++){
19046 this.deselectRow(i, preventViewNotify);
19052 * @param {Number} row The index of the row to select
19053 * @param {Boolean} keepExisting (optional) True to keep existing selections
19055 selectRow : function(index, keepExisting, preventViewNotify){
19056 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19057 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19058 if(!keepExisting || this.singleSelect){
19059 this.clearSelections();
19061 var r = this.grid.dataSource.getAt(index);
19062 this.selections.add(r);
19063 this.last = this.lastActive = index;
19064 if(!preventViewNotify){
19065 this.grid.getView().onRowSelect(index);
19067 this.fireEvent("rowselect", this, index, r);
19068 this.fireEvent("selectionchange", this);
19074 * @param {Number} row The index of the row to deselect
19076 deselectRow : function(index, preventViewNotify){
19077 if(this.locked) return;
19078 if(this.last == index){
19081 if(this.lastActive == index){
19082 this.lastActive = false;
19084 var r = this.grid.dataSource.getAt(index);
19085 this.selections.remove(r);
19086 if(!preventViewNotify){
19087 this.grid.getView().onRowDeselect(index);
19089 this.fireEvent("rowdeselect", this, index);
19090 this.fireEvent("selectionchange", this);
19094 restoreLast : function(){
19096 this.last = this._last;
19101 acceptsNav : function(row, col, cm){
19102 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19106 onEditorKey : function(field, e){
19107 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19112 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19114 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19116 }else if(k == e.ENTER && !e.ctrlKey){
19120 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19122 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19124 }else if(k == e.ESC){
19128 g.startEditing(newCell[0], newCell[1]);
19133 * Ext JS Library 1.1.1
19134 * Copyright(c) 2006-2007, Ext JS, LLC.
19136 * Originally Released Under LGPL - original licence link has changed is not relivant.
19139 * <script type="text/javascript">
19143 * @class Roo.bootstrap.PagingToolbar
19145 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19147 * Create a new PagingToolbar
19148 * @param {Object} config The config object
19150 Roo.bootstrap.PagingToolbar = function(config)
19152 // old args format still supported... - xtype is prefered..
19153 // created from xtype...
19154 var ds = config.dataSource;
19155 this.toolbarItems = [];
19156 if (config.items) {
19157 this.toolbarItems = config.items;
19158 // config.items = [];
19161 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19168 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19172 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19174 * @cfg {Roo.data.Store} dataSource
19175 * The underlying data store providing the paged data
19178 * @cfg {String/HTMLElement/Element} container
19179 * container The id or element that will contain the toolbar
19182 * @cfg {Boolean} displayInfo
19183 * True to display the displayMsg (defaults to false)
19186 * @cfg {Number} pageSize
19187 * The number of records to display per page (defaults to 20)
19191 * @cfg {String} displayMsg
19192 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19194 displayMsg : 'Displaying {0} - {1} of {2}',
19196 * @cfg {String} emptyMsg
19197 * The message to display when no records are found (defaults to "No data to display")
19199 emptyMsg : 'No data to display',
19201 * Customizable piece of the default paging text (defaults to "Page")
19204 beforePageText : "Page",
19206 * Customizable piece of the default paging text (defaults to "of %0")
19209 afterPageText : "of {0}",
19211 * Customizable piece of the default paging text (defaults to "First Page")
19214 firstText : "First Page",
19216 * Customizable piece of the default paging text (defaults to "Previous Page")
19219 prevText : "Previous Page",
19221 * Customizable piece of the default paging text (defaults to "Next Page")
19224 nextText : "Next Page",
19226 * Customizable piece of the default paging text (defaults to "Last Page")
19229 lastText : "Last Page",
19231 * Customizable piece of the default paging text (defaults to "Refresh")
19234 refreshText : "Refresh",
19238 onRender : function(ct, position)
19240 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19241 this.navgroup.parentId = this.id;
19242 this.navgroup.onRender(this.el, null);
19243 // add the buttons to the navgroup
19245 if(this.displayInfo){
19246 Roo.log(this.el.select('ul.navbar-nav',true).first());
19247 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19248 this.displayEl = this.el.select('.x-paging-info', true).first();
19249 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19250 // this.displayEl = navel.el.select('span',true).first();
19256 Roo.each(_this.buttons, function(e){
19257 Roo.factory(e).onRender(_this.el, null);
19261 Roo.each(_this.toolbarItems, function(e) {
19262 _this.navgroup.addItem(e);
19265 this.first = this.navgroup.addItem({
19266 tooltip: this.firstText,
19268 icon : 'fa fa-backward',
19270 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19273 this.prev = this.navgroup.addItem({
19274 tooltip: this.prevText,
19276 icon : 'fa fa-step-backward',
19278 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19280 //this.addSeparator();
19283 var field = this.navgroup.addItem( {
19285 cls : 'x-paging-position',
19287 html : this.beforePageText +
19288 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19289 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19292 this.field = field.el.select('input', true).first();
19293 this.field.on("keydown", this.onPagingKeydown, this);
19294 this.field.on("focus", function(){this.dom.select();});
19297 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19298 //this.field.setHeight(18);
19299 //this.addSeparator();
19300 this.next = this.navgroup.addItem({
19301 tooltip: this.nextText,
19303 html : ' <i class="fa fa-step-forward">',
19305 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19307 this.last = this.navgroup.addItem({
19308 tooltip: this.lastText,
19309 icon : 'fa fa-forward',
19312 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19314 //this.addSeparator();
19315 this.loading = this.navgroup.addItem({
19316 tooltip: this.refreshText,
19317 icon: 'fa fa-refresh',
19319 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19325 updateInfo : function(){
19326 if(this.displayEl){
19327 var count = this.ds.getCount();
19328 var msg = count == 0 ?
19332 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19334 this.displayEl.update(msg);
19339 onLoad : function(ds, r, o){
19340 this.cursor = o.params ? o.params.start : 0;
19341 var d = this.getPageData(),
19345 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19346 this.field.dom.value = ap;
19347 this.first.setDisabled(ap == 1);
19348 this.prev.setDisabled(ap == 1);
19349 this.next.setDisabled(ap == ps);
19350 this.last.setDisabled(ap == ps);
19351 this.loading.enable();
19356 getPageData : function(){
19357 var total = this.ds.getTotalCount();
19360 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19361 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19366 onLoadError : function(){
19367 this.loading.enable();
19371 onPagingKeydown : function(e){
19372 var k = e.getKey();
19373 var d = this.getPageData();
19375 var v = this.field.dom.value, pageNum;
19376 if(!v || isNaN(pageNum = parseInt(v, 10))){
19377 this.field.dom.value = d.activePage;
19380 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19381 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19384 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))
19386 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19387 this.field.dom.value = pageNum;
19388 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19391 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19393 var v = this.field.dom.value, pageNum;
19394 var increment = (e.shiftKey) ? 10 : 1;
19395 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19397 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19398 this.field.dom.value = d.activePage;
19401 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19403 this.field.dom.value = parseInt(v, 10) + increment;
19404 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19405 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19412 beforeLoad : function(){
19414 this.loading.disable();
19419 onClick : function(which){
19426 ds.load({params:{start: 0, limit: this.pageSize}});
19429 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19432 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19435 var total = ds.getTotalCount();
19436 var extra = total % this.pageSize;
19437 var lastStart = extra ? (total - extra) : total-this.pageSize;
19438 ds.load({params:{start: lastStart, limit: this.pageSize}});
19441 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19447 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19448 * @param {Roo.data.Store} store The data store to unbind
19450 unbind : function(ds){
19451 ds.un("beforeload", this.beforeLoad, this);
19452 ds.un("load", this.onLoad, this);
19453 ds.un("loadexception", this.onLoadError, this);
19454 ds.un("remove", this.updateInfo, this);
19455 ds.un("add", this.updateInfo, this);
19456 this.ds = undefined;
19460 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19461 * @param {Roo.data.Store} store The data store to bind
19463 bind : function(ds){
19464 ds.on("beforeload", this.beforeLoad, this);
19465 ds.on("load", this.onLoad, this);
19466 ds.on("loadexception", this.onLoadError, this);
19467 ds.on("remove", this.updateInfo, this);
19468 ds.on("add", this.updateInfo, this);
19479 * @class Roo.bootstrap.MessageBar
19480 * @extends Roo.bootstrap.Component
19481 * Bootstrap MessageBar class
19482 * @cfg {String} html contents of the MessageBar
19483 * @cfg {String} weight (info | success | warning | danger) default info
19484 * @cfg {String} beforeClass insert the bar before the given class
19485 * @cfg {Boolean} closable (true | false) default false
19486 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19489 * Create a new Element
19490 * @param {Object} config The config object
19493 Roo.bootstrap.MessageBar = function(config){
19494 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19497 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19503 beforeClass: 'bootstrap-sticky-wrap',
19505 getAutoCreate : function(){
19509 cls: 'alert alert-dismissable alert-' + this.weight,
19514 html: this.html || ''
19520 cfg.cls += ' alert-messages-fixed';
19534 onRender : function(ct, position)
19536 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19539 var cfg = Roo.apply({}, this.getAutoCreate());
19543 cfg.cls += ' ' + this.cls;
19546 cfg.style = this.style;
19548 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19550 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19553 this.el.select('>button.close').on('click', this.hide, this);
19559 if (!this.rendered) {
19565 this.fireEvent('show', this);
19571 if (!this.rendered) {
19577 this.fireEvent('hide', this);
19580 update : function()
19582 // var e = this.el.dom.firstChild;
19584 // if(this.closable){
19585 // e = e.nextSibling;
19588 // e.data = this.html || '';
19590 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19606 * @class Roo.bootstrap.Graph
19607 * @extends Roo.bootstrap.Component
19608 * Bootstrap Graph class
19612 @cfg {String} graphtype bar | vbar | pie
19613 @cfg {number} g_x coodinator | centre x (pie)
19614 @cfg {number} g_y coodinator | centre y (pie)
19615 @cfg {number} g_r radius (pie)
19616 @cfg {number} g_height height of the chart (respected by all elements in the set)
19617 @cfg {number} g_width width of the chart (respected by all elements in the set)
19618 @cfg {Object} title The title of the chart
19621 -opts (object) options for the chart
19623 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19624 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19626 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.
19627 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19629 o stretch (boolean)
19631 -opts (object) options for the pie
19634 o startAngle (number)
19635 o endAngle (number)
19639 * Create a new Input
19640 * @param {Object} config The config object
19643 Roo.bootstrap.Graph = function(config){
19644 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19650 * The img click event for the img.
19651 * @param {Roo.EventObject} e
19657 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19668 //g_colors: this.colors,
19675 getAutoCreate : function(){
19686 onRender : function(ct,position){
19687 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19688 this.raphael = Raphael(this.el.dom);
19690 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19691 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19692 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19693 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19695 r.text(160, 10, "Single Series Chart").attr(txtattr);
19696 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19697 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19698 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19700 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19701 r.barchart(330, 10, 300, 220, data1);
19702 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19703 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19706 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19707 // r.barchart(30, 30, 560, 250, xdata, {
19708 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19709 // axis : "0 0 1 1",
19710 // axisxlabels : xdata
19711 // //yvalues : cols,
19714 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19716 // this.load(null,xdata,{
19717 // axis : "0 0 1 1",
19718 // axisxlabels : xdata
19723 load : function(graphtype,xdata,opts){
19724 this.raphael.clear();
19726 graphtype = this.graphtype;
19731 var r = this.raphael,
19732 fin = function () {
19733 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19735 fout = function () {
19736 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19738 pfin = function() {
19739 this.sector.stop();
19740 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19743 this.label[0].stop();
19744 this.label[0].attr({ r: 7.5 });
19745 this.label[1].attr({ "font-weight": 800 });
19748 pfout = function() {
19749 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19752 this.label[0].animate({ r: 5 }, 500, "bounce");
19753 this.label[1].attr({ "font-weight": 400 });
19759 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19762 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19765 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19766 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19768 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19775 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19780 setTitle: function(o)
19785 initEvents: function() {
19788 this.el.on('click', this.onClick, this);
19792 onClick : function(e)
19794 Roo.log('img onclick');
19795 this.fireEvent('click', this, e);
19807 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19810 * @class Roo.bootstrap.dash.NumberBox
19811 * @extends Roo.bootstrap.Component
19812 * Bootstrap NumberBox class
19813 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19814 * @cfg {String} headline Box headline
19815 * @cfg {String} content Box content
19816 * @cfg {String} icon Box icon
19817 * @cfg {String} footer Footer text
19818 * @cfg {String} fhref Footer href
19821 * Create a new NumberBox
19822 * @param {Object} config The config object
19826 Roo.bootstrap.dash.NumberBox = function(config){
19827 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19831 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19841 getAutoCreate : function(){
19845 cls : 'small-box bg-' + this.bgcolor,
19853 cls : 'roo-headline',
19854 html : this.headline
19858 cls : 'roo-content',
19859 html : this.content
19873 cls : 'ion ' + this.icon
19882 cls : 'small-box-footer',
19883 href : this.fhref || '#',
19887 cfg.cn.push(footer);
19894 onRender : function(ct,position){
19895 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19902 setHeadline: function (value)
19904 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19907 setFooter: function (value, href)
19909 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19912 this.el.select('a.small-box-footer',true).first().attr('href', href);
19917 setContent: function (value)
19919 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19922 initEvents: function()
19936 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19939 * @class Roo.bootstrap.dash.TabBox
19940 * @extends Roo.bootstrap.Component
19941 * Bootstrap TabBox class
19942 * @cfg {String} title Title of the TabBox
19943 * @cfg {String} icon Icon of the TabBox
19944 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19945 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
19948 * Create a new TabBox
19949 * @param {Object} config The config object
19953 Roo.bootstrap.dash.TabBox = function(config){
19954 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19959 * When a pane is added
19960 * @param {Roo.bootstrap.dash.TabPane} pane
19964 * @event activatepane
19965 * When a pane is activated
19966 * @param {Roo.bootstrap.dash.TabPane} pane
19968 "activatepane" : true
19976 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19981 tabScrollable : false,
19983 getChildContainer : function()
19985 return this.el.select('.tab-content', true).first();
19988 getAutoCreate : function(){
19992 cls: 'pull-left header',
20000 cls: 'fa ' + this.icon
20006 cls: 'nav nav-tabs pull-right',
20012 if(this.tabScrollable){
20019 cls: 'nav nav-tabs pull-right',
20030 cls: 'nav-tabs-custom',
20035 cls: 'tab-content no-padding',
20043 initEvents : function()
20045 //Roo.log('add add pane handler');
20046 this.on('addpane', this.onAddPane, this);
20049 * Updates the box title
20050 * @param {String} html to set the title to.
20052 setTitle : function(value)
20054 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20056 onAddPane : function(pane)
20058 this.panes.push(pane);
20059 //Roo.log('addpane');
20061 // tabs are rendere left to right..
20062 if(!this.showtabs){
20066 var ctr = this.el.select('.nav-tabs', true).first();
20069 var existing = ctr.select('.nav-tab',true);
20070 var qty = existing.getCount();;
20073 var tab = ctr.createChild({
20075 cls : 'nav-tab' + (qty ? '' : ' active'),
20083 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20086 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20088 pane.el.addClass('active');
20093 onTabClick : function(ev,un,ob,pane)
20095 //Roo.log('tab - prev default');
20096 ev.preventDefault();
20099 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20100 pane.tab.addClass('active');
20101 //Roo.log(pane.title);
20102 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20103 // technically we should have a deactivate event.. but maybe add later.
20104 // and it should not de-activate the selected tab...
20105 this.fireEvent('activatepane', pane);
20106 pane.el.addClass('active');
20107 pane.fireEvent('activate');
20112 getActivePane : function()
20115 Roo.each(this.panes, function(p) {
20116 if(p.el.hasClass('active')){
20137 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20139 * @class Roo.bootstrap.TabPane
20140 * @extends Roo.bootstrap.Component
20141 * Bootstrap TabPane class
20142 * @cfg {Boolean} active (false | true) Default false
20143 * @cfg {String} title title of panel
20147 * Create a new TabPane
20148 * @param {Object} config The config object
20151 Roo.bootstrap.dash.TabPane = function(config){
20152 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20158 * When a pane is activated
20159 * @param {Roo.bootstrap.dash.TabPane} pane
20166 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20171 // the tabBox that this is attached to.
20174 getAutoCreate : function()
20182 cfg.cls += ' active';
20187 initEvents : function()
20189 //Roo.log('trigger add pane handler');
20190 this.parent().fireEvent('addpane', this)
20194 * Updates the tab title
20195 * @param {String} html to set the title to.
20197 setTitle: function(str)
20203 this.tab.select('a', true).first().dom.innerHTML = str;
20220 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20223 * @class Roo.bootstrap.menu.Menu
20224 * @extends Roo.bootstrap.Component
20225 * Bootstrap Menu class - container for Menu
20226 * @cfg {String} html Text of the menu
20227 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20228 * @cfg {String} icon Font awesome icon
20229 * @cfg {String} pos Menu align to (top | bottom) default bottom
20233 * Create a new Menu
20234 * @param {Object} config The config object
20238 Roo.bootstrap.menu.Menu = function(config){
20239 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20243 * @event beforeshow
20244 * Fires before this menu is displayed
20245 * @param {Roo.bootstrap.menu.Menu} this
20249 * @event beforehide
20250 * Fires before this menu is hidden
20251 * @param {Roo.bootstrap.menu.Menu} this
20256 * Fires after this menu is displayed
20257 * @param {Roo.bootstrap.menu.Menu} this
20262 * Fires after this menu is hidden
20263 * @param {Roo.bootstrap.menu.Menu} this
20268 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20269 * @param {Roo.bootstrap.menu.Menu} this
20270 * @param {Roo.EventObject} e
20277 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20281 weight : 'default',
20286 getChildContainer : function() {
20287 if(this.isSubMenu){
20291 return this.el.select('ul.dropdown-menu', true).first();
20294 getAutoCreate : function()
20299 cls : 'roo-menu-text',
20307 cls : 'fa ' + this.icon
20318 cls : 'dropdown-button btn btn-' + this.weight,
20323 cls : 'dropdown-toggle btn btn-' + this.weight,
20333 cls : 'dropdown-menu'
20339 if(this.pos == 'top'){
20340 cfg.cls += ' dropup';
20343 if(this.isSubMenu){
20346 cls : 'dropdown-menu'
20353 onRender : function(ct, position)
20355 this.isSubMenu = ct.hasClass('dropdown-submenu');
20357 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20360 initEvents : function()
20362 if(this.isSubMenu){
20366 this.hidden = true;
20368 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20369 this.triggerEl.on('click', this.onTriggerPress, this);
20371 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20372 this.buttonEl.on('click', this.onClick, this);
20378 if(this.isSubMenu){
20382 return this.el.select('ul.dropdown-menu', true).first();
20385 onClick : function(e)
20387 this.fireEvent("click", this, e);
20390 onTriggerPress : function(e)
20392 if (this.isVisible()) {
20399 isVisible : function(){
20400 return !this.hidden;
20405 this.fireEvent("beforeshow", this);
20407 this.hidden = false;
20408 this.el.addClass('open');
20410 Roo.get(document).on("mouseup", this.onMouseUp, this);
20412 this.fireEvent("show", this);
20419 this.fireEvent("beforehide", this);
20421 this.hidden = true;
20422 this.el.removeClass('open');
20424 Roo.get(document).un("mouseup", this.onMouseUp);
20426 this.fireEvent("hide", this);
20429 onMouseUp : function()
20443 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20446 * @class Roo.bootstrap.menu.Item
20447 * @extends Roo.bootstrap.Component
20448 * Bootstrap MenuItem class
20449 * @cfg {Boolean} submenu (true | false) default false
20450 * @cfg {String} html text of the item
20451 * @cfg {String} href the link
20452 * @cfg {Boolean} disable (true | false) default false
20453 * @cfg {Boolean} preventDefault (true | false) default true
20454 * @cfg {String} icon Font awesome icon
20455 * @cfg {String} pos Submenu align to (left | right) default right
20459 * Create a new Item
20460 * @param {Object} config The config object
20464 Roo.bootstrap.menu.Item = function(config){
20465 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20469 * Fires when the mouse is hovering over this menu
20470 * @param {Roo.bootstrap.menu.Item} this
20471 * @param {Roo.EventObject} e
20476 * Fires when the mouse exits this menu
20477 * @param {Roo.bootstrap.menu.Item} this
20478 * @param {Roo.EventObject} e
20484 * The raw click event for the entire grid.
20485 * @param {Roo.EventObject} e
20491 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20496 preventDefault: true,
20501 getAutoCreate : function()
20506 cls : 'roo-menu-item-text',
20514 cls : 'fa ' + this.icon
20523 href : this.href || '#',
20530 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20534 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20536 if(this.pos == 'left'){
20537 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20544 initEvents : function()
20546 this.el.on('mouseover', this.onMouseOver, this);
20547 this.el.on('mouseout', this.onMouseOut, this);
20549 this.el.select('a', true).first().on('click', this.onClick, this);
20553 onClick : function(e)
20555 if(this.preventDefault){
20556 e.preventDefault();
20559 this.fireEvent("click", this, e);
20562 onMouseOver : function(e)
20564 if(this.submenu && this.pos == 'left'){
20565 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20568 this.fireEvent("mouseover", this, e);
20571 onMouseOut : function(e)
20573 this.fireEvent("mouseout", this, e);
20585 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20588 * @class Roo.bootstrap.menu.Separator
20589 * @extends Roo.bootstrap.Component
20590 * Bootstrap Separator class
20593 * Create a new Separator
20594 * @param {Object} config The config object
20598 Roo.bootstrap.menu.Separator = function(config){
20599 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20602 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20604 getAutoCreate : function(){
20625 * @class Roo.bootstrap.Tooltip
20626 * Bootstrap Tooltip class
20627 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20628 * to determine which dom element triggers the tooltip.
20630 * It needs to add support for additional attributes like tooltip-position
20633 * Create a new Toolti
20634 * @param {Object} config The config object
20637 Roo.bootstrap.Tooltip = function(config){
20638 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20641 Roo.apply(Roo.bootstrap.Tooltip, {
20643 * @function init initialize tooltip monitoring.
20647 currentTip : false,
20648 currentRegion : false,
20654 Roo.get(document).on('mouseover', this.enter ,this);
20655 Roo.get(document).on('mouseout', this.leave, this);
20658 this.currentTip = new Roo.bootstrap.Tooltip();
20661 enter : function(ev)
20663 var dom = ev.getTarget();
20664 //Roo.log(['enter',dom]);
20665 var el = Roo.fly(dom);
20666 if (this.currentEl) {
20668 //Roo.log(this.currentEl);
20669 //Roo.log(this.currentEl.contains(dom));
20670 if (this.currentEl == el) {
20673 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20681 if (this.currentTip.el) {
20682 this.currentTip.el.hide(); // force hiding...
20685 if (!el.attr('tooltip')) { // parents who have tip?
20688 this.currentEl = el;
20689 this.currentTip.bind(el);
20690 this.currentRegion = Roo.lib.Region.getRegion(dom);
20691 this.currentTip.enter();
20694 leave : function(ev)
20696 var dom = ev.getTarget();
20697 //Roo.log(['leave',dom]);
20698 if (!this.currentEl) {
20703 if (dom != this.currentEl.dom) {
20706 var xy = ev.getXY();
20707 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
20710 // only activate leave if mouse cursor is outside... bounding box..
20715 if (this.currentTip) {
20716 this.currentTip.leave();
20718 //Roo.log('clear currentEl');
20719 this.currentEl = false;
20724 'left' : ['r-l', [-2,0], 'right'],
20725 'right' : ['l-r', [2,0], 'left'],
20726 'bottom' : ['t-b', [0,2], 'top'],
20727 'top' : [ 'b-t', [0,-2], 'bottom']
20733 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
20738 delay : null, // can be { show : 300 , hide: 500}
20742 hoverState : null, //???
20744 placement : 'bottom',
20746 getAutoCreate : function(){
20753 cls : 'tooltip-arrow'
20756 cls : 'tooltip-inner'
20763 bind : function(el)
20769 enter : function () {
20771 if (this.timeout != null) {
20772 clearTimeout(this.timeout);
20775 this.hoverState = 'in'
20776 //Roo.log("enter - show");
20777 if (!this.delay || !this.delay.show) {
20782 this.timeout = setTimeout(function () {
20783 if (_t.hoverState == 'in') {
20786 }, this.delay.show);
20790 clearTimeout(this.timeout);
20792 this.hoverState = 'out'
20793 if (!this.delay || !this.delay.hide) {
20799 this.timeout = setTimeout(function () {
20800 //Roo.log("leave - timeout");
20802 if (_t.hoverState == 'out') {
20804 Roo.bootstrap.Tooltip.currentEl = false;
20812 this.render(document.body);
20815 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
20816 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
20818 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
20820 var placement = typeof this.placement == 'function' ?
20821 this.placement.call(this, this.el, on_el) :
20824 var autoToken = /\s?auto?\s?/i;
20825 var autoPlace = autoToken.test(placement);
20827 placement = placement.replace(autoToken, '') || 'top';
20831 //this.el.setXY([0,0]);
20833 //this.el.dom.style.display='block';
20834 this.el.addClass(placement);
20836 //this.el.appendTo(on_el);
20838 var p = this.getPosition();
20839 var box = this.el.getBox();
20844 var align = Roo.bootstrap.Tooltip.alignment[placement]
20845 this.el.alignTo(this.bindEl, align[0],align[1]);
20846 //var arrow = this.el.select('.arrow',true).first();
20847 //arrow.set(align[2],
20849 this.el.addClass('in fade');
20850 this.hoverState = null;
20852 if (this.el.hasClass('fade')) {
20863 //this.el.setXY([0,0]);
20864 this.el.removeClass('in');