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 {Number} weekStart default 0
14380 * @cfg {Number} viewMode default empty, (months|years)
14381 * @cfg {Number} minViewMode default empty, (months|years)
14382 * @cfg {Number} startDate default -Infinity
14383 * @cfg {Number} endDate default Infinity
14384 * @cfg {Boolean} todayHighlight default false
14385 * @cfg {Boolean} todayBtn default false
14386 * @cfg {Boolean} calendarWeeks default false
14387 * @cfg {Object} daysOfWeekDisabled default empty
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 UTCDate: function()
14465 return new Date(Date.UTC.apply(Date, arguments));
14468 UTCToday: function()
14470 var today = new Date();
14471 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14474 getDate: function() {
14475 var d = this.getUTCDate();
14476 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14479 getUTCDate: function() {
14483 setDate: function(d) {
14484 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14487 setUTCDate: function(d) {
14489 this.setValue(this.formatDate(this.date));
14492 onRender: function(ct, position)
14495 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14497 this.language = this.language || 'en';
14498 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14499 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14501 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14502 this.format = this.format || 'm/d/y';
14503 this.isInline = false;
14504 this.isInput = true;
14505 this.component = this.el.select('.add-on', true).first() || false;
14506 this.component = (this.component && this.component.length === 0) ? false : this.component;
14507 this.hasInput = this.component && this.inputEL().length;
14509 if (typeof(this.minViewMode === 'string')) {
14510 switch (this.minViewMode) {
14512 this.minViewMode = 1;
14515 this.minViewMode = 2;
14518 this.minViewMode = 0;
14523 if (typeof(this.viewMode === 'string')) {
14524 switch (this.viewMode) {
14537 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14539 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14541 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14543 this.picker().on('mousedown', this.onMousedown, this);
14544 this.picker().on('click', this.onClick, this);
14546 this.picker().addClass('datepicker-dropdown');
14548 this.startViewMode = this.viewMode;
14551 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14552 if(!this.calendarWeeks){
14557 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14558 v.attr('colspan', function(i, val){
14559 return parseInt(val) + 1;
14564 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14566 this.setStartDate(this.startDate);
14567 this.setEndDate(this.endDate);
14569 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14576 if(this.isInline) {
14581 picker : function()
14583 return this.pickerEl;
14584 // return this.el.select('.datepicker', true).first();
14587 fillDow: function()
14589 var dowCnt = this.weekStart;
14598 if(this.calendarWeeks){
14606 while (dowCnt < this.weekStart + 7) {
14610 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14614 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14617 fillMonths: function()
14620 var months = this.picker().select('>.datepicker-months td', true).first();
14622 months.dom.innerHTML = '';
14628 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14631 months.createChild(month);
14638 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;
14640 if (this.date < this.startDate) {
14641 this.viewDate = new Date(this.startDate);
14642 } else if (this.date > this.endDate) {
14643 this.viewDate = new Date(this.endDate);
14645 this.viewDate = new Date(this.date);
14653 var d = new Date(this.viewDate),
14654 year = d.getUTCFullYear(),
14655 month = d.getUTCMonth(),
14656 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14657 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14658 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14659 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14660 currentDate = this.date && this.date.valueOf(),
14661 today = this.UTCToday();
14663 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14665 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14667 // this.picker.select('>tfoot th.today').
14668 // .text(dates[this.language].today)
14669 // .toggle(this.todayBtn !== false);
14671 this.updateNavArrows();
14674 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14676 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14678 prevMonth.setUTCDate(day);
14680 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14682 var nextMonth = new Date(prevMonth);
14684 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14686 nextMonth = nextMonth.valueOf();
14688 var fillMonths = false;
14690 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14692 while(prevMonth.valueOf() < nextMonth) {
14695 if (prevMonth.getUTCDay() === this.weekStart) {
14697 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14705 if(this.calendarWeeks){
14706 // ISO 8601: First week contains first thursday.
14707 // ISO also states week starts on Monday, but we can be more abstract here.
14709 // Start of current week: based on weekstart/current date
14710 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14711 // Thursday of this week
14712 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14713 // First Thursday of year, year from thursday
14714 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14715 // Calendar week: ms between thursdays, div ms per day, div 7 days
14716 calWeek = (th - yth) / 864e5 / 7 + 1;
14718 fillMonths.cn.push({
14726 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14728 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14731 if (this.todayHighlight &&
14732 prevMonth.getUTCFullYear() == today.getFullYear() &&
14733 prevMonth.getUTCMonth() == today.getMonth() &&
14734 prevMonth.getUTCDate() == today.getDate()) {
14735 clsName += ' today';
14738 if (currentDate && prevMonth.valueOf() === currentDate) {
14739 clsName += ' active';
14742 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14743 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14744 clsName += ' disabled';
14747 fillMonths.cn.push({
14749 cls: 'day ' + clsName,
14750 html: prevMonth.getDate()
14753 prevMonth.setDate(prevMonth.getDate()+1);
14756 var currentYear = this.date && this.date.getUTCFullYear();
14757 var currentMonth = this.date && this.date.getUTCMonth();
14759 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14761 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14762 v.removeClass('active');
14764 if(currentYear === year && k === currentMonth){
14765 v.addClass('active');
14768 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14769 v.addClass('disabled');
14775 year = parseInt(year/10, 10) * 10;
14777 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14779 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14782 for (var i = -1; i < 11; i++) {
14783 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14785 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14793 showMode: function(dir)
14796 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14798 Roo.each(this.picker().select('>div',true).elements, function(v){
14799 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14802 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14807 if(this.isInline) return;
14809 this.picker().removeClass(['bottom', 'top']);
14811 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14813 * place to the top of element!
14817 this.picker().addClass('top');
14818 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14823 this.picker().addClass('bottom');
14825 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14828 parseDate : function(value)
14830 if(!value || value instanceof Date){
14833 var v = Date.parseDate(value, this.format);
14834 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
14835 v = Date.parseDate(value, 'Y-m-d');
14837 if(!v && this.altFormats){
14838 if(!this.altFormatsArray){
14839 this.altFormatsArray = this.altFormats.split("|");
14841 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14842 v = Date.parseDate(value, this.altFormatsArray[i]);
14848 formatDate : function(date, fmt)
14850 return (!date || !(date instanceof Date)) ?
14851 date : date.dateFormat(fmt || this.format);
14854 onFocus : function()
14856 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14860 onBlur : function()
14862 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14864 var d = this.inputEl().getValue();
14873 this.picker().show();
14877 this.fireEvent('show', this, this.date);
14882 if(this.isInline) return;
14883 this.picker().hide();
14884 this.viewMode = this.startViewMode;
14887 this.fireEvent('hide', this, this.date);
14891 onMousedown: function(e)
14893 e.stopPropagation();
14894 e.preventDefault();
14899 Roo.bootstrap.DateField.superclass.keyup.call(this);
14903 setValue: function(v)
14906 // v can be a string or a date..
14909 var d = new Date(this.parseDate(v) ).clearTime();
14913 if(isNaN(d.getTime())){
14914 this.date = this.viewDate = '';
14915 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14919 v = this.formatDate(d);
14921 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14923 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14927 this.fireEvent('select', this, this.date);
14931 getValue: function()
14933 return this.formatDate(this.date);
14936 fireKey: function(e)
14938 if (!this.picker().isVisible()){
14939 if (e.keyCode == 27) // allow escape to hide and re-show picker
14944 var dateChanged = false,
14946 newDate, newViewDate;
14951 e.preventDefault();
14955 if (!this.keyboardNavigation) break;
14956 dir = e.keyCode == 37 ? -1 : 1;
14959 newDate = this.moveYear(this.date, dir);
14960 newViewDate = this.moveYear(this.viewDate, dir);
14961 } else if (e.shiftKey){
14962 newDate = this.moveMonth(this.date, dir);
14963 newViewDate = this.moveMonth(this.viewDate, dir);
14965 newDate = new Date(this.date);
14966 newDate.setUTCDate(this.date.getUTCDate() + dir);
14967 newViewDate = new Date(this.viewDate);
14968 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14970 if (this.dateWithinRange(newDate)){
14971 this.date = newDate;
14972 this.viewDate = newViewDate;
14973 this.setValue(this.formatDate(this.date));
14975 e.preventDefault();
14976 dateChanged = true;
14981 if (!this.keyboardNavigation) break;
14982 dir = e.keyCode == 38 ? -1 : 1;
14984 newDate = this.moveYear(this.date, dir);
14985 newViewDate = this.moveYear(this.viewDate, dir);
14986 } else if (e.shiftKey){
14987 newDate = this.moveMonth(this.date, dir);
14988 newViewDate = this.moveMonth(this.viewDate, dir);
14990 newDate = new Date(this.date);
14991 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14992 newViewDate = new Date(this.viewDate);
14993 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14995 if (this.dateWithinRange(newDate)){
14996 this.date = newDate;
14997 this.viewDate = newViewDate;
14998 this.setValue(this.formatDate(this.date));
15000 e.preventDefault();
15001 dateChanged = true;
15005 this.setValue(this.formatDate(this.date));
15007 e.preventDefault();
15010 this.setValue(this.formatDate(this.date));
15024 onClick: function(e)
15026 e.stopPropagation();
15027 e.preventDefault();
15029 var target = e.getTarget();
15031 if(target.nodeName.toLowerCase() === 'i'){
15032 target = Roo.get(target).dom.parentNode;
15035 var nodeName = target.nodeName;
15036 var className = target.className;
15037 var html = target.innerHTML;
15038 //Roo.log(nodeName);
15040 switch(nodeName.toLowerCase()) {
15042 switch(className) {
15048 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15049 switch(this.viewMode){
15051 this.viewDate = this.moveMonth(this.viewDate, dir);
15055 this.viewDate = this.moveYear(this.viewDate, dir);
15061 var date = new Date();
15062 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15064 this.setValue(this.formatDate(this.date));
15071 if (className.indexOf('disabled') < 0) {
15072 this.viewDate.setUTCDate(1);
15073 if (className.indexOf('month') > -1) {
15074 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15076 var year = parseInt(html, 10) || 0;
15077 this.viewDate.setUTCFullYear(year);
15086 //Roo.log(className);
15087 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15088 var day = parseInt(html, 10) || 1;
15089 var year = this.viewDate.getUTCFullYear(),
15090 month = this.viewDate.getUTCMonth();
15092 if (className.indexOf('old') > -1) {
15099 } else if (className.indexOf('new') > -1) {
15107 //Roo.log([year,month,day]);
15108 this.date = this.UTCDate(year, month, day,0,0,0,0);
15109 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15111 //Roo.log(this.formatDate(this.date));
15112 this.setValue(this.formatDate(this.date));
15119 setStartDate: function(startDate)
15121 this.startDate = startDate || -Infinity;
15122 if (this.startDate !== -Infinity) {
15123 this.startDate = this.parseDate(this.startDate);
15126 this.updateNavArrows();
15129 setEndDate: function(endDate)
15131 this.endDate = endDate || Infinity;
15132 if (this.endDate !== Infinity) {
15133 this.endDate = this.parseDate(this.endDate);
15136 this.updateNavArrows();
15139 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15141 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15142 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15143 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15145 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15146 return parseInt(d, 10);
15149 this.updateNavArrows();
15152 updateNavArrows: function()
15154 var d = new Date(this.viewDate),
15155 year = d.getUTCFullYear(),
15156 month = d.getUTCMonth();
15158 Roo.each(this.picker().select('.prev', true).elements, function(v){
15160 switch (this.viewMode) {
15163 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15169 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15176 Roo.each(this.picker().select('.next', true).elements, function(v){
15178 switch (this.viewMode) {
15181 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15187 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15195 moveMonth: function(date, dir)
15197 if (!dir) return date;
15198 var new_date = new Date(date.valueOf()),
15199 day = new_date.getUTCDate(),
15200 month = new_date.getUTCMonth(),
15201 mag = Math.abs(dir),
15203 dir = dir > 0 ? 1 : -1;
15206 // If going back one month, make sure month is not current month
15207 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15209 return new_date.getUTCMonth() == month;
15211 // If going forward one month, make sure month is as expected
15212 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15214 return new_date.getUTCMonth() != new_month;
15216 new_month = month + dir;
15217 new_date.setUTCMonth(new_month);
15218 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15219 if (new_month < 0 || new_month > 11)
15220 new_month = (new_month + 12) % 12;
15222 // For magnitudes >1, move one month at a time...
15223 for (var i=0; i<mag; i++)
15224 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15225 new_date = this.moveMonth(new_date, dir);
15226 // ...then reset the day, keeping it in the new month
15227 new_month = new_date.getUTCMonth();
15228 new_date.setUTCDate(day);
15230 return new_month != new_date.getUTCMonth();
15233 // Common date-resetting loop -- if date is beyond end of month, make it
15236 new_date.setUTCDate(--day);
15237 new_date.setUTCMonth(new_month);
15242 moveYear: function(date, dir)
15244 return this.moveMonth(date, dir*12);
15247 dateWithinRange: function(date)
15249 return date >= this.startDate && date <= this.endDate;
15255 this.picker().remove();
15260 Roo.apply(Roo.bootstrap.DateField, {
15271 html: '<i class="fa fa-arrow-left"/>'
15281 html: '<i class="fa fa-arrow-right"/>'
15323 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15324 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15325 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15326 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15327 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15340 navFnc: 'FullYear',
15345 navFnc: 'FullYear',
15350 Roo.apply(Roo.bootstrap.DateField, {
15354 cls: 'datepicker dropdown-menu',
15358 cls: 'datepicker-days',
15362 cls: 'table-condensed',
15364 Roo.bootstrap.DateField.head,
15368 Roo.bootstrap.DateField.footer
15375 cls: 'datepicker-months',
15379 cls: 'table-condensed',
15381 Roo.bootstrap.DateField.head,
15382 Roo.bootstrap.DateField.content,
15383 Roo.bootstrap.DateField.footer
15390 cls: 'datepicker-years',
15394 cls: 'table-condensed',
15396 Roo.bootstrap.DateField.head,
15397 Roo.bootstrap.DateField.content,
15398 Roo.bootstrap.DateField.footer
15417 * @class Roo.bootstrap.TimeField
15418 * @extends Roo.bootstrap.Input
15419 * Bootstrap DateField class
15423 * Create a new TimeField
15424 * @param {Object} config The config object
15427 Roo.bootstrap.TimeField = function(config){
15428 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15432 * Fires when this field show.
15433 * @param {Roo.bootstrap.DateField} this
15434 * @param {Mixed} date The date value
15439 * Fires when this field hide.
15440 * @param {Roo.bootstrap.DateField} this
15441 * @param {Mixed} date The date value
15446 * Fires when select a date.
15447 * @param {Roo.bootstrap.DateField} this
15448 * @param {Mixed} date The date value
15454 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15457 * @cfg {String} format
15458 * The default time format string which can be overriden for localization support. The format must be
15459 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15463 onRender: function(ct, position)
15466 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15468 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15470 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15472 this.pop = this.picker().select('>.datepicker-time',true).first();
15473 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15475 this.picker().on('mousedown', this.onMousedown, this);
15476 this.picker().on('click', this.onClick, this);
15478 this.picker().addClass('datepicker-dropdown');
15483 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15484 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15485 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15486 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15487 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15488 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15492 fireKey: function(e){
15493 if (!this.picker().isVisible()){
15494 if (e.keyCode == 27) // allow escape to hide and re-show picker
15499 e.preventDefault();
15507 this.onTogglePeriod();
15510 this.onIncrementMinutes();
15513 this.onDecrementMinutes();
15522 onClick: function(e) {
15523 e.stopPropagation();
15524 e.preventDefault();
15527 picker : function()
15529 return this.el.select('.datepicker', true).first();
15532 fillTime: function()
15534 var time = this.pop.select('tbody', true).first();
15536 time.dom.innerHTML = '';
15551 cls: 'hours-up glyphicon glyphicon-chevron-up'
15571 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15592 cls: 'timepicker-hour',
15607 cls: 'timepicker-minute',
15622 cls: 'btn btn-primary period',
15644 cls: 'hours-down glyphicon glyphicon-chevron-down'
15664 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15682 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15689 var hours = this.time.getHours();
15690 var minutes = this.time.getMinutes();
15703 hours = hours - 12;
15707 hours = '0' + hours;
15711 minutes = '0' + minutes;
15714 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15715 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15716 this.pop.select('button', true).first().dom.innerHTML = period;
15722 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15724 var cls = ['bottom'];
15726 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15733 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15738 this.picker().addClass(cls.join('-'));
15742 Roo.each(cls, function(c){
15744 _this.picker().setTop(_this.inputEl().getHeight());
15748 _this.picker().setTop(0 - _this.picker().getHeight());
15753 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15757 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15764 onFocus : function()
15766 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15770 onBlur : function()
15772 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15778 this.picker().show();
15783 this.fireEvent('show', this, this.date);
15788 this.picker().hide();
15791 this.fireEvent('hide', this, this.date);
15794 setTime : function()
15797 this.setValue(this.time.format(this.format));
15799 this.fireEvent('select', this, this.date);
15804 onMousedown: function(e){
15805 e.stopPropagation();
15806 e.preventDefault();
15809 onIncrementHours: function()
15811 Roo.log('onIncrementHours');
15812 this.time = this.time.add(Date.HOUR, 1);
15817 onDecrementHours: function()
15819 Roo.log('onDecrementHours');
15820 this.time = this.time.add(Date.HOUR, -1);
15824 onIncrementMinutes: function()
15826 Roo.log('onIncrementMinutes');
15827 this.time = this.time.add(Date.MINUTE, 1);
15831 onDecrementMinutes: function()
15833 Roo.log('onDecrementMinutes');
15834 this.time = this.time.add(Date.MINUTE, -1);
15838 onTogglePeriod: function()
15840 Roo.log('onTogglePeriod');
15841 this.time = this.time.add(Date.HOUR, 12);
15848 Roo.apply(Roo.bootstrap.TimeField, {
15878 cls: 'btn btn-info ok',
15890 Roo.apply(Roo.bootstrap.TimeField, {
15894 cls: 'datepicker dropdown-menu',
15898 cls: 'datepicker-time',
15902 cls: 'table-condensed',
15904 Roo.bootstrap.TimeField.content,
15905 Roo.bootstrap.TimeField.footer
15924 * @class Roo.bootstrap.CheckBox
15925 * @extends Roo.bootstrap.Input
15926 * Bootstrap CheckBox class
15928 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15929 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15930 * @cfg {String} boxLabel The text that appears beside the checkbox
15931 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15932 * @cfg {Boolean} checked initnal the element
15936 * Create a new CheckBox
15937 * @param {Object} config The config object
15940 Roo.bootstrap.CheckBox = function(config){
15941 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15946 * Fires when the element is checked or unchecked.
15947 * @param {Roo.bootstrap.CheckBox} this This input
15948 * @param {Boolean} checked The new checked value
15954 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15956 inputType: 'checkbox',
15963 getAutoCreate : function()
15965 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15971 cfg.cls = 'form-group checkbox' //input-group
15979 type : this.inputType,
15980 value : (!this.checked) ? this.valueOff : this.inputValue,
15981 cls : 'roo-checkbox', //'form-box',
15982 placeholder : this.placeholder || ''
15986 if (this.weight) { // Validity check?
15987 cfg.cls += " checkbox-" + this.weight;
15990 if (this.disabled) {
15991 input.disabled=true;
15995 input.checked = this.checked;
15999 input.name = this.name;
16003 input.cls += ' input-' + this.size;
16007 ['xs','sm','md','lg'].map(function(size){
16008 if (settings[size]) {
16009 cfg.cls += ' col-' + size + '-' + settings[size];
16015 var inputblock = input;
16020 if (this.before || this.after) {
16023 cls : 'input-group',
16027 inputblock.cn.push({
16029 cls : 'input-group-addon',
16033 inputblock.cn.push(input);
16035 inputblock.cn.push({
16037 cls : 'input-group-addon',
16044 if (align ==='left' && this.fieldLabel.length) {
16045 Roo.log("left and has label");
16051 cls : 'control-label col-md-' + this.labelWidth,
16052 html : this.fieldLabel
16056 cls : "col-md-" + (12 - this.labelWidth),
16063 } else if ( this.fieldLabel.length) {
16068 tag: this.boxLabel ? 'span' : 'label',
16070 cls: 'control-label box-input-label',
16071 //cls : 'input-group-addon',
16072 html : this.fieldLabel
16082 Roo.log(" no label && no align");
16083 cfg.cn = [ inputblock ] ;
16092 html: this.boxLabel
16104 * return the real input element.
16106 inputEl: function ()
16108 return this.el.select('input.roo-checkbox',true).first();
16113 return this.el.select('label.control-label',true).first();
16116 initEvents : function()
16118 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16120 this.inputEl().on('click', this.onClick, this);
16124 onClick : function()
16126 this.setChecked(!this.checked);
16129 setChecked : function(state,suppressEvent)
16131 this.checked = state;
16133 this.inputEl().dom.checked = state;
16135 if(suppressEvent !== true){
16136 this.fireEvent('check', this, state);
16139 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16143 setValue : function(v,suppressEvent)
16145 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16159 * @class Roo.bootstrap.Radio
16160 * @extends Roo.bootstrap.CheckBox
16161 * Bootstrap Radio class
16164 * Create a new Radio
16165 * @param {Object} config The config object
16168 Roo.bootstrap.Radio = function(config){
16169 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16173 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16175 inputType: 'radio',
16179 getAutoCreate : function()
16181 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16187 cfg.cls = 'form-group radio' //input-group
16192 type : this.inputType,
16193 value : (!this.checked) ? this.valueOff : this.inputValue,
16195 placeholder : this.placeholder || ''
16198 if (this.weight) { // Validity check?
16199 cfg.cls += " radio-" + this.weight;
16201 if (this.disabled) {
16202 input.disabled=true;
16206 input.checked = this.checked;
16210 input.name = this.name;
16214 input.cls += ' input-' + this.size;
16218 ['xs','sm','md','lg'].map(function(size){
16219 if (settings[size]) {
16220 cfg.cls += ' col-' + size + '-' + settings[size];
16224 var inputblock = input;
16226 if (this.before || this.after) {
16229 cls : 'input-group',
16233 inputblock.cn.push({
16235 cls : 'input-group-addon',
16239 inputblock.cn.push(input);
16241 inputblock.cn.push({
16243 cls : 'input-group-addon',
16250 if (align ==='left' && this.fieldLabel.length) {
16251 Roo.log("left and has label");
16257 cls : 'control-label col-md-' + this.labelWidth,
16258 html : this.fieldLabel
16262 cls : "col-md-" + (12 - this.labelWidth),
16269 } else if ( this.fieldLabel.length) {
16276 cls: 'control-label box-input-label',
16277 //cls : 'input-group-addon',
16278 html : this.fieldLabel
16288 Roo.log(" no label && no align");
16303 html: this.boxLabel
16310 inputEl: function ()
16312 return this.el.select('input.roo-radio',true).first();
16314 onClick : function()
16316 this.setChecked(true);
16319 setChecked : function(state,suppressEvent)
16322 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16323 v.dom.checked = false;
16327 this.checked = state;
16328 this.inputEl().dom.checked = state;
16330 if(suppressEvent !== true){
16331 this.fireEvent('check', this, state);
16334 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16338 getGroupValue : function()
16341 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16342 if(v.dom.checked == true){
16343 value = v.dom.value;
16351 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16352 * @return {Mixed} value The field value
16354 getValue : function(){
16355 return this.getGroupValue();
16361 //<script type="text/javascript">
16364 * Based Ext JS Library 1.1.1
16365 * Copyright(c) 2006-2007, Ext JS, LLC.
16371 * @class Roo.HtmlEditorCore
16372 * @extends Roo.Component
16373 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16375 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16378 Roo.HtmlEditorCore = function(config){
16381 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16386 * @event initialize
16387 * Fires when the editor is fully initialized (including the iframe)
16388 * @param {Roo.HtmlEditorCore} this
16393 * Fires when the editor is first receives the focus. Any insertion must wait
16394 * until after this event.
16395 * @param {Roo.HtmlEditorCore} this
16399 * @event beforesync
16400 * Fires before the textarea is updated with content from the editor iframe. Return false
16401 * to cancel the sync.
16402 * @param {Roo.HtmlEditorCore} this
16403 * @param {String} html
16407 * @event beforepush
16408 * Fires before the iframe editor is updated with content from the textarea. Return false
16409 * to cancel the push.
16410 * @param {Roo.HtmlEditorCore} this
16411 * @param {String} html
16416 * Fires when the textarea is updated with content from the editor iframe.
16417 * @param {Roo.HtmlEditorCore} this
16418 * @param {String} html
16423 * Fires when the iframe editor is updated with content from the textarea.
16424 * @param {Roo.HtmlEditorCore} this
16425 * @param {String} html
16430 * @event editorevent
16431 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16432 * @param {Roo.HtmlEditorCore} this
16437 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16439 // defaults : white / black...
16440 this.applyBlacklists();
16447 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16451 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16457 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16462 * @cfg {Number} height (in pixels)
16466 * @cfg {Number} width (in pixels)
16471 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16474 stylesheets: false,
16479 // private properties
16480 validationEvent : false,
16482 initialized : false,
16484 sourceEditMode : false,
16485 onFocus : Roo.emptyFn,
16487 hideMode:'offsets',
16491 // blacklist + whitelisted elements..
16498 * Protected method that will not generally be called directly. It
16499 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16500 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16502 getDocMarkup : function(){
16505 Roo.log(this.stylesheets);
16507 // inherit styels from page...??
16508 if (this.stylesheets === false) {
16510 Roo.get(document.head).select('style').each(function(node) {
16511 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16514 Roo.get(document.head).select('link').each(function(node) {
16515 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16518 } else if (!this.stylesheets.length) {
16520 st = '<style type="text/css">' +
16521 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16524 Roo.each(this.stylesheets, function(s) {
16525 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16530 st += '<style type="text/css">' +
16531 'IMG { cursor: pointer } ' +
16535 return '<html><head>' + st +
16536 //<style type="text/css">' +
16537 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16539 ' </head><body class="roo-htmleditor-body"></body></html>';
16543 onRender : function(ct, position)
16546 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16547 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16550 this.el.dom.style.border = '0 none';
16551 this.el.dom.setAttribute('tabIndex', -1);
16552 this.el.addClass('x-hidden hide');
16556 if(Roo.isIE){ // fix IE 1px bogus margin
16557 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16561 this.frameId = Roo.id();
16565 var iframe = this.owner.wrap.createChild({
16567 cls: 'form-control', // bootstrap..
16569 name: this.frameId,
16570 frameBorder : 'no',
16571 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16576 this.iframe = iframe.dom;
16578 this.assignDocWin();
16580 this.doc.designMode = 'on';
16583 this.doc.write(this.getDocMarkup());
16587 var task = { // must defer to wait for browser to be ready
16589 //console.log("run task?" + this.doc.readyState);
16590 this.assignDocWin();
16591 if(this.doc.body || this.doc.readyState == 'complete'){
16593 this.doc.designMode="on";
16597 Roo.TaskMgr.stop(task);
16598 this.initEditor.defer(10, this);
16605 Roo.TaskMgr.start(task);
16612 onResize : function(w, h)
16614 Roo.log('resize: ' +w + ',' + h );
16615 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16619 if(typeof w == 'number'){
16621 this.iframe.style.width = w + 'px';
16623 if(typeof h == 'number'){
16625 this.iframe.style.height = h + 'px';
16627 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16634 * Toggles the editor between standard and source edit mode.
16635 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16637 toggleSourceEdit : function(sourceEditMode){
16639 this.sourceEditMode = sourceEditMode === true;
16641 if(this.sourceEditMode){
16643 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16646 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16647 //this.iframe.className = '';
16650 //this.setSize(this.owner.wrap.getSize());
16651 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16658 * Protected method that will not generally be called directly. If you need/want
16659 * custom HTML cleanup, this is the method you should override.
16660 * @param {String} html The HTML to be cleaned
16661 * return {String} The cleaned HTML
16663 cleanHtml : function(html){
16664 html = String(html);
16665 if(html.length > 5){
16666 if(Roo.isSafari){ // strip safari nonsense
16667 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16670 if(html == ' '){
16677 * HTML Editor -> Textarea
16678 * Protected method that will not generally be called directly. Syncs the contents
16679 * of the editor iframe with the textarea.
16681 syncValue : function(){
16682 if(this.initialized){
16683 var bd = (this.doc.body || this.doc.documentElement);
16684 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16685 var html = bd.innerHTML;
16687 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16688 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16690 html = '<div style="'+m[0]+'">' + html + '</div>';
16693 html = this.cleanHtml(html);
16694 // fix up the special chars.. normaly like back quotes in word...
16695 // however we do not want to do this with chinese..
16696 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16697 var cc = b.charCodeAt();
16699 (cc >= 0x4E00 && cc < 0xA000 ) ||
16700 (cc >= 0x3400 && cc < 0x4E00 ) ||
16701 (cc >= 0xf900 && cc < 0xfb00 )
16707 if(this.owner.fireEvent('beforesync', this, html) !== false){
16708 this.el.dom.value = html;
16709 this.owner.fireEvent('sync', this, html);
16715 * Protected method that will not generally be called directly. Pushes the value of the textarea
16716 * into the iframe editor.
16718 pushValue : function(){
16719 if(this.initialized){
16720 var v = this.el.dom.value.trim();
16722 // if(v.length < 1){
16726 if(this.owner.fireEvent('beforepush', this, v) !== false){
16727 var d = (this.doc.body || this.doc.documentElement);
16729 this.cleanUpPaste();
16730 this.el.dom.value = d.innerHTML;
16731 this.owner.fireEvent('push', this, v);
16737 deferFocus : function(){
16738 this.focus.defer(10, this);
16742 focus : function(){
16743 if(this.win && !this.sourceEditMode){
16750 assignDocWin: function()
16752 var iframe = this.iframe;
16755 this.doc = iframe.contentWindow.document;
16756 this.win = iframe.contentWindow;
16758 // if (!Roo.get(this.frameId)) {
16761 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16762 // this.win = Roo.get(this.frameId).dom.contentWindow;
16764 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16768 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16769 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16774 initEditor : function(){
16775 //console.log("INIT EDITOR");
16776 this.assignDocWin();
16780 this.doc.designMode="on";
16782 this.doc.write(this.getDocMarkup());
16785 var dbody = (this.doc.body || this.doc.documentElement);
16786 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16787 // this copies styles from the containing element into thsi one..
16788 // not sure why we need all of this..
16789 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16791 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16792 //ss['background-attachment'] = 'fixed'; // w3c
16793 dbody.bgProperties = 'fixed'; // ie
16794 //Roo.DomHelper.applyStyles(dbody, ss);
16795 Roo.EventManager.on(this.doc, {
16796 //'mousedown': this.onEditorEvent,
16797 'mouseup': this.onEditorEvent,
16798 'dblclick': this.onEditorEvent,
16799 'click': this.onEditorEvent,
16800 'keyup': this.onEditorEvent,
16805 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16807 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16808 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16810 this.initialized = true;
16812 this.owner.fireEvent('initialize', this);
16817 onDestroy : function(){
16823 //for (var i =0; i < this.toolbars.length;i++) {
16824 // // fixme - ask toolbars for heights?
16825 // this.toolbars[i].onDestroy();
16828 //this.wrap.dom.innerHTML = '';
16829 //this.wrap.remove();
16834 onFirstFocus : function(){
16836 this.assignDocWin();
16839 this.activated = true;
16842 if(Roo.isGecko){ // prevent silly gecko errors
16844 var s = this.win.getSelection();
16845 if(!s.focusNode || s.focusNode.nodeType != 3){
16846 var r = s.getRangeAt(0);
16847 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16852 this.execCmd('useCSS', true);
16853 this.execCmd('styleWithCSS', false);
16856 this.owner.fireEvent('activate', this);
16860 adjustFont: function(btn){
16861 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16862 //if(Roo.isSafari){ // safari
16865 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16866 if(Roo.isSafari){ // safari
16867 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16868 v = (v < 10) ? 10 : v;
16869 v = (v > 48) ? 48 : v;
16870 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16875 v = Math.max(1, v+adjust);
16877 this.execCmd('FontSize', v );
16880 onEditorEvent : function(e){
16881 this.owner.fireEvent('editorevent', this, e);
16882 // this.updateToolbar();
16883 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16886 insertTag : function(tg)
16888 // could be a bit smarter... -> wrap the current selected tRoo..
16889 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16891 range = this.createRange(this.getSelection());
16892 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16893 wrappingNode.appendChild(range.extractContents());
16894 range.insertNode(wrappingNode);
16901 this.execCmd("formatblock", tg);
16905 insertText : function(txt)
16909 var range = this.createRange();
16910 range.deleteContents();
16911 //alert(Sender.getAttribute('label'));
16913 range.insertNode(this.doc.createTextNode(txt));
16919 * Executes a Midas editor command on the editor document and performs necessary focus and
16920 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16921 * @param {String} cmd The Midas command
16922 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16924 relayCmd : function(cmd, value){
16926 this.execCmd(cmd, value);
16927 this.owner.fireEvent('editorevent', this);
16928 //this.updateToolbar();
16929 this.owner.deferFocus();
16933 * Executes a Midas editor command directly on the editor document.
16934 * For visual commands, you should use {@link #relayCmd} instead.
16935 * <b>This should only be called after the editor is initialized.</b>
16936 * @param {String} cmd The Midas command
16937 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16939 execCmd : function(cmd, value){
16940 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16947 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16949 * @param {String} text | dom node..
16951 insertAtCursor : function(text)
16956 if(!this.activated){
16962 var r = this.doc.selection.createRange();
16973 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16977 // from jquery ui (MIT licenced)
16979 var win = this.win;
16981 if (win.getSelection && win.getSelection().getRangeAt) {
16982 range = win.getSelection().getRangeAt(0);
16983 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16984 range.insertNode(node);
16985 } else if (win.document.selection && win.document.selection.createRange) {
16986 // no firefox support
16987 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16988 win.document.selection.createRange().pasteHTML(txt);
16990 // no firefox support
16991 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16992 this.execCmd('InsertHTML', txt);
17001 mozKeyPress : function(e){
17003 var c = e.getCharCode(), cmd;
17006 c = String.fromCharCode(c).toLowerCase();
17020 this.cleanUpPaste.defer(100, this);
17028 e.preventDefault();
17036 fixKeys : function(){ // load time branching for fastest keydown performance
17038 return function(e){
17039 var k = e.getKey(), r;
17042 r = this.doc.selection.createRange();
17045 r.pasteHTML('    ');
17052 r = this.doc.selection.createRange();
17054 var target = r.parentElement();
17055 if(!target || target.tagName.toLowerCase() != 'li'){
17057 r.pasteHTML('<br />');
17063 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17064 this.cleanUpPaste.defer(100, this);
17070 }else if(Roo.isOpera){
17071 return function(e){
17072 var k = e.getKey();
17076 this.execCmd('InsertHTML','    ');
17079 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17080 this.cleanUpPaste.defer(100, this);
17085 }else if(Roo.isSafari){
17086 return function(e){
17087 var k = e.getKey();
17091 this.execCmd('InsertText','\t');
17095 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17096 this.cleanUpPaste.defer(100, this);
17104 getAllAncestors: function()
17106 var p = this.getSelectedNode();
17109 a.push(p); // push blank onto stack..
17110 p = this.getParentElement();
17114 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17118 a.push(this.doc.body);
17122 lastSelNode : false,
17125 getSelection : function()
17127 this.assignDocWin();
17128 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17131 getSelectedNode: function()
17133 // this may only work on Gecko!!!
17135 // should we cache this!!!!
17140 var range = this.createRange(this.getSelection()).cloneRange();
17143 var parent = range.parentElement();
17145 var testRange = range.duplicate();
17146 testRange.moveToElementText(parent);
17147 if (testRange.inRange(range)) {
17150 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17153 parent = parent.parentElement;
17158 // is ancestor a text element.
17159 var ac = range.commonAncestorContainer;
17160 if (ac.nodeType == 3) {
17161 ac = ac.parentNode;
17164 var ar = ac.childNodes;
17167 var other_nodes = [];
17168 var has_other_nodes = false;
17169 for (var i=0;i<ar.length;i++) {
17170 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17173 // fullly contained node.
17175 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17180 // probably selected..
17181 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17182 other_nodes.push(ar[i]);
17186 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17191 has_other_nodes = true;
17193 if (!nodes.length && other_nodes.length) {
17194 nodes= other_nodes;
17196 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17202 createRange: function(sel)
17204 // this has strange effects when using with
17205 // top toolbar - not sure if it's a great idea.
17206 //this.editor.contentWindow.focus();
17207 if (typeof sel != "undefined") {
17209 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17211 return this.doc.createRange();
17214 return this.doc.createRange();
17217 getParentElement: function()
17220 this.assignDocWin();
17221 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17223 var range = this.createRange(sel);
17226 var p = range.commonAncestorContainer;
17227 while (p.nodeType == 3) { // text node
17238 * Range intersection.. the hard stuff...
17242 * [ -- selected range --- ]
17246 * if end is before start or hits it. fail.
17247 * if start is after end or hits it fail.
17249 * if either hits (but other is outside. - then it's not
17255 // @see http://www.thismuchiknow.co.uk/?p=64.
17256 rangeIntersectsNode : function(range, node)
17258 var nodeRange = node.ownerDocument.createRange();
17260 nodeRange.selectNode(node);
17262 nodeRange.selectNodeContents(node);
17265 var rangeStartRange = range.cloneRange();
17266 rangeStartRange.collapse(true);
17268 var rangeEndRange = range.cloneRange();
17269 rangeEndRange.collapse(false);
17271 var nodeStartRange = nodeRange.cloneRange();
17272 nodeStartRange.collapse(true);
17274 var nodeEndRange = nodeRange.cloneRange();
17275 nodeEndRange.collapse(false);
17277 return rangeStartRange.compareBoundaryPoints(
17278 Range.START_TO_START, nodeEndRange) == -1 &&
17279 rangeEndRange.compareBoundaryPoints(
17280 Range.START_TO_START, nodeStartRange) == 1;
17284 rangeCompareNode : function(range, node)
17286 var nodeRange = node.ownerDocument.createRange();
17288 nodeRange.selectNode(node);
17290 nodeRange.selectNodeContents(node);
17294 range.collapse(true);
17296 nodeRange.collapse(true);
17298 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17299 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17301 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17303 var nodeIsBefore = ss == 1;
17304 var nodeIsAfter = ee == -1;
17306 if (nodeIsBefore && nodeIsAfter)
17308 if (!nodeIsBefore && nodeIsAfter)
17309 return 1; //right trailed.
17311 if (nodeIsBefore && !nodeIsAfter)
17312 return 2; // left trailed.
17317 // private? - in a new class?
17318 cleanUpPaste : function()
17320 // cleans up the whole document..
17321 Roo.log('cleanuppaste');
17323 this.cleanUpChildren(this.doc.body);
17324 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17325 if (clean != this.doc.body.innerHTML) {
17326 this.doc.body.innerHTML = clean;
17331 cleanWordChars : function(input) {// change the chars to hex code
17332 var he = Roo.HtmlEditorCore;
17334 var output = input;
17335 Roo.each(he.swapCodes, function(sw) {
17336 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17338 output = output.replace(swapper, sw[1]);
17345 cleanUpChildren : function (n)
17347 if (!n.childNodes.length) {
17350 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17351 this.cleanUpChild(n.childNodes[i]);
17358 cleanUpChild : function (node)
17361 //console.log(node);
17362 if (node.nodeName == "#text") {
17363 // clean up silly Windows -- stuff?
17366 if (node.nodeName == "#comment") {
17367 node.parentNode.removeChild(node);
17368 // clean up silly Windows -- stuff?
17371 var lcname = node.tagName.toLowerCase();
17372 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17373 // whitelist of tags..
17375 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17377 node.parentNode.removeChild(node);
17382 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17384 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17385 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17387 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17388 // remove_keep_children = true;
17391 if (remove_keep_children) {
17392 this.cleanUpChildren(node);
17393 // inserts everything just before this node...
17394 while (node.childNodes.length) {
17395 var cn = node.childNodes[0];
17396 node.removeChild(cn);
17397 node.parentNode.insertBefore(cn, node);
17399 node.parentNode.removeChild(node);
17403 if (!node.attributes || !node.attributes.length) {
17404 this.cleanUpChildren(node);
17408 function cleanAttr(n,v)
17411 if (v.match(/^\./) || v.match(/^\//)) {
17414 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17417 if (v.match(/^#/)) {
17420 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17421 node.removeAttribute(n);
17425 var cwhite = this.cwhite;
17426 var cblack = this.cblack;
17428 function cleanStyle(n,v)
17430 if (v.match(/expression/)) { //XSS?? should we even bother..
17431 node.removeAttribute(n);
17435 var parts = v.split(/;/);
17438 Roo.each(parts, function(p) {
17439 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17443 var l = p.split(':').shift().replace(/\s+/g,'');
17444 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17446 if ( cwhite.length && cblack.indexOf(l) > -1) {
17447 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17448 //node.removeAttribute(n);
17452 // only allow 'c whitelisted system attributes'
17453 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17454 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17455 //node.removeAttribute(n);
17465 if (clean.length) {
17466 node.setAttribute(n, clean.join(';'));
17468 node.removeAttribute(n);
17474 for (var i = node.attributes.length-1; i > -1 ; i--) {
17475 var a = node.attributes[i];
17478 if (a.name.toLowerCase().substr(0,2)=='on') {
17479 node.removeAttribute(a.name);
17482 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17483 node.removeAttribute(a.name);
17486 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17487 cleanAttr(a.name,a.value); // fixme..
17490 if (a.name == 'style') {
17491 cleanStyle(a.name,a.value);
17494 /// clean up MS crap..
17495 // tecnically this should be a list of valid class'es..
17498 if (a.name == 'class') {
17499 if (a.value.match(/^Mso/)) {
17500 node.className = '';
17503 if (a.value.match(/body/)) {
17504 node.className = '';
17515 this.cleanUpChildren(node);
17520 * Clean up MS wordisms...
17522 cleanWord : function(node)
17525 var cleanWordChildren = function()
17527 if (!node.childNodes.length) {
17530 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17531 _t.cleanWord(node.childNodes[i]);
17537 this.cleanWord(this.doc.body);
17540 if (node.nodeName == "#text") {
17541 // clean up silly Windows -- stuff?
17544 if (node.nodeName == "#comment") {
17545 node.parentNode.removeChild(node);
17546 // clean up silly Windows -- stuff?
17550 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17551 node.parentNode.removeChild(node);
17555 // remove - but keep children..
17556 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17557 while (node.childNodes.length) {
17558 var cn = node.childNodes[0];
17559 node.removeChild(cn);
17560 node.parentNode.insertBefore(cn, node);
17562 node.parentNode.removeChild(node);
17563 cleanWordChildren();
17567 if (node.className.length) {
17569 var cn = node.className.split(/\W+/);
17571 Roo.each(cn, function(cls) {
17572 if (cls.match(/Mso[a-zA-Z]+/)) {
17577 node.className = cna.length ? cna.join(' ') : '';
17579 node.removeAttribute("class");
17583 if (node.hasAttribute("lang")) {
17584 node.removeAttribute("lang");
17587 if (node.hasAttribute("style")) {
17589 var styles = node.getAttribute("style").split(";");
17591 Roo.each(styles, function(s) {
17592 if (!s.match(/:/)) {
17595 var kv = s.split(":");
17596 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17599 // what ever is left... we allow.
17602 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17603 if (!nstyle.length) {
17604 node.removeAttribute('style');
17608 cleanWordChildren();
17612 domToHTML : function(currentElement, depth, nopadtext) {
17614 depth = depth || 0;
17615 nopadtext = nopadtext || false;
17617 if (!currentElement) {
17618 return this.domToHTML(this.doc.body);
17621 //Roo.log(currentElement);
17623 var allText = false;
17624 var nodeName = currentElement.nodeName;
17625 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17627 if (nodeName == '#text') {
17628 return currentElement.nodeValue;
17633 if (nodeName != 'BODY') {
17636 // Prints the node tagName, such as <A>, <IMG>, etc
17639 for(i = 0; i < currentElement.attributes.length;i++) {
17641 var aname = currentElement.attributes.item(i).name;
17642 if (!currentElement.attributes.item(i).value.length) {
17645 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17648 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17657 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17660 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17665 // Traverse the tree
17667 var currentElementChild = currentElement.childNodes.item(i);
17668 var allText = true;
17669 var innerHTML = '';
17671 while (currentElementChild) {
17672 // Formatting code (indent the tree so it looks nice on the screen)
17673 var nopad = nopadtext;
17674 if (lastnode == 'SPAN') {
17678 if (currentElementChild.nodeName == '#text') {
17679 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17680 if (!nopad && toadd.length > 80) {
17681 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17683 innerHTML += toadd;
17686 currentElementChild = currentElement.childNodes.item(i);
17692 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17694 // Recursively traverse the tree structure of the child node
17695 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17696 lastnode = currentElementChild.nodeName;
17698 currentElementChild=currentElement.childNodes.item(i);
17704 // The remaining code is mostly for formatting the tree
17705 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17710 ret+= "</"+tagName+">";
17716 applyBlacklists : function()
17718 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17719 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17723 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17724 if (b.indexOf(tag) > -1) {
17727 this.white.push(tag);
17731 Roo.each(w, function(tag) {
17732 if (b.indexOf(tag) > -1) {
17735 if (this.white.indexOf(tag) > -1) {
17738 this.white.push(tag);
17743 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17744 if (w.indexOf(tag) > -1) {
17747 this.black.push(tag);
17751 Roo.each(b, function(tag) {
17752 if (w.indexOf(tag) > -1) {
17755 if (this.black.indexOf(tag) > -1) {
17758 this.black.push(tag);
17763 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
17764 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
17768 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17769 if (b.indexOf(tag) > -1) {
17772 this.cwhite.push(tag);
17776 Roo.each(w, function(tag) {
17777 if (b.indexOf(tag) > -1) {
17780 if (this.cwhite.indexOf(tag) > -1) {
17783 this.cwhite.push(tag);
17788 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
17789 if (w.indexOf(tag) > -1) {
17792 this.cblack.push(tag);
17796 Roo.each(b, function(tag) {
17797 if (w.indexOf(tag) > -1) {
17800 if (this.cblack.indexOf(tag) > -1) {
17803 this.cblack.push(tag);
17808 // hide stuff that is not compatible
17822 * @event specialkey
17826 * @cfg {String} fieldClass @hide
17829 * @cfg {String} focusClass @hide
17832 * @cfg {String} autoCreate @hide
17835 * @cfg {String} inputType @hide
17838 * @cfg {String} invalidClass @hide
17841 * @cfg {String} invalidText @hide
17844 * @cfg {String} msgFx @hide
17847 * @cfg {String} validateOnBlur @hide
17851 Roo.HtmlEditorCore.white = [
17852 'area', 'br', 'img', 'input', 'hr', 'wbr',
17854 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17855 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17856 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17857 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17858 'table', 'ul', 'xmp',
17860 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17863 'dir', 'menu', 'ol', 'ul', 'dl',
17869 Roo.HtmlEditorCore.black = [
17870 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17872 'base', 'basefont', 'bgsound', 'blink', 'body',
17873 'frame', 'frameset', 'head', 'html', 'ilayer',
17874 'iframe', 'layer', 'link', 'meta', 'object',
17875 'script', 'style' ,'title', 'xml' // clean later..
17877 Roo.HtmlEditorCore.clean = [
17878 'script', 'style', 'title', 'xml'
17880 Roo.HtmlEditorCore.remove = [
17885 Roo.HtmlEditorCore.ablack = [
17889 Roo.HtmlEditorCore.aclean = [
17890 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17894 Roo.HtmlEditorCore.pwhite= [
17895 'http', 'https', 'mailto'
17898 // white listed style attributes.
17899 Roo.HtmlEditorCore.cwhite= [
17900 // 'text-align', /// default is to allow most things..
17906 // black listed style attributes.
17907 Roo.HtmlEditorCore.cblack= [
17908 // 'font-size' -- this can be set by the project
17912 Roo.HtmlEditorCore.swapCodes =[
17931 * @class Roo.bootstrap.HtmlEditor
17932 * @extends Roo.bootstrap.TextArea
17933 * Bootstrap HtmlEditor class
17936 * Create a new HtmlEditor
17937 * @param {Object} config The config object
17940 Roo.bootstrap.HtmlEditor = function(config){
17941 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17942 if (!this.toolbars) {
17943 this.toolbars = [];
17945 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17948 * @event initialize
17949 * Fires when the editor is fully initialized (including the iframe)
17950 * @param {HtmlEditor} this
17955 * Fires when the editor is first receives the focus. Any insertion must wait
17956 * until after this event.
17957 * @param {HtmlEditor} this
17961 * @event beforesync
17962 * Fires before the textarea is updated with content from the editor iframe. Return false
17963 * to cancel the sync.
17964 * @param {HtmlEditor} this
17965 * @param {String} html
17969 * @event beforepush
17970 * Fires before the iframe editor is updated with content from the textarea. Return false
17971 * to cancel the push.
17972 * @param {HtmlEditor} this
17973 * @param {String} html
17978 * Fires when the textarea is updated with content from the editor iframe.
17979 * @param {HtmlEditor} this
17980 * @param {String} html
17985 * Fires when the iframe editor is updated with content from the textarea.
17986 * @param {HtmlEditor} this
17987 * @param {String} html
17991 * @event editmodechange
17992 * Fires when the editor switches edit modes
17993 * @param {HtmlEditor} this
17994 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17996 editmodechange: true,
17998 * @event editorevent
17999 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18000 * @param {HtmlEditor} this
18004 * @event firstfocus
18005 * Fires when on first focus - needed by toolbars..
18006 * @param {HtmlEditor} this
18011 * Auto save the htmlEditor value as a file into Events
18012 * @param {HtmlEditor} this
18016 * @event savedpreview
18017 * preview the saved version of htmlEditor
18018 * @param {HtmlEditor} this
18025 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18029 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18034 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18039 * @cfg {Number} height (in pixels)
18043 * @cfg {Number} width (in pixels)
18048 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18051 stylesheets: false,
18056 // private properties
18057 validationEvent : false,
18059 initialized : false,
18062 onFocus : Roo.emptyFn,
18064 hideMode:'offsets',
18067 tbContainer : false,
18069 toolbarContainer :function() {
18070 return this.wrap.select('.x-html-editor-tb',true).first();
18074 * Protected method that will not generally be called directly. It
18075 * is called when the editor creates its toolbar. Override this method if you need to
18076 * add custom toolbar buttons.
18077 * @param {HtmlEditor} editor
18079 createToolbar : function(){
18081 Roo.log("create toolbars");
18083 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18084 this.toolbars[0].render(this.toolbarContainer());
18088 // if (!editor.toolbars || !editor.toolbars.length) {
18089 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18092 // for (var i =0 ; i < editor.toolbars.length;i++) {
18093 // editor.toolbars[i] = Roo.factory(
18094 // typeof(editor.toolbars[i]) == 'string' ?
18095 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18096 // Roo.bootstrap.HtmlEditor);
18097 // editor.toolbars[i].init(editor);
18103 onRender : function(ct, position)
18105 // Roo.log("Call onRender: " + this.xtype);
18107 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18109 this.wrap = this.inputEl().wrap({
18110 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18113 this.editorcore.onRender(ct, position);
18115 if (this.resizable) {
18116 this.resizeEl = new Roo.Resizable(this.wrap, {
18120 minHeight : this.height,
18121 height: this.height,
18122 handles : this.resizable,
18125 resize : function(r, w, h) {
18126 _t.onResize(w,h); // -something
18132 this.createToolbar(this);
18135 if(!this.width && this.resizable){
18136 this.setSize(this.wrap.getSize());
18138 if (this.resizeEl) {
18139 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18140 // should trigger onReize..
18146 onResize : function(w, h)
18148 Roo.log('resize: ' +w + ',' + h );
18149 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18153 if(this.inputEl() ){
18154 if(typeof w == 'number'){
18155 var aw = w - this.wrap.getFrameWidth('lr');
18156 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18159 if(typeof h == 'number'){
18160 var tbh = -11; // fixme it needs to tool bar size!
18161 for (var i =0; i < this.toolbars.length;i++) {
18162 // fixme - ask toolbars for heights?
18163 tbh += this.toolbars[i].el.getHeight();
18164 //if (this.toolbars[i].footer) {
18165 // tbh += this.toolbars[i].footer.el.getHeight();
18173 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18174 ah -= 5; // knock a few pixes off for look..
18175 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18179 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18180 this.editorcore.onResize(ew,eh);
18185 * Toggles the editor between standard and source edit mode.
18186 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18188 toggleSourceEdit : function(sourceEditMode)
18190 this.editorcore.toggleSourceEdit(sourceEditMode);
18192 if(this.editorcore.sourceEditMode){
18193 Roo.log('editor - showing textarea');
18196 // Roo.log(this.syncValue());
18198 this.inputEl().removeClass(['hide', 'x-hidden']);
18199 this.inputEl().dom.removeAttribute('tabIndex');
18200 this.inputEl().focus();
18202 Roo.log('editor - hiding textarea');
18204 // Roo.log(this.pushValue());
18207 this.inputEl().addClass(['hide', 'x-hidden']);
18208 this.inputEl().dom.setAttribute('tabIndex', -1);
18209 //this.deferFocus();
18212 if(this.resizable){
18213 this.setSize(this.wrap.getSize());
18216 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18219 // private (for BoxComponent)
18220 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18222 // private (for BoxComponent)
18223 getResizeEl : function(){
18227 // private (for BoxComponent)
18228 getPositionEl : function(){
18233 initEvents : function(){
18234 this.originalValue = this.getValue();
18238 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18241 // markInvalid : Roo.emptyFn,
18243 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18246 // clearInvalid : Roo.emptyFn,
18248 setValue : function(v){
18249 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18250 this.editorcore.pushValue();
18255 deferFocus : function(){
18256 this.focus.defer(10, this);
18260 focus : function(){
18261 this.editorcore.focus();
18267 onDestroy : function(){
18273 for (var i =0; i < this.toolbars.length;i++) {
18274 // fixme - ask toolbars for heights?
18275 this.toolbars[i].onDestroy();
18278 this.wrap.dom.innerHTML = '';
18279 this.wrap.remove();
18284 onFirstFocus : function(){
18285 //Roo.log("onFirstFocus");
18286 this.editorcore.onFirstFocus();
18287 for (var i =0; i < this.toolbars.length;i++) {
18288 this.toolbars[i].onFirstFocus();
18294 syncValue : function()
18296 this.editorcore.syncValue();
18299 pushValue : function()
18301 this.editorcore.pushValue();
18305 // hide stuff that is not compatible
18319 * @event specialkey
18323 * @cfg {String} fieldClass @hide
18326 * @cfg {String} focusClass @hide
18329 * @cfg {String} autoCreate @hide
18332 * @cfg {String} inputType @hide
18335 * @cfg {String} invalidClass @hide
18338 * @cfg {String} invalidText @hide
18341 * @cfg {String} msgFx @hide
18344 * @cfg {String} validateOnBlur @hide
18353 Roo.namespace('Roo.bootstrap.htmleditor');
18355 * @class Roo.bootstrap.HtmlEditorToolbar1
18360 new Roo.bootstrap.HtmlEditor({
18363 new Roo.bootstrap.HtmlEditorToolbar1({
18364 disable : { fonts: 1 , format: 1, ..., ... , ...],
18370 * @cfg {Object} disable List of elements to disable..
18371 * @cfg {Array} btns List of additional buttons.
18375 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18378 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18381 Roo.apply(this, config);
18383 // default disabled, based on 'good practice'..
18384 this.disable = this.disable || {};
18385 Roo.applyIf(this.disable, {
18388 specialElements : true
18390 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18392 this.editor = config.editor;
18393 this.editorcore = config.editor.editorcore;
18395 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18397 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18398 // dont call parent... till later.
18400 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18405 editorcore : false,
18410 "h1","h2","h3","h4","h5","h6",
18412 "abbr", "acronym", "address", "cite", "samp", "var",
18416 onRender : function(ct, position)
18418 // Roo.log("Call onRender: " + this.xtype);
18420 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18422 this.el.dom.style.marginBottom = '0';
18424 var editorcore = this.editorcore;
18425 var editor= this.editor;
18428 var btn = function(id,cmd , toggle, handler){
18430 var event = toggle ? 'toggle' : 'click';
18435 xns: Roo.bootstrap,
18438 enableToggle:toggle !== false,
18440 pressed : toggle ? false : null,
18443 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18444 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18453 xns: Roo.bootstrap,
18454 glyphicon : 'font',
18458 xns: Roo.bootstrap,
18462 Roo.each(this.formats, function(f) {
18463 style.menu.items.push({
18465 xns: Roo.bootstrap,
18466 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18471 editorcore.insertTag(this.tagname);
18478 children.push(style);
18481 btn('bold',false,true);
18482 btn('italic',false,true);
18483 btn('align-left', 'justifyleft',true);
18484 btn('align-center', 'justifycenter',true);
18485 btn('align-right' , 'justifyright',true);
18486 btn('link', false, false, function(btn) {
18487 //Roo.log("create link?");
18488 var url = prompt(this.createLinkText, this.defaultLinkValue);
18489 if(url && url != 'http:/'+'/'){
18490 this.editorcore.relayCmd('createlink', url);
18493 btn('list','insertunorderedlist',true);
18494 btn('pencil', false,true, function(btn){
18497 this.toggleSourceEdit(btn.pressed);
18503 xns: Roo.bootstrap,
18508 xns: Roo.bootstrap,
18513 cog.menu.items.push({
18515 xns: Roo.bootstrap,
18516 html : Clean styles,
18521 editorcore.insertTag(this.tagname);
18530 this.xtype = 'NavSimplebar';
18532 for(var i=0;i< children.length;i++) {
18534 this.buttons.add(this.addxtypeChild(children[i]));
18538 editor.on('editorevent', this.updateToolbar, this);
18540 onBtnClick : function(id)
18542 this.editorcore.relayCmd(id);
18543 this.editorcore.focus();
18547 * Protected method that will not generally be called directly. It triggers
18548 * a toolbar update by reading the markup state of the current selection in the editor.
18550 updateToolbar: function(){
18552 if(!this.editorcore.activated){
18553 this.editor.onFirstFocus(); // is this neeed?
18557 var btns = this.buttons;
18558 var doc = this.editorcore.doc;
18559 btns.get('bold').setActive(doc.queryCommandState('bold'));
18560 btns.get('italic').setActive(doc.queryCommandState('italic'));
18561 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18563 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18564 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18565 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18567 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18568 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18571 var ans = this.editorcore.getAllAncestors();
18572 if (this.formatCombo) {
18575 var store = this.formatCombo.store;
18576 this.formatCombo.setValue("");
18577 for (var i =0; i < ans.length;i++) {
18578 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18580 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18588 // hides menus... - so this cant be on a menu...
18589 Roo.bootstrap.MenuMgr.hideAll();
18591 Roo.bootstrap.MenuMgr.hideAll();
18592 //this.editorsyncValue();
18594 onFirstFocus: function() {
18595 this.buttons.each(function(item){
18599 toggleSourceEdit : function(sourceEditMode){
18602 if(sourceEditMode){
18603 Roo.log("disabling buttons");
18604 this.buttons.each( function(item){
18605 if(item.cmd != 'pencil'){
18611 Roo.log("enabling buttons");
18612 if(this.editorcore.initialized){
18613 this.buttons.each( function(item){
18619 Roo.log("calling toggole on editor");
18620 // tell the editor that it's been pressed..
18621 this.editor.toggleSourceEdit(sourceEditMode);
18631 * @class Roo.bootstrap.Table.AbstractSelectionModel
18632 * @extends Roo.util.Observable
18633 * Abstract base class for grid SelectionModels. It provides the interface that should be
18634 * implemented by descendant classes. This class should not be directly instantiated.
18637 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18638 this.locked = false;
18639 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18643 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18644 /** @ignore Called by the grid automatically. Do not call directly. */
18645 init : function(grid){
18651 * Locks the selections.
18654 this.locked = true;
18658 * Unlocks the selections.
18660 unlock : function(){
18661 this.locked = false;
18665 * Returns true if the selections are locked.
18666 * @return {Boolean}
18668 isLocked : function(){
18669 return this.locked;
18673 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18674 * @class Roo.bootstrap.Table.RowSelectionModel
18675 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18676 * It supports multiple selections and keyboard selection/navigation.
18678 * @param {Object} config
18681 Roo.bootstrap.Table.RowSelectionModel = function(config){
18682 Roo.apply(this, config);
18683 this.selections = new Roo.util.MixedCollection(false, function(o){
18688 this.lastActive = false;
18692 * @event selectionchange
18693 * Fires when the selection changes
18694 * @param {SelectionModel} this
18696 "selectionchange" : true,
18698 * @event afterselectionchange
18699 * Fires after the selection changes (eg. by key press or clicking)
18700 * @param {SelectionModel} this
18702 "afterselectionchange" : true,
18704 * @event beforerowselect
18705 * Fires when a row is selected being selected, return false to cancel.
18706 * @param {SelectionModel} this
18707 * @param {Number} rowIndex The selected index
18708 * @param {Boolean} keepExisting False if other selections will be cleared
18710 "beforerowselect" : true,
18713 * Fires when a row is selected.
18714 * @param {SelectionModel} this
18715 * @param {Number} rowIndex The selected index
18716 * @param {Roo.data.Record} r The record
18718 "rowselect" : true,
18720 * @event rowdeselect
18721 * Fires when a row is deselected.
18722 * @param {SelectionModel} this
18723 * @param {Number} rowIndex The selected index
18725 "rowdeselect" : true
18727 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18728 this.locked = false;
18731 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18733 * @cfg {Boolean} singleSelect
18734 * True to allow selection of only one row at a time (defaults to false)
18736 singleSelect : false,
18739 initEvents : function(){
18741 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18742 this.grid.on("mousedown", this.handleMouseDown, this);
18743 }else{ // allow click to work like normal
18744 this.grid.on("rowclick", this.handleDragableRowClick, this);
18747 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18748 "up" : function(e){
18750 this.selectPrevious(e.shiftKey);
18751 }else if(this.last !== false && this.lastActive !== false){
18752 var last = this.last;
18753 this.selectRange(this.last, this.lastActive-1);
18754 this.grid.getView().focusRow(this.lastActive);
18755 if(last !== false){
18759 this.selectFirstRow();
18761 this.fireEvent("afterselectionchange", this);
18763 "down" : function(e){
18765 this.selectNext(e.shiftKey);
18766 }else if(this.last !== false && this.lastActive !== false){
18767 var last = this.last;
18768 this.selectRange(this.last, this.lastActive+1);
18769 this.grid.getView().focusRow(this.lastActive);
18770 if(last !== false){
18774 this.selectFirstRow();
18776 this.fireEvent("afterselectionchange", this);
18781 var view = this.grid.view;
18782 view.on("refresh", this.onRefresh, this);
18783 view.on("rowupdated", this.onRowUpdated, this);
18784 view.on("rowremoved", this.onRemove, this);
18788 onRefresh : function(){
18789 var ds = this.grid.dataSource, i, v = this.grid.view;
18790 var s = this.selections;
18791 s.each(function(r){
18792 if((i = ds.indexOfId(r.id)) != -1){
18801 onRemove : function(v, index, r){
18802 this.selections.remove(r);
18806 onRowUpdated : function(v, index, r){
18807 if(this.isSelected(r)){
18808 v.onRowSelect(index);
18814 * @param {Array} records The records to select
18815 * @param {Boolean} keepExisting (optional) True to keep existing selections
18817 selectRecords : function(records, keepExisting){
18819 this.clearSelections();
18821 var ds = this.grid.dataSource;
18822 for(var i = 0, len = records.length; i < len; i++){
18823 this.selectRow(ds.indexOf(records[i]), true);
18828 * Gets the number of selected rows.
18831 getCount : function(){
18832 return this.selections.length;
18836 * Selects the first row in the grid.
18838 selectFirstRow : function(){
18843 * Select the last row.
18844 * @param {Boolean} keepExisting (optional) True to keep existing selections
18846 selectLastRow : function(keepExisting){
18847 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18851 * Selects the row immediately following the last selected row.
18852 * @param {Boolean} keepExisting (optional) True to keep existing selections
18854 selectNext : function(keepExisting){
18855 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18856 this.selectRow(this.last+1, keepExisting);
18857 this.grid.getView().focusRow(this.last);
18862 * Selects the row that precedes the last selected row.
18863 * @param {Boolean} keepExisting (optional) True to keep existing selections
18865 selectPrevious : function(keepExisting){
18867 this.selectRow(this.last-1, keepExisting);
18868 this.grid.getView().focusRow(this.last);
18873 * Returns the selected records
18874 * @return {Array} Array of selected records
18876 getSelections : function(){
18877 return [].concat(this.selections.items);
18881 * Returns the first selected record.
18884 getSelected : function(){
18885 return this.selections.itemAt(0);
18890 * Clears all selections.
18892 clearSelections : function(fast){
18893 if(this.locked) return;
18895 var ds = this.grid.dataSource;
18896 var s = this.selections;
18897 s.each(function(r){
18898 this.deselectRow(ds.indexOfId(r.id));
18902 this.selections.clear();
18909 * Selects all rows.
18911 selectAll : function(){
18912 if(this.locked) return;
18913 this.selections.clear();
18914 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18915 this.selectRow(i, true);
18920 * Returns True if there is a selection.
18921 * @return {Boolean}
18923 hasSelection : function(){
18924 return this.selections.length > 0;
18928 * Returns True if the specified row is selected.
18929 * @param {Number/Record} record The record or index of the record to check
18930 * @return {Boolean}
18932 isSelected : function(index){
18933 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18934 return (r && this.selections.key(r.id) ? true : false);
18938 * Returns True if the specified record id is selected.
18939 * @param {String} id The id of record to check
18940 * @return {Boolean}
18942 isIdSelected : function(id){
18943 return (this.selections.key(id) ? true : false);
18947 handleMouseDown : function(e, t){
18948 var view = this.grid.getView(), rowIndex;
18949 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18952 if(e.shiftKey && this.last !== false){
18953 var last = this.last;
18954 this.selectRange(last, rowIndex, e.ctrlKey);
18955 this.last = last; // reset the last
18956 view.focusRow(rowIndex);
18958 var isSelected = this.isSelected(rowIndex);
18959 if(e.button !== 0 && isSelected){
18960 view.focusRow(rowIndex);
18961 }else if(e.ctrlKey && isSelected){
18962 this.deselectRow(rowIndex);
18963 }else if(!isSelected){
18964 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18965 view.focusRow(rowIndex);
18968 this.fireEvent("afterselectionchange", this);
18971 handleDragableRowClick : function(grid, rowIndex, e)
18973 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18974 this.selectRow(rowIndex, false);
18975 grid.view.focusRow(rowIndex);
18976 this.fireEvent("afterselectionchange", this);
18981 * Selects multiple rows.
18982 * @param {Array} rows Array of the indexes of the row to select
18983 * @param {Boolean} keepExisting (optional) True to keep existing selections
18985 selectRows : function(rows, keepExisting){
18987 this.clearSelections();
18989 for(var i = 0, len = rows.length; i < len; i++){
18990 this.selectRow(rows[i], true);
18995 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18996 * @param {Number} startRow The index of the first row in the range
18997 * @param {Number} endRow The index of the last row in the range
18998 * @param {Boolean} keepExisting (optional) True to retain existing selections
19000 selectRange : function(startRow, endRow, keepExisting){
19001 if(this.locked) return;
19003 this.clearSelections();
19005 if(startRow <= endRow){
19006 for(var i = startRow; i <= endRow; i++){
19007 this.selectRow(i, true);
19010 for(var i = startRow; i >= endRow; i--){
19011 this.selectRow(i, true);
19017 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
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
19021 deselectRange : function(startRow, endRow, preventViewNotify){
19022 if(this.locked) return;
19023 for(var i = startRow; i <= endRow; i++){
19024 this.deselectRow(i, preventViewNotify);
19030 * @param {Number} row The index of the row to select
19031 * @param {Boolean} keepExisting (optional) True to keep existing selections
19033 selectRow : function(index, keepExisting, preventViewNotify){
19034 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19035 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19036 if(!keepExisting || this.singleSelect){
19037 this.clearSelections();
19039 var r = this.grid.dataSource.getAt(index);
19040 this.selections.add(r);
19041 this.last = this.lastActive = index;
19042 if(!preventViewNotify){
19043 this.grid.getView().onRowSelect(index);
19045 this.fireEvent("rowselect", this, index, r);
19046 this.fireEvent("selectionchange", this);
19052 * @param {Number} row The index of the row to deselect
19054 deselectRow : function(index, preventViewNotify){
19055 if(this.locked) return;
19056 if(this.last == index){
19059 if(this.lastActive == index){
19060 this.lastActive = false;
19062 var r = this.grid.dataSource.getAt(index);
19063 this.selections.remove(r);
19064 if(!preventViewNotify){
19065 this.grid.getView().onRowDeselect(index);
19067 this.fireEvent("rowdeselect", this, index);
19068 this.fireEvent("selectionchange", this);
19072 restoreLast : function(){
19074 this.last = this._last;
19079 acceptsNav : function(row, col, cm){
19080 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19084 onEditorKey : function(field, e){
19085 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19090 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19092 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19094 }else if(k == e.ENTER && !e.ctrlKey){
19098 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19100 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19102 }else if(k == e.ESC){
19106 g.startEditing(newCell[0], newCell[1]);
19111 * Ext JS Library 1.1.1
19112 * Copyright(c) 2006-2007, Ext JS, LLC.
19114 * Originally Released Under LGPL - original licence link has changed is not relivant.
19117 * <script type="text/javascript">
19121 * @class Roo.bootstrap.PagingToolbar
19123 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19125 * Create a new PagingToolbar
19126 * @param {Object} config The config object
19128 Roo.bootstrap.PagingToolbar = function(config)
19130 // old args format still supported... - xtype is prefered..
19131 // created from xtype...
19132 var ds = config.dataSource;
19133 this.toolbarItems = [];
19134 if (config.items) {
19135 this.toolbarItems = config.items;
19136 // config.items = [];
19139 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19146 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19150 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19152 * @cfg {Roo.data.Store} dataSource
19153 * The underlying data store providing the paged data
19156 * @cfg {String/HTMLElement/Element} container
19157 * container The id or element that will contain the toolbar
19160 * @cfg {Boolean} displayInfo
19161 * True to display the displayMsg (defaults to false)
19164 * @cfg {Number} pageSize
19165 * The number of records to display per page (defaults to 20)
19169 * @cfg {String} displayMsg
19170 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19172 displayMsg : 'Displaying {0} - {1} of {2}',
19174 * @cfg {String} emptyMsg
19175 * The message to display when no records are found (defaults to "No data to display")
19177 emptyMsg : 'No data to display',
19179 * Customizable piece of the default paging text (defaults to "Page")
19182 beforePageText : "Page",
19184 * Customizable piece of the default paging text (defaults to "of %0")
19187 afterPageText : "of {0}",
19189 * Customizable piece of the default paging text (defaults to "First Page")
19192 firstText : "First Page",
19194 * Customizable piece of the default paging text (defaults to "Previous Page")
19197 prevText : "Previous Page",
19199 * Customizable piece of the default paging text (defaults to "Next Page")
19202 nextText : "Next Page",
19204 * Customizable piece of the default paging text (defaults to "Last Page")
19207 lastText : "Last Page",
19209 * Customizable piece of the default paging text (defaults to "Refresh")
19212 refreshText : "Refresh",
19216 onRender : function(ct, position)
19218 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19219 this.navgroup.parentId = this.id;
19220 this.navgroup.onRender(this.el, null);
19221 // add the buttons to the navgroup
19223 if(this.displayInfo){
19224 Roo.log(this.el.select('ul.navbar-nav',true).first());
19225 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19226 this.displayEl = this.el.select('.x-paging-info', true).first();
19227 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19228 // this.displayEl = navel.el.select('span',true).first();
19234 Roo.each(_this.buttons, function(e){
19235 Roo.factory(e).onRender(_this.el, null);
19239 Roo.each(_this.toolbarItems, function(e) {
19240 _this.navgroup.addItem(e);
19243 this.first = this.navgroup.addItem({
19244 tooltip: this.firstText,
19246 icon : 'fa fa-backward',
19248 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19251 this.prev = this.navgroup.addItem({
19252 tooltip: this.prevText,
19254 icon : 'fa fa-step-backward',
19256 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19258 //this.addSeparator();
19261 var field = this.navgroup.addItem( {
19263 cls : 'x-paging-position',
19265 html : this.beforePageText +
19266 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19267 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19270 this.field = field.el.select('input', true).first();
19271 this.field.on("keydown", this.onPagingKeydown, this);
19272 this.field.on("focus", function(){this.dom.select();});
19275 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19276 //this.field.setHeight(18);
19277 //this.addSeparator();
19278 this.next = this.navgroup.addItem({
19279 tooltip: this.nextText,
19281 html : ' <i class="fa fa-step-forward">',
19283 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19285 this.last = this.navgroup.addItem({
19286 tooltip: this.lastText,
19287 icon : 'fa fa-forward',
19290 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19292 //this.addSeparator();
19293 this.loading = this.navgroup.addItem({
19294 tooltip: this.refreshText,
19295 icon: 'fa fa-refresh',
19297 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19303 updateInfo : function(){
19304 if(this.displayEl){
19305 var count = this.ds.getCount();
19306 var msg = count == 0 ?
19310 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19312 this.displayEl.update(msg);
19317 onLoad : function(ds, r, o){
19318 this.cursor = o.params ? o.params.start : 0;
19319 var d = this.getPageData(),
19323 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19324 this.field.dom.value = ap;
19325 this.first.setDisabled(ap == 1);
19326 this.prev.setDisabled(ap == 1);
19327 this.next.setDisabled(ap == ps);
19328 this.last.setDisabled(ap == ps);
19329 this.loading.enable();
19334 getPageData : function(){
19335 var total = this.ds.getTotalCount();
19338 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19339 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19344 onLoadError : function(){
19345 this.loading.enable();
19349 onPagingKeydown : function(e){
19350 var k = e.getKey();
19351 var d = this.getPageData();
19353 var v = this.field.dom.value, pageNum;
19354 if(!v || isNaN(pageNum = parseInt(v, 10))){
19355 this.field.dom.value = d.activePage;
19358 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19359 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19362 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))
19364 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19365 this.field.dom.value = pageNum;
19366 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19369 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19371 var v = this.field.dom.value, pageNum;
19372 var increment = (e.shiftKey) ? 10 : 1;
19373 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19375 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19376 this.field.dom.value = d.activePage;
19379 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19381 this.field.dom.value = parseInt(v, 10) + increment;
19382 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19383 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19390 beforeLoad : function(){
19392 this.loading.disable();
19397 onClick : function(which){
19404 ds.load({params:{start: 0, limit: this.pageSize}});
19407 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19410 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19413 var total = ds.getTotalCount();
19414 var extra = total % this.pageSize;
19415 var lastStart = extra ? (total - extra) : total-this.pageSize;
19416 ds.load({params:{start: lastStart, limit: this.pageSize}});
19419 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19425 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19426 * @param {Roo.data.Store} store The data store to unbind
19428 unbind : function(ds){
19429 ds.un("beforeload", this.beforeLoad, this);
19430 ds.un("load", this.onLoad, this);
19431 ds.un("loadexception", this.onLoadError, this);
19432 ds.un("remove", this.updateInfo, this);
19433 ds.un("add", this.updateInfo, this);
19434 this.ds = undefined;
19438 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19439 * @param {Roo.data.Store} store The data store to bind
19441 bind : function(ds){
19442 ds.on("beforeload", this.beforeLoad, this);
19443 ds.on("load", this.onLoad, this);
19444 ds.on("loadexception", this.onLoadError, this);
19445 ds.on("remove", this.updateInfo, this);
19446 ds.on("add", this.updateInfo, this);
19457 * @class Roo.bootstrap.MessageBar
19458 * @extends Roo.bootstrap.Component
19459 * Bootstrap MessageBar class
19460 * @cfg {String} html contents of the MessageBar
19461 * @cfg {String} weight (info | success | warning | danger) default info
19462 * @cfg {String} beforeClass insert the bar before the given class
19463 * @cfg {Boolean} closable (true | false) default false
19464 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19467 * Create a new Element
19468 * @param {Object} config The config object
19471 Roo.bootstrap.MessageBar = function(config){
19472 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19475 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19481 beforeClass: 'bootstrap-sticky-wrap',
19483 getAutoCreate : function(){
19487 cls: 'alert alert-dismissable alert-' + this.weight,
19492 html: this.html || ''
19498 cfg.cls += ' alert-messages-fixed';
19512 onRender : function(ct, position)
19514 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19517 var cfg = Roo.apply({}, this.getAutoCreate());
19521 cfg.cls += ' ' + this.cls;
19524 cfg.style = this.style;
19526 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19528 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19531 this.el.select('>button.close').on('click', this.hide, this);
19537 if (!this.rendered) {
19543 this.fireEvent('show', this);
19549 if (!this.rendered) {
19555 this.fireEvent('hide', this);
19558 update : function()
19560 // var e = this.el.dom.firstChild;
19562 // if(this.closable){
19563 // e = e.nextSibling;
19566 // e.data = this.html || '';
19568 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19584 * @class Roo.bootstrap.Graph
19585 * @extends Roo.bootstrap.Component
19586 * Bootstrap Graph class
19590 @cfg {String} graphtype bar | vbar | pie
19591 @cfg {number} g_x coodinator | centre x (pie)
19592 @cfg {number} g_y coodinator | centre y (pie)
19593 @cfg {number} g_r radius (pie)
19594 @cfg {number} g_height height of the chart (respected by all elements in the set)
19595 @cfg {number} g_width width of the chart (respected by all elements in the set)
19596 @cfg {Object} title The title of the chart
19599 -opts (object) options for the chart
19601 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19602 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19604 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.
19605 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19607 o stretch (boolean)
19609 -opts (object) options for the pie
19612 o startAngle (number)
19613 o endAngle (number)
19617 * Create a new Input
19618 * @param {Object} config The config object
19621 Roo.bootstrap.Graph = function(config){
19622 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19628 * The img click event for the img.
19629 * @param {Roo.EventObject} e
19635 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19646 //g_colors: this.colors,
19653 getAutoCreate : function(){
19664 onRender : function(ct,position){
19665 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19666 this.raphael = Raphael(this.el.dom);
19668 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19669 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19670 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19671 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19673 r.text(160, 10, "Single Series Chart").attr(txtattr);
19674 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19675 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19676 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19678 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19679 r.barchart(330, 10, 300, 220, data1);
19680 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19681 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19684 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19685 // r.barchart(30, 30, 560, 250, xdata, {
19686 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19687 // axis : "0 0 1 1",
19688 // axisxlabels : xdata
19689 // //yvalues : cols,
19692 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19694 // this.load(null,xdata,{
19695 // axis : "0 0 1 1",
19696 // axisxlabels : xdata
19701 load : function(graphtype,xdata,opts){
19702 this.raphael.clear();
19704 graphtype = this.graphtype;
19709 var r = this.raphael,
19710 fin = function () {
19711 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19713 fout = function () {
19714 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19716 pfin = function() {
19717 this.sector.stop();
19718 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19721 this.label[0].stop();
19722 this.label[0].attr({ r: 7.5 });
19723 this.label[1].attr({ "font-weight": 800 });
19726 pfout = function() {
19727 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19730 this.label[0].animate({ r: 5 }, 500, "bounce");
19731 this.label[1].attr({ "font-weight": 400 });
19737 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19740 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19743 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19744 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19746 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19753 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19758 setTitle: function(o)
19763 initEvents: function() {
19766 this.el.on('click', this.onClick, this);
19770 onClick : function(e)
19772 Roo.log('img onclick');
19773 this.fireEvent('click', this, e);
19785 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19788 * @class Roo.bootstrap.dash.NumberBox
19789 * @extends Roo.bootstrap.Component
19790 * Bootstrap NumberBox class
19791 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19792 * @cfg {String} headline Box headline
19793 * @cfg {String} content Box content
19794 * @cfg {String} icon Box icon
19795 * @cfg {String} footer Footer text
19796 * @cfg {String} fhref Footer href
19799 * Create a new NumberBox
19800 * @param {Object} config The config object
19804 Roo.bootstrap.dash.NumberBox = function(config){
19805 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19809 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19819 getAutoCreate : function(){
19823 cls : 'small-box bg-' + this.bgcolor,
19831 cls : 'roo-headline',
19832 html : this.headline
19836 cls : 'roo-content',
19837 html : this.content
19851 cls : 'ion ' + this.icon
19860 cls : 'small-box-footer',
19861 href : this.fhref || '#',
19865 cfg.cn.push(footer);
19872 onRender : function(ct,position){
19873 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19880 setHeadline: function (value)
19882 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19885 setFooter: function (value, href)
19887 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19890 this.el.select('a.small-box-footer',true).first().attr('href', href);
19895 setContent: function (value)
19897 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19900 initEvents: function()
19914 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19917 * @class Roo.bootstrap.dash.TabBox
19918 * @extends Roo.bootstrap.Component
19919 * Bootstrap TabBox class
19920 * @cfg {String} title Title of the TabBox
19921 * @cfg {String} icon Icon of the TabBox
19922 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19923 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
19926 * Create a new TabBox
19927 * @param {Object} config The config object
19931 Roo.bootstrap.dash.TabBox = function(config){
19932 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19937 * When a pane is added
19938 * @param {Roo.bootstrap.dash.TabPane} pane
19942 * @event activatepane
19943 * When a pane is activated
19944 * @param {Roo.bootstrap.dash.TabPane} pane
19946 "activatepane" : true
19954 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19959 tabScrollable : false,
19961 getChildContainer : function()
19963 return this.el.select('.tab-content', true).first();
19966 getAutoCreate : function(){
19970 cls: 'pull-left header',
19978 cls: 'fa ' + this.icon
19984 cls: 'nav nav-tabs pull-right',
19990 if(this.tabScrollable){
19997 cls: 'nav nav-tabs pull-right',
20008 cls: 'nav-tabs-custom',
20013 cls: 'tab-content no-padding',
20021 initEvents : function()
20023 //Roo.log('add add pane handler');
20024 this.on('addpane', this.onAddPane, this);
20027 * Updates the box title
20028 * @param {String} html to set the title to.
20030 setTitle : function(value)
20032 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20034 onAddPane : function(pane)
20036 this.panes.push(pane);
20037 //Roo.log('addpane');
20039 // tabs are rendere left to right..
20040 if(!this.showtabs){
20044 var ctr = this.el.select('.nav-tabs', true).first();
20047 var existing = ctr.select('.nav-tab',true);
20048 var qty = existing.getCount();;
20051 var tab = ctr.createChild({
20053 cls : 'nav-tab' + (qty ? '' : ' active'),
20061 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20064 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20066 pane.el.addClass('active');
20071 onTabClick : function(ev,un,ob,pane)
20073 //Roo.log('tab - prev default');
20074 ev.preventDefault();
20077 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20078 pane.tab.addClass('active');
20079 //Roo.log(pane.title);
20080 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20081 // technically we should have a deactivate event.. but maybe add later.
20082 // and it should not de-activate the selected tab...
20083 this.fireEvent('activatepane', pane);
20084 pane.el.addClass('active');
20085 pane.fireEvent('activate');
20090 getActivePane : function()
20093 Roo.each(this.panes, function(p) {
20094 if(p.el.hasClass('active')){
20115 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20117 * @class Roo.bootstrap.TabPane
20118 * @extends Roo.bootstrap.Component
20119 * Bootstrap TabPane class
20120 * @cfg {Boolean} active (false | true) Default false
20121 * @cfg {String} title title of panel
20125 * Create a new TabPane
20126 * @param {Object} config The config object
20129 Roo.bootstrap.dash.TabPane = function(config){
20130 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20136 * When a pane is activated
20137 * @param {Roo.bootstrap.dash.TabPane} pane
20144 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20149 // the tabBox that this is attached to.
20152 getAutoCreate : function()
20160 cfg.cls += ' active';
20165 initEvents : function()
20167 //Roo.log('trigger add pane handler');
20168 this.parent().fireEvent('addpane', this)
20172 * Updates the tab title
20173 * @param {String} html to set the title to.
20175 setTitle: function(str)
20181 this.tab.select('a', true).first().dom.innerHTML = str;
20198 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20201 * @class Roo.bootstrap.menu.Menu
20202 * @extends Roo.bootstrap.Component
20203 * Bootstrap Menu class - container for Menu
20204 * @cfg {String} html Text of the menu
20205 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20206 * @cfg {String} icon Font awesome icon
20207 * @cfg {String} pos Menu align to (top | bottom) default bottom
20211 * Create a new Menu
20212 * @param {Object} config The config object
20216 Roo.bootstrap.menu.Menu = function(config){
20217 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20221 * @event beforeshow
20222 * Fires before this menu is displayed
20223 * @param {Roo.bootstrap.menu.Menu} this
20227 * @event beforehide
20228 * Fires before this menu is hidden
20229 * @param {Roo.bootstrap.menu.Menu} this
20234 * Fires after this menu is displayed
20235 * @param {Roo.bootstrap.menu.Menu} this
20240 * Fires after this menu is hidden
20241 * @param {Roo.bootstrap.menu.Menu} this
20246 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20247 * @param {Roo.bootstrap.menu.Menu} this
20248 * @param {Roo.EventObject} e
20255 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20259 weight : 'default',
20264 getChildContainer : function() {
20265 if(this.isSubMenu){
20269 return this.el.select('ul.dropdown-menu', true).first();
20272 getAutoCreate : function()
20277 cls : 'roo-menu-text',
20285 cls : 'fa ' + this.icon
20296 cls : 'dropdown-button btn btn-' + this.weight,
20301 cls : 'dropdown-toggle btn btn-' + this.weight,
20311 cls : 'dropdown-menu'
20317 if(this.pos == 'top'){
20318 cfg.cls += ' dropup';
20321 if(this.isSubMenu){
20324 cls : 'dropdown-menu'
20331 onRender : function(ct, position)
20333 this.isSubMenu = ct.hasClass('dropdown-submenu');
20335 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20338 initEvents : function()
20340 if(this.isSubMenu){
20344 this.hidden = true;
20346 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20347 this.triggerEl.on('click', this.onTriggerPress, this);
20349 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20350 this.buttonEl.on('click', this.onClick, this);
20356 if(this.isSubMenu){
20360 return this.el.select('ul.dropdown-menu', true).first();
20363 onClick : function(e)
20365 this.fireEvent("click", this, e);
20368 onTriggerPress : function(e)
20370 if (this.isVisible()) {
20377 isVisible : function(){
20378 return !this.hidden;
20383 this.fireEvent("beforeshow", this);
20385 this.hidden = false;
20386 this.el.addClass('open');
20388 Roo.get(document).on("mouseup", this.onMouseUp, this);
20390 this.fireEvent("show", this);
20397 this.fireEvent("beforehide", this);
20399 this.hidden = true;
20400 this.el.removeClass('open');
20402 Roo.get(document).un("mouseup", this.onMouseUp);
20404 this.fireEvent("hide", this);
20407 onMouseUp : function()
20421 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20424 * @class Roo.bootstrap.menu.Item
20425 * @extends Roo.bootstrap.Component
20426 * Bootstrap MenuItem class
20427 * @cfg {Boolean} submenu (true | false) default false
20428 * @cfg {String} html text of the item
20429 * @cfg {String} href the link
20430 * @cfg {Boolean} disable (true | false) default false
20431 * @cfg {Boolean} preventDefault (true | false) default true
20432 * @cfg {String} icon Font awesome icon
20433 * @cfg {String} pos Submenu align to (left | right) default right
20437 * Create a new Item
20438 * @param {Object} config The config object
20442 Roo.bootstrap.menu.Item = function(config){
20443 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20447 * Fires when the mouse is hovering over this menu
20448 * @param {Roo.bootstrap.menu.Item} this
20449 * @param {Roo.EventObject} e
20454 * Fires when the mouse exits this menu
20455 * @param {Roo.bootstrap.menu.Item} this
20456 * @param {Roo.EventObject} e
20462 * The raw click event for the entire grid.
20463 * @param {Roo.EventObject} e
20469 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20474 preventDefault: true,
20479 getAutoCreate : function()
20484 cls : 'roo-menu-item-text',
20492 cls : 'fa ' + this.icon
20501 href : this.href || '#',
20508 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20512 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20514 if(this.pos == 'left'){
20515 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20522 initEvents : function()
20524 this.el.on('mouseover', this.onMouseOver, this);
20525 this.el.on('mouseout', this.onMouseOut, this);
20527 this.el.select('a', true).first().on('click', this.onClick, this);
20531 onClick : function(e)
20533 if(this.preventDefault){
20534 e.preventDefault();
20537 this.fireEvent("click", this, e);
20540 onMouseOver : function(e)
20542 if(this.submenu && this.pos == 'left'){
20543 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20546 this.fireEvent("mouseover", this, e);
20549 onMouseOut : function(e)
20551 this.fireEvent("mouseout", this, e);
20563 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20566 * @class Roo.bootstrap.menu.Separator
20567 * @extends Roo.bootstrap.Component
20568 * Bootstrap Separator class
20571 * Create a new Separator
20572 * @param {Object} config The config object
20576 Roo.bootstrap.menu.Separator = function(config){
20577 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20580 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20582 getAutoCreate : function(){
20603 * @class Roo.bootstrap.Tooltip
20604 * Bootstrap Tooltip class
20605 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20606 * to determine which dom element triggers the tooltip.
20608 * It needs to add support for additional attributes like tooltip-position
20611 * Create a new Toolti
20612 * @param {Object} config The config object
20615 Roo.bootstrap.Tooltip = function(config){
20616 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20619 Roo.apply(Roo.bootstrap.Tooltip, {
20621 * @function init initialize tooltip monitoring.
20625 currentTip : false,
20626 currentRegion : false,
20632 Roo.get(document).on('mouseover', this.enter ,this);
20633 Roo.get(document).on('mouseout', this.leave, this);
20636 this.currentTip = new Roo.bootstrap.Tooltip();
20639 enter : function(ev)
20641 var dom = ev.getTarget();
20642 //Roo.log(['enter',dom]);
20643 var el = Roo.fly(dom);
20644 if (this.currentEl) {
20646 //Roo.log(this.currentEl);
20647 //Roo.log(this.currentEl.contains(dom));
20648 if (this.currentEl == el) {
20651 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20659 if (this.currentTip.el) {
20660 this.currentTip.el.hide(); // force hiding...
20663 if (!el.attr('tooltip')) { // parents who have tip?
20666 this.currentEl = el;
20667 this.currentTip.bind(el);
20668 this.currentRegion = Roo.lib.Region.getRegion(dom);
20669 this.currentTip.enter();
20672 leave : function(ev)
20674 var dom = ev.getTarget();
20675 //Roo.log(['leave',dom]);
20676 if (!this.currentEl) {
20681 if (dom != this.currentEl.dom) {
20684 var xy = ev.getXY();
20685 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
20688 // only activate leave if mouse cursor is outside... bounding box..
20693 if (this.currentTip) {
20694 this.currentTip.leave();
20696 //Roo.log('clear currentEl');
20697 this.currentEl = false;
20702 'left' : ['r-l', [-2,0], 'right'],
20703 'right' : ['l-r', [2,0], 'left'],
20704 'bottom' : ['t-b', [0,2], 'top'],
20705 'top' : [ 'b-t', [0,-2], 'bottom']
20711 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
20716 delay : null, // can be { show : 300 , hide: 500}
20720 hoverState : null, //???
20722 placement : 'bottom',
20724 getAutoCreate : function(){
20731 cls : 'tooltip-arrow'
20734 cls : 'tooltip-inner'
20741 bind : function(el)
20747 enter : function () {
20749 if (this.timeout != null) {
20750 clearTimeout(this.timeout);
20753 this.hoverState = 'in'
20754 //Roo.log("enter - show");
20755 if (!this.delay || !this.delay.show) {
20760 this.timeout = setTimeout(function () {
20761 if (_t.hoverState == 'in') {
20764 }, this.delay.show);
20768 clearTimeout(this.timeout);
20770 this.hoverState = 'out'
20771 if (!this.delay || !this.delay.hide) {
20777 this.timeout = setTimeout(function () {
20778 //Roo.log("leave - timeout");
20780 if (_t.hoverState == 'out') {
20782 Roo.bootstrap.Tooltip.currentEl = false;
20790 this.render(document.body);
20793 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
20794 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
20796 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
20798 var placement = typeof this.placement == 'function' ?
20799 this.placement.call(this, this.el, on_el) :
20802 var autoToken = /\s?auto?\s?/i;
20803 var autoPlace = autoToken.test(placement);
20805 placement = placement.replace(autoToken, '') || 'top';
20809 //this.el.setXY([0,0]);
20811 //this.el.dom.style.display='block';
20812 this.el.addClass(placement);
20814 //this.el.appendTo(on_el);
20816 var p = this.getPosition();
20817 var box = this.el.getBox();
20822 var align = Roo.bootstrap.Tooltip.alignment[placement]
20823 this.el.alignTo(this.bindEl, align[0],align[1]);
20824 //var arrow = this.el.select('.arrow',true).first();
20825 //arrow.set(align[2],
20827 this.el.addClass('in fade');
20828 this.hoverState = null;
20830 if (this.el.hasClass('fade')) {
20841 //this.el.setXY([0,0]);
20842 this.el.removeClass('in');