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 ( primary | success | info | warning | danger | link ) default
448 * @cfg {String} size ( lg | sm | xs)
449 * @cfg {String} tag ( a | input | submit)
450 * @cfg {String} href empty or href
451 * @cfg {Boolean} disabled default false;
452 * @cfg {Boolean} isClose default false;
453 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
454 * @cfg {String} badge text for badge
455 * @cfg {String} theme default
456 * @cfg {Boolean} inverse
457 * @cfg {Boolean} toggle
458 * @cfg {String} ontext text for on toggle state
459 * @cfg {String} offtext text for off toggle state
460 * @cfg {Boolean} defaulton
461 * @cfg {Boolean} preventDefault default true
462 * @cfg {Boolean} removeClass remove the standard class..
463 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
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 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 default true
2065 * @cfg {Boolean} allow_close default true
2068 * Create a new Modal Dialog
2069 * @param {Object} config The config object
2072 Roo.bootstrap.Modal = function(config){
2073 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2078 * The raw btnclick event for the button
2079 * @param {Roo.EventObject} e
2083 this.buttons = this.buttons || [];
2086 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2088 title : 'test dialog',
2095 specificTitle: false,
2097 buttonPosition: 'right',
2103 onRender : function(ct, position)
2105 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2108 var cfg = Roo.apply({}, this.getAutoCreate());
2111 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2113 //if (!cfg.name.length) {
2117 cfg.cls += ' ' + this.cls;
2120 cfg.style = this.style;
2122 this.el = Roo.get(document.body).createChild(cfg, position);
2124 //var type = this.el.dom.type;
2126 if(this.tabIndex !== undefined){
2127 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2132 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2133 this.maskEl.enableDisplayMode("block");
2135 //this.el.addClass("x-dlg-modal");
2137 if (this.buttons.length) {
2138 Roo.each(this.buttons, function(bb) {
2139 b = Roo.apply({}, bb);
2140 b.xns = b.xns || Roo.bootstrap;
2141 b.xtype = b.xtype || 'Button';
2142 if (typeof(b.listeners) == 'undefined') {
2143 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2146 var btn = Roo.factory(b);
2148 btn.onRender(this.el.select('.modal-footer div').first());
2152 // render the children.
2155 if(typeof(this.items) != 'undefined'){
2156 var items = this.items;
2159 for(var i =0;i < items.length;i++) {
2160 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2164 this.items = nitems;
2166 this.body = this.el.select('.modal-body',true).first();
2167 this.close = this.el.select('.modal-header .close', true).first();
2168 this.footer = this.el.select('.modal-footer',true).first();
2170 //this.el.addClass([this.fieldClass, this.cls]);
2173 getAutoCreate : function(){
2178 html : this.html || ''
2183 cls : 'modal-title',
2187 if(this.specificTitle){
2193 if (this.allow_close) {
2204 style : 'display: none',
2207 cls: "modal-dialog",
2210 cls : "modal-content",
2213 cls : 'modal-header',
2218 cls : 'modal-footer',
2222 cls: 'btn-' + this.buttonPosition
2239 modal.cls += ' fade';
2245 getChildContainer : function() {
2247 return this.el.select('.modal-body',true).first();
2250 getButtonContainer : function() {
2251 return this.el.select('.modal-footer div',true).first();
2254 initEvents : function()
2256 this.el.select('.modal-header .close').on('click', this.hide, this);
2258 // this.addxtype(this);
2262 if (!this.rendered) {
2266 this.el.setStyle('display', 'block');
2270 (function(){ _this.el.addClass('in'); }).defer(50);
2272 this.el.addClass('in');
2275 Roo.get(document.body).addClass("x-body-masked");
2276 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2278 this.el.setStyle('zIndex', '10001');
2279 this.fireEvent('show', this);
2286 Roo.get(document.body).removeClass("x-body-masked");
2287 this.el.removeClass('in');
2291 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2293 this.el.setStyle('display', 'none');
2296 this.fireEvent('hide', this);
2299 addButton : function(str, cb)
2303 var b = Roo.apply({}, { html : str } );
2304 b.xns = b.xns || Roo.bootstrap;
2305 b.xtype = b.xtype || 'Button';
2306 if (typeof(b.listeners) == 'undefined') {
2307 b.listeners = { click : cb.createDelegate(this) };
2310 var btn = Roo.factory(b);
2312 btn.onRender(this.el.select('.modal-footer div').first());
2318 setDefaultButton : function(btn)
2320 //this.el.select('.modal-footer').()
2322 resizeTo: function(w,h)
2326 setContentSize : function(w, h)
2330 onButtonClick: function(btn,e)
2333 this.fireEvent('btnclick', btn.name, e);
2335 setTitle: function(str) {
2336 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2342 Roo.apply(Roo.bootstrap.Modal, {
2344 * Button config that displays a single OK button
2353 * Button config that displays Yes and No buttons
2369 * Button config that displays OK and Cancel buttons
2384 * Button config that displays Yes, No and Cancel buttons
2406 * messagebox - can be used as a replace
2410 * @class Roo.MessageBox
2411 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2415 Roo.Msg.alert('Status', 'Changes saved successfully.');
2417 // Prompt for user data:
2418 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2420 // process text value...
2424 // Show a dialog using config options:
2426 title:'Save Changes?',
2427 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2428 buttons: Roo.Msg.YESNOCANCEL,
2435 Roo.bootstrap.MessageBox = function(){
2436 var dlg, opt, mask, waitTimer;
2437 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2438 var buttons, activeTextEl, bwidth;
2442 var handleButton = function(button){
2444 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2448 var handleHide = function(){
2450 dlg.el.removeClass(opt.cls);
2453 // Roo.TaskMgr.stop(waitTimer);
2454 // waitTimer = null;
2459 var updateButtons = function(b){
2462 buttons["ok"].hide();
2463 buttons["cancel"].hide();
2464 buttons["yes"].hide();
2465 buttons["no"].hide();
2466 //dlg.footer.dom.style.display = 'none';
2469 dlg.footer.dom.style.display = '';
2470 for(var k in buttons){
2471 if(typeof buttons[k] != "function"){
2474 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2475 width += buttons[k].el.getWidth()+15;
2485 var handleEsc = function(d, k, e){
2486 if(opt && opt.closable !== false){
2496 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2497 * @return {Roo.BasicDialog} The BasicDialog element
2499 getDialog : function(){
2501 dlg = new Roo.bootstrap.Modal( {
2504 //constraintoviewport:false,
2506 //collapsible : false,
2511 //buttonAlign:"center",
2512 closeClick : function(){
2513 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2516 handleButton("cancel");
2521 dlg.on("hide", handleHide);
2523 //dlg.addKeyListener(27, handleEsc);
2525 this.buttons = buttons;
2526 var bt = this.buttonText;
2527 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2528 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2529 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2530 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2532 bodyEl = dlg.body.createChild({
2534 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2535 '<textarea class="roo-mb-textarea"></textarea>' +
2536 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2538 msgEl = bodyEl.dom.firstChild;
2539 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2540 textboxEl.enableDisplayMode();
2541 textboxEl.addKeyListener([10,13], function(){
2542 if(dlg.isVisible() && opt && opt.buttons){
2545 }else if(opt.buttons.yes){
2546 handleButton("yes");
2550 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2551 textareaEl.enableDisplayMode();
2552 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2553 progressEl.enableDisplayMode();
2554 var pf = progressEl.dom.firstChild;
2556 pp = Roo.get(pf.firstChild);
2557 pp.setHeight(pf.offsetHeight);
2565 * Updates the message box body text
2566 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2567 * the XHTML-compliant non-breaking space character '&#160;')
2568 * @return {Roo.MessageBox} This message box
2570 updateText : function(text){
2571 if(!dlg.isVisible() && !opt.width){
2572 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2574 msgEl.innerHTML = text || ' ';
2576 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2577 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2579 Math.min(opt.width || cw , this.maxWidth),
2580 Math.max(opt.minWidth || this.minWidth, bwidth)
2583 activeTextEl.setWidth(w);
2585 if(dlg.isVisible()){
2586 dlg.fixedcenter = false;
2588 // to big, make it scroll. = But as usual stupid IE does not support
2591 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2592 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2593 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2595 bodyEl.dom.style.height = '';
2596 bodyEl.dom.style.overflowY = '';
2599 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2601 bodyEl.dom.style.overflowX = '';
2604 dlg.setContentSize(w, bodyEl.getHeight());
2605 if(dlg.isVisible()){
2606 dlg.fixedcenter = true;
2612 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2613 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2614 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2615 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2616 * @return {Roo.MessageBox} This message box
2618 updateProgress : function(value, text){
2620 this.updateText(text);
2622 if (pp) { // weird bug on my firefox - for some reason this is not defined
2623 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2629 * Returns true if the message box is currently displayed
2630 * @return {Boolean} True if the message box is visible, else false
2632 isVisible : function(){
2633 return dlg && dlg.isVisible();
2637 * Hides the message box if it is displayed
2640 if(this.isVisible()){
2646 * Displays a new message box, or reinitializes an existing message box, based on the config options
2647 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2648 * The following config object properties are supported:
2650 Property Type Description
2651 ---------- --------------- ------------------------------------------------------------------------------------
2652 animEl String/Element An id or Element from which the message box should animate as it opens and
2653 closes (defaults to undefined)
2654 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2655 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2656 closable Boolean False to hide the top-right close button (defaults to true). Note that
2657 progress and wait dialogs will ignore this property and always hide the
2658 close button as they can only be closed programmatically.
2659 cls String A custom CSS class to apply to the message box element
2660 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2661 displayed (defaults to 75)
2662 fn Function A callback function to execute after closing the dialog. The arguments to the
2663 function will be btn (the name of the button that was clicked, if applicable,
2664 e.g. "ok"), and text (the value of the active text field, if applicable).
2665 Progress and wait dialogs will ignore this option since they do not respond to
2666 user actions and can only be closed programmatically, so any required function
2667 should be called by the same code after it closes the dialog.
2668 icon String A CSS class that provides a background image to be used as an icon for
2669 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2670 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2671 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2672 modal Boolean False to allow user interaction with the page while the message box is
2673 displayed (defaults to true)
2674 msg String A string that will replace the existing message box body text (defaults
2675 to the XHTML-compliant non-breaking space character ' ')
2676 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2677 progress Boolean True to display a progress bar (defaults to false)
2678 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2679 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2680 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2681 title String The title text
2682 value String The string value to set into the active textbox element if displayed
2683 wait Boolean True to display a progress bar (defaults to false)
2684 width Number The width of the dialog in pixels
2691 msg: 'Please enter your address:',
2693 buttons: Roo.MessageBox.OKCANCEL,
2696 animEl: 'addAddressBtn'
2699 * @param {Object} config Configuration options
2700 * @return {Roo.MessageBox} This message box
2702 show : function(options)
2705 // this causes nightmares if you show one dialog after another
2706 // especially on callbacks..
2708 if(this.isVisible()){
2711 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2712 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2713 Roo.log("New Dialog Message:" + options.msg )
2714 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2715 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2718 var d = this.getDialog();
2720 d.setTitle(opt.title || " ");
2721 d.close.setDisplayed(opt.closable !== false);
2722 activeTextEl = textboxEl;
2723 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2728 textareaEl.setHeight(typeof opt.multiline == "number" ?
2729 opt.multiline : this.defaultTextHeight);
2730 activeTextEl = textareaEl;
2739 progressEl.setDisplayed(opt.progress === true);
2740 this.updateProgress(0);
2741 activeTextEl.dom.value = opt.value || "";
2743 dlg.setDefaultButton(activeTextEl);
2745 var bs = opt.buttons;
2749 }else if(bs && bs.yes){
2750 db = buttons["yes"];
2752 dlg.setDefaultButton(db);
2754 bwidth = updateButtons(opt.buttons);
2755 this.updateText(opt.msg);
2757 d.el.addClass(opt.cls);
2759 d.proxyDrag = opt.proxyDrag === true;
2760 d.modal = opt.modal !== false;
2761 d.mask = opt.modal !== false ? mask : false;
2763 // force it to the end of the z-index stack so it gets a cursor in FF
2764 document.body.appendChild(dlg.el.dom);
2765 d.animateTarget = null;
2766 d.show(options.animEl);
2772 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2773 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2774 * and closing the message box when the process is complete.
2775 * @param {String} title The title bar text
2776 * @param {String} msg The message box body text
2777 * @return {Roo.MessageBox} This message box
2779 progress : function(title, msg){
2786 minWidth: this.minProgressWidth,
2793 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2794 * If a callback function is passed it will be called after the user clicks the button, and the
2795 * id of the button that was clicked will be passed as the only parameter to the callback
2796 * (could also be the top-right close button).
2797 * @param {String} title The title bar text
2798 * @param {String} msg The message box body text
2799 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2800 * @param {Object} scope (optional) The scope of the callback function
2801 * @return {Roo.MessageBox} This message box
2803 alert : function(title, msg, fn, scope){
2816 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2817 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2818 * You are responsible for closing the message box when the process is complete.
2819 * @param {String} msg The message box body text
2820 * @param {String} title (optional) The title bar text
2821 * @return {Roo.MessageBox} This message box
2823 wait : function(msg, title){
2834 waitTimer = Roo.TaskMgr.start({
2836 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2844 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2845 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2846 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2847 * @param {String} title The title bar text
2848 * @param {String} msg The message box body text
2849 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2850 * @param {Object} scope (optional) The scope of the callback function
2851 * @return {Roo.MessageBox} This message box
2853 confirm : function(title, msg, fn, scope){
2857 buttons: this.YESNO,
2866 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2867 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2868 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2869 * (could also be the top-right close button) and the text that was entered will be passed as the two
2870 * parameters to the callback.
2871 * @param {String} title The title bar text
2872 * @param {String} msg The message box body text
2873 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2874 * @param {Object} scope (optional) The scope of the callback function
2875 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2876 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2877 * @return {Roo.MessageBox} This message box
2879 prompt : function(title, msg, fn, scope, multiline){
2883 buttons: this.OKCANCEL,
2888 multiline: multiline,
2895 * Button config that displays a single OK button
2900 * Button config that displays Yes and No buttons
2903 YESNO : {yes:true, no:true},
2905 * Button config that displays OK and Cancel buttons
2908 OKCANCEL : {ok:true, cancel:true},
2910 * Button config that displays Yes, No and Cancel buttons
2913 YESNOCANCEL : {yes:true, no:true, cancel:true},
2916 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2919 defaultTextHeight : 75,
2921 * The maximum width in pixels of the message box (defaults to 600)
2926 * The minimum width in pixels of the message box (defaults to 100)
2931 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2932 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2935 minProgressWidth : 250,
2937 * An object containing the default button text strings that can be overriden for localized language support.
2938 * Supported properties are: ok, cancel, yes and no.
2939 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2952 * Shorthand for {@link Roo.MessageBox}
2954 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2955 Roo.Msg = Roo.Msg || Roo.MessageBox;
2964 * @class Roo.bootstrap.Navbar
2965 * @extends Roo.bootstrap.Component
2966 * Bootstrap Navbar class
2969 * Create a new Navbar
2970 * @param {Object} config The config object
2974 Roo.bootstrap.Navbar = function(config){
2975 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2979 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2988 getAutoCreate : function(){
2991 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2995 initEvents :function ()
2997 //Roo.log(this.el.select('.navbar-toggle',true));
2998 this.el.select('.navbar-toggle',true).on('click', function() {
2999 // Roo.log('click');
3000 this.el.select('.navbar-collapse',true).toggleClass('in');
3008 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3010 var size = this.el.getSize();
3011 this.maskEl.setSize(size.width, size.height);
3012 this.maskEl.enableDisplayMode("block");
3021 getChildContainer : function()
3023 if (this.el.select('.collapse').getCount()) {
3024 return this.el.select('.collapse',true).first();
3057 * @class Roo.bootstrap.NavSimplebar
3058 * @extends Roo.bootstrap.Navbar
3059 * Bootstrap Sidebar class
3061 * @cfg {Boolean} inverse is inverted color
3063 * @cfg {String} type (nav | pills | tabs)
3064 * @cfg {Boolean} arrangement stacked | justified
3065 * @cfg {String} align (left | right) alignment
3067 * @cfg {Boolean} main (true|false) main nav bar? default false
3068 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3070 * @cfg {String} tag (header|footer|nav|div) default is nav
3076 * Create a new Sidebar
3077 * @param {Object} config The config object
3081 Roo.bootstrap.NavSimplebar = function(config){
3082 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3085 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3101 getAutoCreate : function(){
3105 tag : this.tag || 'div',
3118 this.type = this.type || 'nav';
3119 if (['tabs','pills'].indexOf(this.type)!==-1) {
3120 cfg.cn[0].cls += ' nav-' + this.type
3124 if (this.type!=='nav') {
3125 Roo.log('nav type must be nav/tabs/pills')
3127 cfg.cn[0].cls += ' navbar-nav'
3133 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3134 cfg.cn[0].cls += ' nav-' + this.arrangement;
3138 if (this.align === 'right') {
3139 cfg.cn[0].cls += ' navbar-right';
3143 cfg.cls += ' navbar-inverse';
3170 * @class Roo.bootstrap.NavHeaderbar
3171 * @extends Roo.bootstrap.NavSimplebar
3172 * Bootstrap Sidebar class
3174 * @cfg {String} brand what is brand
3175 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3176 * @cfg {String} brand_href href of the brand
3177 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3178 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3181 * Create a new Sidebar
3182 * @param {Object} config The config object
3186 Roo.bootstrap.NavHeaderbar = function(config){
3187 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3190 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3198 getAutoCreate : function(){
3201 tag: this.nav || 'nav',
3210 cls: 'navbar-header',
3215 cls: 'navbar-toggle',
3216 'data-toggle': 'collapse',
3221 html: 'Toggle navigation'
3243 cls: 'collapse navbar-collapse',
3247 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3249 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3250 cfg.cls += ' navbar-' + this.position;
3252 // tag can override this..
3254 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3257 if (this.brand !== '') {
3260 href: this.brand_href ? this.brand_href : '#',
3261 cls: 'navbar-brand',
3269 cfg.cls += ' main-nav';
3277 initEvents : function()
3279 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3281 if (this.autohide) {
3286 Roo.get(document).on('scroll',function(e) {
3287 var ns = Roo.get(document).getScroll().top;
3288 var os = prevScroll;
3292 ft.removeClass('slideDown');
3293 ft.addClass('slideUp');
3296 ft.removeClass('slideUp');
3297 ft.addClass('slideDown');
3321 * @class Roo.bootstrap.NavSidebar
3322 * @extends Roo.bootstrap.Navbar
3323 * Bootstrap Sidebar class
3326 * Create a new Sidebar
3327 * @param {Object} config The config object
3331 Roo.bootstrap.NavSidebar = function(config){
3332 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3335 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3337 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3339 getAutoCreate : function(){
3344 cls: 'sidebar sidebar-nav'
3366 * @class Roo.bootstrap.NavGroup
3367 * @extends Roo.bootstrap.Component
3368 * Bootstrap NavGroup class
3369 * @cfg {String} align left | right
3370 * @cfg {Boolean} inverse false | true
3371 * @cfg {String} type (nav|pills|tab) default nav
3372 * @cfg {String} navId - reference Id for navbar.
3376 * Create a new nav group
3377 * @param {Object} config The config object
3380 Roo.bootstrap.NavGroup = function(config){
3381 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3384 Roo.bootstrap.NavGroup.register(this);
3388 * Fires when the active item changes
3389 * @param {Roo.bootstrap.NavGroup} this
3390 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3391 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3398 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3409 getAutoCreate : function()
3411 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3418 if (['tabs','pills'].indexOf(this.type)!==-1) {
3419 cfg.cls += ' nav-' + this.type
3421 if (this.type!=='nav') {
3422 Roo.log('nav type must be nav/tabs/pills')
3424 cfg.cls += ' navbar-nav'
3427 if (this.parent().sidebar) {
3430 cls: 'dashboard-menu sidebar-menu'
3436 if (this.form === true) {
3442 if (this.align === 'right') {
3443 cfg.cls += ' navbar-right';
3445 cfg.cls += ' navbar-left';
3449 if (this.align === 'right') {
3450 cfg.cls += ' navbar-right';
3454 cfg.cls += ' navbar-inverse';
3462 * sets the active Navigation item
3463 * @param {Roo.bootstrap.NavItem} the new current navitem
3465 setActiveItem : function(item)
3468 Roo.each(this.navItems, function(v){
3473 v.setActive(false, true);
3480 item.setActive(true, true);
3481 this.fireEvent('changed', this, item, prev);
3486 * gets the active Navigation item
3487 * @return {Roo.bootstrap.NavItem} the current navitem
3489 getActive : function()
3493 Roo.each(this.navItems, function(v){
3504 indexOfNav : function()
3508 Roo.each(this.navItems, function(v,i){
3519 * adds a Navigation item
3520 * @param {Roo.bootstrap.NavItem} the navitem to add
3522 addItem : function(cfg)
3524 var cn = new Roo.bootstrap.NavItem(cfg);
3526 cn.parentId = this.id;
3527 cn.onRender(this.el, null);
3531 * register a Navigation item
3532 * @param {Roo.bootstrap.NavItem} the navitem to add
3534 register : function(item)
3536 this.navItems.push( item);
3537 item.navId = this.navId;
3542 * clear all the Navigation item
3545 clearAll : function()
3548 this.el.dom.innerHTML = '';
3551 getNavItem: function(tabId)
3554 Roo.each(this.navItems, function(e) {
3555 if (e.tabId == tabId) {
3565 setActiveNext : function()
3567 var i = this.indexOfNav(this.getActive());
3568 if (i > this.navItems.length) {
3571 this.setActiveItem(this.navItems[i+1]);
3573 setActivePrev : function()
3575 var i = this.indexOfNav(this.getActive());
3579 this.setActiveItem(this.navItems[i-1]);
3581 clearWasActive : function(except) {
3582 Roo.each(this.navItems, function(e) {
3583 if (e.tabId != except.tabId && e.was_active) {
3584 e.was_active = false;
3591 getWasActive : function ()
3594 Roo.each(this.navItems, function(e) {
3609 Roo.apply(Roo.bootstrap.NavGroup, {
3613 * register a Navigation Group
3614 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3616 register : function(navgrp)
3618 this.groups[navgrp.navId] = navgrp;
3622 * fetch a Navigation Group based on the navigation ID
3623 * @param {string} the navgroup to add
3624 * @returns {Roo.bootstrap.NavGroup} the navgroup
3626 get: function(navId) {
3627 if (typeof(this.groups[navId]) == 'undefined') {
3629 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3631 return this.groups[navId] ;
3646 * @class Roo.bootstrap.NavItem
3647 * @extends Roo.bootstrap.Component
3648 * Bootstrap Navbar.NavItem class
3649 * @cfg {String} href link to
3650 * @cfg {String} html content of button
3651 * @cfg {String} badge text inside badge
3652 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3653 * @cfg {String} glyphicon name of glyphicon
3654 * @cfg {String} icon name of font awesome icon
3655 * @cfg {Boolean} active Is item active
3656 * @cfg {Boolean} disabled Is item disabled
3658 * @cfg {Boolean} preventDefault (true | false) default false
3659 * @cfg {String} tabId the tab that this item activates.
3660 * @cfg {String} tagtype (a|span) render as a href or span?
3663 * Create a new Navbar Item
3664 * @param {Object} config The config object
3666 Roo.bootstrap.NavItem = function(config){
3667 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3672 * The raw click event for the entire grid.
3673 * @param {Roo.EventObject} e
3678 * Fires when the active item active state changes
3679 * @param {Roo.bootstrap.NavItem} this
3680 * @param {boolean} state the new state
3688 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3696 preventDefault : false,
3703 getAutoCreate : function(){
3711 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3713 if (this.disabled) {
3714 cfg.cls += ' disabled';
3717 if (this.href || this.html || this.glyphicon || this.icon) {
3721 href : this.href || "#",
3722 html: this.html || ''
3727 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3730 if(this.glyphicon) {
3731 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3736 cfg.cn[0].html += " <span class='caret'></span>";
3740 if (this.badge !== '') {
3742 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3750 initEvents: function()
3752 if (typeof (this.menu) != 'undefined') {
3753 this.menu.parentType = this.xtype;
3754 this.menu.triggerEl = this.el;
3755 this.addxtype(Roo.apply({}, this.menu));
3758 this.el.select('a',true).on('click', this.onClick, this);
3760 if(this.tagtype == 'span'){
3761 this.el.select('span',true).on('click', this.onClick, this);
3764 // at this point parent should be available..
3765 this.parent().register(this);
3768 onClick : function(e)
3771 if(this.preventDefault){
3774 if (this.disabled) {
3778 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3779 if (tg && tg.transition) {
3780 Roo.log("waiting for the transitionend");
3784 Roo.log("fire event clicked");
3785 if(this.fireEvent('click', this, e) === false){
3789 if(this.tagtype == 'span'){
3793 var p = this.parent();
3794 if (['tabs','pills'].indexOf(p.type)!==-1) {
3795 if (typeof(p.setActiveItem) !== 'undefined') {
3796 p.setActiveItem(this);
3799 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3800 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3801 // remove the collapsed menu expand...
3802 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3807 isActive: function () {
3810 setActive : function(state, fire, is_was_active)
3812 if (this.active && !state & this.navId) {
3813 this.was_active = true;
3814 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3816 nv.clearWasActive(this);
3820 this.active = state;
3823 this.el.removeClass('active');
3824 } else if (!this.el.hasClass('active')) {
3825 this.el.addClass('active');
3828 this.fireEvent('changed', this, state);
3831 // show a panel if it's registered and related..
3833 if (!this.navId || !this.tabId || !state || is_was_active) {
3837 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3841 var pan = tg.getPanelByName(this.tabId);
3845 // if we can not flip to new panel - go back to old nav highlight..
3846 if (false == tg.showPanel(pan)) {
3847 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3849 var onav = nv.getWasActive();
3851 onav.setActive(true, false, true);
3860 // this should not be here...
3861 setDisabled : function(state)
3863 this.disabled = state;
3865 this.el.removeClass('disabled');
3866 } else if (!this.el.hasClass('disabled')) {
3867 this.el.addClass('disabled');
3873 * Fetch the element to display the tooltip on.
3874 * @return {Roo.Element} defaults to this.el
3876 tooltipEl : function()
3878 return this.el.select('' + this.tagtype + '', true).first();
3889 * <span> icon </span>
3890 * <span> text </span>
3891 * <span>badge </span>
3895 * @class Roo.bootstrap.NavSidebarItem
3896 * @extends Roo.bootstrap.NavItem
3897 * Bootstrap Navbar.NavSidebarItem class
3899 * Create a new Navbar Button
3900 * @param {Object} config The config object
3902 Roo.bootstrap.NavSidebarItem = function(config){
3903 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3908 * The raw click event for the entire grid.
3909 * @param {Roo.EventObject} e
3914 * Fires when the active item active state changes
3915 * @param {Roo.bootstrap.NavSidebarItem} this
3916 * @param {boolean} state the new state
3924 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3927 getAutoCreate : function(){
3932 href : this.href || '#',
3944 html : this.html || ''
3949 cfg.cls += ' active';
3953 if (this.glyphicon || this.icon) {
3954 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3955 a.cn.push({ tag : 'i', cls : c }) ;
3960 if (this.badge !== '') {
3961 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3965 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3966 a.cls += 'dropdown-toggle treeview' ;
3990 * @class Roo.bootstrap.Row
3991 * @extends Roo.bootstrap.Component
3992 * Bootstrap Row class (contains columns...)
3996 * @param {Object} config The config object
3999 Roo.bootstrap.Row = function(config){
4000 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4003 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4005 getAutoCreate : function(){
4024 * @class Roo.bootstrap.Element
4025 * @extends Roo.bootstrap.Component
4026 * Bootstrap Element class
4027 * @cfg {String} html contents of the element
4028 * @cfg {String} tag tag of the element
4029 * @cfg {String} cls class of the element
4032 * Create a new Element
4033 * @param {Object} config The config object
4036 Roo.bootstrap.Element = function(config){
4037 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4040 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4047 getAutoCreate : function(){
4072 * @class Roo.bootstrap.Pagination
4073 * @extends Roo.bootstrap.Component
4074 * Bootstrap Pagination class
4075 * @cfg {String} size xs | sm | md | lg
4076 * @cfg {Boolean} inverse false | true
4079 * Create a new Pagination
4080 * @param {Object} config The config object
4083 Roo.bootstrap.Pagination = function(config){
4084 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4087 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4093 getAutoCreate : function(){
4099 cfg.cls += ' inverse';
4105 cfg.cls += " " + this.cls;
4123 * @class Roo.bootstrap.PaginationItem
4124 * @extends Roo.bootstrap.Component
4125 * Bootstrap PaginationItem class
4126 * @cfg {String} html text
4127 * @cfg {String} href the link
4128 * @cfg {Boolean} preventDefault (true | false) default true
4129 * @cfg {Boolean} active (true | false) default false
4133 * Create a new PaginationItem
4134 * @param {Object} config The config object
4138 Roo.bootstrap.PaginationItem = function(config){
4139 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4144 * The raw click event for the entire grid.
4145 * @param {Roo.EventObject} e
4151 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4155 preventDefault: true,
4159 getAutoCreate : function(){
4165 href : this.href ? this.href : '#',
4166 html : this.html ? this.html : ''
4176 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4182 initEvents: function() {
4184 this.el.on('click', this.onClick, this);
4187 onClick : function(e)
4189 Roo.log('PaginationItem on click ');
4190 if(this.preventDefault){
4194 this.fireEvent('click', this, e);
4210 * @class Roo.bootstrap.Slider
4211 * @extends Roo.bootstrap.Component
4212 * Bootstrap Slider class
4215 * Create a new Slider
4216 * @param {Object} config The config object
4219 Roo.bootstrap.Slider = function(config){
4220 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4223 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4225 getAutoCreate : function(){
4229 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4233 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4245 * Ext JS Library 1.1.1
4246 * Copyright(c) 2006-2007, Ext JS, LLC.
4248 * Originally Released Under LGPL - original licence link has changed is not relivant.
4251 * <script type="text/javascript">
4256 * @class Roo.grid.ColumnModel
4257 * @extends Roo.util.Observable
4258 * This is the default implementation of a ColumnModel used by the Grid. It defines
4259 * the columns in the grid.
4262 var colModel = new Roo.grid.ColumnModel([
4263 {header: "Ticker", width: 60, sortable: true, locked: true},
4264 {header: "Company Name", width: 150, sortable: true},
4265 {header: "Market Cap.", width: 100, sortable: true},
4266 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4267 {header: "Employees", width: 100, sortable: true, resizable: false}
4272 * The config options listed for this class are options which may appear in each
4273 * individual column definition.
4274 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4276 * @param {Object} config An Array of column config objects. See this class's
4277 * config objects for details.
4279 Roo.grid.ColumnModel = function(config){
4281 * The config passed into the constructor
4283 this.config = config;
4286 // if no id, create one
4287 // if the column does not have a dataIndex mapping,
4288 // map it to the order it is in the config
4289 for(var i = 0, len = config.length; i < len; i++){
4291 if(typeof c.dataIndex == "undefined"){
4294 if(typeof c.renderer == "string"){
4295 c.renderer = Roo.util.Format[c.renderer];
4297 if(typeof c.id == "undefined"){
4300 if(c.editor && c.editor.xtype){
4301 c.editor = Roo.factory(c.editor, Roo.grid);
4303 if(c.editor && c.editor.isFormField){
4304 c.editor = new Roo.grid.GridEditor(c.editor);
4306 this.lookup[c.id] = c;
4310 * The width of columns which have no width specified (defaults to 100)
4313 this.defaultWidth = 100;
4316 * Default sortable of columns which have no sortable specified (defaults to false)
4319 this.defaultSortable = false;
4323 * @event widthchange
4324 * Fires when the width of a column changes.
4325 * @param {ColumnModel} this
4326 * @param {Number} columnIndex The column index
4327 * @param {Number} newWidth The new width
4329 "widthchange": true,
4331 * @event headerchange
4332 * Fires when the text of a header changes.
4333 * @param {ColumnModel} this
4334 * @param {Number} columnIndex The column index
4335 * @param {Number} newText The new header text
4337 "headerchange": true,
4339 * @event hiddenchange
4340 * Fires when a column is hidden or "unhidden".
4341 * @param {ColumnModel} this
4342 * @param {Number} columnIndex The column index
4343 * @param {Boolean} hidden true if hidden, false otherwise
4345 "hiddenchange": true,
4347 * @event columnmoved
4348 * Fires when a column is moved.
4349 * @param {ColumnModel} this
4350 * @param {Number} oldIndex
4351 * @param {Number} newIndex
4353 "columnmoved" : true,
4355 * @event columlockchange
4356 * Fires when a column's locked state is changed
4357 * @param {ColumnModel} this
4358 * @param {Number} colIndex
4359 * @param {Boolean} locked true if locked
4361 "columnlockchange" : true
4363 Roo.grid.ColumnModel.superclass.constructor.call(this);
4365 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4367 * @cfg {String} header The header text to display in the Grid view.
4370 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4371 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4372 * specified, the column's index is used as an index into the Record's data Array.
4375 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4376 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4379 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4380 * Defaults to the value of the {@link #defaultSortable} property.
4381 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4384 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4387 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4390 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4393 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4396 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4397 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4398 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4399 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4402 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4405 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4408 * @cfg {String} cursor (Optional)
4411 * Returns the id of the column at the specified index.
4412 * @param {Number} index The column index
4413 * @return {String} the id
4415 getColumnId : function(index){
4416 return this.config[index].id;
4420 * Returns the column for a specified id.
4421 * @param {String} id The column id
4422 * @return {Object} the column
4424 getColumnById : function(id){
4425 return this.lookup[id];
4430 * Returns the column for a specified dataIndex.
4431 * @param {String} dataIndex The column dataIndex
4432 * @return {Object|Boolean} the column or false if not found
4434 getColumnByDataIndex: function(dataIndex){
4435 var index = this.findColumnIndex(dataIndex);
4436 return index > -1 ? this.config[index] : false;
4440 * Returns the index for a specified column id.
4441 * @param {String} id The column id
4442 * @return {Number} the index, or -1 if not found
4444 getIndexById : function(id){
4445 for(var i = 0, len = this.config.length; i < len; i++){
4446 if(this.config[i].id == id){
4454 * Returns the index for a specified column dataIndex.
4455 * @param {String} dataIndex The column dataIndex
4456 * @return {Number} the index, or -1 if not found
4459 findColumnIndex : function(dataIndex){
4460 for(var i = 0, len = this.config.length; i < len; i++){
4461 if(this.config[i].dataIndex == dataIndex){
4469 moveColumn : function(oldIndex, newIndex){
4470 var c = this.config[oldIndex];
4471 this.config.splice(oldIndex, 1);
4472 this.config.splice(newIndex, 0, c);
4473 this.dataMap = null;
4474 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4477 isLocked : function(colIndex){
4478 return this.config[colIndex].locked === true;
4481 setLocked : function(colIndex, value, suppressEvent){
4482 if(this.isLocked(colIndex) == value){
4485 this.config[colIndex].locked = value;
4487 this.fireEvent("columnlockchange", this, colIndex, value);
4491 getTotalLockedWidth : function(){
4493 for(var i = 0; i < this.config.length; i++){
4494 if(this.isLocked(i) && !this.isHidden(i)){
4495 this.totalWidth += this.getColumnWidth(i);
4501 getLockedCount : function(){
4502 for(var i = 0, len = this.config.length; i < len; i++){
4503 if(!this.isLocked(i)){
4510 * Returns the number of columns.
4513 getColumnCount : function(visibleOnly){
4514 if(visibleOnly === true){
4516 for(var i = 0, len = this.config.length; i < len; i++){
4517 if(!this.isHidden(i)){
4523 return this.config.length;
4527 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4528 * @param {Function} fn
4529 * @param {Object} scope (optional)
4530 * @return {Array} result
4532 getColumnsBy : function(fn, scope){
4534 for(var i = 0, len = this.config.length; i < len; i++){
4535 var c = this.config[i];
4536 if(fn.call(scope||this, c, i) === true){
4544 * Returns true if the specified column is sortable.
4545 * @param {Number} col The column index
4548 isSortable : function(col){
4549 if(typeof this.config[col].sortable == "undefined"){
4550 return this.defaultSortable;
4552 return this.config[col].sortable;
4556 * Returns the rendering (formatting) function defined for the column.
4557 * @param {Number} col The column index.
4558 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4560 getRenderer : function(col){
4561 if(!this.config[col].renderer){
4562 return Roo.grid.ColumnModel.defaultRenderer;
4564 return this.config[col].renderer;
4568 * Sets the rendering (formatting) function for a column.
4569 * @param {Number} col The column index
4570 * @param {Function} fn The function to use to process the cell's raw data
4571 * to return HTML markup for the grid view. The render function is called with
4572 * the following parameters:<ul>
4573 * <li>Data value.</li>
4574 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4575 * <li>css A CSS style string to apply to the table cell.</li>
4576 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4577 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4578 * <li>Row index</li>
4579 * <li>Column index</li>
4580 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4582 setRenderer : function(col, fn){
4583 this.config[col].renderer = fn;
4587 * Returns the width for the specified column.
4588 * @param {Number} col The column index
4591 getColumnWidth : function(col){
4592 return this.config[col].width * 1 || this.defaultWidth;
4596 * Sets the width for a column.
4597 * @param {Number} col The column index
4598 * @param {Number} width The new width
4600 setColumnWidth : function(col, width, suppressEvent){
4601 this.config[col].width = width;
4602 this.totalWidth = null;
4604 this.fireEvent("widthchange", this, col, width);
4609 * Returns the total width of all columns.
4610 * @param {Boolean} includeHidden True to include hidden column widths
4613 getTotalWidth : function(includeHidden){
4614 if(!this.totalWidth){
4615 this.totalWidth = 0;
4616 for(var i = 0, len = this.config.length; i < len; i++){
4617 if(includeHidden || !this.isHidden(i)){
4618 this.totalWidth += this.getColumnWidth(i);
4622 return this.totalWidth;
4626 * Returns the header for the specified column.
4627 * @param {Number} col The column index
4630 getColumnHeader : function(col){
4631 return this.config[col].header;
4635 * Sets the header for a column.
4636 * @param {Number} col The column index
4637 * @param {String} header The new header
4639 setColumnHeader : function(col, header){
4640 this.config[col].header = header;
4641 this.fireEvent("headerchange", this, col, header);
4645 * Returns the tooltip for the specified column.
4646 * @param {Number} col The column index
4649 getColumnTooltip : function(col){
4650 return this.config[col].tooltip;
4653 * Sets the tooltip for a column.
4654 * @param {Number} col The column index
4655 * @param {String} tooltip The new tooltip
4657 setColumnTooltip : function(col, tooltip){
4658 this.config[col].tooltip = tooltip;
4662 * Returns the dataIndex for the specified column.
4663 * @param {Number} col The column index
4666 getDataIndex : function(col){
4667 return this.config[col].dataIndex;
4671 * Sets the dataIndex for a column.
4672 * @param {Number} col The column index
4673 * @param {Number} dataIndex The new dataIndex
4675 setDataIndex : function(col, dataIndex){
4676 this.config[col].dataIndex = dataIndex;
4682 * Returns true if the cell is editable.
4683 * @param {Number} colIndex The column index
4684 * @param {Number} rowIndex The row index
4687 isCellEditable : function(colIndex, rowIndex){
4688 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4692 * Returns the editor defined for the cell/column.
4693 * return false or null to disable editing.
4694 * @param {Number} colIndex The column index
4695 * @param {Number} rowIndex The row index
4698 getCellEditor : function(colIndex, rowIndex){
4699 return this.config[colIndex].editor;
4703 * Sets if a column is editable.
4704 * @param {Number} col The column index
4705 * @param {Boolean} editable True if the column is editable
4707 setEditable : function(col, editable){
4708 this.config[col].editable = editable;
4713 * Returns true if the column is hidden.
4714 * @param {Number} colIndex The column index
4717 isHidden : function(colIndex){
4718 return this.config[colIndex].hidden;
4723 * Returns true if the column width cannot be changed
4725 isFixed : function(colIndex){
4726 return this.config[colIndex].fixed;
4730 * Returns true if the column can be resized
4733 isResizable : function(colIndex){
4734 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4737 * Sets if a column is hidden.
4738 * @param {Number} colIndex The column index
4739 * @param {Boolean} hidden True if the column is hidden
4741 setHidden : function(colIndex, hidden){
4742 this.config[colIndex].hidden = hidden;
4743 this.totalWidth = null;
4744 this.fireEvent("hiddenchange", this, colIndex, hidden);
4748 * Sets the editor for a column.
4749 * @param {Number} col The column index
4750 * @param {Object} editor The editor object
4752 setEditor : function(col, editor){
4753 this.config[col].editor = editor;
4757 Roo.grid.ColumnModel.defaultRenderer = function(value){
4758 if(typeof value == "string" && value.length < 1){
4764 // Alias for backwards compatibility
4765 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4768 * Ext JS Library 1.1.1
4769 * Copyright(c) 2006-2007, Ext JS, LLC.
4771 * Originally Released Under LGPL - original licence link has changed is not relivant.
4774 * <script type="text/javascript">
4778 * @class Roo.LoadMask
4779 * A simple utility class for generically masking elements while loading data. If the element being masked has
4780 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4781 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4782 * element's UpdateManager load indicator and will be destroyed after the initial load.
4784 * Create a new LoadMask
4785 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4786 * @param {Object} config The config object
4788 Roo.LoadMask = function(el, config){
4789 this.el = Roo.get(el);
4790 Roo.apply(this, config);
4792 this.store.on('beforeload', this.onBeforeLoad, this);
4793 this.store.on('load', this.onLoad, this);
4794 this.store.on('loadexception', this.onLoadException, this);
4795 this.removeMask = false;
4797 var um = this.el.getUpdateManager();
4798 um.showLoadIndicator = false; // disable the default indicator
4799 um.on('beforeupdate', this.onBeforeLoad, this);
4800 um.on('update', this.onLoad, this);
4801 um.on('failure', this.onLoad, this);
4802 this.removeMask = true;
4806 Roo.LoadMask.prototype = {
4808 * @cfg {Boolean} removeMask
4809 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4810 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4814 * The text to display in a centered loading message box (defaults to 'Loading...')
4818 * @cfg {String} msgCls
4819 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4821 msgCls : 'x-mask-loading',
4824 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4830 * Disables the mask to prevent it from being displayed
4832 disable : function(){
4833 this.disabled = true;
4837 * Enables the mask so that it can be displayed
4839 enable : function(){
4840 this.disabled = false;
4843 onLoadException : function()
4847 if (typeof(arguments[3]) != 'undefined') {
4848 Roo.MessageBox.alert("Error loading",arguments[3]);
4852 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4853 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4862 this.el.unmask(this.removeMask);
4867 this.el.unmask(this.removeMask);
4871 onBeforeLoad : function(){
4873 this.el.mask(this.msg, this.msgCls);
4878 destroy : function(){
4880 this.store.un('beforeload', this.onBeforeLoad, this);
4881 this.store.un('load', this.onLoad, this);
4882 this.store.un('loadexception', this.onLoadException, this);
4884 var um = this.el.getUpdateManager();
4885 um.un('beforeupdate', this.onBeforeLoad, this);
4886 um.un('update', this.onLoad, this);
4887 um.un('failure', this.onLoad, this);
4898 * @class Roo.bootstrap.Table
4899 * @extends Roo.bootstrap.Component
4900 * Bootstrap Table class
4901 * @cfg {String} cls table class
4902 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4903 * @cfg {String} bgcolor Specifies the background color for a table
4904 * @cfg {Number} border Specifies whether the table cells should have borders or not
4905 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4906 * @cfg {Number} cellspacing Specifies the space between cells
4907 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4908 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4909 * @cfg {String} sortable Specifies that the table should be sortable
4910 * @cfg {String} summary Specifies a summary of the content of a table
4911 * @cfg {Number} width Specifies the width of a table
4912 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4914 * @cfg {boolean} striped Should the rows be alternative striped
4915 * @cfg {boolean} bordered Add borders to the table
4916 * @cfg {boolean} hover Add hover highlighting
4917 * @cfg {boolean} condensed Format condensed
4918 * @cfg {boolean} responsive Format condensed
4919 * @cfg {Boolean} loadMask (true|false) default false
4920 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4921 * @cfg {Boolean} thead (true|false) generate thead, default true
4922 * @cfg {Boolean} RowSelection (true|false) default false
4923 * @cfg {Boolean} CellSelection (true|false) default false
4924 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4928 * Create a new Table
4929 * @param {Object} config The config object
4932 Roo.bootstrap.Table = function(config){
4933 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4936 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4937 this.sm = this.selModel;
4938 this.sm.xmodule = this.xmodule || false;
4940 if (this.cm && typeof(this.cm.config) == 'undefined') {
4941 this.colModel = new Roo.grid.ColumnModel(this.cm);
4942 this.cm = this.colModel;
4943 this.cm.xmodule = this.xmodule || false;
4946 this.store= Roo.factory(this.store, Roo.data);
4947 this.ds = this.store;
4948 this.ds.xmodule = this.xmodule || false;
4951 if (this.footer && this.store) {
4952 this.footer.dataSource = this.ds;
4953 this.footer = Roo.factory(this.footer);
4960 * Fires when a cell is clicked
4961 * @param {Roo.bootstrap.Table} this
4962 * @param {Roo.Element} el
4963 * @param {Number} rowIndex
4964 * @param {Number} columnIndex
4965 * @param {Roo.EventObject} e
4969 * @event celldblclick
4970 * Fires when a cell is double clicked
4971 * @param {Roo.bootstrap.Table} this
4972 * @param {Roo.Element} el
4973 * @param {Number} rowIndex
4974 * @param {Number} columnIndex
4975 * @param {Roo.EventObject} e
4977 "celldblclick" : true,
4980 * Fires when a row is clicked
4981 * @param {Roo.bootstrap.Table} this
4982 * @param {Roo.Element} el
4983 * @param {Number} rowIndex
4984 * @param {Roo.EventObject} e
4988 * @event rowdblclick
4989 * Fires when a row is double clicked
4990 * @param {Roo.bootstrap.Table} this
4991 * @param {Roo.Element} el
4992 * @param {Number} rowIndex
4993 * @param {Roo.EventObject} e
4995 "rowdblclick" : true,
4998 * Fires when a mouseover occur
4999 * @param {Roo.bootstrap.Table} this
5000 * @param {Roo.Element} el
5001 * @param {Number} rowIndex
5002 * @param {Number} columnIndex
5003 * @param {Roo.EventObject} e
5008 * Fires when a mouseout occur
5009 * @param {Roo.bootstrap.Table} this
5010 * @param {Roo.Element} el
5011 * @param {Number} rowIndex
5012 * @param {Number} columnIndex
5013 * @param {Roo.EventObject} e
5018 * Fires when a row is rendered, so you can change add a style to it.
5019 * @param {Roo.bootstrap.Table} this
5020 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5027 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5051 RowSelection : false,
5052 CellSelection : false,
5055 // Roo.Element - the tbody
5058 getAutoCreate : function(){
5059 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5068 cfg.cls += ' table-striped';
5072 cfg.cls += ' table-hover';
5074 if (this.bordered) {
5075 cfg.cls += ' table-bordered';
5077 if (this.condensed) {
5078 cfg.cls += ' table-condensed';
5080 if (this.responsive) {
5081 cfg.cls += ' table-responsive';
5085 cfg.cls+= ' ' +this.cls;
5088 // this lot should be simplifed...
5091 cfg.align=this.align;
5094 cfg.bgcolor=this.bgcolor;
5097 cfg.border=this.border;
5099 if (this.cellpadding) {
5100 cfg.cellpadding=this.cellpadding;
5102 if (this.cellspacing) {
5103 cfg.cellspacing=this.cellspacing;
5106 cfg.frame=this.frame;
5109 cfg.rules=this.rules;
5111 if (this.sortable) {
5112 cfg.sortable=this.sortable;
5115 cfg.summary=this.summary;
5118 cfg.width=this.width;
5121 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5124 if(this.store || this.cm){
5126 cfg.cn.push(this.renderHeader());
5129 cfg.cn.push(this.renderBody());
5132 cfg.cn.push(this.renderFooter());
5135 cfg.cls+= ' TableGrid';
5138 return { cn : [ cfg ] };
5141 initEvents : function()
5143 if(!this.store || !this.cm){
5147 //Roo.log('initEvents with ds!!!!');
5149 this.mainBody = this.el.select('tbody', true).first();
5154 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5155 e.on('click', _this.sort, _this);
5158 this.el.on("click", this.onClick, this);
5159 this.el.on("dblclick", this.onDblClick, this);
5161 this.parent().el.setStyle('position', 'relative');
5163 this.footer.parentId = this.id;
5164 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5167 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5169 this.store.on('load', this.onLoad, this);
5170 this.store.on('beforeload', this.onBeforeLoad, this);
5171 this.store.on('update', this.onUpdate, this);
5175 onMouseover : function(e, el)
5177 var cell = Roo.get(el);
5183 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5184 cell = cell.findParent('td', false, true);
5187 var row = cell.findParent('tr', false, true);
5188 var cellIndex = cell.dom.cellIndex;
5189 var rowIndex = row.dom.rowIndex - 1; // start from 0
5191 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5195 onMouseout : function(e, el)
5197 var cell = Roo.get(el);
5203 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5204 cell = cell.findParent('td', false, true);
5207 var row = cell.findParent('tr', false, true);
5208 var cellIndex = cell.dom.cellIndex;
5209 var rowIndex = row.dom.rowIndex - 1; // start from 0
5211 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5215 onClick : function(e, el)
5217 var cell = Roo.get(el);
5219 if(!cell || (!this.CellSelection && !this.RowSelection)){
5224 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5225 cell = cell.findParent('td', false, true);
5228 var row = cell.findParent('tr', false, true);
5229 var cellIndex = cell.dom.cellIndex;
5230 var rowIndex = row.dom.rowIndex - 1;
5232 if(this.CellSelection){
5233 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5236 if(this.RowSelection){
5237 this.fireEvent('rowclick', this, row, rowIndex, e);
5243 onDblClick : function(e,el)
5245 var cell = Roo.get(el);
5247 if(!cell || (!this.CellSelection && !this.RowSelection)){
5251 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5252 cell = cell.findParent('td', false, true);
5255 var row = cell.findParent('tr', false, true);
5256 var cellIndex = cell.dom.cellIndex;
5257 var rowIndex = row.dom.rowIndex - 1;
5259 if(this.CellSelection){
5260 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5263 if(this.RowSelection){
5264 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5268 sort : function(e,el)
5270 var col = Roo.get(el)
5272 if(!col.hasClass('sortable')){
5276 var sort = col.attr('sort');
5279 if(col.hasClass('glyphicon-arrow-up')){
5283 this.store.sortInfo = {field : sort, direction : dir};
5286 Roo.log("calling footer first");
5287 this.footer.onClick('first');
5290 this.store.load({ params : { start : 0 } });
5294 renderHeader : function()
5303 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5305 var config = cm.config[i];
5310 html: cm.getColumnHeader(i)
5313 if(typeof(config.hidden) != 'undefined' && config.hidden){
5314 c.style += ' display:none;';
5317 if(typeof(config.dataIndex) != 'undefined'){
5318 c.sort = config.dataIndex;
5321 if(typeof(config.sortable) != 'undefined' && config.sortable){
5325 if(typeof(config.align) != 'undefined' && config.align.length){
5326 c.style += ' text-align:' + config.align + ';';
5329 if(typeof(config.width) != 'undefined'){
5330 c.style += ' width:' + config.width + 'px;';
5339 renderBody : function()
5349 colspan : this.cm.getColumnCount()
5359 renderFooter : function()
5369 colspan : this.cm.getColumnCount()
5383 Roo.log('ds onload');
5388 var ds = this.store;
5390 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5391 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5393 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5394 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5397 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5398 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5402 var tbody = this.mainBody;
5404 if(ds.getCount() > 0){
5405 ds.data.each(function(d,rowIndex){
5406 var row = this.renderRow(cm, ds, rowIndex);
5408 tbody.createChild(row);
5412 if(row.cellObjects.length){
5413 Roo.each(row.cellObjects, function(r){
5414 _this.renderCellObject(r);
5421 Roo.each(this.el.select('tbody td', true).elements, function(e){
5422 e.on('mouseover', _this.onMouseover, _this);
5425 Roo.each(this.el.select('tbody td', true).elements, function(e){
5426 e.on('mouseout', _this.onMouseout, _this);
5429 //if(this.loadMask){
5430 // this.maskEl.hide();
5435 onUpdate : function(ds,record)
5437 this.refreshRow(record);
5439 onRemove : function(ds, record, index, isUpdate){
5440 if(isUpdate !== true){
5441 this.fireEvent("beforerowremoved", this, index, record);
5443 var bt = this.mainBody.dom;
5445 bt.removeChild(bt.rows[index]);
5448 if(isUpdate !== true){
5449 //this.stripeRows(index);
5450 //this.syncRowHeights(index, index);
5452 this.fireEvent("rowremoved", this, index, record);
5457 refreshRow : function(record){
5458 var ds = this.store, index;
5459 if(typeof record == 'number'){
5461 record = ds.getAt(index);
5463 index = ds.indexOf(record);
5465 this.insertRow(ds, index, true);
5466 this.onRemove(ds, record, index+1, true);
5467 //this.syncRowHeights(index, index);
5469 this.fireEvent("rowupdated", this, index, record);
5472 insertRow : function(dm, rowIndex, isUpdate){
5475 this.fireEvent("beforerowsinserted", this, rowIndex);
5477 //var s = this.getScrollState();
5478 var row = this.renderRow(this.cm, this.store, rowIndex);
5479 // insert before rowIndex..
5480 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5484 if(row.cellObjects.length){
5485 Roo.each(row.cellObjects, function(r){
5486 _this.renderCellObject(r);
5491 this.fireEvent("rowsinserted", this, rowIndex);
5492 //this.syncRowHeights(firstRow, lastRow);
5493 //this.stripeRows(firstRow);
5500 getRowDom : function(rowIndex)
5502 // not sure if I need to check this.. but let's do it anyway..
5503 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5504 this.mainBody.dom.rows[rowIndex] : false
5506 // returns the object tree for a tr..
5509 renderRow : function(cm, ds, rowIndex) {
5511 var d = ds.getAt(rowIndex);
5518 var cellObjects = [];
5520 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5521 var config = cm.config[i];
5523 var renderer = cm.getRenderer(i);
5527 if(typeof(renderer) !== 'undefined'){
5528 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5530 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5531 // and are rendered into the cells after the row is rendered - using the id for the element.
5533 if(typeof(value) === 'object'){
5543 rowIndex : rowIndex,
5548 this.fireEvent('rowclass', this, rowcfg);
5552 cls : rowcfg.rowClass,
5554 html: (typeof(value) === 'object') ? '' : value
5561 if(typeof(config.hidden) != 'undefined' && config.hidden){
5562 td.style += ' display:none;';
5565 if(typeof(config.align) != 'undefined' && config.align.length){
5566 td.style += ' text-align:' + config.align + ';';
5569 if(typeof(config.width) != 'undefined'){
5570 td.style += ' width:' + config.width + 'px;';
5573 if(typeof(config.cursor) != 'undefined'){
5574 td.style += ' cursor:' + config.cursor + ';';
5581 row.cellObjects = cellObjects;
5589 onBeforeLoad : function()
5591 //Roo.log('ds onBeforeLoad');
5595 //if(this.loadMask){
5596 // this.maskEl.show();
5602 this.el.select('tbody', true).first().dom.innerHTML = '';
5605 getSelectionModel : function(){
5607 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5609 return this.selModel;
5612 * Render the Roo.bootstrap object from renderder
5614 renderCellObject : function(r)
5618 var t = r.cfg.render(r.container);
5621 Roo.each(r.cfg.cn, function(c){
5623 container: t.getChildContainer(),
5626 _this.renderCellObject(child);
5643 * @class Roo.bootstrap.TableCell
5644 * @extends Roo.bootstrap.Component
5645 * Bootstrap TableCell class
5646 * @cfg {String} html cell contain text
5647 * @cfg {String} cls cell class
5648 * @cfg {String} tag cell tag (td|th) default td
5649 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5650 * @cfg {String} align Aligns the content in a cell
5651 * @cfg {String} axis Categorizes cells
5652 * @cfg {String} bgcolor Specifies the background color of a cell
5653 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5654 * @cfg {Number} colspan Specifies the number of columns a cell should span
5655 * @cfg {String} headers Specifies one or more header cells a cell is related to
5656 * @cfg {Number} height Sets the height of a cell
5657 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5658 * @cfg {Number} rowspan Sets the number of rows a cell should span
5659 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5660 * @cfg {String} valign Vertical aligns the content in a cell
5661 * @cfg {Number} width Specifies the width of a cell
5664 * Create a new TableCell
5665 * @param {Object} config The config object
5668 Roo.bootstrap.TableCell = function(config){
5669 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5672 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5692 getAutoCreate : function(){
5693 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5713 cfg.align=this.align
5719 cfg.bgcolor=this.bgcolor
5722 cfg.charoff=this.charoff
5725 cfg.colspan=this.colspan
5728 cfg.headers=this.headers
5731 cfg.height=this.height
5734 cfg.nowrap=this.nowrap
5737 cfg.rowspan=this.rowspan
5740 cfg.scope=this.scope
5743 cfg.valign=this.valign
5746 cfg.width=this.width
5765 * @class Roo.bootstrap.TableRow
5766 * @extends Roo.bootstrap.Component
5767 * Bootstrap TableRow class
5768 * @cfg {String} cls row class
5769 * @cfg {String} align Aligns the content in a table row
5770 * @cfg {String} bgcolor Specifies a background color for a table row
5771 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5772 * @cfg {String} valign Vertical aligns the content in a table row
5775 * Create a new TableRow
5776 * @param {Object} config The config object
5779 Roo.bootstrap.TableRow = function(config){
5780 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5783 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5791 getAutoCreate : function(){
5792 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5802 cfg.align = this.align;
5805 cfg.bgcolor = this.bgcolor;
5808 cfg.charoff = this.charoff;
5811 cfg.valign = this.valign;
5829 * @class Roo.bootstrap.TableBody
5830 * @extends Roo.bootstrap.Component
5831 * Bootstrap TableBody class
5832 * @cfg {String} cls element class
5833 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5834 * @cfg {String} align Aligns the content inside the element
5835 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5836 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5839 * Create a new TableBody
5840 * @param {Object} config The config object
5843 Roo.bootstrap.TableBody = function(config){
5844 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5847 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5855 getAutoCreate : function(){
5856 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5870 cfg.align = this.align;
5873 cfg.charoff = this.charoff;
5876 cfg.valign = this.valign;
5883 // initEvents : function()
5890 // this.store = Roo.factory(this.store, Roo.data);
5891 // this.store.on('load', this.onLoad, this);
5893 // this.store.load();
5897 // onLoad: function ()
5899 // this.fireEvent('load', this);
5909 * Ext JS Library 1.1.1
5910 * Copyright(c) 2006-2007, Ext JS, LLC.
5912 * Originally Released Under LGPL - original licence link has changed is not relivant.
5915 * <script type="text/javascript">
5918 // as we use this in bootstrap.
5919 Roo.namespace('Roo.form');
5921 * @class Roo.form.Action
5922 * Internal Class used to handle form actions
5924 * @param {Roo.form.BasicForm} el The form element or its id
5925 * @param {Object} config Configuration options
5930 // define the action interface
5931 Roo.form.Action = function(form, options){
5933 this.options = options || {};
5936 * Client Validation Failed
5939 Roo.form.Action.CLIENT_INVALID = 'client';
5941 * Server Validation Failed
5944 Roo.form.Action.SERVER_INVALID = 'server';
5946 * Connect to Server Failed
5949 Roo.form.Action.CONNECT_FAILURE = 'connect';
5951 * Reading Data from Server Failed
5954 Roo.form.Action.LOAD_FAILURE = 'load';
5956 Roo.form.Action.prototype = {
5958 failureType : undefined,
5959 response : undefined,
5963 run : function(options){
5968 success : function(response){
5973 handleResponse : function(response){
5977 // default connection failure
5978 failure : function(response){
5980 this.response = response;
5981 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5982 this.form.afterAction(this, false);
5985 processResponse : function(response){
5986 this.response = response;
5987 if(!response.responseText){
5990 this.result = this.handleResponse(response);
5994 // utility functions used internally
5995 getUrl : function(appendParams){
5996 var url = this.options.url || this.form.url || this.form.el.dom.action;
5998 var p = this.getParams();
6000 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6006 getMethod : function(){
6007 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6010 getParams : function(){
6011 var bp = this.form.baseParams;
6012 var p = this.options.params;
6014 if(typeof p == "object"){
6015 p = Roo.urlEncode(Roo.applyIf(p, bp));
6016 }else if(typeof p == 'string' && bp){
6017 p += '&' + Roo.urlEncode(bp);
6020 p = Roo.urlEncode(bp);
6025 createCallback : function(){
6027 success: this.success,
6028 failure: this.failure,
6030 timeout: (this.form.timeout*1000),
6031 upload: this.form.fileUpload ? this.success : undefined
6036 Roo.form.Action.Submit = function(form, options){
6037 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6040 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6043 haveProgress : false,
6044 uploadComplete : false,
6046 // uploadProgress indicator.
6047 uploadProgress : function()
6049 if (!this.form.progressUrl) {
6053 if (!this.haveProgress) {
6054 Roo.MessageBox.progress("Uploading", "Uploading");
6056 if (this.uploadComplete) {
6057 Roo.MessageBox.hide();
6061 this.haveProgress = true;
6063 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6065 var c = new Roo.data.Connection();
6067 url : this.form.progressUrl,
6072 success : function(req){
6073 //console.log(data);
6077 rdata = Roo.decode(req.responseText)
6079 Roo.log("Invalid data from server..");
6083 if (!rdata || !rdata.success) {
6085 Roo.MessageBox.alert(Roo.encode(rdata));
6088 var data = rdata.data;
6090 if (this.uploadComplete) {
6091 Roo.MessageBox.hide();
6096 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6097 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6100 this.uploadProgress.defer(2000,this);
6103 failure: function(data) {
6104 Roo.log('progress url failed ');
6115 // run get Values on the form, so it syncs any secondary forms.
6116 this.form.getValues();
6118 var o = this.options;
6119 var method = this.getMethod();
6120 var isPost = method == 'POST';
6121 if(o.clientValidation === false || this.form.isValid()){
6123 if (this.form.progressUrl) {
6124 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6125 (new Date() * 1) + '' + Math.random());
6130 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6131 form:this.form.el.dom,
6132 url:this.getUrl(!isPost),
6134 params:isPost ? this.getParams() : null,
6135 isUpload: this.form.fileUpload
6138 this.uploadProgress();
6140 }else if (o.clientValidation !== false){ // client validation failed
6141 this.failureType = Roo.form.Action.CLIENT_INVALID;
6142 this.form.afterAction(this, false);
6146 success : function(response)
6148 this.uploadComplete= true;
6149 if (this.haveProgress) {
6150 Roo.MessageBox.hide();
6154 var result = this.processResponse(response);
6155 if(result === true || result.success){
6156 this.form.afterAction(this, true);
6160 this.form.markInvalid(result.errors);
6161 this.failureType = Roo.form.Action.SERVER_INVALID;
6163 this.form.afterAction(this, false);
6165 failure : function(response)
6167 this.uploadComplete= true;
6168 if (this.haveProgress) {
6169 Roo.MessageBox.hide();
6172 this.response = response;
6173 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6174 this.form.afterAction(this, false);
6177 handleResponse : function(response){
6178 if(this.form.errorReader){
6179 var rs = this.form.errorReader.read(response);
6182 for(var i = 0, len = rs.records.length; i < len; i++) {
6183 var r = rs.records[i];
6187 if(errors.length < 1){
6191 success : rs.success,
6197 ret = Roo.decode(response.responseText);
6201 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6211 Roo.form.Action.Load = function(form, options){
6212 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6213 this.reader = this.form.reader;
6216 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6221 Roo.Ajax.request(Roo.apply(
6222 this.createCallback(), {
6223 method:this.getMethod(),
6224 url:this.getUrl(false),
6225 params:this.getParams()
6229 success : function(response){
6231 var result = this.processResponse(response);
6232 if(result === true || !result.success || !result.data){
6233 this.failureType = Roo.form.Action.LOAD_FAILURE;
6234 this.form.afterAction(this, false);
6237 this.form.clearInvalid();
6238 this.form.setValues(result.data);
6239 this.form.afterAction(this, true);
6242 handleResponse : function(response){
6243 if(this.form.reader){
6244 var rs = this.form.reader.read(response);
6245 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6247 success : rs.success,
6251 return Roo.decode(response.responseText);
6255 Roo.form.Action.ACTION_TYPES = {
6256 'load' : Roo.form.Action.Load,
6257 'submit' : Roo.form.Action.Submit
6266 * @class Roo.bootstrap.Form
6267 * @extends Roo.bootstrap.Component
6268 * Bootstrap Form class
6269 * @cfg {String} method GET | POST (default POST)
6270 * @cfg {String} labelAlign top | left (default top)
6271 * @cfg {String} align left | right - for navbars
6272 * @cfg {Boolean} loadMask load mask when submit (default true)
6277 * @param {Object} config The config object
6281 Roo.bootstrap.Form = function(config){
6282 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6285 * @event clientvalidation
6286 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6287 * @param {Form} this
6288 * @param {Boolean} valid true if the form has passed client-side validation
6290 clientvalidation: true,
6292 * @event beforeaction
6293 * Fires before any action is performed. Return false to cancel the action.
6294 * @param {Form} this
6295 * @param {Action} action The action to be performed
6299 * @event actionfailed
6300 * Fires when an action fails.
6301 * @param {Form} this
6302 * @param {Action} action The action that failed
6304 actionfailed : true,
6306 * @event actioncomplete
6307 * Fires when an action is completed.
6308 * @param {Form} this
6309 * @param {Action} action The action that completed
6311 actioncomplete : true
6316 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6319 * @cfg {String} method
6320 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6325 * The URL to use for form actions if one isn't supplied in the action options.
6328 * @cfg {Boolean} fileUpload
6329 * Set to true if this form is a file upload.
6333 * @cfg {Object} baseParams
6334 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6338 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6342 * @cfg {Sting} align (left|right) for navbar forms
6347 activeAction : null,
6350 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6351 * element by passing it or its id or mask the form itself by passing in true.
6354 waitMsgTarget : false,
6358 getAutoCreate : function(){
6362 method : this.method || 'POST',
6363 id : this.id || Roo.id(),
6366 if (this.parent().xtype.match(/^Nav/)) {
6367 cfg.cls = 'navbar-form navbar-' + this.align;
6371 if (this.labelAlign == 'left' ) {
6372 cfg.cls += ' form-horizontal';
6378 initEvents : function()
6380 this.el.on('submit', this.onSubmit, this);
6381 // this was added as random key presses on the form where triggering form submit.
6382 this.el.on('keypress', function(e) {
6383 if (e.getCharCode() != 13) {
6386 // we might need to allow it for textareas.. and some other items.
6387 // check e.getTarget().
6389 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6393 Roo.log("keypress blocked");
6401 onSubmit : function(e){
6406 * Returns true if client-side validation on the form is successful.
6409 isValid : function(){
6410 var items = this.getItems();
6412 items.each(function(f){
6421 * Returns true if any fields in this form have changed since their original load.
6424 isDirty : function(){
6426 var items = this.getItems();
6427 items.each(function(f){
6437 * Performs a predefined action (submit or load) or custom actions you define on this form.
6438 * @param {String} actionName The name of the action type
6439 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6440 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6441 * accept other config options):
6443 Property Type Description
6444 ---------------- --------------- ----------------------------------------------------------------------------------
6445 url String The url for the action (defaults to the form's url)
6446 method String The form method to use (defaults to the form's method, or POST if not defined)
6447 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6448 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6449 validate the form on the client (defaults to false)
6451 * @return {BasicForm} this
6453 doAction : function(action, options){
6454 if(typeof action == 'string'){
6455 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6457 if(this.fireEvent('beforeaction', this, action) !== false){
6458 this.beforeAction(action);
6459 action.run.defer(100, action);
6465 beforeAction : function(action){
6466 var o = action.options;
6469 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6471 // not really supported yet.. ??
6473 //if(this.waitMsgTarget === true){
6474 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6475 //}else if(this.waitMsgTarget){
6476 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6477 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6479 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6485 afterAction : function(action, success){
6486 this.activeAction = null;
6487 var o = action.options;
6489 //if(this.waitMsgTarget === true){
6491 //}else if(this.waitMsgTarget){
6492 // this.waitMsgTarget.unmask();
6494 // Roo.MessageBox.updateProgress(1);
6495 // Roo.MessageBox.hide();
6502 Roo.callback(o.success, o.scope, [this, action]);
6503 this.fireEvent('actioncomplete', this, action);
6507 // failure condition..
6508 // we have a scenario where updates need confirming.
6509 // eg. if a locking scenario exists..
6510 // we look for { errors : { needs_confirm : true }} in the response.
6512 (typeof(action.result) != 'undefined') &&
6513 (typeof(action.result.errors) != 'undefined') &&
6514 (typeof(action.result.errors.needs_confirm) != 'undefined')
6517 Roo.log("not supported yet");
6520 Roo.MessageBox.confirm(
6521 "Change requires confirmation",
6522 action.result.errorMsg,
6527 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6537 Roo.callback(o.failure, o.scope, [this, action]);
6538 // show an error message if no failed handler is set..
6539 if (!this.hasListener('actionfailed')) {
6540 Roo.log("need to add dialog support");
6542 Roo.MessageBox.alert("Error",
6543 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6544 action.result.errorMsg :
6545 "Saving Failed, please check your entries or try again"
6550 this.fireEvent('actionfailed', this, action);
6555 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6556 * @param {String} id The value to search for
6559 findField : function(id){
6560 var items = this.getItems();
6561 var field = items.get(id);
6563 items.each(function(f){
6564 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6571 return field || null;
6574 * Mark fields in this form invalid in bulk.
6575 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6576 * @return {BasicForm} this
6578 markInvalid : function(errors){
6579 if(errors instanceof Array){
6580 for(var i = 0, len = errors.length; i < len; i++){
6581 var fieldError = errors[i];
6582 var f = this.findField(fieldError.id);
6584 f.markInvalid(fieldError.msg);
6590 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6591 field.markInvalid(errors[id]);
6595 //Roo.each(this.childForms || [], function (f) {
6596 // f.markInvalid(errors);
6603 * Set values for fields in this form in bulk.
6604 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6605 * @return {BasicForm} this
6607 setValues : function(values){
6608 if(values instanceof Array){ // array of objects
6609 for(var i = 0, len = values.length; i < len; i++){
6611 var f = this.findField(v.id);
6613 f.setValue(v.value);
6614 if(this.trackResetOnLoad){
6615 f.originalValue = f.getValue();
6619 }else{ // object hash
6622 if(typeof values[id] != 'function' && (field = this.findField(id))){
6624 if (field.setFromData &&
6626 field.displayField &&
6627 // combos' with local stores can
6628 // be queried via setValue()
6629 // to set their value..
6630 (field.store && !field.store.isLocal)
6634 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6635 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6636 field.setFromData(sd);
6639 field.setValue(values[id]);
6643 if(this.trackResetOnLoad){
6644 field.originalValue = field.getValue();
6650 //Roo.each(this.childForms || [], function (f) {
6651 // f.setValues(values);
6658 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6659 * they are returned as an array.
6660 * @param {Boolean} asString
6663 getValues : function(asString){
6664 //if (this.childForms) {
6665 // copy values from the child forms
6666 // Roo.each(this.childForms, function (f) {
6667 // this.setValues(f.getValues());
6673 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6674 if(asString === true){
6677 return Roo.urlDecode(fs);
6681 * Returns the fields in this form as an object with key/value pairs.
6682 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6685 getFieldValues : function(with_hidden)
6687 var items = this.getItems();
6689 items.each(function(f){
6693 var v = f.getValue();
6694 if (f.inputType =='radio') {
6695 if (typeof(ret[f.getName()]) == 'undefined') {
6696 ret[f.getName()] = ''; // empty..
6699 if (!f.el.dom.checked) {
6707 // not sure if this supported any more..
6708 if ((typeof(v) == 'object') && f.getRawValue) {
6709 v = f.getRawValue() ; // dates..
6711 // combo boxes where name != hiddenName...
6712 if (f.name != f.getName()) {
6713 ret[f.name] = f.getRawValue();
6715 ret[f.getName()] = v;
6722 * Clears all invalid messages in this form.
6723 * @return {BasicForm} this
6725 clearInvalid : function(){
6726 var items = this.getItems();
6728 items.each(function(f){
6739 * @return {BasicForm} this
6742 var items = this.getItems();
6743 items.each(function(f){
6747 Roo.each(this.childForms || [], function (f) {
6754 getItems : function()
6756 var r=new Roo.util.MixedCollection(false, function(o){
6757 return o.id || (o.id = Roo.id());
6759 var iter = function(el) {
6766 Roo.each(el.items,function(e) {
6785 * Ext JS Library 1.1.1
6786 * Copyright(c) 2006-2007, Ext JS, LLC.
6788 * Originally Released Under LGPL - original licence link has changed is not relivant.
6791 * <script type="text/javascript">
6794 * @class Roo.form.VTypes
6795 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6798 Roo.form.VTypes = function(){
6799 // closure these in so they are only created once.
6800 var alpha = /^[a-zA-Z_]+$/;
6801 var alphanum = /^[a-zA-Z0-9_]+$/;
6802 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6803 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6805 // All these messages and functions are configurable
6808 * The function used to validate email addresses
6809 * @param {String} value The email address
6811 'email' : function(v){
6812 return email.test(v);
6815 * The error text to display when the email validation function returns false
6818 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6820 * The keystroke filter mask to be applied on email input
6823 'emailMask' : /[a-z0-9_\.\-@]/i,
6826 * The function used to validate URLs
6827 * @param {String} value The URL
6829 'url' : function(v){
6833 * The error text to display when the url validation function returns false
6836 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6839 * The function used to validate alpha values
6840 * @param {String} value The value
6842 'alpha' : function(v){
6843 return alpha.test(v);
6846 * The error text to display when the alpha validation function returns false
6849 'alphaText' : 'This field should only contain letters and _',
6851 * The keystroke filter mask to be applied on alpha input
6854 'alphaMask' : /[a-z_]/i,
6857 * The function used to validate alphanumeric values
6858 * @param {String} value The value
6860 'alphanum' : function(v){
6861 return alphanum.test(v);
6864 * The error text to display when the alphanumeric validation function returns false
6867 'alphanumText' : 'This field should only contain letters, numbers and _',
6869 * The keystroke filter mask to be applied on alphanumeric input
6872 'alphanumMask' : /[a-z0-9_]/i
6882 * @class Roo.bootstrap.Input
6883 * @extends Roo.bootstrap.Component
6884 * Bootstrap Input class
6885 * @cfg {Boolean} disabled is it disabled
6886 * @cfg {String} fieldLabel - the label associated
6887 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6888 * @cfg {String} name name of the input
6889 * @cfg {string} fieldLabel - the label associated
6890 * @cfg {string} inputType - input / file submit ...
6891 * @cfg {string} placeholder - placeholder to put in text.
6892 * @cfg {string} before - input group add on before
6893 * @cfg {string} after - input group add on after
6894 * @cfg {string} size - (lg|sm) or leave empty..
6895 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6896 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6897 * @cfg {Number} md colspan out of 12 for computer-sized screens
6898 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6899 * @cfg {string} value default value of the input
6900 * @cfg {Number} labelWidth set the width of label (0-12)
6901 * @cfg {String} labelAlign (top|left)
6902 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6903 * @cfg {String} align (left|center|right) Default left
6907 * Create a new Input
6908 * @param {Object} config The config object
6911 Roo.bootstrap.Input = function(config){
6912 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6917 * Fires when this field receives input focus.
6918 * @param {Roo.form.Field} this
6923 * Fires when this field loses input focus.
6924 * @param {Roo.form.Field} this
6929 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6930 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6931 * @param {Roo.form.Field} this
6932 * @param {Roo.EventObject} e The event object
6937 * Fires just before the field blurs if the field value has changed.
6938 * @param {Roo.form.Field} this
6939 * @param {Mixed} newValue The new value
6940 * @param {Mixed} oldValue The original value
6945 * Fires after the field has been marked as invalid.
6946 * @param {Roo.form.Field} this
6947 * @param {String} msg The validation message
6952 * Fires after the field has been validated with no errors.
6953 * @param {Roo.form.Field} this
6958 * Fires after the key up
6959 * @param {Roo.form.Field} this
6960 * @param {Roo.EventObject} e The event Object
6966 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6968 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6969 automatic validation (defaults to "keyup").
6971 validationEvent : "keyup",
6973 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6975 validateOnBlur : true,
6977 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6979 validationDelay : 250,
6981 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6983 focusClass : "x-form-focus", // not needed???
6987 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6989 invalidClass : "has-error",
6992 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6994 selectOnFocus : false,
6997 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7001 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7006 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7008 disableKeyFilter : false,
7011 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7015 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7019 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7021 blankText : "This field is required",
7024 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7028 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7030 maxLength : Number.MAX_VALUE,
7032 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7034 minLengthText : "The minimum length for this field is {0}",
7036 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7038 maxLengthText : "The maximum length for this field is {0}",
7042 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7043 * If available, this function will be called only after the basic validators all return true, and will be passed the
7044 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7048 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7049 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7050 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7054 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7077 formatedValue : false,
7079 parentLabelAlign : function()
7082 while (parent.parent()) {
7083 parent = parent.parent();
7084 if (typeof(parent.labelAlign) !='undefined') {
7085 return parent.labelAlign;
7092 getAutoCreate : function(){
7094 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7100 if(this.inputType != 'hidden'){
7101 cfg.cls = 'form-group' //input-group
7107 type : this.inputType,
7109 cls : 'form-control',
7110 placeholder : this.placeholder || ''
7115 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7118 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7119 input.maxLength = this.maxLength;
7122 if (this.disabled) {
7123 input.disabled=true;
7126 if (this.readOnly) {
7127 input.readonly=true;
7131 input.name = this.name;
7134 input.cls += ' input-' + this.size;
7137 ['xs','sm','md','lg'].map(function(size){
7138 if (settings[size]) {
7139 cfg.cls += ' col-' + size + '-' + settings[size];
7143 var inputblock = input;
7145 if (this.before || this.after) {
7148 cls : 'input-group',
7151 if (this.before && typeof(this.before) == 'string') {
7153 inputblock.cn.push({
7155 cls : 'roo-input-before input-group-addon',
7159 if (this.before && typeof(this.before) == 'object') {
7160 this.before = Roo.factory(this.before);
7161 Roo.log(this.before);
7162 inputblock.cn.push({
7164 cls : 'roo-input-before input-group-' +
7165 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7169 inputblock.cn.push(input);
7171 if (this.after && typeof(this.after) == 'string') {
7172 inputblock.cn.push({
7174 cls : 'roo-input-after input-group-addon',
7178 if (this.after && typeof(this.after) == 'object') {
7179 this.after = Roo.factory(this.after);
7180 Roo.log(this.after);
7181 inputblock.cn.push({
7183 cls : 'roo-input-after input-group-' +
7184 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7189 if (align ==='left' && this.fieldLabel.length) {
7190 Roo.log("left and has label");
7196 cls : 'control-label col-sm-' + this.labelWidth,
7197 html : this.fieldLabel
7201 cls : "col-sm-" + (12 - this.labelWidth),
7208 } else if ( this.fieldLabel.length) {
7214 //cls : 'input-group-addon',
7215 html : this.fieldLabel
7225 Roo.log(" no label && no align");
7234 Roo.log('input-parentType: ' + this.parentType);
7236 if (this.parentType === 'Navbar' && this.parent().bar) {
7237 cfg.cls += ' navbar-form';
7245 * return the real input element.
7247 inputEl: function ()
7249 return this.el.select('input.form-control',true).first();
7252 tooltipEl : function()
7254 return this.inputEl();
7257 setDisabled : function(v)
7259 var i = this.inputEl().dom;
7261 i.removeAttribute('disabled');
7265 i.setAttribute('disabled','true');
7267 initEvents : function()
7270 this.inputEl().on("keydown" , this.fireKey, this);
7271 this.inputEl().on("focus", this.onFocus, this);
7272 this.inputEl().on("blur", this.onBlur, this);
7274 this.inputEl().relayEvent('keyup', this);
7276 // reference to original value for reset
7277 this.originalValue = this.getValue();
7278 //Roo.form.TextField.superclass.initEvents.call(this);
7279 if(this.validationEvent == 'keyup'){
7280 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7281 this.inputEl().on('keyup', this.filterValidation, this);
7283 else if(this.validationEvent !== false){
7284 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7287 if(this.selectOnFocus){
7288 this.on("focus", this.preFocus, this);
7291 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7292 this.inputEl().on("keypress", this.filterKeys, this);
7295 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7296 this.el.on("click", this.autoSize, this);
7299 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7300 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7303 if (typeof(this.before) == 'object') {
7304 this.before.render(this.el.select('.roo-input-before',true).first());
7306 if (typeof(this.after) == 'object') {
7307 this.after.render(this.el.select('.roo-input-after',true).first());
7312 filterValidation : function(e){
7313 if(!e.isNavKeyPress()){
7314 this.validationTask.delay(this.validationDelay);
7318 * Validates the field value
7319 * @return {Boolean} True if the value is valid, else false
7321 validate : function(){
7322 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7323 if(this.disabled || this.validateValue(this.getRawValue())){
7324 this.clearInvalid();
7332 * Validates a value according to the field's validation rules and marks the field as invalid
7333 * if the validation fails
7334 * @param {Mixed} value The value to validate
7335 * @return {Boolean} True if the value is valid, else false
7337 validateValue : function(value){
7338 if(value.length < 1) { // if it's blank
7339 if(this.allowBlank){
7340 this.clearInvalid();
7343 this.markInvalid(this.blankText);
7347 if(value.length < this.minLength){
7348 this.markInvalid(String.format(this.minLengthText, this.minLength));
7351 if(value.length > this.maxLength){
7352 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7356 var vt = Roo.form.VTypes;
7357 if(!vt[this.vtype](value, this)){
7358 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7362 if(typeof this.validator == "function"){
7363 var msg = this.validator(value);
7365 this.markInvalid(msg);
7369 if(this.regex && !this.regex.test(value)){
7370 this.markInvalid(this.regexText);
7379 fireKey : function(e){
7380 //Roo.log('field ' + e.getKey());
7381 if(e.isNavKeyPress()){
7382 this.fireEvent("specialkey", this, e);
7385 focus : function (selectText){
7387 this.inputEl().focus();
7388 if(selectText === true){
7389 this.inputEl().dom.select();
7395 onFocus : function(){
7396 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7397 // this.el.addClass(this.focusClass);
7400 this.hasFocus = true;
7401 this.startValue = this.getValue();
7402 this.fireEvent("focus", this);
7406 beforeBlur : Roo.emptyFn,
7410 onBlur : function(){
7412 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7413 //this.el.removeClass(this.focusClass);
7415 this.hasFocus = false;
7416 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7419 var v = this.getValue();
7420 if(String(v) !== String(this.startValue)){
7421 this.fireEvent('change', this, v, this.startValue);
7423 this.fireEvent("blur", this);
7427 * Resets the current field value to the originally loaded value and clears any validation messages
7430 this.setValue(this.originalValue);
7431 this.clearInvalid();
7434 * Returns the name of the field
7435 * @return {Mixed} name The name field
7437 getName: function(){
7441 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7442 * @return {Mixed} value The field value
7444 getValue : function(){
7446 var v = this.inputEl().getValue();
7451 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7452 * @return {Mixed} value The field value
7454 getRawValue : function(){
7455 var v = this.inputEl().getValue();
7461 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7462 * @param {Mixed} value The value to set
7464 setRawValue : function(v){
7465 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7468 selectText : function(start, end){
7469 var v = this.getRawValue();
7471 start = start === undefined ? 0 : start;
7472 end = end === undefined ? v.length : end;
7473 var d = this.inputEl().dom;
7474 if(d.setSelectionRange){
7475 d.setSelectionRange(start, end);
7476 }else if(d.createTextRange){
7477 var range = d.createTextRange();
7478 range.moveStart("character", start);
7479 range.moveEnd("character", v.length-end);
7486 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7487 * @param {Mixed} value The value to set
7489 setValue : function(v){
7492 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7498 processValue : function(value){
7499 if(this.stripCharsRe){
7500 var newValue = value.replace(this.stripCharsRe, '');
7501 if(newValue !== value){
7502 this.setRawValue(newValue);
7509 preFocus : function(){
7511 if(this.selectOnFocus){
7512 this.inputEl().dom.select();
7515 filterKeys : function(e){
7517 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7520 var c = e.getCharCode(), cc = String.fromCharCode(c);
7521 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7524 if(!this.maskRe.test(cc)){
7529 * Clear any invalid styles/messages for this field
7531 clearInvalid : function(){
7533 if(!this.el || this.preventMark){ // not rendered
7536 this.el.removeClass(this.invalidClass);
7538 switch(this.msgTarget){
7540 this.el.dom.qtip = '';
7543 this.el.dom.title = '';
7547 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7552 this.errorIcon.dom.qtip = '';
7553 this.errorIcon.hide();
7554 this.un('resize', this.alignErrorIcon, this);
7558 var t = Roo.getDom(this.msgTarget);
7560 t.style.display = 'none';
7564 this.fireEvent('valid', this);
7567 * Mark this field as invalid
7568 * @param {String} msg The validation message
7570 markInvalid : function(msg){
7571 if(!this.el || this.preventMark){ // not rendered
7574 this.el.addClass(this.invalidClass);
7576 msg = msg || this.invalidText;
7577 switch(this.msgTarget){
7579 this.el.dom.qtip = msg;
7580 this.el.dom.qclass = 'x-form-invalid-tip';
7581 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7582 Roo.QuickTips.enable();
7586 this.el.dom.title = msg;
7590 var elp = this.el.findParent('.x-form-element', 5, true);
7591 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7592 this.errorEl.setWidth(elp.getWidth(true)-20);
7594 this.errorEl.update(msg);
7595 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7598 if(!this.errorIcon){
7599 var elp = this.el.findParent('.x-form-element', 5, true);
7600 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7602 this.alignErrorIcon();
7603 this.errorIcon.dom.qtip = msg;
7604 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7605 this.errorIcon.show();
7606 this.on('resize', this.alignErrorIcon, this);
7609 var t = Roo.getDom(this.msgTarget);
7611 t.style.display = this.msgDisplay;
7615 this.fireEvent('invalid', this, msg);
7618 SafariOnKeyDown : function(event)
7620 // this is a workaround for a password hang bug on chrome/ webkit.
7622 var isSelectAll = false;
7624 if(this.inputEl().dom.selectionEnd > 0){
7625 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7627 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7628 event.preventDefault();
7633 if(isSelectAll){ // backspace and delete key
7635 event.preventDefault();
7636 // this is very hacky as keydown always get's upper case.
7638 var cc = String.fromCharCode(event.getCharCode());
7639 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7643 adjustWidth : function(tag, w){
7644 tag = tag.toLowerCase();
7645 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7646 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7650 if(tag == 'textarea'){
7653 }else if(Roo.isOpera){
7657 if(tag == 'textarea'){
7676 * @class Roo.bootstrap.TextArea
7677 * @extends Roo.bootstrap.Input
7678 * Bootstrap TextArea class
7679 * @cfg {Number} cols Specifies the visible width of a text area
7680 * @cfg {Number} rows Specifies the visible number of lines in a text area
7681 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7682 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7683 * @cfg {string} html text
7686 * Create a new TextArea
7687 * @param {Object} config The config object
7690 Roo.bootstrap.TextArea = function(config){
7691 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7695 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7705 getAutoCreate : function(){
7707 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7718 value : this.value || '',
7719 html: this.html || '',
7720 cls : 'form-control',
7721 placeholder : this.placeholder || ''
7725 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7726 input.maxLength = this.maxLength;
7730 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7734 input.cols = this.cols;
7737 if (this.readOnly) {
7738 input.readonly = true;
7742 input.name = this.name;
7746 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7750 ['xs','sm','md','lg'].map(function(size){
7751 if (settings[size]) {
7752 cfg.cls += ' col-' + size + '-' + settings[size];
7756 var inputblock = input;
7758 if (this.before || this.after) {
7761 cls : 'input-group',
7765 inputblock.cn.push({
7767 cls : 'input-group-addon',
7771 inputblock.cn.push(input);
7773 inputblock.cn.push({
7775 cls : 'input-group-addon',
7782 if (align ==='left' && this.fieldLabel.length) {
7783 Roo.log("left and has label");
7789 cls : 'control-label col-sm-' + this.labelWidth,
7790 html : this.fieldLabel
7794 cls : "col-sm-" + (12 - this.labelWidth),
7801 } else if ( this.fieldLabel.length) {
7807 //cls : 'input-group-addon',
7808 html : this.fieldLabel
7818 Roo.log(" no label && no align");
7828 if (this.disabled) {
7829 input.disabled=true;
7836 * return the real textarea element.
7838 inputEl: function ()
7840 return this.el.select('textarea.form-control',true).first();
7848 * trigger field - base class for combo..
7853 * @class Roo.bootstrap.TriggerField
7854 * @extends Roo.bootstrap.Input
7855 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7856 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7857 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7858 * for which you can provide a custom implementation. For example:
7860 var trigger = new Roo.bootstrap.TriggerField();
7861 trigger.onTriggerClick = myTriggerFn;
7862 trigger.applyTo('my-field');
7865 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7866 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7867 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7868 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7870 * Create a new TriggerField.
7871 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7872 * to the base TextField)
7874 Roo.bootstrap.TriggerField = function(config){
7875 this.mimicing = false;
7876 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7879 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7881 * @cfg {String} triggerClass A CSS class to apply to the trigger
7884 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7888 /** @cfg {Boolean} grow @hide */
7889 /** @cfg {Number} growMin @hide */
7890 /** @cfg {Number} growMax @hide */
7896 autoSize: Roo.emptyFn,
7903 actionMode : 'wrap',
7907 getAutoCreate : function(){
7909 var align = this.labelAlign || this.parentLabelAlign();
7914 cls: 'form-group' //input-group
7921 type : this.inputType,
7922 cls : 'form-control',
7923 autocomplete: 'false',
7924 placeholder : this.placeholder || ''
7928 input.name = this.name;
7931 input.cls += ' input-' + this.size;
7934 if (this.disabled) {
7935 input.disabled=true;
7938 var inputblock = input;
7940 if (this.before || this.after) {
7943 cls : 'input-group',
7947 inputblock.cn.push({
7949 cls : 'input-group-addon',
7953 inputblock.cn.push(input);
7955 inputblock.cn.push({
7957 cls : 'input-group-addon',
7970 cls: 'form-hidden-field'
7978 Roo.log('multiple');
7986 cls: 'form-hidden-field'
7990 cls: 'select2-choices',
7994 cls: 'select2-search-field',
8007 cls: 'select2-container input-group',
8012 // cls: 'typeahead typeahead-long dropdown-menu',
8013 // style: 'display:none'
8018 if(!this.multiple && this.showToggleBtn){
8021 cls : 'input-group-addon btn dropdown-toggle',
8029 cls: 'combobox-clear',
8043 combobox.cls += ' select2-container-multi';
8046 if (align ==='left' && this.fieldLabel.length) {
8048 Roo.log("left and has label");
8054 cls : 'control-label col-sm-' + this.labelWidth,
8055 html : this.fieldLabel
8059 cls : "col-sm-" + (12 - this.labelWidth),
8066 } else if ( this.fieldLabel.length) {
8072 //cls : 'input-group-addon',
8073 html : this.fieldLabel
8083 Roo.log(" no label && no align");
8090 ['xs','sm','md','lg'].map(function(size){
8091 if (settings[size]) {
8092 cfg.cls += ' col-' + size + '-' + settings[size];
8103 onResize : function(w, h){
8104 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8105 // if(typeof w == 'number'){
8106 // var x = w - this.trigger.getWidth();
8107 // this.inputEl().setWidth(this.adjustWidth('input', x));
8108 // this.trigger.setStyle('left', x+'px');
8113 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8116 getResizeEl : function(){
8117 return this.inputEl();
8121 getPositionEl : function(){
8122 return this.inputEl();
8126 alignErrorIcon : function(){
8127 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8131 initEvents : function(){
8135 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8136 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8137 if(!this.multiple && this.showToggleBtn){
8138 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8139 if(this.hideTrigger){
8140 this.trigger.setDisplayed(false);
8142 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8146 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8149 //this.trigger.addClassOnOver('x-form-trigger-over');
8150 //this.trigger.addClassOnClick('x-form-trigger-click');
8153 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8157 createList : function()
8159 this.list = Roo.get(document.body).createChild({
8161 cls: 'typeahead typeahead-long dropdown-menu',
8162 style: 'display:none'
8165 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8170 initTrigger : function(){
8175 onDestroy : function(){
8177 this.trigger.removeAllListeners();
8178 // this.trigger.remove();
8181 // this.wrap.remove();
8183 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8187 onFocus : function(){
8188 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8191 this.wrap.addClass('x-trigger-wrap-focus');
8192 this.mimicing = true;
8193 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8194 if(this.monitorTab){
8195 this.el.on("keydown", this.checkTab, this);
8202 checkTab : function(e){
8203 if(e.getKey() == e.TAB){
8209 onBlur : function(){
8214 mimicBlur : function(e, t){
8216 if(!this.wrap.contains(t) && this.validateBlur()){
8223 triggerBlur : function(){
8224 this.mimicing = false;
8225 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8226 if(this.monitorTab){
8227 this.el.un("keydown", this.checkTab, this);
8229 //this.wrap.removeClass('x-trigger-wrap-focus');
8230 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8234 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8235 validateBlur : function(e, t){
8240 onDisable : function(){
8241 this.inputEl().dom.disabled = true;
8242 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8244 // this.wrap.addClass('x-item-disabled');
8249 onEnable : function(){
8250 this.inputEl().dom.disabled = false;
8251 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8253 // this.el.removeClass('x-item-disabled');
8258 onShow : function(){
8259 var ae = this.getActionEl();
8262 ae.dom.style.display = '';
8263 ae.dom.style.visibility = 'visible';
8269 onHide : function(){
8270 var ae = this.getActionEl();
8271 ae.dom.style.display = 'none';
8275 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8276 * by an implementing function.
8278 * @param {EventObject} e
8280 onTriggerClick : Roo.emptyFn
8284 * Ext JS Library 1.1.1
8285 * Copyright(c) 2006-2007, Ext JS, LLC.
8287 * Originally Released Under LGPL - original licence link has changed is not relivant.
8290 * <script type="text/javascript">
8295 * @class Roo.data.SortTypes
8297 * Defines the default sorting (casting?) comparison functions used when sorting data.
8299 Roo.data.SortTypes = {
8301 * Default sort that does nothing
8302 * @param {Mixed} s The value being converted
8303 * @return {Mixed} The comparison value
8310 * The regular expression used to strip tags
8314 stripTagsRE : /<\/?[^>]+>/gi,
8317 * Strips all HTML tags to sort on text only
8318 * @param {Mixed} s The value being converted
8319 * @return {String} The comparison value
8321 asText : function(s){
8322 return String(s).replace(this.stripTagsRE, "");
8326 * Strips all HTML tags to sort on text only - Case insensitive
8327 * @param {Mixed} s The value being converted
8328 * @return {String} The comparison value
8330 asUCText : function(s){
8331 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8335 * Case insensitive string
8336 * @param {Mixed} s The value being converted
8337 * @return {String} The comparison value
8339 asUCString : function(s) {
8340 return String(s).toUpperCase();
8345 * @param {Mixed} s The value being converted
8346 * @return {Number} The comparison value
8348 asDate : function(s) {
8352 if(s instanceof Date){
8355 return Date.parse(String(s));
8360 * @param {Mixed} s The value being converted
8361 * @return {Float} The comparison value
8363 asFloat : function(s) {
8364 var val = parseFloat(String(s).replace(/,/g, ""));
8365 if(isNaN(val)) val = 0;
8371 * @param {Mixed} s The value being converted
8372 * @return {Number} The comparison value
8374 asInt : function(s) {
8375 var val = parseInt(String(s).replace(/,/g, ""));
8376 if(isNaN(val)) val = 0;
8381 * Ext JS Library 1.1.1
8382 * Copyright(c) 2006-2007, Ext JS, LLC.
8384 * Originally Released Under LGPL - original licence link has changed is not relivant.
8387 * <script type="text/javascript">
8391 * @class Roo.data.Record
8392 * Instances of this class encapsulate both record <em>definition</em> information, and record
8393 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8394 * to access Records cached in an {@link Roo.data.Store} object.<br>
8396 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8397 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8400 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8402 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8403 * {@link #create}. The parameters are the same.
8404 * @param {Array} data An associative Array of data values keyed by the field name.
8405 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8406 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8407 * not specified an integer id is generated.
8409 Roo.data.Record = function(data, id){
8410 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8415 * Generate a constructor for a specific record layout.
8416 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8417 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8418 * Each field definition object may contain the following properties: <ul>
8419 * <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,
8420 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8421 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8422 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8423 * is being used, then this is a string containing the javascript expression to reference the data relative to
8424 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8425 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8426 * this may be omitted.</p></li>
8427 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8428 * <ul><li>auto (Default, implies no conversion)</li>
8433 * <li>date</li></ul></p></li>
8434 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8435 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8436 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8437 * by the Reader into an object that will be stored in the Record. It is passed the
8438 * following parameters:<ul>
8439 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8441 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8443 * <br>usage:<br><pre><code>
8444 var TopicRecord = Roo.data.Record.create(
8445 {name: 'title', mapping: 'topic_title'},
8446 {name: 'author', mapping: 'username'},
8447 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8448 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8449 {name: 'lastPoster', mapping: 'user2'},
8450 {name: 'excerpt', mapping: 'post_text'}
8453 var myNewRecord = new TopicRecord({
8454 title: 'Do my job please',
8457 lastPost: new Date(),
8458 lastPoster: 'Animal',
8459 excerpt: 'No way dude!'
8461 myStore.add(myNewRecord);
8466 Roo.data.Record.create = function(o){
8468 f.superclass.constructor.apply(this, arguments);
8470 Roo.extend(f, Roo.data.Record);
8471 var p = f.prototype;
8472 p.fields = new Roo.util.MixedCollection(false, function(field){
8475 for(var i = 0, len = o.length; i < len; i++){
8476 p.fields.add(new Roo.data.Field(o[i]));
8478 f.getField = function(name){
8479 return p.fields.get(name);
8484 Roo.data.Record.AUTO_ID = 1000;
8485 Roo.data.Record.EDIT = 'edit';
8486 Roo.data.Record.REJECT = 'reject';
8487 Roo.data.Record.COMMIT = 'commit';
8489 Roo.data.Record.prototype = {
8491 * Readonly flag - true if this record has been modified.
8500 join : function(store){
8505 * Set the named field to the specified value.
8506 * @param {String} name The name of the field to set.
8507 * @param {Object} value The value to set the field to.
8509 set : function(name, value){
8510 if(this.data[name] == value){
8517 if(typeof this.modified[name] == 'undefined'){
8518 this.modified[name] = this.data[name];
8520 this.data[name] = value;
8521 if(!this.editing && this.store){
8522 this.store.afterEdit(this);
8527 * Get the value of the named field.
8528 * @param {String} name The name of the field to get the value of.
8529 * @return {Object} The value of the field.
8531 get : function(name){
8532 return this.data[name];
8536 beginEdit : function(){
8537 this.editing = true;
8542 cancelEdit : function(){
8543 this.editing = false;
8544 delete this.modified;
8548 endEdit : function(){
8549 this.editing = false;
8550 if(this.dirty && this.store){
8551 this.store.afterEdit(this);
8556 * Usually called by the {@link Roo.data.Store} which owns the Record.
8557 * Rejects all changes made to the Record since either creation, or the last commit operation.
8558 * Modified fields are reverted to their original values.
8560 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8561 * of reject operations.
8563 reject : function(){
8564 var m = this.modified;
8566 if(typeof m[n] != "function"){
8567 this.data[n] = m[n];
8571 delete this.modified;
8572 this.editing = false;
8574 this.store.afterReject(this);
8579 * Usually called by the {@link Roo.data.Store} which owns the Record.
8580 * Commits all changes made to the Record since either creation, or the last commit operation.
8582 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8583 * of commit operations.
8585 commit : function(){
8587 delete this.modified;
8588 this.editing = false;
8590 this.store.afterCommit(this);
8595 hasError : function(){
8596 return this.error != null;
8600 clearError : function(){
8605 * Creates a copy of this record.
8606 * @param {String} id (optional) A new record id if you don't want to use this record's id
8609 copy : function(newId) {
8610 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8614 * Ext JS Library 1.1.1
8615 * Copyright(c) 2006-2007, Ext JS, LLC.
8617 * Originally Released Under LGPL - original licence link has changed is not relivant.
8620 * <script type="text/javascript">
8626 * @class Roo.data.Store
8627 * @extends Roo.util.Observable
8628 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8629 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8631 * 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
8632 * has no knowledge of the format of the data returned by the Proxy.<br>
8634 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8635 * instances from the data object. These records are cached and made available through accessor functions.
8637 * Creates a new Store.
8638 * @param {Object} config A config object containing the objects needed for the Store to access data,
8639 * and read the data into Records.
8641 Roo.data.Store = function(config){
8642 this.data = new Roo.util.MixedCollection(false);
8643 this.data.getKey = function(o){
8646 this.baseParams = {};
8653 "multisort" : "_multisort"
8656 if(config && config.data){
8657 this.inlineData = config.data;
8661 Roo.apply(this, config);
8663 if(this.reader){ // reader passed
8664 this.reader = Roo.factory(this.reader, Roo.data);
8665 this.reader.xmodule = this.xmodule || false;
8666 if(!this.recordType){
8667 this.recordType = this.reader.recordType;
8669 if(this.reader.onMetaChange){
8670 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8674 if(this.recordType){
8675 this.fields = this.recordType.prototype.fields;
8681 * @event datachanged
8682 * Fires when the data cache has changed, and a widget which is using this Store
8683 * as a Record cache should refresh its view.
8684 * @param {Store} this
8689 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8690 * @param {Store} this
8691 * @param {Object} meta The JSON metadata
8696 * Fires when Records have been added to the Store
8697 * @param {Store} this
8698 * @param {Roo.data.Record[]} records The array of Records added
8699 * @param {Number} index The index at which the record(s) were added
8704 * Fires when a Record has been removed from the Store
8705 * @param {Store} this
8706 * @param {Roo.data.Record} record The Record that was removed
8707 * @param {Number} index The index at which the record was removed
8712 * Fires when a Record has been updated
8713 * @param {Store} this
8714 * @param {Roo.data.Record} record The Record that was updated
8715 * @param {String} operation The update operation being performed. Value may be one of:
8717 Roo.data.Record.EDIT
8718 Roo.data.Record.REJECT
8719 Roo.data.Record.COMMIT
8725 * Fires when the data cache has been cleared.
8726 * @param {Store} this
8731 * Fires before a request is made for a new data object. If the beforeload handler returns false
8732 * the load action will be canceled.
8733 * @param {Store} this
8734 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8738 * @event beforeloadadd
8739 * Fires after a new set of Records has been loaded.
8740 * @param {Store} this
8741 * @param {Roo.data.Record[]} records The Records that were loaded
8742 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8744 beforeloadadd : true,
8747 * Fires after a new set of Records has been loaded, before they are added to the store.
8748 * @param {Store} this
8749 * @param {Roo.data.Record[]} records The Records that were loaded
8750 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8751 * @params {Object} return from reader
8755 * @event loadexception
8756 * Fires if an exception occurs in the Proxy during loading.
8757 * Called with the signature of the Proxy's "loadexception" event.
8758 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8761 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8762 * @param {Object} load options
8763 * @param {Object} jsonData from your request (normally this contains the Exception)
8765 loadexception : true
8769 this.proxy = Roo.factory(this.proxy, Roo.data);
8770 this.proxy.xmodule = this.xmodule || false;
8771 this.relayEvents(this.proxy, ["loadexception"]);
8773 this.sortToggle = {};
8774 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8776 Roo.data.Store.superclass.constructor.call(this);
8778 if(this.inlineData){
8779 this.loadData(this.inlineData);
8780 delete this.inlineData;
8784 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8786 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8787 * without a remote query - used by combo/forms at present.
8791 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8794 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8797 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8798 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8801 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8802 * on any HTTP request
8805 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8808 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8812 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8813 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8818 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8819 * loaded or when a record is removed. (defaults to false).
8821 pruneModifiedRecords : false,
8827 * Add Records to the Store and fires the add event.
8828 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8830 add : function(records){
8831 records = [].concat(records);
8832 for(var i = 0, len = records.length; i < len; i++){
8833 records[i].join(this);
8835 var index = this.data.length;
8836 this.data.addAll(records);
8837 this.fireEvent("add", this, records, index);
8841 * Remove a Record from the Store and fires the remove event.
8842 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8844 remove : function(record){
8845 var index = this.data.indexOf(record);
8846 this.data.removeAt(index);
8847 if(this.pruneModifiedRecords){
8848 this.modified.remove(record);
8850 this.fireEvent("remove", this, record, index);
8854 * Remove all Records from the Store and fires the clear event.
8856 removeAll : function(){
8858 if(this.pruneModifiedRecords){
8861 this.fireEvent("clear", this);
8865 * Inserts Records to the Store at the given index and fires the add event.
8866 * @param {Number} index The start index at which to insert the passed Records.
8867 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8869 insert : function(index, records){
8870 records = [].concat(records);
8871 for(var i = 0, len = records.length; i < len; i++){
8872 this.data.insert(index, records[i]);
8873 records[i].join(this);
8875 this.fireEvent("add", this, records, index);
8879 * Get the index within the cache of the passed Record.
8880 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8881 * @return {Number} The index of the passed Record. Returns -1 if not found.
8883 indexOf : function(record){
8884 return this.data.indexOf(record);
8888 * Get the index within the cache of the Record with the passed id.
8889 * @param {String} id The id of the Record to find.
8890 * @return {Number} The index of the Record. Returns -1 if not found.
8892 indexOfId : function(id){
8893 return this.data.indexOfKey(id);
8897 * Get the Record with the specified id.
8898 * @param {String} id The id of the Record to find.
8899 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8901 getById : function(id){
8902 return this.data.key(id);
8906 * Get the Record at the specified index.
8907 * @param {Number} index The index of the Record to find.
8908 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8910 getAt : function(index){
8911 return this.data.itemAt(index);
8915 * Returns a range of Records between specified indices.
8916 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8917 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8918 * @return {Roo.data.Record[]} An array of Records
8920 getRange : function(start, end){
8921 return this.data.getRange(start, end);
8925 storeOptions : function(o){
8926 o = Roo.apply({}, o);
8929 this.lastOptions = o;
8933 * Loads the Record cache from the configured Proxy using the configured Reader.
8935 * If using remote paging, then the first load call must specify the <em>start</em>
8936 * and <em>limit</em> properties in the options.params property to establish the initial
8937 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8939 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8940 * and this call will return before the new data has been loaded. Perform any post-processing
8941 * in a callback function, or in a "load" event handler.</strong>
8943 * @param {Object} options An object containing properties which control loading options:<ul>
8944 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8945 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8946 * passed the following arguments:<ul>
8947 * <li>r : Roo.data.Record[]</li>
8948 * <li>options: Options object from the load call</li>
8949 * <li>success: Boolean success indicator</li></ul></li>
8950 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8951 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8954 load : function(options){
8955 options = options || {};
8956 if(this.fireEvent("beforeload", this, options) !== false){
8957 this.storeOptions(options);
8958 var p = Roo.apply(options.params || {}, this.baseParams);
8959 // if meta was not loaded from remote source.. try requesting it.
8960 if (!this.reader.metaFromRemote) {
8963 if(this.sortInfo && this.remoteSort){
8964 var pn = this.paramNames;
8965 p[pn["sort"]] = this.sortInfo.field;
8966 p[pn["dir"]] = this.sortInfo.direction;
8968 if (this.multiSort) {
8969 var pn = this.paramNames;
8970 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8973 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8978 * Reloads the Record cache from the configured Proxy using the configured Reader and
8979 * the options from the last load operation performed.
8980 * @param {Object} options (optional) An object containing properties which may override the options
8981 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8982 * the most recently used options are reused).
8984 reload : function(options){
8985 this.load(Roo.applyIf(options||{}, this.lastOptions));
8989 // Called as a callback by the Reader during a load operation.
8990 loadRecords : function(o, options, success){
8991 if(!o || success === false){
8992 if(success !== false){
8993 this.fireEvent("load", this, [], options, o);
8995 if(options.callback){
8996 options.callback.call(options.scope || this, [], options, false);
9000 // if data returned failure - throw an exception.
9001 if (o.success === false) {
9002 // show a message if no listener is registered.
9003 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9004 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9006 // loadmask wil be hooked into this..
9007 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9010 var r = o.records, t = o.totalRecords || r.length;
9012 this.fireEvent("beforeloadadd", this, r, options, o);
9014 if(!options || options.add !== true){
9015 if(this.pruneModifiedRecords){
9018 for(var i = 0, len = r.length; i < len; i++){
9022 this.data = this.snapshot;
9023 delete this.snapshot;
9026 this.data.addAll(r);
9027 this.totalLength = t;
9029 this.fireEvent("datachanged", this);
9031 this.totalLength = Math.max(t, this.data.length+r.length);
9034 this.fireEvent("load", this, r, options, o);
9035 if(options.callback){
9036 options.callback.call(options.scope || this, r, options, true);
9042 * Loads data from a passed data block. A Reader which understands the format of the data
9043 * must have been configured in the constructor.
9044 * @param {Object} data The data block from which to read the Records. The format of the data expected
9045 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9046 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9048 loadData : function(o, append){
9049 var r = this.reader.readRecords(o);
9050 this.loadRecords(r, {add: append}, true);
9054 * Gets the number of cached records.
9056 * <em>If using paging, this may not be the total size of the dataset. If the data object
9057 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9058 * the data set size</em>
9060 getCount : function(){
9061 return this.data.length || 0;
9065 * Gets the total number of records in the dataset as returned by the server.
9067 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9068 * the dataset size</em>
9070 getTotalCount : function(){
9071 return this.totalLength || 0;
9075 * Returns the sort state of the Store as an object with two properties:
9077 field {String} The name of the field by which the Records are sorted
9078 direction {String} The sort order, "ASC" or "DESC"
9081 getSortState : function(){
9082 return this.sortInfo;
9086 applySort : function(){
9087 if(this.sortInfo && !this.remoteSort){
9088 var s = this.sortInfo, f = s.field;
9089 var st = this.fields.get(f).sortType;
9090 var fn = function(r1, r2){
9091 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9092 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9094 this.data.sort(s.direction, fn);
9095 if(this.snapshot && this.snapshot != this.data){
9096 this.snapshot.sort(s.direction, fn);
9102 * Sets the default sort column and order to be used by the next load operation.
9103 * @param {String} fieldName The name of the field to sort by.
9104 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9106 setDefaultSort : function(field, dir){
9107 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9112 * If remote sorting is used, the sort is performed on the server, and the cache is
9113 * reloaded. If local sorting is used, the cache is sorted internally.
9114 * @param {String} fieldName The name of the field to sort by.
9115 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9117 sort : function(fieldName, dir){
9118 var f = this.fields.get(fieldName);
9120 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9122 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9123 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9128 this.sortToggle[f.name] = dir;
9129 this.sortInfo = {field: f.name, direction: dir};
9130 if(!this.remoteSort){
9132 this.fireEvent("datachanged", this);
9134 this.load(this.lastOptions);
9139 * Calls the specified function for each of the Records in the cache.
9140 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9141 * Returning <em>false</em> aborts and exits the iteration.
9142 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9144 each : function(fn, scope){
9145 this.data.each(fn, scope);
9149 * Gets all records modified since the last commit. Modified records are persisted across load operations
9150 * (e.g., during paging).
9151 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9153 getModifiedRecords : function(){
9154 return this.modified;
9158 createFilterFn : function(property, value, anyMatch){
9159 if(!value.exec){ // not a regex
9160 value = String(value);
9161 if(value.length == 0){
9164 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9167 return value.test(r.data[property]);
9172 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9173 * @param {String} property A field on your records
9174 * @param {Number} start The record index to start at (defaults to 0)
9175 * @param {Number} end The last record index to include (defaults to length - 1)
9176 * @return {Number} The sum
9178 sum : function(property, start, end){
9179 var rs = this.data.items, v = 0;
9181 end = (end || end === 0) ? end : rs.length-1;
9183 for(var i = start; i <= end; i++){
9184 v += (rs[i].data[property] || 0);
9190 * Filter the records by a specified property.
9191 * @param {String} field A field on your records
9192 * @param {String/RegExp} value Either a string that the field
9193 * should start with or a RegExp to test against the field
9194 * @param {Boolean} anyMatch True to match any part not just the beginning
9196 filter : function(property, value, anyMatch){
9197 var fn = this.createFilterFn(property, value, anyMatch);
9198 return fn ? this.filterBy(fn) : this.clearFilter();
9202 * Filter by a function. The specified function will be called with each
9203 * record in this data source. If the function returns true the record is included,
9204 * otherwise it is filtered.
9205 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9206 * @param {Object} scope (optional) The scope of the function (defaults to this)
9208 filterBy : function(fn, scope){
9209 this.snapshot = this.snapshot || this.data;
9210 this.data = this.queryBy(fn, scope||this);
9211 this.fireEvent("datachanged", this);
9215 * Query the records by a specified property.
9216 * @param {String} field A field on your records
9217 * @param {String/RegExp} value Either a string that the field
9218 * should start with or a RegExp to test against the field
9219 * @param {Boolean} anyMatch True to match any part not just the beginning
9220 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9222 query : function(property, value, anyMatch){
9223 var fn = this.createFilterFn(property, value, anyMatch);
9224 return fn ? this.queryBy(fn) : this.data.clone();
9228 * Query by a function. The specified function will be called with each
9229 * record in this data source. If the function returns true the record is included
9231 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9232 * @param {Object} scope (optional) The scope of the function (defaults to this)
9233 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9235 queryBy : function(fn, scope){
9236 var data = this.snapshot || this.data;
9237 return data.filterBy(fn, scope||this);
9241 * Collects unique values for a particular dataIndex from this store.
9242 * @param {String} dataIndex The property to collect
9243 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9244 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9245 * @return {Array} An array of the unique values
9247 collect : function(dataIndex, allowNull, bypassFilter){
9248 var d = (bypassFilter === true && this.snapshot) ?
9249 this.snapshot.items : this.data.items;
9250 var v, sv, r = [], l = {};
9251 for(var i = 0, len = d.length; i < len; i++){
9252 v = d[i].data[dataIndex];
9254 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9263 * Revert to a view of the Record cache with no filtering applied.
9264 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9266 clearFilter : function(suppressEvent){
9267 if(this.snapshot && this.snapshot != this.data){
9268 this.data = this.snapshot;
9269 delete this.snapshot;
9270 if(suppressEvent !== true){
9271 this.fireEvent("datachanged", this);
9277 afterEdit : function(record){
9278 if(this.modified.indexOf(record) == -1){
9279 this.modified.push(record);
9281 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9285 afterReject : function(record){
9286 this.modified.remove(record);
9287 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9291 afterCommit : function(record){
9292 this.modified.remove(record);
9293 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9297 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9298 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9300 commitChanges : function(){
9301 var m = this.modified.slice(0);
9303 for(var i = 0, len = m.length; i < len; i++){
9309 * Cancel outstanding changes on all changed records.
9311 rejectChanges : function(){
9312 var m = this.modified.slice(0);
9314 for(var i = 0, len = m.length; i < len; i++){
9319 onMetaChange : function(meta, rtype, o){
9320 this.recordType = rtype;
9321 this.fields = rtype.prototype.fields;
9322 delete this.snapshot;
9323 this.sortInfo = meta.sortInfo || this.sortInfo;
9325 this.fireEvent('metachange', this, this.reader.meta);
9328 moveIndex : function(data, type)
9330 var index = this.indexOf(data);
9332 var newIndex = index + type;
9336 this.insert(newIndex, data);
9341 * Ext JS Library 1.1.1
9342 * Copyright(c) 2006-2007, Ext JS, LLC.
9344 * Originally Released Under LGPL - original licence link has changed is not relivant.
9347 * <script type="text/javascript">
9351 * @class Roo.data.SimpleStore
9352 * @extends Roo.data.Store
9353 * Small helper class to make creating Stores from Array data easier.
9354 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9355 * @cfg {Array} fields An array of field definition objects, or field name strings.
9356 * @cfg {Array} data The multi-dimensional array of data
9358 * @param {Object} config
9360 Roo.data.SimpleStore = function(config){
9361 Roo.data.SimpleStore.superclass.constructor.call(this, {
9363 reader: new Roo.data.ArrayReader({
9366 Roo.data.Record.create(config.fields)
9368 proxy : new Roo.data.MemoryProxy(config.data)
9372 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9374 * Ext JS Library 1.1.1
9375 * Copyright(c) 2006-2007, Ext JS, LLC.
9377 * Originally Released Under LGPL - original licence link has changed is not relivant.
9380 * <script type="text/javascript">
9385 * @extends Roo.data.Store
9386 * @class Roo.data.JsonStore
9387 * Small helper class to make creating Stores for JSON data easier. <br/>
9389 var store = new Roo.data.JsonStore({
9390 url: 'get-images.php',
9392 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9395 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9396 * JsonReader and HttpProxy (unless inline data is provided).</b>
9397 * @cfg {Array} fields An array of field definition objects, or field name strings.
9399 * @param {Object} config
9401 Roo.data.JsonStore = function(c){
9402 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9403 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9404 reader: new Roo.data.JsonReader(c, c.fields)
9407 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9409 * Ext JS Library 1.1.1
9410 * Copyright(c) 2006-2007, Ext JS, LLC.
9412 * Originally Released Under LGPL - original licence link has changed is not relivant.
9415 * <script type="text/javascript">
9419 Roo.data.Field = function(config){
9420 if(typeof config == "string"){
9421 config = {name: config};
9423 Roo.apply(this, config);
9429 var st = Roo.data.SortTypes;
9430 // named sortTypes are supported, here we look them up
9431 if(typeof this.sortType == "string"){
9432 this.sortType = st[this.sortType];
9435 // set default sortType for strings and dates
9439 this.sortType = st.asUCString;
9442 this.sortType = st.asDate;
9445 this.sortType = st.none;
9450 var stripRe = /[\$,%]/g;
9452 // prebuilt conversion function for this field, instead of
9453 // switching every time we're reading a value
9455 var cv, dateFormat = this.dateFormat;
9460 cv = function(v){ return v; };
9463 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9467 return v !== undefined && v !== null && v !== '' ?
9468 parseInt(String(v).replace(stripRe, ""), 10) : '';
9473 return v !== undefined && v !== null && v !== '' ?
9474 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9479 cv = function(v){ return v === true || v === "true" || v == 1; };
9486 if(v instanceof Date){
9490 if(dateFormat == "timestamp"){
9491 return new Date(v*1000);
9493 return Date.parseDate(v, dateFormat);
9495 var parsed = Date.parse(v);
9496 return parsed ? new Date(parsed) : null;
9505 Roo.data.Field.prototype = {
9513 * Ext JS Library 1.1.1
9514 * Copyright(c) 2006-2007, Ext JS, LLC.
9516 * Originally Released Under LGPL - original licence link has changed is not relivant.
9519 * <script type="text/javascript">
9522 // Base class for reading structured data from a data source. This class is intended to be
9523 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9526 * @class Roo.data.DataReader
9527 * Base class for reading structured data from a data source. This class is intended to be
9528 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9531 Roo.data.DataReader = function(meta, recordType){
9535 this.recordType = recordType instanceof Array ?
9536 Roo.data.Record.create(recordType) : recordType;
9539 Roo.data.DataReader.prototype = {
9541 * Create an empty record
9542 * @param {Object} data (optional) - overlay some values
9543 * @return {Roo.data.Record} record created.
9545 newRow : function(d) {
9547 this.recordType.prototype.fields.each(function(c) {
9549 case 'int' : da[c.name] = 0; break;
9550 case 'date' : da[c.name] = new Date(); break;
9551 case 'float' : da[c.name] = 0.0; break;
9552 case 'boolean' : da[c.name] = false; break;
9553 default : da[c.name] = ""; break;
9557 return new this.recordType(Roo.apply(da, d));
9562 * Ext JS Library 1.1.1
9563 * Copyright(c) 2006-2007, Ext JS, LLC.
9565 * Originally Released Under LGPL - original licence link has changed is not relivant.
9568 * <script type="text/javascript">
9572 * @class Roo.data.DataProxy
9573 * @extends Roo.data.Observable
9574 * This class is an abstract base class for implementations which provide retrieval of
9575 * unformatted data objects.<br>
9577 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9578 * (of the appropriate type which knows how to parse the data object) to provide a block of
9579 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9581 * Custom implementations must implement the load method as described in
9582 * {@link Roo.data.HttpProxy#load}.
9584 Roo.data.DataProxy = function(){
9588 * Fires before a network request is made to retrieve a data object.
9589 * @param {Object} This DataProxy object.
9590 * @param {Object} params The params parameter to the load function.
9595 * Fires before the load method's callback is called.
9596 * @param {Object} This DataProxy object.
9597 * @param {Object} o The data object.
9598 * @param {Object} arg The callback argument object passed to the load function.
9602 * @event loadexception
9603 * Fires if an Exception occurs during data retrieval.
9604 * @param {Object} This DataProxy object.
9605 * @param {Object} o The data object.
9606 * @param {Object} arg The callback argument object passed to the load function.
9607 * @param {Object} e The Exception.
9609 loadexception : true
9611 Roo.data.DataProxy.superclass.constructor.call(this);
9614 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9617 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9621 * Ext JS Library 1.1.1
9622 * Copyright(c) 2006-2007, Ext JS, LLC.
9624 * Originally Released Under LGPL - original licence link has changed is not relivant.
9627 * <script type="text/javascript">
9630 * @class Roo.data.MemoryProxy
9631 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9632 * to the Reader when its load method is called.
9634 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9636 Roo.data.MemoryProxy = function(data){
9640 Roo.data.MemoryProxy.superclass.constructor.call(this);
9644 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9646 * Load data from the requested source (in this case an in-memory
9647 * data object passed to the constructor), read the data object into
9648 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9649 * process that block using the passed callback.
9650 * @param {Object} params This parameter is not used by the MemoryProxy class.
9651 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9652 * object into a block of Roo.data.Records.
9653 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9654 * The function must be passed <ul>
9655 * <li>The Record block object</li>
9656 * <li>The "arg" argument from the load function</li>
9657 * <li>A boolean success indicator</li>
9659 * @param {Object} scope The scope in which to call the callback
9660 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9662 load : function(params, reader, callback, scope, arg){
9663 params = params || {};
9666 result = reader.readRecords(this.data);
9668 this.fireEvent("loadexception", this, arg, null, e);
9669 callback.call(scope, null, arg, false);
9672 callback.call(scope, result, arg, true);
9676 update : function(params, records){
9681 * Ext JS Library 1.1.1
9682 * Copyright(c) 2006-2007, Ext JS, LLC.
9684 * Originally Released Under LGPL - original licence link has changed is not relivant.
9687 * <script type="text/javascript">
9690 * @class Roo.data.HttpProxy
9691 * @extends Roo.data.DataProxy
9692 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9693 * configured to reference a certain URL.<br><br>
9695 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9696 * from which the running page was served.<br><br>
9698 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9700 * Be aware that to enable the browser to parse an XML document, the server must set
9701 * the Content-Type header in the HTTP response to "text/xml".
9703 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9704 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9705 * will be used to make the request.
9707 Roo.data.HttpProxy = function(conn){
9708 Roo.data.HttpProxy.superclass.constructor.call(this);
9709 // is conn a conn config or a real conn?
9711 this.useAjax = !conn || !conn.events;
9715 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9716 // thse are take from connection...
9719 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9722 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9723 * extra parameters to each request made by this object. (defaults to undefined)
9726 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9727 * to each request made by this object. (defaults to undefined)
9730 * @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)
9733 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9736 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9742 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9746 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9747 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9748 * a finer-grained basis than the DataProxy events.
9750 getConnection : function(){
9751 return this.useAjax ? Roo.Ajax : this.conn;
9755 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9756 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9757 * process that block using the passed callback.
9758 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9759 * for the request to the remote server.
9760 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9761 * object into a block of Roo.data.Records.
9762 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9763 * The function must be passed <ul>
9764 * <li>The Record block object</li>
9765 * <li>The "arg" argument from the load function</li>
9766 * <li>A boolean success indicator</li>
9768 * @param {Object} scope The scope in which to call the callback
9769 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9771 load : function(params, reader, callback, scope, arg){
9772 if(this.fireEvent("beforeload", this, params) !== false){
9774 params : params || {},
9776 callback : callback,
9781 callback : this.loadResponse,
9785 Roo.applyIf(o, this.conn);
9786 if(this.activeRequest){
9787 Roo.Ajax.abort(this.activeRequest);
9789 this.activeRequest = Roo.Ajax.request(o);
9791 this.conn.request(o);
9794 callback.call(scope||this, null, arg, false);
9799 loadResponse : function(o, success, response){
9800 delete this.activeRequest;
9802 this.fireEvent("loadexception", this, o, response);
9803 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9808 result = o.reader.read(response);
9810 this.fireEvent("loadexception", this, o, response, e);
9811 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9815 this.fireEvent("load", this, o, o.request.arg);
9816 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9820 update : function(dataSet){
9825 updateResponse : function(dataSet){
9830 * Ext JS Library 1.1.1
9831 * Copyright(c) 2006-2007, Ext JS, LLC.
9833 * Originally Released Under LGPL - original licence link has changed is not relivant.
9836 * <script type="text/javascript">
9840 * @class Roo.data.ScriptTagProxy
9841 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9842 * other than the originating domain of the running page.<br><br>
9844 * <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
9845 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9847 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9848 * source code that is used as the source inside a <script> tag.<br><br>
9850 * In order for the browser to process the returned data, the server must wrap the data object
9851 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9852 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9853 * depending on whether the callback name was passed:
9856 boolean scriptTag = false;
9857 String cb = request.getParameter("callback");
9860 response.setContentType("text/javascript");
9862 response.setContentType("application/x-json");
9864 Writer out = response.getWriter();
9866 out.write(cb + "(");
9868 out.print(dataBlock.toJsonString());
9875 * @param {Object} config A configuration object.
9877 Roo.data.ScriptTagProxy = function(config){
9878 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9879 Roo.apply(this, config);
9880 this.head = document.getElementsByTagName("head")[0];
9883 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9885 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9887 * @cfg {String} url The URL from which to request the data object.
9890 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9894 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9895 * the server the name of the callback function set up by the load call to process the returned data object.
9896 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9897 * javascript output which calls this named function passing the data object as its only parameter.
9899 callbackParam : "callback",
9901 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9902 * name to the request.
9907 * Load data from the configured URL, read the data object into
9908 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9909 * process that block using the passed callback.
9910 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9911 * for the request to the remote server.
9912 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9913 * object into a block of Roo.data.Records.
9914 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9915 * The function must be passed <ul>
9916 * <li>The Record block object</li>
9917 * <li>The "arg" argument from the load function</li>
9918 * <li>A boolean success indicator</li>
9920 * @param {Object} scope The scope in which to call the callback
9921 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9923 load : function(params, reader, callback, scope, arg){
9924 if(this.fireEvent("beforeload", this, params) !== false){
9926 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9929 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9931 url += "&_dc=" + (new Date().getTime());
9933 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9936 cb : "stcCallback"+transId,
9937 scriptId : "stcScript"+transId,
9941 callback : callback,
9947 window[trans.cb] = function(o){
9948 conn.handleResponse(o, trans);
9951 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9953 if(this.autoAbort !== false){
9957 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9959 var script = document.createElement("script");
9960 script.setAttribute("src", url);
9961 script.setAttribute("type", "text/javascript");
9962 script.setAttribute("id", trans.scriptId);
9963 this.head.appendChild(script);
9967 callback.call(scope||this, null, arg, false);
9972 isLoading : function(){
9973 return this.trans ? true : false;
9977 * Abort the current server request.
9980 if(this.isLoading()){
9981 this.destroyTrans(this.trans);
9986 destroyTrans : function(trans, isLoaded){
9987 this.head.removeChild(document.getElementById(trans.scriptId));
9988 clearTimeout(trans.timeoutId);
9990 window[trans.cb] = undefined;
9992 delete window[trans.cb];
9995 // if hasn't been loaded, wait for load to remove it to prevent script error
9996 window[trans.cb] = function(){
9997 window[trans.cb] = undefined;
9999 delete window[trans.cb];
10006 handleResponse : function(o, trans){
10007 this.trans = false;
10008 this.destroyTrans(trans, true);
10011 result = trans.reader.readRecords(o);
10013 this.fireEvent("loadexception", this, o, trans.arg, e);
10014 trans.callback.call(trans.scope||window, null, trans.arg, false);
10017 this.fireEvent("load", this, o, trans.arg);
10018 trans.callback.call(trans.scope||window, result, trans.arg, true);
10022 handleFailure : function(trans){
10023 this.trans = false;
10024 this.destroyTrans(trans, false);
10025 this.fireEvent("loadexception", this, null, trans.arg);
10026 trans.callback.call(trans.scope||window, null, trans.arg, false);
10030 * Ext JS Library 1.1.1
10031 * Copyright(c) 2006-2007, Ext JS, LLC.
10033 * Originally Released Under LGPL - original licence link has changed is not relivant.
10036 * <script type="text/javascript">
10040 * @class Roo.data.JsonReader
10041 * @extends Roo.data.DataReader
10042 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10043 * based on mappings in a provided Roo.data.Record constructor.
10045 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10046 * in the reply previously.
10051 var RecordDef = Roo.data.Record.create([
10052 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10053 {name: 'occupation'} // This field will use "occupation" as the mapping.
10055 var myReader = new Roo.data.JsonReader({
10056 totalProperty: "results", // The property which contains the total dataset size (optional)
10057 root: "rows", // The property which contains an Array of row objects
10058 id: "id" // The property within each row object that provides an ID for the record (optional)
10062 * This would consume a JSON file like this:
10064 { 'results': 2, 'rows': [
10065 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10066 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10069 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10070 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10071 * paged from the remote server.
10072 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10073 * @cfg {String} root name of the property which contains the Array of row objects.
10074 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10076 * Create a new JsonReader
10077 * @param {Object} meta Metadata configuration options
10078 * @param {Object} recordType Either an Array of field definition objects,
10079 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10081 Roo.data.JsonReader = function(meta, recordType){
10084 // set some defaults:
10085 Roo.applyIf(meta, {
10086 totalProperty: 'total',
10087 successProperty : 'success',
10092 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10094 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10097 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10098 * Used by Store query builder to append _requestMeta to params.
10101 metaFromRemote : false,
10103 * This method is only used by a DataProxy which has retrieved data from a remote server.
10104 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10105 * @return {Object} data A data block which is used by an Roo.data.Store object as
10106 * a cache of Roo.data.Records.
10108 read : function(response){
10109 var json = response.responseText;
10111 var o = /* eval:var:o */ eval("("+json+")");
10113 throw {message: "JsonReader.read: Json object not found"};
10119 this.metaFromRemote = true;
10120 this.meta = o.metaData;
10121 this.recordType = Roo.data.Record.create(o.metaData.fields);
10122 this.onMetaChange(this.meta, this.recordType, o);
10124 return this.readRecords(o);
10127 // private function a store will implement
10128 onMetaChange : function(meta, recordType, o){
10135 simpleAccess: function(obj, subsc) {
10142 getJsonAccessor: function(){
10144 return function(expr) {
10146 return(re.test(expr))
10147 ? new Function("obj", "return obj." + expr)
10152 return Roo.emptyFn;
10157 * Create a data block containing Roo.data.Records from an XML document.
10158 * @param {Object} o An object which contains an Array of row objects in the property specified
10159 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10160 * which contains the total size of the dataset.
10161 * @return {Object} data A data block which is used by an Roo.data.Store object as
10162 * a cache of Roo.data.Records.
10164 readRecords : function(o){
10166 * After any data loads, the raw JSON data is available for further custom processing.
10170 var s = this.meta, Record = this.recordType,
10171 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10173 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10175 if(s.totalProperty) {
10176 this.getTotal = this.getJsonAccessor(s.totalProperty);
10178 if(s.successProperty) {
10179 this.getSuccess = this.getJsonAccessor(s.successProperty);
10181 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10183 var g = this.getJsonAccessor(s.id);
10184 this.getId = function(rec) {
10186 return (r === undefined || r === "") ? null : r;
10189 this.getId = function(){return null;};
10192 for(var jj = 0; jj < fl; jj++){
10194 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10195 this.ef[jj] = this.getJsonAccessor(map);
10199 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10200 if(s.totalProperty){
10201 var vt = parseInt(this.getTotal(o), 10);
10206 if(s.successProperty){
10207 var vs = this.getSuccess(o);
10208 if(vs === false || vs === 'false'){
10213 for(var i = 0; i < c; i++){
10216 var id = this.getId(n);
10217 for(var j = 0; j < fl; j++){
10219 var v = this.ef[j](n);
10221 Roo.log('missing convert for ' + f.name);
10225 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10227 var record = new Record(values, id);
10229 records[i] = record;
10235 totalRecords : totalRecords
10240 * Ext JS Library 1.1.1
10241 * Copyright(c) 2006-2007, Ext JS, LLC.
10243 * Originally Released Under LGPL - original licence link has changed is not relivant.
10246 * <script type="text/javascript">
10250 * @class Roo.data.ArrayReader
10251 * @extends Roo.data.DataReader
10252 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10253 * Each element of that Array represents a row of data fields. The
10254 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10255 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10259 var RecordDef = Roo.data.Record.create([
10260 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10261 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10263 var myReader = new Roo.data.ArrayReader({
10264 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10268 * This would consume an Array like this:
10270 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10272 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10274 * Create a new JsonReader
10275 * @param {Object} meta Metadata configuration options.
10276 * @param {Object} recordType Either an Array of field definition objects
10277 * as specified to {@link Roo.data.Record#create},
10278 * or an {@link Roo.data.Record} object
10279 * created using {@link Roo.data.Record#create}.
10281 Roo.data.ArrayReader = function(meta, recordType){
10282 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10285 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10287 * Create a data block containing Roo.data.Records from an XML document.
10288 * @param {Object} o An Array of row objects which represents the dataset.
10289 * @return {Object} data A data block which is used by an Roo.data.Store object as
10290 * a cache of Roo.data.Records.
10292 readRecords : function(o){
10293 var sid = this.meta ? this.meta.id : null;
10294 var recordType = this.recordType, fields = recordType.prototype.fields;
10297 for(var i = 0; i < root.length; i++){
10300 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10301 for(var j = 0, jlen = fields.length; j < jlen; j++){
10302 var f = fields.items[j];
10303 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10304 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10306 values[f.name] = v;
10308 var record = new recordType(values, id);
10310 records[records.length] = record;
10314 totalRecords : records.length
10323 * @class Roo.bootstrap.ComboBox
10324 * @extends Roo.bootstrap.TriggerField
10325 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10326 * @cfg {Boolean} append (true|false) default false
10327 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10328 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10329 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10330 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10331 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10333 * Create a new ComboBox.
10334 * @param {Object} config Configuration options
10336 Roo.bootstrap.ComboBox = function(config){
10337 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10341 * Fires when the dropdown list is expanded
10342 * @param {Roo.bootstrap.ComboBox} combo This combo box
10347 * Fires when the dropdown list is collapsed
10348 * @param {Roo.bootstrap.ComboBox} combo This combo box
10352 * @event beforeselect
10353 * Fires before a list item is selected. Return false to cancel the selection.
10354 * @param {Roo.bootstrap.ComboBox} combo This combo box
10355 * @param {Roo.data.Record} record The data record returned from the underlying store
10356 * @param {Number} index The index of the selected item in the dropdown list
10358 'beforeselect' : true,
10361 * Fires when a list item is selected
10362 * @param {Roo.bootstrap.ComboBox} combo This combo box
10363 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10364 * @param {Number} index The index of the selected item in the dropdown list
10368 * @event beforequery
10369 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10370 * The event object passed has these properties:
10371 * @param {Roo.bootstrap.ComboBox} combo This combo box
10372 * @param {String} query The query
10373 * @param {Boolean} forceAll true to force "all" query
10374 * @param {Boolean} cancel true to cancel the query
10375 * @param {Object} e The query event object
10377 'beforequery': true,
10380 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10381 * @param {Roo.bootstrap.ComboBox} combo This combo box
10386 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10387 * @param {Roo.bootstrap.ComboBox} combo This combo box
10388 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10393 * Fires when the remove value from the combobox array
10394 * @param {Roo.bootstrap.ComboBox} combo This combo box
10401 this.tickItems = [];
10403 this.selectedIndex = -1;
10404 if(this.mode == 'local'){
10405 if(config.queryDelay === undefined){
10406 this.queryDelay = 10;
10408 if(config.minChars === undefined){
10414 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10417 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10418 * rendering into an Roo.Editor, defaults to false)
10421 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10422 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10425 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10428 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10429 * the dropdown list (defaults to undefined, with no header element)
10433 * @cfg {String/Roo.Template} tpl The template to use to render the output
10437 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10439 listWidth: undefined,
10441 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10442 * mode = 'remote' or 'text' if mode = 'local')
10444 displayField: undefined,
10446 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10447 * mode = 'remote' or 'value' if mode = 'local').
10448 * Note: use of a valueField requires the user make a selection
10449 * in order for a value to be mapped.
10451 valueField: undefined,
10455 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10456 * field's data value (defaults to the underlying DOM element's name)
10458 hiddenName: undefined,
10460 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10464 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10466 selectedClass: 'active',
10469 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10473 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10474 * anchor positions (defaults to 'tl-bl')
10476 listAlign: 'tl-bl?',
10478 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10482 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10483 * query specified by the allQuery config option (defaults to 'query')
10485 triggerAction: 'query',
10487 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10488 * (defaults to 4, does not apply if editable = false)
10492 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10493 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10497 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10498 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10502 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10503 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10507 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10508 * when editable = true (defaults to false)
10510 selectOnFocus:false,
10512 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10514 queryParam: 'query',
10516 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10517 * when mode = 'remote' (defaults to 'Loading...')
10519 loadingText: 'Loading...',
10521 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10525 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10529 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10530 * traditional select (defaults to true)
10534 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10538 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10542 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10543 * listWidth has a higher value)
10547 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10548 * allow the user to set arbitrary text into the field (defaults to false)
10550 forceSelection:false,
10552 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10553 * if typeAhead = true (defaults to 250)
10555 typeAheadDelay : 250,
10557 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10558 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10560 valueNotFoundText : undefined,
10562 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10564 blockFocus : false,
10567 * @cfg {Boolean} disableClear Disable showing of clear button.
10569 disableClear : false,
10571 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10573 alwaysQuery : false,
10576 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10590 btnPosition : 'right',
10591 triggerList : true,
10592 showToggleBtn : true,
10593 // element that contains real text value.. (when hidden is used..)
10595 getAutoCreate : function()
10602 if(!this.tickable){
10603 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10608 * ComboBox with tickable selections
10611 var align = this.labelAlign || this.parentLabelAlign();
10614 cls : 'form-group roo-combobox-tickable' //input-group
10620 cls : 'tickable-buttons',
10625 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10632 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10639 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10646 Roo.each(buttons.cn, function(c){
10648 c.cls += ' btn-' + _this.size;
10651 if (_this.disabled) {
10662 cls: 'form-hidden-field'
10666 cls: 'select2-choices',
10670 cls: 'select2-search-field',
10682 cls: 'select2-container input-group select2-container-multi',
10687 // cls: 'typeahead typeahead-long dropdown-menu',
10688 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10693 if (align ==='left' && this.fieldLabel.length) {
10695 Roo.log("left and has label");
10701 cls : 'control-label col-sm-' + this.labelWidth,
10702 html : this.fieldLabel
10706 cls : "col-sm-" + (12 - this.labelWidth),
10713 } else if ( this.fieldLabel.length) {
10719 //cls : 'input-group-addon',
10720 html : this.fieldLabel
10730 Roo.log(" no label && no align");
10737 ['xs','sm','md','lg'].map(function(size){
10738 if (settings[size]) {
10739 cfg.cls += ' col-' + size + '-' + settings[size];
10748 initEvents: function()
10752 throw "can not find store for combo";
10754 this.store = Roo.factory(this.store, Roo.data);
10757 this.initTickableEvents();
10761 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10763 if(this.hiddenName){
10765 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10767 this.hiddenField.dom.value =
10768 this.hiddenValue !== undefined ? this.hiddenValue :
10769 this.value !== undefined ? this.value : '';
10771 // prevent input submission
10772 this.el.dom.removeAttribute('name');
10773 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10778 // this.el.dom.setAttribute('autocomplete', 'off');
10781 var cls = 'x-combo-list';
10783 //this.list = new Roo.Layer({
10784 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10790 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10791 _this.list.setWidth(lw);
10794 this.list.on('mouseover', this.onViewOver, this);
10795 this.list.on('mousemove', this.onViewMove, this);
10797 this.list.on('scroll', this.onViewScroll, this);
10800 this.list.swallowEvent('mousewheel');
10801 this.assetHeight = 0;
10804 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10805 this.assetHeight += this.header.getHeight();
10808 this.innerList = this.list.createChild({cls:cls+'-inner'});
10809 this.innerList.on('mouseover', this.onViewOver, this);
10810 this.innerList.on('mousemove', this.onViewMove, this);
10811 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10813 if(this.allowBlank && !this.pageSize && !this.disableClear){
10814 this.footer = this.list.createChild({cls:cls+'-ft'});
10815 this.pageTb = new Roo.Toolbar(this.footer);
10819 this.footer = this.list.createChild({cls:cls+'-ft'});
10820 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10821 {pageSize: this.pageSize});
10825 if (this.pageTb && this.allowBlank && !this.disableClear) {
10827 this.pageTb.add(new Roo.Toolbar.Fill(), {
10828 cls: 'x-btn-icon x-btn-clear',
10830 handler: function()
10833 _this.clearValue();
10834 _this.onSelect(false, -1);
10839 this.assetHeight += this.footer.getHeight();
10844 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10847 this.view = new Roo.View(this.list, this.tpl, {
10848 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10850 //this.view.wrapEl.setDisplayed(false);
10851 this.view.on('click', this.onViewClick, this);
10855 this.store.on('beforeload', this.onBeforeLoad, this);
10856 this.store.on('load', this.onLoad, this);
10857 this.store.on('loadexception', this.onLoadException, this);
10859 if(this.resizable){
10860 this.resizer = new Roo.Resizable(this.list, {
10861 pinned:true, handles:'se'
10863 this.resizer.on('resize', function(r, w, h){
10864 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10865 this.listWidth = w;
10866 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10867 this.restrictHeight();
10869 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10872 if(!this.editable){
10873 this.editable = true;
10874 this.setEditable(false);
10879 if (typeof(this.events.add.listeners) != 'undefined') {
10881 this.addicon = this.wrap.createChild(
10882 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10884 this.addicon.on('click', function(e) {
10885 this.fireEvent('add', this);
10888 if (typeof(this.events.edit.listeners) != 'undefined') {
10890 this.editicon = this.wrap.createChild(
10891 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10892 if (this.addicon) {
10893 this.editicon.setStyle('margin-left', '40px');
10895 this.editicon.on('click', function(e) {
10897 // we fire even if inothing is selected..
10898 this.fireEvent('edit', this, this.lastData );
10904 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10905 "up" : function(e){
10906 this.inKeyMode = true;
10910 "down" : function(e){
10911 if(!this.isExpanded()){
10912 this.onTriggerClick();
10914 this.inKeyMode = true;
10919 "enter" : function(e){
10920 // this.onViewClick();
10924 if(this.fireEvent("specialkey", this, e)){
10925 this.onViewClick(false);
10931 "esc" : function(e){
10935 "tab" : function(e){
10938 if(this.fireEvent("specialkey", this, e)){
10939 this.onViewClick(false);
10947 doRelay : function(foo, bar, hname){
10948 if(hname == 'down' || this.scope.isExpanded()){
10949 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10958 this.queryDelay = Math.max(this.queryDelay || 10,
10959 this.mode == 'local' ? 10 : 250);
10962 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10964 if(this.typeAhead){
10965 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10967 if(this.editable !== false){
10968 this.inputEl().on("keyup", this.onKeyUp, this);
10970 if(this.forceSelection){
10971 this.inputEl().on('blur', this.doForce, this);
10975 this.choices = this.el.select('ul.select2-choices', true).first();
10976 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10980 initTickableEvents: function()
10984 if(this.hiddenName){
10986 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10988 this.hiddenField.dom.value =
10989 this.hiddenValue !== undefined ? this.hiddenValue :
10990 this.value !== undefined ? this.value : '';
10992 // prevent input submission
10993 this.el.dom.removeAttribute('name');
10994 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10999 // this.list = this.el.select('ul.dropdown-menu',true).first();
11001 this.choices = this.el.select('ul.select2-choices', true).first();
11002 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11003 if(this.triggerList){
11004 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11007 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11008 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11010 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11011 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11013 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11014 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11016 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11017 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11018 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11021 this.cancelBtn.hide();
11026 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11027 _this.list.setWidth(lw);
11030 this.list.on('mouseover', this.onViewOver, this);
11031 this.list.on('mousemove', this.onViewMove, this);
11033 this.list.on('scroll', this.onViewScroll, this);
11036 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>';
11039 this.view = new Roo.View(this.list, this.tpl, {
11040 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11043 //this.view.wrapEl.setDisplayed(false);
11044 this.view.on('click', this.onViewClick, this);
11048 this.store.on('beforeload', this.onBeforeLoad, this);
11049 this.store.on('load', this.onLoad, this);
11050 this.store.on('loadexception', this.onLoadException, this);
11052 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
11053 // "up" : function(e){
11054 // this.inKeyMode = true;
11055 // this.selectPrev();
11058 // "down" : function(e){
11059 // if(!this.isExpanded()){
11060 // this.onTriggerClick();
11062 // this.inKeyMode = true;
11063 // this.selectNext();
11067 // "enter" : function(e){
11068 //// this.onViewClick();
11070 // this.collapse();
11072 // if(this.fireEvent("specialkey", this, e)){
11073 // this.onViewClick(false);
11079 // "esc" : function(e){
11080 // this.collapse();
11083 // "tab" : function(e){
11084 // this.collapse();
11086 // if(this.fireEvent("specialkey", this, e)){
11087 // this.onViewClick(false);
11095 // doRelay : function(foo, bar, hname){
11096 // if(hname == 'down' || this.scope.isExpanded()){
11097 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11102 // forceKeyDown: true
11106 this.queryDelay = Math.max(this.queryDelay || 10,
11107 this.mode == 'local' ? 10 : 250);
11110 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11112 if(this.typeAhead){
11113 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11117 onDestroy : function(){
11119 this.view.setStore(null);
11120 this.view.el.removeAllListeners();
11121 this.view.el.remove();
11122 this.view.purgeListeners();
11125 this.list.dom.innerHTML = '';
11129 this.store.un('beforeload', this.onBeforeLoad, this);
11130 this.store.un('load', this.onLoad, this);
11131 this.store.un('loadexception', this.onLoadException, this);
11133 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11137 fireKey : function(e){
11138 if(e.isNavKeyPress() && !this.list.isVisible()){
11139 this.fireEvent("specialkey", this, e);
11144 onResize: function(w, h){
11145 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11147 // if(typeof w != 'number'){
11148 // // we do not handle it!?!?
11151 // var tw = this.trigger.getWidth();
11152 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11153 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11155 // this.inputEl().setWidth( this.adjustWidth('input', x));
11157 // //this.trigger.setStyle('left', x+'px');
11159 // if(this.list && this.listWidth === undefined){
11160 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11161 // this.list.setWidth(lw);
11162 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11170 * Allow or prevent the user from directly editing the field text. If false is passed,
11171 * the user will only be able to select from the items defined in the dropdown list. This method
11172 * is the runtime equivalent of setting the 'editable' config option at config time.
11173 * @param {Boolean} value True to allow the user to directly edit the field text
11175 setEditable : function(value){
11176 if(value == this.editable){
11179 this.editable = value;
11181 this.inputEl().dom.setAttribute('readOnly', true);
11182 this.inputEl().on('mousedown', this.onTriggerClick, this);
11183 this.inputEl().addClass('x-combo-noedit');
11185 this.inputEl().dom.setAttribute('readOnly', false);
11186 this.inputEl().un('mousedown', this.onTriggerClick, this);
11187 this.inputEl().removeClass('x-combo-noedit');
11193 onBeforeLoad : function(combo,opts){
11194 if(!this.hasFocus){
11198 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11200 this.restrictHeight();
11201 this.selectedIndex = -1;
11205 onLoad : function(){
11207 this.hasQuery = false;
11209 if(!this.hasFocus){
11213 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11214 this.loading.hide();
11217 if(this.store.getCount() > 0){
11219 // this.restrictHeight();
11220 if(this.lastQuery == this.allQuery){
11221 if(this.editable && !this.tickable){
11222 this.inputEl().dom.select();
11226 !this.selectByValue(this.value, true) &&
11227 this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' ||
11228 this.store.lastOptions.add != true)
11230 this.select(0, true);
11233 if(this.autoFocus){
11236 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11237 this.taTask.delay(this.typeAheadDelay);
11241 this.onEmptyResults();
11247 onLoadException : function()
11249 this.hasQuery = false;
11251 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11252 this.loading.hide();
11256 Roo.log(this.store.reader.jsonData);
11257 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11259 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11265 onTypeAhead : function(){
11266 if(this.store.getCount() > 0){
11267 var r = this.store.getAt(0);
11268 var newValue = r.data[this.displayField];
11269 var len = newValue.length;
11270 var selStart = this.getRawValue().length;
11272 if(selStart != len){
11273 this.setRawValue(newValue);
11274 this.selectText(selStart, newValue.length);
11280 onSelect : function(record, index){
11282 if(this.fireEvent('beforeselect', this, record, index) !== false){
11284 this.setFromData(index > -1 ? record.data : false);
11287 this.fireEvent('select', this, record, index);
11292 * Returns the currently selected field value or empty string if no value is set.
11293 * @return {String} value The selected value
11295 getValue : function(){
11298 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11301 if(this.valueField){
11302 return typeof this.value != 'undefined' ? this.value : '';
11304 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11309 * Clears any text/value currently set in the field
11311 clearValue : function(){
11312 if(this.hiddenField){
11313 this.hiddenField.dom.value = '';
11316 this.setRawValue('');
11317 this.lastSelectionText = '';
11322 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11323 * will be displayed in the field. If the value does not match the data value of an existing item,
11324 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11325 * Otherwise the field will be blank (although the value will still be set).
11326 * @param {String} value The value to match
11328 setValue : function(v){
11335 if(this.valueField){
11336 var r = this.findRecord(this.valueField, v);
11338 text = r.data[this.displayField];
11339 }else if(this.valueNotFoundText !== undefined){
11340 text = this.valueNotFoundText;
11343 this.lastSelectionText = text;
11344 if(this.hiddenField){
11345 this.hiddenField.dom.value = v;
11347 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11351 * @property {Object} the last set data for the element
11356 * Sets the value of the field based on a object which is related to the record format for the store.
11357 * @param {Object} value the value to set as. or false on reset?
11359 setFromData : function(o){
11366 var dv = ''; // display value
11367 var vv = ''; // value value..
11369 if (this.displayField) {
11370 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11372 // this is an error condition!!!
11373 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11376 if(this.valueField){
11377 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11380 if(this.hiddenField){
11381 this.hiddenField.dom.value = vv;
11383 this.lastSelectionText = dv;
11384 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11388 // no hidden field.. - we store the value in 'value', but still display
11389 // display field!!!!
11390 this.lastSelectionText = dv;
11391 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11397 reset : function(){
11398 // overridden so that last data is reset..
11399 this.setValue(this.originalValue);
11400 this.clearInvalid();
11401 this.lastData = false;
11403 this.view.clearSelections();
11407 findRecord : function(prop, value){
11409 if(this.store.getCount() > 0){
11410 this.store.each(function(r){
11411 if(r.data[prop] == value){
11421 getName: function()
11423 // returns hidden if it's set..
11424 if (!this.rendered) {return ''};
11425 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11429 onViewMove : function(e, t){
11430 this.inKeyMode = false;
11434 onViewOver : function(e, t){
11435 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11438 var item = this.view.findItemFromChild(t);
11441 var index = this.view.indexOf(item);
11442 this.select(index, false);
11447 onViewClick : function(view, doFocus, el, e)
11449 var index = this.view.getSelectedIndexes()[0];
11451 var r = this.store.getAt(index);
11455 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11462 Roo.each(this.tickItems, function(v,k){
11464 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11465 _this.tickItems.splice(k, 1);
11475 this.tickItems.push(r.data);
11480 this.onSelect(r, index);
11482 if(doFocus !== false && !this.blockFocus){
11483 this.inputEl().focus();
11488 restrictHeight : function(){
11489 //this.innerList.dom.style.height = '';
11490 //var inner = this.innerList.dom;
11491 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11492 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11493 //this.list.beginUpdate();
11494 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11495 this.list.alignTo(this.inputEl(), this.listAlign);
11496 this.list.alignTo(this.inputEl(), this.listAlign);
11497 //this.list.endUpdate();
11501 onEmptyResults : function(){
11506 * Returns true if the dropdown list is expanded, else false.
11508 isExpanded : function(){
11509 return this.list.isVisible();
11513 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11514 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11515 * @param {String} value The data value of the item to select
11516 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11517 * selected item if it is not currently in view (defaults to true)
11518 * @return {Boolean} True if the value matched an item in the list, else false
11520 selectByValue : function(v, scrollIntoView){
11521 if(v !== undefined && v !== null){
11522 var r = this.findRecord(this.valueField || this.displayField, v);
11524 this.select(this.store.indexOf(r), scrollIntoView);
11532 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11533 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11534 * @param {Number} index The zero-based index of the list item to select
11535 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11536 * selected item if it is not currently in view (defaults to true)
11538 select : function(index, scrollIntoView){
11539 this.selectedIndex = index;
11540 this.view.select(index);
11541 if(scrollIntoView !== false){
11542 var el = this.view.getNode(index);
11543 if(el && !this.multiple && !this.tickable){
11544 this.list.scrollChildIntoView(el, false);
11550 selectNext : function(){
11551 var ct = this.store.getCount();
11553 if(this.selectedIndex == -1){
11555 }else if(this.selectedIndex < ct-1){
11556 this.select(this.selectedIndex+1);
11562 selectPrev : function(){
11563 var ct = this.store.getCount();
11565 if(this.selectedIndex == -1){
11567 }else if(this.selectedIndex != 0){
11568 this.select(this.selectedIndex-1);
11574 onKeyUp : function(e){
11575 if(this.editable !== false && !e.isSpecialKey()){
11576 this.lastKey = e.getKey();
11577 this.dqTask.delay(this.queryDelay);
11582 validateBlur : function(){
11583 return !this.list || !this.list.isVisible();
11587 initQuery : function(){
11588 this.doQuery(this.getRawValue());
11592 doForce : function(){
11593 if(this.inputEl().dom.value.length > 0){
11594 this.inputEl().dom.value =
11595 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11601 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11602 * query allowing the query action to be canceled if needed.
11603 * @param {String} query The SQL query to execute
11604 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11605 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11606 * saved in the current store (defaults to false)
11608 doQuery : function(q, forceAll){
11610 if(q === undefined || q === null){
11615 forceAll: forceAll,
11619 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11624 forceAll = qe.forceAll;
11625 if(forceAll === true || (q.length >= this.minChars)){
11627 this.hasQuery = true;
11629 if(this.lastQuery != q || this.alwaysQuery){
11630 this.lastQuery = q;
11631 if(this.mode == 'local'){
11632 this.selectedIndex = -1;
11634 this.store.clearFilter();
11636 this.store.filter(this.displayField, q);
11640 this.store.baseParams[this.queryParam] = q;
11642 var options = {params : this.getParams(q)};
11645 options.add = true;
11646 options.params.start = this.page * this.pageSize;
11649 this.store.load(options);
11651 * this code will make the page width larger, at the beginning, the list not align correctly,
11652 * we should expand the list on onLoad
11653 * so command out it
11658 this.selectedIndex = -1;
11663 this.loadNext = false;
11667 getParams : function(q){
11669 //p[this.queryParam] = q;
11673 p.limit = this.pageSize;
11679 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11681 collapse : function(){
11682 if(!this.isExpanded()){
11690 this.cancelBtn.hide();
11691 this.trigger.show();
11694 Roo.get(document).un('mousedown', this.collapseIf, this);
11695 Roo.get(document).un('mousewheel', this.collapseIf, this);
11696 if (!this.editable) {
11697 Roo.get(document).un('keydown', this.listKeyPress, this);
11699 this.fireEvent('collapse', this);
11703 collapseIf : function(e){
11704 var in_combo = e.within(this.el);
11705 var in_list = e.within(this.list);
11706 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11708 if (in_combo || in_list || is_list) {
11709 //e.stopPropagation();
11714 this.onTickableFooterButtonClick(e, false, false);
11722 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11724 expand : function(){
11726 if(this.isExpanded() || !this.hasFocus){
11730 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11731 this.list.setWidth(lw);
11738 this.restrictHeight();
11742 this.tickItems = Roo.apply([], this.item);
11745 this.cancelBtn.show();
11746 this.trigger.hide();
11750 Roo.get(document).on('mousedown', this.collapseIf, this);
11751 Roo.get(document).on('mousewheel', this.collapseIf, this);
11752 if (!this.editable) {
11753 Roo.get(document).on('keydown', this.listKeyPress, this);
11756 this.fireEvent('expand', this);
11760 // Implements the default empty TriggerField.onTriggerClick function
11761 onTriggerClick : function(e)
11763 Roo.log('trigger click');
11765 if(this.disabled || !this.triggerList){
11770 this.loadNext = false;
11772 if(this.isExpanded()){
11774 if (!this.blockFocus) {
11775 this.inputEl().focus();
11779 this.hasFocus = true;
11780 if(this.triggerAction == 'all') {
11781 this.doQuery(this.allQuery, true);
11783 this.doQuery(this.getRawValue());
11785 if (!this.blockFocus) {
11786 this.inputEl().focus();
11791 onTickableTriggerClick : function(e)
11798 this.loadNext = false;
11799 this.hasFocus = true;
11801 if(this.triggerAction == 'all') {
11802 this.doQuery(this.allQuery, true);
11804 this.doQuery(this.getRawValue());
11808 onSearchFieldClick : function(e)
11810 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11815 this.loadNext = false;
11816 this.hasFocus = true;
11818 if(this.triggerAction == 'all') {
11819 this.doQuery(this.allQuery, true);
11821 this.doQuery(this.getRawValue());
11825 listKeyPress : function(e)
11827 //Roo.log('listkeypress');
11828 // scroll to first matching element based on key pres..
11829 if (e.isSpecialKey()) {
11832 var k = String.fromCharCode(e.getKey()).toUpperCase();
11835 var csel = this.view.getSelectedNodes();
11836 var cselitem = false;
11838 var ix = this.view.indexOf(csel[0]);
11839 cselitem = this.store.getAt(ix);
11840 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11846 this.store.each(function(v) {
11848 // start at existing selection.
11849 if (cselitem.id == v.id) {
11855 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11856 match = this.store.indexOf(v);
11862 if (match === false) {
11863 return true; // no more action?
11866 this.view.select(match);
11867 var sn = Roo.get(this.view.getSelectedNodes()[0])
11868 sn.scrollIntoView(sn.dom.parentNode, false);
11871 onViewScroll : function(e, t){
11873 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){
11877 this.hasQuery = true;
11879 this.loading = this.list.select('.loading', true).first();
11881 if(this.loading === null){
11882 this.list.createChild({
11884 cls: 'loading select2-more-results select2-active',
11885 html: 'Loading more results...'
11888 this.loading = this.list.select('.loading', true).first();
11890 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11892 this.loading.hide();
11895 this.loading.show();
11900 this.loadNext = true;
11902 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11907 addItem : function(o)
11909 var dv = ''; // display value
11911 if (this.displayField) {
11912 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11914 // this is an error condition!!!
11915 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11922 var choice = this.choices.createChild({
11924 cls: 'select2-search-choice',
11933 cls: 'select2-search-choice-close',
11938 }, this.searchField);
11940 var close = choice.select('a.select2-search-choice-close', true).first()
11942 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11950 this.inputEl().dom.value = '';
11954 onRemoveItem : function(e, _self, o)
11956 e.preventDefault();
11957 var index = this.item.indexOf(o.data) * 1;
11960 Roo.log('not this item?!');
11964 this.item.splice(index, 1);
11969 this.fireEvent('remove', this, e);
11973 syncValue : function()
11975 if(!this.item.length){
11982 Roo.each(this.item, function(i){
11983 if(_this.valueField){
11984 value.push(i[_this.valueField]);
11991 this.value = value.join(',');
11993 if(this.hiddenField){
11994 this.hiddenField.dom.value = this.value;
11998 clearItem : function()
12000 if(!this.multiple){
12006 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12013 inputEl: function ()
12016 return this.searchField;
12018 return this.el.select('input.form-control',true).first();
12022 onTickableFooterButtonClick : function(e, btn, el)
12024 e.preventDefault();
12026 if(btn && btn.name == 'cancel'){
12027 this.tickItems = Roo.apply([], this.item);
12036 Roo.each(this.tickItems, function(o){
12044 validate : function()
12046 var v = this.getRawValue();
12049 v = this.getValue();
12052 if(this.disabled || this.validateValue(v)){
12053 this.clearInvalid();
12062 * @cfg {Boolean} grow
12066 * @cfg {Number} growMin
12070 * @cfg {Number} growMax
12080 * Ext JS Library 1.1.1
12081 * Copyright(c) 2006-2007, Ext JS, LLC.
12083 * Originally Released Under LGPL - original licence link has changed is not relivant.
12086 * <script type="text/javascript">
12091 * @extends Roo.util.Observable
12092 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12093 * This class also supports single and multi selection modes. <br>
12094 * Create a data model bound view:
12096 var store = new Roo.data.Store(...);
12098 var view = new Roo.View({
12100 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12102 singleSelect: true,
12103 selectedClass: "ydataview-selected",
12107 // listen for node click?
12108 view.on("click", function(vw, index, node, e){
12109 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12113 dataModel.load("foobar.xml");
12115 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12117 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12118 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12120 * Note: old style constructor is still suported (container, template, config)
12123 * Create a new View
12124 * @param {Object} config The config object
12127 Roo.View = function(config, depreciated_tpl, depreciated_config){
12129 this.parent = false;
12131 if (typeof(depreciated_tpl) == 'undefined') {
12132 // new way.. - universal constructor.
12133 Roo.apply(this, config);
12134 this.el = Roo.get(this.el);
12137 this.el = Roo.get(config);
12138 this.tpl = depreciated_tpl;
12139 Roo.apply(this, depreciated_config);
12141 this.wrapEl = this.el.wrap().wrap();
12142 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12145 if(typeof(this.tpl) == "string"){
12146 this.tpl = new Roo.Template(this.tpl);
12148 // support xtype ctors..
12149 this.tpl = new Roo.factory(this.tpl, Roo);
12153 this.tpl.compile();
12158 * @event beforeclick
12159 * Fires before a click is processed. Returns false to cancel the default action.
12160 * @param {Roo.View} this
12161 * @param {Number} index The index of the target node
12162 * @param {HTMLElement} node The target node
12163 * @param {Roo.EventObject} e The raw event object
12165 "beforeclick" : true,
12168 * Fires when a template node is clicked.
12169 * @param {Roo.View} this
12170 * @param {Number} index The index of the target node
12171 * @param {HTMLElement} node The target node
12172 * @param {Roo.EventObject} e The raw event object
12177 * Fires when a template node is double clicked.
12178 * @param {Roo.View} this
12179 * @param {Number} index The index of the target node
12180 * @param {HTMLElement} node The target node
12181 * @param {Roo.EventObject} e The raw event object
12185 * @event contextmenu
12186 * Fires when a template node is right clicked.
12187 * @param {Roo.View} this
12188 * @param {Number} index The index of the target node
12189 * @param {HTMLElement} node The target node
12190 * @param {Roo.EventObject} e The raw event object
12192 "contextmenu" : true,
12194 * @event selectionchange
12195 * Fires when the selected nodes change.
12196 * @param {Roo.View} this
12197 * @param {Array} selections Array of the selected nodes
12199 "selectionchange" : true,
12202 * @event beforeselect
12203 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12204 * @param {Roo.View} this
12205 * @param {HTMLElement} node The node to be selected
12206 * @param {Array} selections Array of currently selected nodes
12208 "beforeselect" : true,
12210 * @event preparedata
12211 * Fires on every row to render, to allow you to change the data.
12212 * @param {Roo.View} this
12213 * @param {Object} data to be rendered (change this)
12215 "preparedata" : true
12223 "click": this.onClick,
12224 "dblclick": this.onDblClick,
12225 "contextmenu": this.onContextMenu,
12229 this.selections = [];
12231 this.cmp = new Roo.CompositeElementLite([]);
12233 this.store = Roo.factory(this.store, Roo.data);
12234 this.setStore(this.store, true);
12237 if ( this.footer && this.footer.xtype) {
12239 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12241 this.footer.dataSource = this.store
12242 this.footer.container = fctr;
12243 this.footer = Roo.factory(this.footer, Roo);
12244 fctr.insertFirst(this.el);
12246 // this is a bit insane - as the paging toolbar seems to detach the el..
12247 // dom.parentNode.parentNode.parentNode
12248 // they get detached?
12252 Roo.View.superclass.constructor.call(this);
12257 Roo.extend(Roo.View, Roo.util.Observable, {
12260 * @cfg {Roo.data.Store} store Data store to load data from.
12265 * @cfg {String|Roo.Element} el The container element.
12270 * @cfg {String|Roo.Template} tpl The template used by this View
12274 * @cfg {String} dataName the named area of the template to use as the data area
12275 * Works with domtemplates roo-name="name"
12279 * @cfg {String} selectedClass The css class to add to selected nodes
12281 selectedClass : "x-view-selected",
12283 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12288 * @cfg {String} text to display on mask (default Loading)
12292 * @cfg {Boolean} multiSelect Allow multiple selection
12294 multiSelect : false,
12296 * @cfg {Boolean} singleSelect Allow single selection
12298 singleSelect: false,
12301 * @cfg {Boolean} toggleSelect - selecting
12303 toggleSelect : false,
12306 * @cfg {Boolean} tickable - selecting
12311 * Returns the element this view is bound to.
12312 * @return {Roo.Element}
12314 getEl : function(){
12315 return this.wrapEl;
12321 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12323 refresh : function(){
12324 Roo.log('refresh');
12327 // if we are using something like 'domtemplate', then
12328 // the what gets used is:
12329 // t.applySubtemplate(NAME, data, wrapping data..)
12330 // the outer template then get' applied with
12331 // the store 'extra data'
12332 // and the body get's added to the
12333 // roo-name="data" node?
12334 // <span class='roo-tpl-{name}'></span> ?????
12338 this.clearSelections();
12339 this.el.update("");
12341 var records = this.store.getRange();
12342 if(records.length < 1) {
12344 // is this valid?? = should it render a template??
12346 this.el.update(this.emptyText);
12350 if (this.dataName) {
12351 this.el.update(t.apply(this.store.meta)); //????
12352 el = this.el.child('.roo-tpl-' + this.dataName);
12355 for(var i = 0, len = records.length; i < len; i++){
12356 var data = this.prepareData(records[i].data, i, records[i]);
12357 this.fireEvent("preparedata", this, data, i, records[i]);
12359 var d = Roo.apply({}, data);
12362 Roo.apply(d, {'roo-id' : Roo.id()});
12366 Roo.each(this.parent.item, function(item){
12367 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12370 Roo.apply(d, {'roo-data-checked' : 'checked'});
12374 html[html.length] = Roo.util.Format.trim(
12376 t.applySubtemplate(this.dataName, d, this.store.meta) :
12383 el.update(html.join(""));
12384 this.nodes = el.dom.childNodes;
12385 this.updateIndexes(0);
12390 * Function to override to reformat the data that is sent to
12391 * the template for each node.
12392 * DEPRICATED - use the preparedata event handler.
12393 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12394 * a JSON object for an UpdateManager bound view).
12396 prepareData : function(data, index, record)
12398 this.fireEvent("preparedata", this, data, index, record);
12402 onUpdate : function(ds, record){
12403 Roo.log('on update');
12404 this.clearSelections();
12405 var index = this.store.indexOf(record);
12406 var n = this.nodes[index];
12407 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12408 n.parentNode.removeChild(n);
12409 this.updateIndexes(index, index);
12415 onAdd : function(ds, records, index)
12417 Roo.log(['on Add', ds, records, index] );
12418 this.clearSelections();
12419 if(this.nodes.length == 0){
12423 var n = this.nodes[index];
12424 for(var i = 0, len = records.length; i < len; i++){
12425 var d = this.prepareData(records[i].data, i, records[i]);
12427 this.tpl.insertBefore(n, d);
12430 this.tpl.append(this.el, d);
12433 this.updateIndexes(index);
12436 onRemove : function(ds, record, index){
12437 Roo.log('onRemove');
12438 this.clearSelections();
12439 var el = this.dataName ?
12440 this.el.child('.roo-tpl-' + this.dataName) :
12443 el.dom.removeChild(this.nodes[index]);
12444 this.updateIndexes(index);
12448 * Refresh an individual node.
12449 * @param {Number} index
12451 refreshNode : function(index){
12452 this.onUpdate(this.store, this.store.getAt(index));
12455 updateIndexes : function(startIndex, endIndex){
12456 var ns = this.nodes;
12457 startIndex = startIndex || 0;
12458 endIndex = endIndex || ns.length - 1;
12459 for(var i = startIndex; i <= endIndex; i++){
12460 ns[i].nodeIndex = i;
12465 * Changes the data store this view uses and refresh the view.
12466 * @param {Store} store
12468 setStore : function(store, initial){
12469 if(!initial && this.store){
12470 this.store.un("datachanged", this.refresh);
12471 this.store.un("add", this.onAdd);
12472 this.store.un("remove", this.onRemove);
12473 this.store.un("update", this.onUpdate);
12474 this.store.un("clear", this.refresh);
12475 this.store.un("beforeload", this.onBeforeLoad);
12476 this.store.un("load", this.onLoad);
12477 this.store.un("loadexception", this.onLoad);
12481 store.on("datachanged", this.refresh, this);
12482 store.on("add", this.onAdd, this);
12483 store.on("remove", this.onRemove, this);
12484 store.on("update", this.onUpdate, this);
12485 store.on("clear", this.refresh, this);
12486 store.on("beforeload", this.onBeforeLoad, this);
12487 store.on("load", this.onLoad, this);
12488 store.on("loadexception", this.onLoad, this);
12496 * onbeforeLoad - masks the loading area.
12499 onBeforeLoad : function(store,opts)
12501 Roo.log('onBeforeLoad');
12503 this.el.update("");
12505 this.el.mask(this.mask ? this.mask : "Loading" );
12507 onLoad : function ()
12514 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12515 * @param {HTMLElement} node
12516 * @return {HTMLElement} The template node
12518 findItemFromChild : function(node){
12519 var el = this.dataName ?
12520 this.el.child('.roo-tpl-' + this.dataName,true) :
12523 if(!node || node.parentNode == el){
12526 var p = node.parentNode;
12527 while(p && p != el){
12528 if(p.parentNode == el){
12537 onClick : function(e){
12538 var item = this.findItemFromChild(e.getTarget());
12540 var index = this.indexOf(item);
12541 if(this.onItemClick(item, index, e) !== false){
12542 this.fireEvent("click", this, index, item, e);
12545 this.clearSelections();
12550 onContextMenu : function(e){
12551 var item = this.findItemFromChild(e.getTarget());
12553 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12558 onDblClick : function(e){
12559 var item = this.findItemFromChild(e.getTarget());
12561 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12565 onItemClick : function(item, index, e)
12567 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12570 if (this.toggleSelect) {
12571 var m = this.isSelected(item) ? 'unselect' : 'select';
12574 _t[m](item, true, false);
12577 if(this.multiSelect || this.singleSelect){
12578 if(this.multiSelect && e.shiftKey && this.lastSelection){
12579 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12581 this.select(item, this.multiSelect && e.ctrlKey);
12582 this.lastSelection = item;
12585 if(!this.tickable){
12586 e.preventDefault();
12594 * Get the number of selected nodes.
12597 getSelectionCount : function(){
12598 return this.selections.length;
12602 * Get the currently selected nodes.
12603 * @return {Array} An array of HTMLElements
12605 getSelectedNodes : function(){
12606 return this.selections;
12610 * Get the indexes of the selected nodes.
12613 getSelectedIndexes : function(){
12614 var indexes = [], s = this.selections;
12615 for(var i = 0, len = s.length; i < len; i++){
12616 indexes.push(s[i].nodeIndex);
12622 * Clear all selections
12623 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12625 clearSelections : function(suppressEvent){
12626 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12627 this.cmp.elements = this.selections;
12628 this.cmp.removeClass(this.selectedClass);
12629 this.selections = [];
12630 if(!suppressEvent){
12631 this.fireEvent("selectionchange", this, this.selections);
12637 * Returns true if the passed node is selected
12638 * @param {HTMLElement/Number} node The node or node index
12639 * @return {Boolean}
12641 isSelected : function(node){
12642 var s = this.selections;
12646 node = this.getNode(node);
12647 return s.indexOf(node) !== -1;
12652 * @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
12653 * @param {Boolean} keepExisting (optional) true to keep existing selections
12654 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12656 select : function(nodeInfo, keepExisting, suppressEvent){
12657 if(nodeInfo instanceof Array){
12659 this.clearSelections(true);
12661 for(var i = 0, len = nodeInfo.length; i < len; i++){
12662 this.select(nodeInfo[i], true, true);
12666 var node = this.getNode(nodeInfo);
12667 if(!node || this.isSelected(node)){
12668 return; // already selected.
12671 this.clearSelections(true);
12674 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12675 Roo.fly(node).addClass(this.selectedClass);
12676 this.selections.push(node);
12677 if(!suppressEvent){
12678 this.fireEvent("selectionchange", this, this.selections);
12686 * @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
12687 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12688 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12690 unselect : function(nodeInfo, keepExisting, suppressEvent)
12692 if(nodeInfo instanceof Array){
12693 Roo.each(this.selections, function(s) {
12694 this.unselect(s, nodeInfo);
12698 var node = this.getNode(nodeInfo);
12699 if(!node || !this.isSelected(node)){
12700 Roo.log("not selected");
12701 return; // not selected.
12705 Roo.each(this.selections, function(s) {
12707 Roo.fly(node).removeClass(this.selectedClass);
12714 this.selections= ns;
12715 this.fireEvent("selectionchange", this, this.selections);
12719 * Gets a template node.
12720 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12721 * @return {HTMLElement} The node or null if it wasn't found
12723 getNode : function(nodeInfo){
12724 if(typeof nodeInfo == "string"){
12725 return document.getElementById(nodeInfo);
12726 }else if(typeof nodeInfo == "number"){
12727 return this.nodes[nodeInfo];
12733 * Gets a range template nodes.
12734 * @param {Number} startIndex
12735 * @param {Number} endIndex
12736 * @return {Array} An array of nodes
12738 getNodes : function(start, end){
12739 var ns = this.nodes;
12740 start = start || 0;
12741 end = typeof end == "undefined" ? ns.length - 1 : end;
12744 for(var i = start; i <= end; i++){
12748 for(var i = start; i >= end; i--){
12756 * Finds the index of the passed node
12757 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12758 * @return {Number} The index of the node or -1
12760 indexOf : function(node){
12761 node = this.getNode(node);
12762 if(typeof node.nodeIndex == "number"){
12763 return node.nodeIndex;
12765 var ns = this.nodes;
12766 for(var i = 0, len = ns.length; i < len; i++){
12777 * based on jquery fullcalendar
12781 Roo.bootstrap = Roo.bootstrap || {};
12783 * @class Roo.bootstrap.Calendar
12784 * @extends Roo.bootstrap.Component
12785 * Bootstrap Calendar class
12786 * @cfg {Boolean} loadMask (true|false) default false
12787 * @cfg {Object} header generate the user specific header of the calendar, default false
12790 * Create a new Container
12791 * @param {Object} config The config object
12796 Roo.bootstrap.Calendar = function(config){
12797 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12801 * Fires when a date is selected
12802 * @param {DatePicker} this
12803 * @param {Date} date The selected date
12807 * @event monthchange
12808 * Fires when the displayed month changes
12809 * @param {DatePicker} this
12810 * @param {Date} date The selected month
12812 'monthchange': true,
12814 * @event evententer
12815 * Fires when mouse over an event
12816 * @param {Calendar} this
12817 * @param {event} Event
12819 'evententer': true,
12821 * @event eventleave
12822 * Fires when the mouse leaves an
12823 * @param {Calendar} this
12826 'eventleave': true,
12828 * @event eventclick
12829 * Fires when the mouse click an
12830 * @param {Calendar} this
12839 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12842 * @cfg {Number} startDay
12843 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12851 getAutoCreate : function(){
12854 var fc_button = function(name, corner, style, content ) {
12855 return Roo.apply({},{
12857 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12859 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12862 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12873 style : 'width:100%',
12880 cls : 'fc-header-left',
12882 fc_button('prev', 'left', 'arrow', '‹' ),
12883 fc_button('next', 'right', 'arrow', '›' ),
12884 { tag: 'span', cls: 'fc-header-space' },
12885 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12893 cls : 'fc-header-center',
12897 cls: 'fc-header-title',
12900 html : 'month / year'
12908 cls : 'fc-header-right',
12910 /* fc_button('month', 'left', '', 'month' ),
12911 fc_button('week', '', '', 'week' ),
12912 fc_button('day', 'right', '', 'day' )
12924 header = this.header;
12927 var cal_heads = function() {
12929 // fixme - handle this.
12931 for (var i =0; i < Date.dayNames.length; i++) {
12932 var d = Date.dayNames[i];
12935 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12936 html : d.substring(0,3)
12940 ret[0].cls += ' fc-first';
12941 ret[6].cls += ' fc-last';
12944 var cal_cell = function(n) {
12947 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12952 cls: 'fc-day-number',
12956 cls: 'fc-day-content',
12960 style: 'position: relative;' // height: 17px;
12972 var cal_rows = function() {
12975 for (var r = 0; r < 6; r++) {
12982 for (var i =0; i < Date.dayNames.length; i++) {
12983 var d = Date.dayNames[i];
12984 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12987 row.cn[0].cls+=' fc-first';
12988 row.cn[0].cn[0].style = 'min-height:90px';
12989 row.cn[6].cls+=' fc-last';
12993 ret[0].cls += ' fc-first';
12994 ret[4].cls += ' fc-prev-last';
12995 ret[5].cls += ' fc-last';
13002 cls: 'fc-border-separate',
13003 style : 'width:100%',
13011 cls : 'fc-first fc-last',
13029 cls : 'fc-content',
13030 style : "position: relative;",
13033 cls : 'fc-view fc-view-month fc-grid',
13034 style : 'position: relative',
13035 unselectable : 'on',
13038 cls : 'fc-event-container',
13039 style : 'position:absolute;z-index:8;top:0;left:0;'
13057 initEvents : function()
13060 throw "can not find store for calendar";
13066 style: "text-align:center",
13070 style: "background-color:white;width:50%;margin:250 auto",
13074 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13085 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13087 var size = this.el.select('.fc-content', true).first().getSize();
13088 this.maskEl.setSize(size.width, size.height);
13089 this.maskEl.enableDisplayMode("block");
13090 if(!this.loadMask){
13091 this.maskEl.hide();
13094 this.store = Roo.factory(this.store, Roo.data);
13095 this.store.on('load', this.onLoad, this);
13096 this.store.on('beforeload', this.onBeforeLoad, this);
13100 this.cells = this.el.select('.fc-day',true);
13101 //Roo.log(this.cells);
13102 this.textNodes = this.el.query('.fc-day-number');
13103 this.cells.addClassOnOver('fc-state-hover');
13105 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13106 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13107 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13108 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13110 this.on('monthchange', this.onMonthChange, this);
13112 this.update(new Date().clearTime());
13115 resize : function() {
13116 var sz = this.el.getSize();
13118 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13119 this.el.select('.fc-day-content div',true).setHeight(34);
13124 showPrevMonth : function(e){
13125 this.update(this.activeDate.add("mo", -1));
13127 showToday : function(e){
13128 this.update(new Date().clearTime());
13131 showNextMonth : function(e){
13132 this.update(this.activeDate.add("mo", 1));
13136 showPrevYear : function(){
13137 this.update(this.activeDate.add("y", -1));
13141 showNextYear : function(){
13142 this.update(this.activeDate.add("y", 1));
13147 update : function(date)
13149 var vd = this.activeDate;
13150 this.activeDate = date;
13151 // if(vd && this.el){
13152 // var t = date.getTime();
13153 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13154 // Roo.log('using add remove');
13156 // this.fireEvent('monthchange', this, date);
13158 // this.cells.removeClass("fc-state-highlight");
13159 // this.cells.each(function(c){
13160 // if(c.dateValue == t){
13161 // c.addClass("fc-state-highlight");
13162 // setTimeout(function(){
13163 // try{c.dom.firstChild.focus();}catch(e){}
13173 var days = date.getDaysInMonth();
13175 var firstOfMonth = date.getFirstDateOfMonth();
13176 var startingPos = firstOfMonth.getDay()-this.startDay;
13178 if(startingPos < this.startDay){
13182 var pm = date.add(Date.MONTH, -1);
13183 var prevStart = pm.getDaysInMonth()-startingPos;
13185 this.cells = this.el.select('.fc-day',true);
13186 this.textNodes = this.el.query('.fc-day-number');
13187 this.cells.addClassOnOver('fc-state-hover');
13189 var cells = this.cells.elements;
13190 var textEls = this.textNodes;
13192 Roo.each(cells, function(cell){
13193 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13196 days += startingPos;
13198 // convert everything to numbers so it's fast
13199 var day = 86400000;
13200 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13203 //Roo.log(prevStart);
13205 var today = new Date().clearTime().getTime();
13206 var sel = date.clearTime().getTime();
13207 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13208 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13209 var ddMatch = this.disabledDatesRE;
13210 var ddText = this.disabledDatesText;
13211 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13212 var ddaysText = this.disabledDaysText;
13213 var format = this.format;
13215 var setCellClass = function(cal, cell){
13219 //Roo.log('set Cell Class');
13221 var t = d.getTime();
13225 cell.dateValue = t;
13227 cell.className += " fc-today";
13228 cell.className += " fc-state-highlight";
13229 cell.title = cal.todayText;
13232 // disable highlight in other month..
13233 //cell.className += " fc-state-highlight";
13238 cell.className = " fc-state-disabled";
13239 cell.title = cal.minText;
13243 cell.className = " fc-state-disabled";
13244 cell.title = cal.maxText;
13248 if(ddays.indexOf(d.getDay()) != -1){
13249 cell.title = ddaysText;
13250 cell.className = " fc-state-disabled";
13253 if(ddMatch && format){
13254 var fvalue = d.dateFormat(format);
13255 if(ddMatch.test(fvalue)){
13256 cell.title = ddText.replace("%0", fvalue);
13257 cell.className = " fc-state-disabled";
13261 if (!cell.initialClassName) {
13262 cell.initialClassName = cell.dom.className;
13265 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13270 for(; i < startingPos; i++) {
13271 textEls[i].innerHTML = (++prevStart);
13272 d.setDate(d.getDate()+1);
13274 cells[i].className = "fc-past fc-other-month";
13275 setCellClass(this, cells[i]);
13280 for(; i < days; i++){
13281 intDay = i - startingPos + 1;
13282 textEls[i].innerHTML = (intDay);
13283 d.setDate(d.getDate()+1);
13285 cells[i].className = ''; // "x-date-active";
13286 setCellClass(this, cells[i]);
13290 for(; i < 42; i++) {
13291 textEls[i].innerHTML = (++extraDays);
13292 d.setDate(d.getDate()+1);
13294 cells[i].className = "fc-future fc-other-month";
13295 setCellClass(this, cells[i]);
13298 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13300 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13302 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13303 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13305 if(totalRows != 6){
13306 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13307 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13310 this.fireEvent('monthchange', this, date);
13314 if(!this.internalRender){
13315 var main = this.el.dom.firstChild;
13316 var w = main.offsetWidth;
13317 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13318 Roo.fly(main).setWidth(w);
13319 this.internalRender = true;
13320 // opera does not respect the auto grow header center column
13321 // then, after it gets a width opera refuses to recalculate
13322 // without a second pass
13323 if(Roo.isOpera && !this.secondPass){
13324 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13325 this.secondPass = true;
13326 this.update.defer(10, this, [date]);
13333 findCell : function(dt) {
13334 dt = dt.clearTime().getTime();
13336 this.cells.each(function(c){
13337 //Roo.log("check " +c.dateValue + '?=' + dt);
13338 if(c.dateValue == dt){
13348 findCells : function(ev) {
13349 var s = ev.start.clone().clearTime().getTime();
13351 var e= ev.end.clone().clearTime().getTime();
13354 this.cells.each(function(c){
13355 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13357 if(c.dateValue > e){
13360 if(c.dateValue < s){
13369 // findBestRow: function(cells)
13373 // for (var i =0 ; i < cells.length;i++) {
13374 // ret = Math.max(cells[i].rows || 0,ret);
13381 addItem : function(ev)
13383 // look for vertical location slot in
13384 var cells = this.findCells(ev);
13386 // ev.row = this.findBestRow(cells);
13388 // work out the location.
13392 for(var i =0; i < cells.length; i++) {
13394 cells[i].row = cells[0].row;
13397 cells[i].row = cells[i].row + 1;
13407 if (crow.start.getY() == cells[i].getY()) {
13409 crow.end = cells[i];
13426 cells[0].events.push(ev);
13428 this.calevents.push(ev);
13431 clearEvents: function() {
13433 if(!this.calevents){
13437 Roo.each(this.cells.elements, function(c){
13443 Roo.each(this.calevents, function(e) {
13444 Roo.each(e.els, function(el) {
13445 el.un('mouseenter' ,this.onEventEnter, this);
13446 el.un('mouseleave' ,this.onEventLeave, this);
13451 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13457 renderEvents: function()
13461 this.cells.each(function(c) {
13470 if(c.row != c.events.length){
13471 r = 4 - (4 - (c.row - c.events.length));
13474 c.events = ev.slice(0, r);
13475 c.more = ev.slice(r);
13477 if(c.more.length && c.more.length == 1){
13478 c.events.push(c.more.pop());
13481 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13485 this.cells.each(function(c) {
13487 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13490 for (var e = 0; e < c.events.length; e++){
13491 var ev = c.events[e];
13492 var rows = ev.rows;
13494 for(var i = 0; i < rows.length; i++) {
13496 // how many rows should it span..
13499 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13500 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13502 unselectable : "on",
13505 cls: 'fc-event-inner',
13509 // cls: 'fc-event-time',
13510 // html : cells.length > 1 ? '' : ev.time
13514 cls: 'fc-event-title',
13515 html : String.format('{0}', ev.title)
13522 cls: 'ui-resizable-handle ui-resizable-e',
13523 html : '  '
13530 cfg.cls += ' fc-event-start';
13532 if ((i+1) == rows.length) {
13533 cfg.cls += ' fc-event-end';
13536 var ctr = _this.el.select('.fc-event-container',true).first();
13537 var cg = ctr.createChild(cfg);
13539 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13540 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13542 var r = (c.more.length) ? 1 : 0;
13543 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13544 cg.setWidth(ebox.right - sbox.x -2);
13546 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13547 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13548 cg.on('click', _this.onEventClick, _this, ev);
13559 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13560 style : 'position: absolute',
13561 unselectable : "on",
13564 cls: 'fc-event-inner',
13568 cls: 'fc-event-title',
13576 cls: 'ui-resizable-handle ui-resizable-e',
13577 html : '  '
13583 var ctr = _this.el.select('.fc-event-container',true).first();
13584 var cg = ctr.createChild(cfg);
13586 var sbox = c.select('.fc-day-content',true).first().getBox();
13587 var ebox = c.select('.fc-day-content',true).first().getBox();
13589 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13590 cg.setWidth(ebox.right - sbox.x -2);
13592 cg.on('click', _this.onMoreEventClick, _this, c.more);
13602 onEventEnter: function (e, el,event,d) {
13603 this.fireEvent('evententer', this, el, event);
13606 onEventLeave: function (e, el,event,d) {
13607 this.fireEvent('eventleave', this, el, event);
13610 onEventClick: function (e, el,event,d) {
13611 this.fireEvent('eventclick', this, el, event);
13614 onMonthChange: function () {
13618 onMoreEventClick: function(e, el, more)
13622 this.calpopover.placement = 'right';
13623 this.calpopover.setTitle('More');
13625 this.calpopover.setContent('');
13627 var ctr = this.calpopover.el.select('.popover-content', true).first();
13629 Roo.each(more, function(m){
13631 cls : 'fc-event-hori fc-event-draggable',
13634 var cg = ctr.createChild(cfg);
13636 cg.on('click', _this.onEventClick, _this, m);
13639 this.calpopover.show(el);
13644 onLoad: function ()
13646 this.calevents = [];
13649 if(this.store.getCount() > 0){
13650 this.store.data.each(function(d){
13653 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13654 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13655 time : d.data.start_time,
13656 title : d.data.title,
13657 description : d.data.description,
13658 venue : d.data.venue
13663 this.renderEvents();
13665 if(this.calevents.length && this.loadMask){
13666 this.maskEl.hide();
13670 onBeforeLoad: function()
13672 this.clearEvents();
13674 this.maskEl.show();
13688 * @class Roo.bootstrap.Popover
13689 * @extends Roo.bootstrap.Component
13690 * Bootstrap Popover class
13691 * @cfg {String} html contents of the popover (or false to use children..)
13692 * @cfg {String} title of popover (or false to hide)
13693 * @cfg {String} placement how it is placed
13694 * @cfg {String} trigger click || hover (or false to trigger manually)
13695 * @cfg {String} over what (parent or false to trigger manually.)
13696 * @cfg {Number} delay - delay before showing
13699 * Create a new Popover
13700 * @param {Object} config The config object
13703 Roo.bootstrap.Popover = function(config){
13704 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13707 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13709 title: 'Fill in a title',
13712 placement : 'right',
13713 trigger : 'hover', // hover
13719 can_build_overlaid : false,
13721 getChildContainer : function()
13723 return this.el.select('.popover-content',true).first();
13726 getAutoCreate : function(){
13727 Roo.log('make popover?');
13729 cls : 'popover roo-dynamic',
13730 style: 'display:block',
13736 cls : 'popover-inner',
13740 cls: 'popover-title',
13744 cls : 'popover-content',
13755 setTitle: function(str)
13757 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13759 setContent: function(str)
13761 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13763 // as it get's added to the bottom of the page.
13764 onRender : function(ct, position)
13766 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13768 var cfg = Roo.apply({}, this.getAutoCreate());
13772 cfg.cls += ' ' + this.cls;
13775 cfg.style = this.style;
13777 Roo.log("adding to ")
13778 this.el = Roo.get(document.body).createChild(cfg, position);
13784 initEvents : function()
13786 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13787 this.el.enableDisplayMode('block');
13789 if (this.over === false) {
13792 if (this.triggers === false) {
13795 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13796 var triggers = this.trigger ? this.trigger.split(' ') : [];
13797 Roo.each(triggers, function(trigger) {
13799 if (trigger == 'click') {
13800 on_el.on('click', this.toggle, this);
13801 } else if (trigger != 'manual') {
13802 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13803 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13805 on_el.on(eventIn ,this.enter, this);
13806 on_el.on(eventOut, this.leave, this);
13817 toggle : function () {
13818 this.hoverState == 'in' ? this.leave() : this.enter();
13821 enter : function () {
13824 clearTimeout(this.timeout);
13826 this.hoverState = 'in'
13828 if (!this.delay || !this.delay.show) {
13833 this.timeout = setTimeout(function () {
13834 if (_t.hoverState == 'in') {
13837 }, this.delay.show)
13839 leave : function() {
13840 clearTimeout(this.timeout);
13842 this.hoverState = 'out'
13844 if (!this.delay || !this.delay.hide) {
13849 this.timeout = setTimeout(function () {
13850 if (_t.hoverState == 'out') {
13853 }, this.delay.hide)
13856 show : function (on_el)
13859 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13862 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13863 if (this.html !== false) {
13864 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13866 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13867 if (!this.title.length) {
13868 this.el.select('.popover-title',true).hide();
13871 var placement = typeof this.placement == 'function' ?
13872 this.placement.call(this, this.el, on_el) :
13875 var autoToken = /\s?auto?\s?/i;
13876 var autoPlace = autoToken.test(placement);
13878 placement = placement.replace(autoToken, '') || 'top';
13882 //this.el.setXY([0,0]);
13884 this.el.dom.style.display='block';
13885 this.el.addClass(placement);
13887 //this.el.appendTo(on_el);
13889 var p = this.getPosition();
13890 var box = this.el.getBox();
13895 var align = Roo.bootstrap.Popover.alignment[placement]
13896 this.el.alignTo(on_el, align[0],align[1]);
13897 //var arrow = this.el.select('.arrow',true).first();
13898 //arrow.set(align[2],
13900 this.el.addClass('in');
13901 this.hoverState = null;
13903 if (this.el.hasClass('fade')) {
13910 this.el.setXY([0,0]);
13911 this.el.removeClass('in');
13918 Roo.bootstrap.Popover.alignment = {
13919 'left' : ['r-l', [-10,0], 'right'],
13920 'right' : ['l-r', [10,0], 'left'],
13921 'bottom' : ['t-b', [0,10], 'top'],
13922 'top' : [ 'b-t', [0,-10], 'bottom']
13933 * @class Roo.bootstrap.Progress
13934 * @extends Roo.bootstrap.Component
13935 * Bootstrap Progress class
13936 * @cfg {Boolean} striped striped of the progress bar
13937 * @cfg {Boolean} active animated of the progress bar
13941 * Create a new Progress
13942 * @param {Object} config The config object
13945 Roo.bootstrap.Progress = function(config){
13946 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13949 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13954 getAutoCreate : function(){
13962 cfg.cls += ' progress-striped';
13966 cfg.cls += ' active';
13985 * @class Roo.bootstrap.ProgressBar
13986 * @extends Roo.bootstrap.Component
13987 * Bootstrap ProgressBar class
13988 * @cfg {Number} aria_valuenow aria-value now
13989 * @cfg {Number} aria_valuemin aria-value min
13990 * @cfg {Number} aria_valuemax aria-value max
13991 * @cfg {String} label label for the progress bar
13992 * @cfg {String} panel (success | info | warning | danger )
13993 * @cfg {String} role role of the progress bar
13994 * @cfg {String} sr_only text
13998 * Create a new ProgressBar
13999 * @param {Object} config The config object
14002 Roo.bootstrap.ProgressBar = function(config){
14003 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14006 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14010 aria_valuemax : 100,
14016 getAutoCreate : function()
14021 cls: 'progress-bar',
14022 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14034 cfg.role = this.role;
14037 if(this.aria_valuenow){
14038 cfg['aria-valuenow'] = this.aria_valuenow;
14041 if(this.aria_valuemin){
14042 cfg['aria-valuemin'] = this.aria_valuemin;
14045 if(this.aria_valuemax){
14046 cfg['aria-valuemax'] = this.aria_valuemax;
14049 if(this.label && !this.sr_only){
14050 cfg.html = this.label;
14054 cfg.cls += ' progress-bar-' + this.panel;
14060 update : function(aria_valuenow)
14062 this.aria_valuenow = aria_valuenow;
14064 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14079 * @class Roo.bootstrap.TabGroup
14080 * @extends Roo.bootstrap.Column
14081 * Bootstrap Column class
14082 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14083 * @cfg {Boolean} carousel true to make the group behave like a carousel
14086 * Create a new TabGroup
14087 * @param {Object} config The config object
14090 Roo.bootstrap.TabGroup = function(config){
14091 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14093 this.navId = Roo.id();
14096 Roo.bootstrap.TabGroup.register(this);
14100 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14103 transition : false,
14105 getAutoCreate : function()
14107 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14109 cfg.cls += ' tab-content';
14111 if (this.carousel) {
14112 cfg.cls += ' carousel slide';
14114 cls : 'carousel-inner'
14121 getChildContainer : function()
14123 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14127 * register a Navigation item
14128 * @param {Roo.bootstrap.NavItem} the navitem to add
14130 register : function(item)
14132 this.tabs.push( item);
14133 item.navId = this.navId; // not really needed..
14137 getActivePanel : function()
14140 Roo.each(this.tabs, function(t) {
14150 getPanelByName : function(n)
14153 Roo.each(this.tabs, function(t) {
14154 if (t.tabId == n) {
14162 indexOfPanel : function(p)
14165 Roo.each(this.tabs, function(t,i) {
14166 if (t.tabId == p.tabId) {
14175 * show a specific panel
14176 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14177 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14179 showPanel : function (pan)
14182 if (typeof(pan) == 'number') {
14183 pan = this.tabs[pan];
14185 if (typeof(pan) == 'string') {
14186 pan = this.getPanelByName(pan);
14188 if (pan.tabId == this.getActivePanel().tabId) {
14191 var cur = this.getActivePanel();
14193 if (false === cur.fireEvent('beforedeactivate')) {
14197 if (this.carousel) {
14198 this.transition = true;
14199 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14200 var lr = dir == 'next' ? 'left' : 'right';
14201 pan.el.addClass(dir); // or prev
14202 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14203 cur.el.addClass(lr); // or right
14204 pan.el.addClass(lr);
14207 cur.el.on('transitionend', function() {
14208 Roo.log("trans end?");
14210 pan.el.removeClass([lr,dir]);
14211 pan.setActive(true);
14213 cur.el.removeClass([lr]);
14214 cur.setActive(false);
14216 _this.transition = false;
14218 }, this, { single: true } );
14222 cur.setActive(false);
14223 pan.setActive(true);
14227 showPanelNext : function()
14229 var i = this.indexOfPanel(this.getActivePanel());
14230 if (i > this.tabs.length) {
14233 this.showPanel(this.tabs[i+1]);
14235 showPanelPrev : function()
14237 var i = this.indexOfPanel(this.getActivePanel());
14241 this.showPanel(this.tabs[i-1]);
14252 Roo.apply(Roo.bootstrap.TabGroup, {
14256 * register a Navigation Group
14257 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14259 register : function(navgrp)
14261 this.groups[navgrp.navId] = navgrp;
14265 * fetch a Navigation Group based on the navigation ID
14266 * if one does not exist , it will get created.
14267 * @param {string} the navgroup to add
14268 * @returns {Roo.bootstrap.NavGroup} the navgroup
14270 get: function(navId) {
14271 if (typeof(this.groups[navId]) == 'undefined') {
14272 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14274 return this.groups[navId] ;
14289 * @class Roo.bootstrap.TabPanel
14290 * @extends Roo.bootstrap.Component
14291 * Bootstrap TabPanel class
14292 * @cfg {Boolean} active panel active
14293 * @cfg {String} html panel content
14294 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14295 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14299 * Create a new TabPanel
14300 * @param {Object} config The config object
14303 Roo.bootstrap.TabPanel = function(config){
14304 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14308 * Fires when the active status changes
14309 * @param {Roo.bootstrap.TabPanel} this
14310 * @param {Boolean} state the new state
14315 * @event beforedeactivate
14316 * Fires before a tab is de-activated - can be used to do validation on a form.
14317 * @param {Roo.bootstrap.TabPanel} this
14318 * @return {Boolean} false if there is an error
14321 'beforedeactivate': true
14324 this.tabId = this.tabId || Roo.id();
14328 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14335 getAutoCreate : function(){
14338 // item is needed for carousel - not sure if it has any effect otherwise
14339 cls: 'tab-pane item',
14340 html: this.html || ''
14344 cfg.cls += ' active';
14348 cfg.tabId = this.tabId;
14355 initEvents: function()
14357 Roo.log('-------- init events on tab panel ---------');
14359 var p = this.parent();
14360 this.navId = this.navId || p.navId;
14362 if (typeof(this.navId) != 'undefined') {
14363 // not really needed.. but just in case.. parent should be a NavGroup.
14364 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14365 Roo.log(['register', tg, this]);
14371 onRender : function(ct, position)
14373 // Roo.log("Call onRender: " + this.xtype);
14375 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14383 setActive: function(state)
14385 Roo.log("panel - set active " + this.tabId + "=" + state);
14387 this.active = state;
14389 this.el.removeClass('active');
14391 } else if (!this.el.hasClass('active')) {
14392 this.el.addClass('active');
14394 this.fireEvent('changed', this, state);
14411 * @class Roo.bootstrap.DateField
14412 * @extends Roo.bootstrap.Input
14413 * Bootstrap DateField class
14414 * @cfg {Number} weekStart default 0
14415 * @cfg {String} viewMode default empty, (months|years)
14416 * @cfg {String} minViewMode default empty, (months|years)
14417 * @cfg {Number} startDate default -Infinity
14418 * @cfg {Number} endDate default Infinity
14419 * @cfg {Boolean} todayHighlight default false
14420 * @cfg {Boolean} todayBtn default false
14421 * @cfg {Boolean} calendarWeeks default false
14422 * @cfg {Object} daysOfWeekDisabled default empty
14423 * @cfg {Boolean} singleMode default false (true | false)
14425 * @cfg {Boolean} keyboardNavigation default true
14426 * @cfg {String} language default en
14429 * Create a new DateField
14430 * @param {Object} config The config object
14433 Roo.bootstrap.DateField = function(config){
14434 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14438 * Fires when this field show.
14439 * @param {Roo.bootstrap.DateField} this
14440 * @param {Mixed} date The date value
14445 * Fires when this field hide.
14446 * @param {Roo.bootstrap.DateField} this
14447 * @param {Mixed} date The date value
14452 * Fires when select a date.
14453 * @param {Roo.bootstrap.DateField} this
14454 * @param {Mixed} date The date value
14460 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14463 * @cfg {String} format
14464 * The default date format string which can be overriden for localization support. The format must be
14465 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14469 * @cfg {String} altFormats
14470 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14471 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14473 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14481 todayHighlight : false,
14487 keyboardNavigation: true,
14489 calendarWeeks: false,
14491 startDate: -Infinity,
14495 daysOfWeekDisabled: [],
14499 singleMode : false,
14501 UTCDate: function()
14503 return new Date(Date.UTC.apply(Date, arguments));
14506 UTCToday: function()
14508 var today = new Date();
14509 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14512 getDate: function() {
14513 var d = this.getUTCDate();
14514 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14517 getUTCDate: function() {
14521 setDate: function(d) {
14522 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14525 setUTCDate: function(d) {
14527 this.setValue(this.formatDate(this.date));
14530 onRender: function(ct, position)
14533 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14535 this.language = this.language || 'en';
14536 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14537 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14539 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14540 this.format = this.format || 'm/d/y';
14541 this.isInline = false;
14542 this.isInput = true;
14543 this.component = this.el.select('.add-on', true).first() || false;
14544 this.component = (this.component && this.component.length === 0) ? false : this.component;
14545 this.hasInput = this.component && this.inputEL().length;
14547 if (typeof(this.minViewMode === 'string')) {
14548 switch (this.minViewMode) {
14550 this.minViewMode = 1;
14553 this.minViewMode = 2;
14556 this.minViewMode = 0;
14561 if (typeof(this.viewMode === 'string')) {
14562 switch (this.viewMode) {
14575 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14577 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14579 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14581 this.picker().on('mousedown', this.onMousedown, this);
14582 this.picker().on('click', this.onClick, this);
14584 this.picker().addClass('datepicker-dropdown');
14586 this.startViewMode = this.viewMode;
14588 if(this.singleMode){
14589 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14590 v.setVisibilityMode(Roo.Element.DISPLAY)
14594 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14595 v.setStyle('width', '189px');
14599 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14600 if(!this.calendarWeeks){
14605 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14606 v.attr('colspan', function(i, val){
14607 return parseInt(val) + 1;
14612 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14614 this.setStartDate(this.startDate);
14615 this.setEndDate(this.endDate);
14617 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14624 if(this.isInline) {
14629 picker : function()
14631 return this.pickerEl;
14632 // return this.el.select('.datepicker', true).first();
14635 fillDow: function()
14637 var dowCnt = this.weekStart;
14646 if(this.calendarWeeks){
14654 while (dowCnt < this.weekStart + 7) {
14658 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14662 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14665 fillMonths: function()
14668 var months = this.picker().select('>.datepicker-months td', true).first();
14670 months.dom.innerHTML = '';
14676 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14679 months.createChild(month);
14686 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;
14688 if (this.date < this.startDate) {
14689 this.viewDate = new Date(this.startDate);
14690 } else if (this.date > this.endDate) {
14691 this.viewDate = new Date(this.endDate);
14693 this.viewDate = new Date(this.date);
14701 var d = new Date(this.viewDate),
14702 year = d.getUTCFullYear(),
14703 month = d.getUTCMonth(),
14704 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14705 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14706 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14707 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14708 currentDate = this.date && this.date.valueOf(),
14709 today = this.UTCToday();
14711 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14713 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14715 // this.picker.select('>tfoot th.today').
14716 // .text(dates[this.language].today)
14717 // .toggle(this.todayBtn !== false);
14719 this.updateNavArrows();
14722 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14724 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14726 prevMonth.setUTCDate(day);
14728 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14730 var nextMonth = new Date(prevMonth);
14732 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14734 nextMonth = nextMonth.valueOf();
14736 var fillMonths = false;
14738 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14740 while(prevMonth.valueOf() < nextMonth) {
14743 if (prevMonth.getUTCDay() === this.weekStart) {
14745 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14753 if(this.calendarWeeks){
14754 // ISO 8601: First week contains first thursday.
14755 // ISO also states week starts on Monday, but we can be more abstract here.
14757 // Start of current week: based on weekstart/current date
14758 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14759 // Thursday of this week
14760 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14761 // First Thursday of year, year from thursday
14762 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14763 // Calendar week: ms between thursdays, div ms per day, div 7 days
14764 calWeek = (th - yth) / 864e5 / 7 + 1;
14766 fillMonths.cn.push({
14774 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14776 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14779 if (this.todayHighlight &&
14780 prevMonth.getUTCFullYear() == today.getFullYear() &&
14781 prevMonth.getUTCMonth() == today.getMonth() &&
14782 prevMonth.getUTCDate() == today.getDate()) {
14783 clsName += ' today';
14786 if (currentDate && prevMonth.valueOf() === currentDate) {
14787 clsName += ' active';
14790 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14791 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14792 clsName += ' disabled';
14795 fillMonths.cn.push({
14797 cls: 'day ' + clsName,
14798 html: prevMonth.getDate()
14801 prevMonth.setDate(prevMonth.getDate()+1);
14804 var currentYear = this.date && this.date.getUTCFullYear();
14805 var currentMonth = this.date && this.date.getUTCMonth();
14807 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14809 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14810 v.removeClass('active');
14812 if(currentYear === year && k === currentMonth){
14813 v.addClass('active');
14816 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14817 v.addClass('disabled');
14823 year = parseInt(year/10, 10) * 10;
14825 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14827 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14830 for (var i = -1; i < 11; i++) {
14831 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14833 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14841 showMode: function(dir)
14844 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14847 Roo.each(this.picker().select('>div',true).elements, function(v){
14848 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14851 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14856 if(this.isInline) return;
14858 this.picker().removeClass(['bottom', 'top']);
14860 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14862 * place to the top of element!
14866 this.picker().addClass('top');
14867 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14872 this.picker().addClass('bottom');
14874 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14877 parseDate : function(value)
14879 if(!value || value instanceof Date){
14882 var v = Date.parseDate(value, this.format);
14883 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
14884 v = Date.parseDate(value, 'Y-m-d');
14886 if(!v && this.altFormats){
14887 if(!this.altFormatsArray){
14888 this.altFormatsArray = this.altFormats.split("|");
14890 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14891 v = Date.parseDate(value, this.altFormatsArray[i]);
14897 formatDate : function(date, fmt)
14899 return (!date || !(date instanceof Date)) ?
14900 date : date.dateFormat(fmt || this.format);
14903 onFocus : function()
14905 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14909 onBlur : function()
14911 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14913 var d = this.inputEl().getValue();
14922 this.picker().show();
14926 this.fireEvent('show', this, this.date);
14931 if(this.isInline) return;
14932 this.picker().hide();
14933 this.viewMode = this.startViewMode;
14936 this.fireEvent('hide', this, this.date);
14940 onMousedown: function(e)
14942 e.stopPropagation();
14943 e.preventDefault();
14948 Roo.bootstrap.DateField.superclass.keyup.call(this);
14952 setValue: function(v)
14955 // v can be a string or a date..
14958 var d = new Date(this.parseDate(v) ).clearTime();
14960 if(isNaN(d.getTime())){
14961 this.date = this.viewDate = '';
14962 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14966 v = this.formatDate(d);
14968 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14970 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14974 this.fireEvent('select', this, this.date);
14978 getValue: function()
14980 return this.formatDate(this.date);
14983 fireKey: function(e)
14985 if (!this.picker().isVisible()){
14986 if (e.keyCode == 27) // allow escape to hide and re-show picker
14991 var dateChanged = false,
14993 newDate, newViewDate;
14998 e.preventDefault();
15002 if (!this.keyboardNavigation) break;
15003 dir = e.keyCode == 37 ? -1 : 1;
15006 newDate = this.moveYear(this.date, dir);
15007 newViewDate = this.moveYear(this.viewDate, dir);
15008 } else if (e.shiftKey){
15009 newDate = this.moveMonth(this.date, dir);
15010 newViewDate = this.moveMonth(this.viewDate, dir);
15012 newDate = new Date(this.date);
15013 newDate.setUTCDate(this.date.getUTCDate() + dir);
15014 newViewDate = new Date(this.viewDate);
15015 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15017 if (this.dateWithinRange(newDate)){
15018 this.date = newDate;
15019 this.viewDate = newViewDate;
15020 this.setValue(this.formatDate(this.date));
15022 e.preventDefault();
15023 dateChanged = true;
15028 if (!this.keyboardNavigation) break;
15029 dir = e.keyCode == 38 ? -1 : 1;
15031 newDate = this.moveYear(this.date, dir);
15032 newViewDate = this.moveYear(this.viewDate, dir);
15033 } else if (e.shiftKey){
15034 newDate = this.moveMonth(this.date, dir);
15035 newViewDate = this.moveMonth(this.viewDate, dir);
15037 newDate = new Date(this.date);
15038 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15039 newViewDate = new Date(this.viewDate);
15040 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15042 if (this.dateWithinRange(newDate)){
15043 this.date = newDate;
15044 this.viewDate = newViewDate;
15045 this.setValue(this.formatDate(this.date));
15047 e.preventDefault();
15048 dateChanged = true;
15052 this.setValue(this.formatDate(this.date));
15054 e.preventDefault();
15057 this.setValue(this.formatDate(this.date));
15071 onClick: function(e)
15073 e.stopPropagation();
15074 e.preventDefault();
15076 var target = e.getTarget();
15078 if(target.nodeName.toLowerCase() === 'i'){
15079 target = Roo.get(target).dom.parentNode;
15082 var nodeName = target.nodeName;
15083 var className = target.className;
15084 var html = target.innerHTML;
15085 //Roo.log(nodeName);
15087 switch(nodeName.toLowerCase()) {
15089 switch(className) {
15095 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15096 switch(this.viewMode){
15098 this.viewDate = this.moveMonth(this.viewDate, dir);
15102 this.viewDate = this.moveYear(this.viewDate, dir);
15108 var date = new Date();
15109 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15111 this.setValue(this.formatDate(this.date));
15118 if (className.indexOf('disabled') < 0) {
15119 this.viewDate.setUTCDate(1);
15120 if (className.indexOf('month') > -1) {
15121 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15123 var year = parseInt(html, 10) || 0;
15124 this.viewDate.setUTCFullYear(year);
15128 if(this.singleMode){
15129 this.setValue(this.formatDate(this.viewDate));
15140 //Roo.log(className);
15141 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15142 var day = parseInt(html, 10) || 1;
15143 var year = this.viewDate.getUTCFullYear(),
15144 month = this.viewDate.getUTCMonth();
15146 if (className.indexOf('old') > -1) {
15153 } else if (className.indexOf('new') > -1) {
15161 //Roo.log([year,month,day]);
15162 this.date = this.UTCDate(year, month, day,0,0,0,0);
15163 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15165 //Roo.log(this.formatDate(this.date));
15166 this.setValue(this.formatDate(this.date));
15173 setStartDate: function(startDate)
15175 this.startDate = startDate || -Infinity;
15176 if (this.startDate !== -Infinity) {
15177 this.startDate = this.parseDate(this.startDate);
15180 this.updateNavArrows();
15183 setEndDate: function(endDate)
15185 this.endDate = endDate || Infinity;
15186 if (this.endDate !== Infinity) {
15187 this.endDate = this.parseDate(this.endDate);
15190 this.updateNavArrows();
15193 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15195 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15196 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15197 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15199 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15200 return parseInt(d, 10);
15203 this.updateNavArrows();
15206 updateNavArrows: function()
15208 if(this.singleMode){
15212 var d = new Date(this.viewDate),
15213 year = d.getUTCFullYear(),
15214 month = d.getUTCMonth();
15216 Roo.each(this.picker().select('.prev', true).elements, function(v){
15218 switch (this.viewMode) {
15221 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15227 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15234 Roo.each(this.picker().select('.next', true).elements, function(v){
15236 switch (this.viewMode) {
15239 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15245 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15253 moveMonth: function(date, dir)
15255 if (!dir) return date;
15256 var new_date = new Date(date.valueOf()),
15257 day = new_date.getUTCDate(),
15258 month = new_date.getUTCMonth(),
15259 mag = Math.abs(dir),
15261 dir = dir > 0 ? 1 : -1;
15264 // If going back one month, make sure month is not current month
15265 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15267 return new_date.getUTCMonth() == month;
15269 // If going forward one month, make sure month is as expected
15270 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15272 return new_date.getUTCMonth() != new_month;
15274 new_month = month + dir;
15275 new_date.setUTCMonth(new_month);
15276 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15277 if (new_month < 0 || new_month > 11)
15278 new_month = (new_month + 12) % 12;
15280 // For magnitudes >1, move one month at a time...
15281 for (var i=0; i<mag; i++)
15282 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15283 new_date = this.moveMonth(new_date, dir);
15284 // ...then reset the day, keeping it in the new month
15285 new_month = new_date.getUTCMonth();
15286 new_date.setUTCDate(day);
15288 return new_month != new_date.getUTCMonth();
15291 // Common date-resetting loop -- if date is beyond end of month, make it
15294 new_date.setUTCDate(--day);
15295 new_date.setUTCMonth(new_month);
15300 moveYear: function(date, dir)
15302 return this.moveMonth(date, dir*12);
15305 dateWithinRange: function(date)
15307 return date >= this.startDate && date <= this.endDate;
15313 this.picker().remove();
15318 Roo.apply(Roo.bootstrap.DateField, {
15329 html: '<i class="fa fa-arrow-left"/>'
15339 html: '<i class="fa fa-arrow-right"/>'
15381 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15382 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15383 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15384 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15385 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15398 navFnc: 'FullYear',
15403 navFnc: 'FullYear',
15408 Roo.apply(Roo.bootstrap.DateField, {
15412 cls: 'datepicker dropdown-menu roo-dynamic',
15416 cls: 'datepicker-days',
15420 cls: 'table-condensed',
15422 Roo.bootstrap.DateField.head,
15426 Roo.bootstrap.DateField.footer
15433 cls: 'datepicker-months',
15437 cls: 'table-condensed',
15439 Roo.bootstrap.DateField.head,
15440 Roo.bootstrap.DateField.content,
15441 Roo.bootstrap.DateField.footer
15448 cls: 'datepicker-years',
15452 cls: 'table-condensed',
15454 Roo.bootstrap.DateField.head,
15455 Roo.bootstrap.DateField.content,
15456 Roo.bootstrap.DateField.footer
15475 * @class Roo.bootstrap.TimeField
15476 * @extends Roo.bootstrap.Input
15477 * Bootstrap DateField class
15481 * Create a new TimeField
15482 * @param {Object} config The config object
15485 Roo.bootstrap.TimeField = function(config){
15486 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15490 * Fires when this field show.
15491 * @param {Roo.bootstrap.DateField} this
15492 * @param {Mixed} date The date value
15497 * Fires when this field hide.
15498 * @param {Roo.bootstrap.DateField} this
15499 * @param {Mixed} date The date value
15504 * Fires when select a date.
15505 * @param {Roo.bootstrap.DateField} this
15506 * @param {Mixed} date The date value
15512 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15515 * @cfg {String} format
15516 * The default time format string which can be overriden for localization support. The format must be
15517 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15521 onRender: function(ct, position)
15524 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15526 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15528 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15530 this.pop = this.picker().select('>.datepicker-time',true).first();
15531 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15533 this.picker().on('mousedown', this.onMousedown, this);
15534 this.picker().on('click', this.onClick, this);
15536 this.picker().addClass('datepicker-dropdown');
15541 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15542 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15543 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15544 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15545 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15546 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15550 fireKey: function(e){
15551 if (!this.picker().isVisible()){
15552 if (e.keyCode == 27) // allow escape to hide and re-show picker
15557 e.preventDefault();
15565 this.onTogglePeriod();
15568 this.onIncrementMinutes();
15571 this.onDecrementMinutes();
15580 onClick: function(e) {
15581 e.stopPropagation();
15582 e.preventDefault();
15585 picker : function()
15587 return this.el.select('.datepicker', true).first();
15590 fillTime: function()
15592 var time = this.pop.select('tbody', true).first();
15594 time.dom.innerHTML = '';
15609 cls: 'hours-up glyphicon glyphicon-chevron-up'
15629 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15650 cls: 'timepicker-hour',
15665 cls: 'timepicker-minute',
15680 cls: 'btn btn-primary period',
15702 cls: 'hours-down glyphicon glyphicon-chevron-down'
15722 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15740 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15747 var hours = this.time.getHours();
15748 var minutes = this.time.getMinutes();
15761 hours = hours - 12;
15765 hours = '0' + hours;
15769 minutes = '0' + minutes;
15772 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15773 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15774 this.pop.select('button', true).first().dom.innerHTML = period;
15780 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15782 var cls = ['bottom'];
15784 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15791 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15796 this.picker().addClass(cls.join('-'));
15800 Roo.each(cls, function(c){
15802 _this.picker().setTop(_this.inputEl().getHeight());
15806 _this.picker().setTop(0 - _this.picker().getHeight());
15811 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15815 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15822 onFocus : function()
15824 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15828 onBlur : function()
15830 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15836 this.picker().show();
15841 this.fireEvent('show', this, this.date);
15846 this.picker().hide();
15849 this.fireEvent('hide', this, this.date);
15852 setTime : function()
15855 this.setValue(this.time.format(this.format));
15857 this.fireEvent('select', this, this.date);
15862 onMousedown: function(e){
15863 e.stopPropagation();
15864 e.preventDefault();
15867 onIncrementHours: function()
15869 Roo.log('onIncrementHours');
15870 this.time = this.time.add(Date.HOUR, 1);
15875 onDecrementHours: function()
15877 Roo.log('onDecrementHours');
15878 this.time = this.time.add(Date.HOUR, -1);
15882 onIncrementMinutes: function()
15884 Roo.log('onIncrementMinutes');
15885 this.time = this.time.add(Date.MINUTE, 1);
15889 onDecrementMinutes: function()
15891 Roo.log('onDecrementMinutes');
15892 this.time = this.time.add(Date.MINUTE, -1);
15896 onTogglePeriod: function()
15898 Roo.log('onTogglePeriod');
15899 this.time = this.time.add(Date.HOUR, 12);
15906 Roo.apply(Roo.bootstrap.TimeField, {
15936 cls: 'btn btn-info ok',
15948 Roo.apply(Roo.bootstrap.TimeField, {
15952 cls: 'datepicker dropdown-menu',
15956 cls: 'datepicker-time',
15960 cls: 'table-condensed',
15962 Roo.bootstrap.TimeField.content,
15963 Roo.bootstrap.TimeField.footer
15982 * @class Roo.bootstrap.CheckBox
15983 * @extends Roo.bootstrap.Input
15984 * Bootstrap CheckBox class
15986 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15987 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15988 * @cfg {String} boxLabel The text that appears beside the checkbox
15989 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15990 * @cfg {Boolean} checked initnal the element
15994 * Create a new CheckBox
15995 * @param {Object} config The config object
15998 Roo.bootstrap.CheckBox = function(config){
15999 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16004 * Fires when the element is checked or unchecked.
16005 * @param {Roo.bootstrap.CheckBox} this This input
16006 * @param {Boolean} checked The new checked value
16012 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16014 inputType: 'checkbox',
16021 getAutoCreate : function()
16023 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16029 cfg.cls = 'form-group checkbox' //input-group
16037 type : this.inputType,
16038 value : (!this.checked) ? this.valueOff : this.inputValue,
16039 cls : 'roo-checkbox', //'form-box',
16040 placeholder : this.placeholder || ''
16044 if (this.weight) { // Validity check?
16045 cfg.cls += " checkbox-" + this.weight;
16048 if (this.disabled) {
16049 input.disabled=true;
16053 input.checked = this.checked;
16057 input.name = this.name;
16061 input.cls += ' input-' + this.size;
16065 ['xs','sm','md','lg'].map(function(size){
16066 if (settings[size]) {
16067 cfg.cls += ' col-' + size + '-' + settings[size];
16073 var inputblock = input;
16078 if (this.before || this.after) {
16081 cls : 'input-group',
16085 inputblock.cn.push({
16087 cls : 'input-group-addon',
16091 inputblock.cn.push(input);
16093 inputblock.cn.push({
16095 cls : 'input-group-addon',
16102 if (align ==='left' && this.fieldLabel.length) {
16103 Roo.log("left and has label");
16109 cls : 'control-label col-md-' + this.labelWidth,
16110 html : this.fieldLabel
16114 cls : "col-md-" + (12 - this.labelWidth),
16121 } else if ( this.fieldLabel.length) {
16126 tag: this.boxLabel ? 'span' : 'label',
16128 cls: 'control-label box-input-label',
16129 //cls : 'input-group-addon',
16130 html : this.fieldLabel
16140 Roo.log(" no label && no align");
16141 cfg.cn = [ inputblock ] ;
16150 html: this.boxLabel
16162 * return the real input element.
16164 inputEl: function ()
16166 return this.el.select('input.roo-checkbox',true).first();
16171 return this.el.select('label.control-label',true).first();
16174 initEvents : function()
16176 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16178 this.inputEl().on('click', this.onClick, this);
16182 onClick : function()
16184 this.setChecked(!this.checked);
16187 setChecked : function(state,suppressEvent)
16189 this.checked = state;
16191 this.inputEl().dom.checked = state;
16193 if(suppressEvent !== true){
16194 this.fireEvent('check', this, state);
16197 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16201 setValue : function(v,suppressEvent)
16203 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16217 * @class Roo.bootstrap.Radio
16218 * @extends Roo.bootstrap.CheckBox
16219 * Bootstrap Radio class
16222 * Create a new Radio
16223 * @param {Object} config The config object
16226 Roo.bootstrap.Radio = function(config){
16227 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16231 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16233 inputType: 'radio',
16237 getAutoCreate : function()
16239 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16245 cfg.cls = 'form-group radio' //input-group
16250 type : this.inputType,
16251 value : (!this.checked) ? this.valueOff : this.inputValue,
16253 placeholder : this.placeholder || ''
16256 if (this.weight) { // Validity check?
16257 cfg.cls += " radio-" + this.weight;
16259 if (this.disabled) {
16260 input.disabled=true;
16264 input.checked = this.checked;
16268 input.name = this.name;
16272 input.cls += ' input-' + this.size;
16276 ['xs','sm','md','lg'].map(function(size){
16277 if (settings[size]) {
16278 cfg.cls += ' col-' + size + '-' + settings[size];
16282 var inputblock = input;
16284 if (this.before || this.after) {
16287 cls : 'input-group',
16291 inputblock.cn.push({
16293 cls : 'input-group-addon',
16297 inputblock.cn.push(input);
16299 inputblock.cn.push({
16301 cls : 'input-group-addon',
16308 if (align ==='left' && this.fieldLabel.length) {
16309 Roo.log("left and has label");
16315 cls : 'control-label col-md-' + this.labelWidth,
16316 html : this.fieldLabel
16320 cls : "col-md-" + (12 - this.labelWidth),
16327 } else if ( this.fieldLabel.length) {
16334 cls: 'control-label box-input-label',
16335 //cls : 'input-group-addon',
16336 html : this.fieldLabel
16346 Roo.log(" no label && no align");
16361 html: this.boxLabel
16368 inputEl: function ()
16370 return this.el.select('input.roo-radio',true).first();
16372 onClick : function()
16374 this.setChecked(true);
16377 setChecked : function(state,suppressEvent)
16380 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16381 v.dom.checked = false;
16385 this.checked = state;
16386 this.inputEl().dom.checked = state;
16388 if(suppressEvent !== true){
16389 this.fireEvent('check', this, state);
16392 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16396 getGroupValue : function()
16399 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16400 if(v.dom.checked == true){
16401 value = v.dom.value;
16409 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16410 * @return {Mixed} value The field value
16412 getValue : function(){
16413 return this.getGroupValue();
16419 //<script type="text/javascript">
16422 * Based Ext JS Library 1.1.1
16423 * Copyright(c) 2006-2007, Ext JS, LLC.
16429 * @class Roo.HtmlEditorCore
16430 * @extends Roo.Component
16431 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16433 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16436 Roo.HtmlEditorCore = function(config){
16439 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16444 * @event initialize
16445 * Fires when the editor is fully initialized (including the iframe)
16446 * @param {Roo.HtmlEditorCore} this
16451 * Fires when the editor is first receives the focus. Any insertion must wait
16452 * until after this event.
16453 * @param {Roo.HtmlEditorCore} this
16457 * @event beforesync
16458 * Fires before the textarea is updated with content from the editor iframe. Return false
16459 * to cancel the sync.
16460 * @param {Roo.HtmlEditorCore} this
16461 * @param {String} html
16465 * @event beforepush
16466 * Fires before the iframe editor is updated with content from the textarea. Return false
16467 * to cancel the push.
16468 * @param {Roo.HtmlEditorCore} this
16469 * @param {String} html
16474 * Fires when the textarea is updated with content from the editor iframe.
16475 * @param {Roo.HtmlEditorCore} this
16476 * @param {String} html
16481 * Fires when the iframe editor is updated with content from the textarea.
16482 * @param {Roo.HtmlEditorCore} this
16483 * @param {String} html
16488 * @event editorevent
16489 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16490 * @param {Roo.HtmlEditorCore} this
16495 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16497 // defaults : white / black...
16498 this.applyBlacklists();
16505 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16509 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16515 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16520 * @cfg {Number} height (in pixels)
16524 * @cfg {Number} width (in pixels)
16529 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16532 stylesheets: false,
16537 // private properties
16538 validationEvent : false,
16540 initialized : false,
16542 sourceEditMode : false,
16543 onFocus : Roo.emptyFn,
16545 hideMode:'offsets',
16549 // blacklist + whitelisted elements..
16556 * Protected method that will not generally be called directly. It
16557 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16558 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16560 getDocMarkup : function(){
16563 Roo.log(this.stylesheets);
16565 // inherit styels from page...??
16566 if (this.stylesheets === false) {
16568 Roo.get(document.head).select('style').each(function(node) {
16569 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16572 Roo.get(document.head).select('link').each(function(node) {
16573 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16576 } else if (!this.stylesheets.length) {
16578 st = '<style type="text/css">' +
16579 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16582 Roo.each(this.stylesheets, function(s) {
16583 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16588 st += '<style type="text/css">' +
16589 'IMG { cursor: pointer } ' +
16593 return '<html><head>' + st +
16594 //<style type="text/css">' +
16595 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16597 ' </head><body class="roo-htmleditor-body"></body></html>';
16601 onRender : function(ct, position)
16604 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16605 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16608 this.el.dom.style.border = '0 none';
16609 this.el.dom.setAttribute('tabIndex', -1);
16610 this.el.addClass('x-hidden hide');
16614 if(Roo.isIE){ // fix IE 1px bogus margin
16615 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16619 this.frameId = Roo.id();
16623 var iframe = this.owner.wrap.createChild({
16625 cls: 'form-control', // bootstrap..
16627 name: this.frameId,
16628 frameBorder : 'no',
16629 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16634 this.iframe = iframe.dom;
16636 this.assignDocWin();
16638 this.doc.designMode = 'on';
16641 this.doc.write(this.getDocMarkup());
16645 var task = { // must defer to wait for browser to be ready
16647 //console.log("run task?" + this.doc.readyState);
16648 this.assignDocWin();
16649 if(this.doc.body || this.doc.readyState == 'complete'){
16651 this.doc.designMode="on";
16655 Roo.TaskMgr.stop(task);
16656 this.initEditor.defer(10, this);
16663 Roo.TaskMgr.start(task);
16670 onResize : function(w, h)
16672 Roo.log('resize: ' +w + ',' + h );
16673 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16677 if(typeof w == 'number'){
16679 this.iframe.style.width = w + 'px';
16681 if(typeof h == 'number'){
16683 this.iframe.style.height = h + 'px';
16685 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16692 * Toggles the editor between standard and source edit mode.
16693 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16695 toggleSourceEdit : function(sourceEditMode){
16697 this.sourceEditMode = sourceEditMode === true;
16699 if(this.sourceEditMode){
16701 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16704 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16705 //this.iframe.className = '';
16708 //this.setSize(this.owner.wrap.getSize());
16709 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16716 * Protected method that will not generally be called directly. If you need/want
16717 * custom HTML cleanup, this is the method you should override.
16718 * @param {String} html The HTML to be cleaned
16719 * return {String} The cleaned HTML
16721 cleanHtml : function(html){
16722 html = String(html);
16723 if(html.length > 5){
16724 if(Roo.isSafari){ // strip safari nonsense
16725 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16728 if(html == ' '){
16735 * HTML Editor -> Textarea
16736 * Protected method that will not generally be called directly. Syncs the contents
16737 * of the editor iframe with the textarea.
16739 syncValue : function(){
16740 if(this.initialized){
16741 var bd = (this.doc.body || this.doc.documentElement);
16742 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16743 var html = bd.innerHTML;
16745 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16746 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16748 html = '<div style="'+m[0]+'">' + html + '</div>';
16751 html = this.cleanHtml(html);
16752 // fix up the special chars.. normaly like back quotes in word...
16753 // however we do not want to do this with chinese..
16754 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16755 var cc = b.charCodeAt();
16757 (cc >= 0x4E00 && cc < 0xA000 ) ||
16758 (cc >= 0x3400 && cc < 0x4E00 ) ||
16759 (cc >= 0xf900 && cc < 0xfb00 )
16765 if(this.owner.fireEvent('beforesync', this, html) !== false){
16766 this.el.dom.value = html;
16767 this.owner.fireEvent('sync', this, html);
16773 * Protected method that will not generally be called directly. Pushes the value of the textarea
16774 * into the iframe editor.
16776 pushValue : function(){
16777 if(this.initialized){
16778 var v = this.el.dom.value.trim();
16780 // if(v.length < 1){
16784 if(this.owner.fireEvent('beforepush', this, v) !== false){
16785 var d = (this.doc.body || this.doc.documentElement);
16787 this.cleanUpPaste();
16788 this.el.dom.value = d.innerHTML;
16789 this.owner.fireEvent('push', this, v);
16795 deferFocus : function(){
16796 this.focus.defer(10, this);
16800 focus : function(){
16801 if(this.win && !this.sourceEditMode){
16808 assignDocWin: function()
16810 var iframe = this.iframe;
16813 this.doc = iframe.contentWindow.document;
16814 this.win = iframe.contentWindow;
16816 // if (!Roo.get(this.frameId)) {
16819 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16820 // this.win = Roo.get(this.frameId).dom.contentWindow;
16822 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16826 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16827 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16832 initEditor : function(){
16833 //console.log("INIT EDITOR");
16834 this.assignDocWin();
16838 this.doc.designMode="on";
16840 this.doc.write(this.getDocMarkup());
16843 var dbody = (this.doc.body || this.doc.documentElement);
16844 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16845 // this copies styles from the containing element into thsi one..
16846 // not sure why we need all of this..
16847 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16849 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16850 //ss['background-attachment'] = 'fixed'; // w3c
16851 dbody.bgProperties = 'fixed'; // ie
16852 //Roo.DomHelper.applyStyles(dbody, ss);
16853 Roo.EventManager.on(this.doc, {
16854 //'mousedown': this.onEditorEvent,
16855 'mouseup': this.onEditorEvent,
16856 'dblclick': this.onEditorEvent,
16857 'click': this.onEditorEvent,
16858 'keyup': this.onEditorEvent,
16863 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16865 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16866 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16868 this.initialized = true;
16870 this.owner.fireEvent('initialize', this);
16875 onDestroy : function(){
16881 //for (var i =0; i < this.toolbars.length;i++) {
16882 // // fixme - ask toolbars for heights?
16883 // this.toolbars[i].onDestroy();
16886 //this.wrap.dom.innerHTML = '';
16887 //this.wrap.remove();
16892 onFirstFocus : function(){
16894 this.assignDocWin();
16897 this.activated = true;
16900 if(Roo.isGecko){ // prevent silly gecko errors
16902 var s = this.win.getSelection();
16903 if(!s.focusNode || s.focusNode.nodeType != 3){
16904 var r = s.getRangeAt(0);
16905 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16910 this.execCmd('useCSS', true);
16911 this.execCmd('styleWithCSS', false);
16914 this.owner.fireEvent('activate', this);
16918 adjustFont: function(btn){
16919 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16920 //if(Roo.isSafari){ // safari
16923 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16924 if(Roo.isSafari){ // safari
16925 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16926 v = (v < 10) ? 10 : v;
16927 v = (v > 48) ? 48 : v;
16928 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16933 v = Math.max(1, v+adjust);
16935 this.execCmd('FontSize', v );
16938 onEditorEvent : function(e){
16939 this.owner.fireEvent('editorevent', this, e);
16940 // this.updateToolbar();
16941 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16944 insertTag : function(tg)
16946 // could be a bit smarter... -> wrap the current selected tRoo..
16947 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16949 range = this.createRange(this.getSelection());
16950 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16951 wrappingNode.appendChild(range.extractContents());
16952 range.insertNode(wrappingNode);
16959 this.execCmd("formatblock", tg);
16963 insertText : function(txt)
16967 var range = this.createRange();
16968 range.deleteContents();
16969 //alert(Sender.getAttribute('label'));
16971 range.insertNode(this.doc.createTextNode(txt));
16977 * Executes a Midas editor command on the editor document and performs necessary focus and
16978 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16979 * @param {String} cmd The Midas command
16980 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16982 relayCmd : function(cmd, value){
16984 this.execCmd(cmd, value);
16985 this.owner.fireEvent('editorevent', this);
16986 //this.updateToolbar();
16987 this.owner.deferFocus();
16991 * Executes a Midas editor command directly on the editor document.
16992 * For visual commands, you should use {@link #relayCmd} instead.
16993 * <b>This should only be called after the editor is initialized.</b>
16994 * @param {String} cmd The Midas command
16995 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16997 execCmd : function(cmd, value){
16998 this.doc.execCommand(cmd, false, value === undefined ? null : value);
17005 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17007 * @param {String} text | dom node..
17009 insertAtCursor : function(text)
17014 if(!this.activated){
17020 var r = this.doc.selection.createRange();
17031 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17035 // from jquery ui (MIT licenced)
17037 var win = this.win;
17039 if (win.getSelection && win.getSelection().getRangeAt) {
17040 range = win.getSelection().getRangeAt(0);
17041 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17042 range.insertNode(node);
17043 } else if (win.document.selection && win.document.selection.createRange) {
17044 // no firefox support
17045 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17046 win.document.selection.createRange().pasteHTML(txt);
17048 // no firefox support
17049 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17050 this.execCmd('InsertHTML', txt);
17059 mozKeyPress : function(e){
17061 var c = e.getCharCode(), cmd;
17064 c = String.fromCharCode(c).toLowerCase();
17078 this.cleanUpPaste.defer(100, this);
17086 e.preventDefault();
17094 fixKeys : function(){ // load time branching for fastest keydown performance
17096 return function(e){
17097 var k = e.getKey(), r;
17100 r = this.doc.selection.createRange();
17103 r.pasteHTML('    ');
17110 r = this.doc.selection.createRange();
17112 var target = r.parentElement();
17113 if(!target || target.tagName.toLowerCase() != 'li'){
17115 r.pasteHTML('<br />');
17121 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17122 this.cleanUpPaste.defer(100, this);
17128 }else if(Roo.isOpera){
17129 return function(e){
17130 var k = e.getKey();
17134 this.execCmd('InsertHTML','    ');
17137 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17138 this.cleanUpPaste.defer(100, this);
17143 }else if(Roo.isSafari){
17144 return function(e){
17145 var k = e.getKey();
17149 this.execCmd('InsertText','\t');
17153 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17154 this.cleanUpPaste.defer(100, this);
17162 getAllAncestors: function()
17164 var p = this.getSelectedNode();
17167 a.push(p); // push blank onto stack..
17168 p = this.getParentElement();
17172 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17176 a.push(this.doc.body);
17180 lastSelNode : false,
17183 getSelection : function()
17185 this.assignDocWin();
17186 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17189 getSelectedNode: function()
17191 // this may only work on Gecko!!!
17193 // should we cache this!!!!
17198 var range = this.createRange(this.getSelection()).cloneRange();
17201 var parent = range.parentElement();
17203 var testRange = range.duplicate();
17204 testRange.moveToElementText(parent);
17205 if (testRange.inRange(range)) {
17208 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17211 parent = parent.parentElement;
17216 // is ancestor a text element.
17217 var ac = range.commonAncestorContainer;
17218 if (ac.nodeType == 3) {
17219 ac = ac.parentNode;
17222 var ar = ac.childNodes;
17225 var other_nodes = [];
17226 var has_other_nodes = false;
17227 for (var i=0;i<ar.length;i++) {
17228 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17231 // fullly contained node.
17233 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17238 // probably selected..
17239 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17240 other_nodes.push(ar[i]);
17244 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17249 has_other_nodes = true;
17251 if (!nodes.length && other_nodes.length) {
17252 nodes= other_nodes;
17254 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17260 createRange: function(sel)
17262 // this has strange effects when using with
17263 // top toolbar - not sure if it's a great idea.
17264 //this.editor.contentWindow.focus();
17265 if (typeof sel != "undefined") {
17267 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17269 return this.doc.createRange();
17272 return this.doc.createRange();
17275 getParentElement: function()
17278 this.assignDocWin();
17279 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17281 var range = this.createRange(sel);
17284 var p = range.commonAncestorContainer;
17285 while (p.nodeType == 3) { // text node
17296 * Range intersection.. the hard stuff...
17300 * [ -- selected range --- ]
17304 * if end is before start or hits it. fail.
17305 * if start is after end or hits it fail.
17307 * if either hits (but other is outside. - then it's not
17313 // @see http://www.thismuchiknow.co.uk/?p=64.
17314 rangeIntersectsNode : function(range, node)
17316 var nodeRange = node.ownerDocument.createRange();
17318 nodeRange.selectNode(node);
17320 nodeRange.selectNodeContents(node);
17323 var rangeStartRange = range.cloneRange();
17324 rangeStartRange.collapse(true);
17326 var rangeEndRange = range.cloneRange();
17327 rangeEndRange.collapse(false);
17329 var nodeStartRange = nodeRange.cloneRange();
17330 nodeStartRange.collapse(true);
17332 var nodeEndRange = nodeRange.cloneRange();
17333 nodeEndRange.collapse(false);
17335 return rangeStartRange.compareBoundaryPoints(
17336 Range.START_TO_START, nodeEndRange) == -1 &&
17337 rangeEndRange.compareBoundaryPoints(
17338 Range.START_TO_START, nodeStartRange) == 1;
17342 rangeCompareNode : function(range, node)
17344 var nodeRange = node.ownerDocument.createRange();
17346 nodeRange.selectNode(node);
17348 nodeRange.selectNodeContents(node);
17352 range.collapse(true);
17354 nodeRange.collapse(true);
17356 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17357 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17359 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17361 var nodeIsBefore = ss == 1;
17362 var nodeIsAfter = ee == -1;
17364 if (nodeIsBefore && nodeIsAfter)
17366 if (!nodeIsBefore && nodeIsAfter)
17367 return 1; //right trailed.
17369 if (nodeIsBefore && !nodeIsAfter)
17370 return 2; // left trailed.
17375 // private? - in a new class?
17376 cleanUpPaste : function()
17378 // cleans up the whole document..
17379 Roo.log('cleanuppaste');
17381 this.cleanUpChildren(this.doc.body);
17382 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17383 if (clean != this.doc.body.innerHTML) {
17384 this.doc.body.innerHTML = clean;
17389 cleanWordChars : function(input) {// change the chars to hex code
17390 var he = Roo.HtmlEditorCore;
17392 var output = input;
17393 Roo.each(he.swapCodes, function(sw) {
17394 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17396 output = output.replace(swapper, sw[1]);
17403 cleanUpChildren : function (n)
17405 if (!n.childNodes.length) {
17408 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17409 this.cleanUpChild(n.childNodes[i]);
17416 cleanUpChild : function (node)
17419 //console.log(node);
17420 if (node.nodeName == "#text") {
17421 // clean up silly Windows -- stuff?
17424 if (node.nodeName == "#comment") {
17425 node.parentNode.removeChild(node);
17426 // clean up silly Windows -- stuff?
17429 var lcname = node.tagName.toLowerCase();
17430 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17431 // whitelist of tags..
17433 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17435 node.parentNode.removeChild(node);
17440 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17442 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17443 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17445 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17446 // remove_keep_children = true;
17449 if (remove_keep_children) {
17450 this.cleanUpChildren(node);
17451 // inserts everything just before this node...
17452 while (node.childNodes.length) {
17453 var cn = node.childNodes[0];
17454 node.removeChild(cn);
17455 node.parentNode.insertBefore(cn, node);
17457 node.parentNode.removeChild(node);
17461 if (!node.attributes || !node.attributes.length) {
17462 this.cleanUpChildren(node);
17466 function cleanAttr(n,v)
17469 if (v.match(/^\./) || v.match(/^\//)) {
17472 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17475 if (v.match(/^#/)) {
17478 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17479 node.removeAttribute(n);
17483 var cwhite = this.cwhite;
17484 var cblack = this.cblack;
17486 function cleanStyle(n,v)
17488 if (v.match(/expression/)) { //XSS?? should we even bother..
17489 node.removeAttribute(n);
17493 var parts = v.split(/;/);
17496 Roo.each(parts, function(p) {
17497 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17501 var l = p.split(':').shift().replace(/\s+/g,'');
17502 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17504 if ( cwhite.length && cblack.indexOf(l) > -1) {
17505 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17506 //node.removeAttribute(n);
17510 // only allow 'c whitelisted system attributes'
17511 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17512 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17513 //node.removeAttribute(n);
17523 if (clean.length) {
17524 node.setAttribute(n, clean.join(';'));
17526 node.removeAttribute(n);
17532 for (var i = node.attributes.length-1; i > -1 ; i--) {
17533 var a = node.attributes[i];
17536 if (a.name.toLowerCase().substr(0,2)=='on') {
17537 node.removeAttribute(a.name);
17540 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17541 node.removeAttribute(a.name);
17544 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17545 cleanAttr(a.name,a.value); // fixme..
17548 if (a.name == 'style') {
17549 cleanStyle(a.name,a.value);
17552 /// clean up MS crap..
17553 // tecnically this should be a list of valid class'es..
17556 if (a.name == 'class') {
17557 if (a.value.match(/^Mso/)) {
17558 node.className = '';
17561 if (a.value.match(/body/)) {
17562 node.className = '';
17573 this.cleanUpChildren(node);
17578 * Clean up MS wordisms...
17580 cleanWord : function(node)
17583 var cleanWordChildren = function()
17585 if (!node.childNodes.length) {
17588 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17589 _t.cleanWord(node.childNodes[i]);
17595 this.cleanWord(this.doc.body);
17598 if (node.nodeName == "#text") {
17599 // clean up silly Windows -- stuff?
17602 if (node.nodeName == "#comment") {
17603 node.parentNode.removeChild(node);
17604 // clean up silly Windows -- stuff?
17608 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17609 node.parentNode.removeChild(node);
17613 // remove - but keep children..
17614 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17615 while (node.childNodes.length) {
17616 var cn = node.childNodes[0];
17617 node.removeChild(cn);
17618 node.parentNode.insertBefore(cn, node);
17620 node.parentNode.removeChild(node);
17621 cleanWordChildren();
17625 if (node.className.length) {
17627 var cn = node.className.split(/\W+/);
17629 Roo.each(cn, function(cls) {
17630 if (cls.match(/Mso[a-zA-Z]+/)) {
17635 node.className = cna.length ? cna.join(' ') : '';
17637 node.removeAttribute("class");
17641 if (node.hasAttribute("lang")) {
17642 node.removeAttribute("lang");
17645 if (node.hasAttribute("style")) {
17647 var styles = node.getAttribute("style").split(";");
17649 Roo.each(styles, function(s) {
17650 if (!s.match(/:/)) {
17653 var kv = s.split(":");
17654 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17657 // what ever is left... we allow.
17660 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17661 if (!nstyle.length) {
17662 node.removeAttribute('style');
17666 cleanWordChildren();
17670 domToHTML : function(currentElement, depth, nopadtext) {
17672 depth = depth || 0;
17673 nopadtext = nopadtext || false;
17675 if (!currentElement) {
17676 return this.domToHTML(this.doc.body);
17679 //Roo.log(currentElement);
17681 var allText = false;
17682 var nodeName = currentElement.nodeName;
17683 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17685 if (nodeName == '#text') {
17686 return currentElement.nodeValue;
17691 if (nodeName != 'BODY') {
17694 // Prints the node tagName, such as <A>, <IMG>, etc
17697 for(i = 0; i < currentElement.attributes.length;i++) {
17699 var aname = currentElement.attributes.item(i).name;
17700 if (!currentElement.attributes.item(i).value.length) {
17703 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17706 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17715 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17718 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17723 // Traverse the tree
17725 var currentElementChild = currentElement.childNodes.item(i);
17726 var allText = true;
17727 var innerHTML = '';
17729 while (currentElementChild) {
17730 // Formatting code (indent the tree so it looks nice on the screen)
17731 var nopad = nopadtext;
17732 if (lastnode == 'SPAN') {
17736 if (currentElementChild.nodeName == '#text') {
17737 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17738 if (!nopad && toadd.length > 80) {
17739 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17741 innerHTML += toadd;
17744 currentElementChild = currentElement.childNodes.item(i);
17750 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17752 // Recursively traverse the tree structure of the child node
17753 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17754 lastnode = currentElementChild.nodeName;
17756 currentElementChild=currentElement.childNodes.item(i);
17762 // The remaining code is mostly for formatting the tree
17763 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17768 ret+= "</"+tagName+">";
17774 applyBlacklists : function()
17776 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
17777 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
17781 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17782 if (b.indexOf(tag) > -1) {
17785 this.white.push(tag);
17789 Roo.each(w, function(tag) {
17790 if (b.indexOf(tag) > -1) {
17793 if (this.white.indexOf(tag) > -1) {
17796 this.white.push(tag);
17801 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17802 if (w.indexOf(tag) > -1) {
17805 this.black.push(tag);
17809 Roo.each(b, function(tag) {
17810 if (w.indexOf(tag) > -1) {
17813 if (this.black.indexOf(tag) > -1) {
17816 this.black.push(tag);
17821 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
17822 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
17826 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17827 if (b.indexOf(tag) > -1) {
17830 this.cwhite.push(tag);
17834 Roo.each(w, function(tag) {
17835 if (b.indexOf(tag) > -1) {
17838 if (this.cwhite.indexOf(tag) > -1) {
17841 this.cwhite.push(tag);
17846 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
17847 if (w.indexOf(tag) > -1) {
17850 this.cblack.push(tag);
17854 Roo.each(b, function(tag) {
17855 if (w.indexOf(tag) > -1) {
17858 if (this.cblack.indexOf(tag) > -1) {
17861 this.cblack.push(tag);
17866 // hide stuff that is not compatible
17880 * @event specialkey
17884 * @cfg {String} fieldClass @hide
17887 * @cfg {String} focusClass @hide
17890 * @cfg {String} autoCreate @hide
17893 * @cfg {String} inputType @hide
17896 * @cfg {String} invalidClass @hide
17899 * @cfg {String} invalidText @hide
17902 * @cfg {String} msgFx @hide
17905 * @cfg {String} validateOnBlur @hide
17909 Roo.HtmlEditorCore.white = [
17910 'area', 'br', 'img', 'input', 'hr', 'wbr',
17912 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17913 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17914 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17915 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17916 'table', 'ul', 'xmp',
17918 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17921 'dir', 'menu', 'ol', 'ul', 'dl',
17927 Roo.HtmlEditorCore.black = [
17928 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17930 'base', 'basefont', 'bgsound', 'blink', 'body',
17931 'frame', 'frameset', 'head', 'html', 'ilayer',
17932 'iframe', 'layer', 'link', 'meta', 'object',
17933 'script', 'style' ,'title', 'xml' // clean later..
17935 Roo.HtmlEditorCore.clean = [
17936 'script', 'style', 'title', 'xml'
17938 Roo.HtmlEditorCore.remove = [
17943 Roo.HtmlEditorCore.ablack = [
17947 Roo.HtmlEditorCore.aclean = [
17948 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17952 Roo.HtmlEditorCore.pwhite= [
17953 'http', 'https', 'mailto'
17956 // white listed style attributes.
17957 Roo.HtmlEditorCore.cwhite= [
17958 // 'text-align', /// default is to allow most things..
17964 // black listed style attributes.
17965 Roo.HtmlEditorCore.cblack= [
17966 // 'font-size' -- this can be set by the project
17970 Roo.HtmlEditorCore.swapCodes =[
17989 * @class Roo.bootstrap.HtmlEditor
17990 * @extends Roo.bootstrap.TextArea
17991 * Bootstrap HtmlEditor class
17994 * Create a new HtmlEditor
17995 * @param {Object} config The config object
17998 Roo.bootstrap.HtmlEditor = function(config){
17999 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18000 if (!this.toolbars) {
18001 this.toolbars = [];
18003 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18006 * @event initialize
18007 * Fires when the editor is fully initialized (including the iframe)
18008 * @param {HtmlEditor} this
18013 * Fires when the editor is first receives the focus. Any insertion must wait
18014 * until after this event.
18015 * @param {HtmlEditor} this
18019 * @event beforesync
18020 * Fires before the textarea is updated with content from the editor iframe. Return false
18021 * to cancel the sync.
18022 * @param {HtmlEditor} this
18023 * @param {String} html
18027 * @event beforepush
18028 * Fires before the iframe editor is updated with content from the textarea. Return false
18029 * to cancel the push.
18030 * @param {HtmlEditor} this
18031 * @param {String} html
18036 * Fires when the textarea is updated with content from the editor iframe.
18037 * @param {HtmlEditor} this
18038 * @param {String} html
18043 * Fires when the iframe editor is updated with content from the textarea.
18044 * @param {HtmlEditor} this
18045 * @param {String} html
18049 * @event editmodechange
18050 * Fires when the editor switches edit modes
18051 * @param {HtmlEditor} this
18052 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18054 editmodechange: true,
18056 * @event editorevent
18057 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18058 * @param {HtmlEditor} this
18062 * @event firstfocus
18063 * Fires when on first focus - needed by toolbars..
18064 * @param {HtmlEditor} this
18069 * Auto save the htmlEditor value as a file into Events
18070 * @param {HtmlEditor} this
18074 * @event savedpreview
18075 * preview the saved version of htmlEditor
18076 * @param {HtmlEditor} this
18083 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
18087 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18092 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18097 * @cfg {Number} height (in pixels)
18101 * @cfg {Number} width (in pixels)
18106 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18109 stylesheets: false,
18114 // private properties
18115 validationEvent : false,
18117 initialized : false,
18120 onFocus : Roo.emptyFn,
18122 hideMode:'offsets',
18125 tbContainer : false,
18127 toolbarContainer :function() {
18128 return this.wrap.select('.x-html-editor-tb',true).first();
18132 * Protected method that will not generally be called directly. It
18133 * is called when the editor creates its toolbar. Override this method if you need to
18134 * add custom toolbar buttons.
18135 * @param {HtmlEditor} editor
18137 createToolbar : function(){
18139 Roo.log("create toolbars");
18141 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18142 this.toolbars[0].render(this.toolbarContainer());
18146 // if (!editor.toolbars || !editor.toolbars.length) {
18147 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18150 // for (var i =0 ; i < editor.toolbars.length;i++) {
18151 // editor.toolbars[i] = Roo.factory(
18152 // typeof(editor.toolbars[i]) == 'string' ?
18153 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
18154 // Roo.bootstrap.HtmlEditor);
18155 // editor.toolbars[i].init(editor);
18161 onRender : function(ct, position)
18163 // Roo.log("Call onRender: " + this.xtype);
18165 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18167 this.wrap = this.inputEl().wrap({
18168 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18171 this.editorcore.onRender(ct, position);
18173 if (this.resizable) {
18174 this.resizeEl = new Roo.Resizable(this.wrap, {
18178 minHeight : this.height,
18179 height: this.height,
18180 handles : this.resizable,
18183 resize : function(r, w, h) {
18184 _t.onResize(w,h); // -something
18190 this.createToolbar(this);
18193 if(!this.width && this.resizable){
18194 this.setSize(this.wrap.getSize());
18196 if (this.resizeEl) {
18197 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18198 // should trigger onReize..
18204 onResize : function(w, h)
18206 Roo.log('resize: ' +w + ',' + h );
18207 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18211 if(this.inputEl() ){
18212 if(typeof w == 'number'){
18213 var aw = w - this.wrap.getFrameWidth('lr');
18214 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18217 if(typeof h == 'number'){
18218 var tbh = -11; // fixme it needs to tool bar size!
18219 for (var i =0; i < this.toolbars.length;i++) {
18220 // fixme - ask toolbars for heights?
18221 tbh += this.toolbars[i].el.getHeight();
18222 //if (this.toolbars[i].footer) {
18223 // tbh += this.toolbars[i].footer.el.getHeight();
18231 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18232 ah -= 5; // knock a few pixes off for look..
18233 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18237 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18238 this.editorcore.onResize(ew,eh);
18243 * Toggles the editor between standard and source edit mode.
18244 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18246 toggleSourceEdit : function(sourceEditMode)
18248 this.editorcore.toggleSourceEdit(sourceEditMode);
18250 if(this.editorcore.sourceEditMode){
18251 Roo.log('editor - showing textarea');
18254 // Roo.log(this.syncValue());
18256 this.inputEl().removeClass(['hide', 'x-hidden']);
18257 this.inputEl().dom.removeAttribute('tabIndex');
18258 this.inputEl().focus();
18260 Roo.log('editor - hiding textarea');
18262 // Roo.log(this.pushValue());
18265 this.inputEl().addClass(['hide', 'x-hidden']);
18266 this.inputEl().dom.setAttribute('tabIndex', -1);
18267 //this.deferFocus();
18270 if(this.resizable){
18271 this.setSize(this.wrap.getSize());
18274 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18277 // private (for BoxComponent)
18278 adjustSize : Roo.BoxComponent.prototype.adjustSize,
18280 // private (for BoxComponent)
18281 getResizeEl : function(){
18285 // private (for BoxComponent)
18286 getPositionEl : function(){
18291 initEvents : function(){
18292 this.originalValue = this.getValue();
18296 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18299 // markInvalid : Roo.emptyFn,
18301 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18304 // clearInvalid : Roo.emptyFn,
18306 setValue : function(v){
18307 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18308 this.editorcore.pushValue();
18313 deferFocus : function(){
18314 this.focus.defer(10, this);
18318 focus : function(){
18319 this.editorcore.focus();
18325 onDestroy : function(){
18331 for (var i =0; i < this.toolbars.length;i++) {
18332 // fixme - ask toolbars for heights?
18333 this.toolbars[i].onDestroy();
18336 this.wrap.dom.innerHTML = '';
18337 this.wrap.remove();
18342 onFirstFocus : function(){
18343 //Roo.log("onFirstFocus");
18344 this.editorcore.onFirstFocus();
18345 for (var i =0; i < this.toolbars.length;i++) {
18346 this.toolbars[i].onFirstFocus();
18352 syncValue : function()
18354 this.editorcore.syncValue();
18357 pushValue : function()
18359 this.editorcore.pushValue();
18363 // hide stuff that is not compatible
18377 * @event specialkey
18381 * @cfg {String} fieldClass @hide
18384 * @cfg {String} focusClass @hide
18387 * @cfg {String} autoCreate @hide
18390 * @cfg {String} inputType @hide
18393 * @cfg {String} invalidClass @hide
18396 * @cfg {String} invalidText @hide
18399 * @cfg {String} msgFx @hide
18402 * @cfg {String} validateOnBlur @hide
18411 Roo.namespace('Roo.bootstrap.htmleditor');
18413 * @class Roo.bootstrap.HtmlEditorToolbar1
18418 new Roo.bootstrap.HtmlEditor({
18421 new Roo.bootstrap.HtmlEditorToolbar1({
18422 disable : { fonts: 1 , format: 1, ..., ... , ...],
18428 * @cfg {Object} disable List of elements to disable..
18429 * @cfg {Array} btns List of additional buttons.
18433 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18436 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18439 Roo.apply(this, config);
18441 // default disabled, based on 'good practice'..
18442 this.disable = this.disable || {};
18443 Roo.applyIf(this.disable, {
18446 specialElements : true
18448 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18450 this.editor = config.editor;
18451 this.editorcore = config.editor.editorcore;
18453 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18455 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18456 // dont call parent... till later.
18458 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18463 editorcore : false,
18468 "h1","h2","h3","h4","h5","h6",
18470 "abbr", "acronym", "address", "cite", "samp", "var",
18474 onRender : function(ct, position)
18476 // Roo.log("Call onRender: " + this.xtype);
18478 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18480 this.el.dom.style.marginBottom = '0';
18482 var editorcore = this.editorcore;
18483 var editor= this.editor;
18486 var btn = function(id,cmd , toggle, handler){
18488 var event = toggle ? 'toggle' : 'click';
18493 xns: Roo.bootstrap,
18496 enableToggle:toggle !== false,
18498 pressed : toggle ? false : null,
18501 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18502 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18511 xns: Roo.bootstrap,
18512 glyphicon : 'font',
18516 xns: Roo.bootstrap,
18520 Roo.each(this.formats, function(f) {
18521 style.menu.items.push({
18523 xns: Roo.bootstrap,
18524 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18529 editorcore.insertTag(this.tagname);
18536 children.push(style);
18539 btn('bold',false,true);
18540 btn('italic',false,true);
18541 btn('align-left', 'justifyleft',true);
18542 btn('align-center', 'justifycenter',true);
18543 btn('align-right' , 'justifyright',true);
18544 btn('link', false, false, function(btn) {
18545 //Roo.log("create link?");
18546 var url = prompt(this.createLinkText, this.defaultLinkValue);
18547 if(url && url != 'http:/'+'/'){
18548 this.editorcore.relayCmd('createlink', url);
18551 btn('list','insertunorderedlist',true);
18552 btn('pencil', false,true, function(btn){
18555 this.toggleSourceEdit(btn.pressed);
18561 xns: Roo.bootstrap,
18566 xns: Roo.bootstrap,
18571 cog.menu.items.push({
18573 xns: Roo.bootstrap,
18574 html : Clean styles,
18579 editorcore.insertTag(this.tagname);
18588 this.xtype = 'NavSimplebar';
18590 for(var i=0;i< children.length;i++) {
18592 this.buttons.add(this.addxtypeChild(children[i]));
18596 editor.on('editorevent', this.updateToolbar, this);
18598 onBtnClick : function(id)
18600 this.editorcore.relayCmd(id);
18601 this.editorcore.focus();
18605 * Protected method that will not generally be called directly. It triggers
18606 * a toolbar update by reading the markup state of the current selection in the editor.
18608 updateToolbar: function(){
18610 if(!this.editorcore.activated){
18611 this.editor.onFirstFocus(); // is this neeed?
18615 var btns = this.buttons;
18616 var doc = this.editorcore.doc;
18617 btns.get('bold').setActive(doc.queryCommandState('bold'));
18618 btns.get('italic').setActive(doc.queryCommandState('italic'));
18619 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18621 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18622 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18623 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18625 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18626 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18629 var ans = this.editorcore.getAllAncestors();
18630 if (this.formatCombo) {
18633 var store = this.formatCombo.store;
18634 this.formatCombo.setValue("");
18635 for (var i =0; i < ans.length;i++) {
18636 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18638 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18646 // hides menus... - so this cant be on a menu...
18647 Roo.bootstrap.MenuMgr.hideAll();
18649 Roo.bootstrap.MenuMgr.hideAll();
18650 //this.editorsyncValue();
18652 onFirstFocus: function() {
18653 this.buttons.each(function(item){
18657 toggleSourceEdit : function(sourceEditMode){
18660 if(sourceEditMode){
18661 Roo.log("disabling buttons");
18662 this.buttons.each( function(item){
18663 if(item.cmd != 'pencil'){
18669 Roo.log("enabling buttons");
18670 if(this.editorcore.initialized){
18671 this.buttons.each( function(item){
18677 Roo.log("calling toggole on editor");
18678 // tell the editor that it's been pressed..
18679 this.editor.toggleSourceEdit(sourceEditMode);
18689 * @class Roo.bootstrap.Table.AbstractSelectionModel
18690 * @extends Roo.util.Observable
18691 * Abstract base class for grid SelectionModels. It provides the interface that should be
18692 * implemented by descendant classes. This class should not be directly instantiated.
18695 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18696 this.locked = false;
18697 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18701 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18702 /** @ignore Called by the grid automatically. Do not call directly. */
18703 init : function(grid){
18709 * Locks the selections.
18712 this.locked = true;
18716 * Unlocks the selections.
18718 unlock : function(){
18719 this.locked = false;
18723 * Returns true if the selections are locked.
18724 * @return {Boolean}
18726 isLocked : function(){
18727 return this.locked;
18731 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18732 * @class Roo.bootstrap.Table.RowSelectionModel
18733 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18734 * It supports multiple selections and keyboard selection/navigation.
18736 * @param {Object} config
18739 Roo.bootstrap.Table.RowSelectionModel = function(config){
18740 Roo.apply(this, config);
18741 this.selections = new Roo.util.MixedCollection(false, function(o){
18746 this.lastActive = false;
18750 * @event selectionchange
18751 * Fires when the selection changes
18752 * @param {SelectionModel} this
18754 "selectionchange" : true,
18756 * @event afterselectionchange
18757 * Fires after the selection changes (eg. by key press or clicking)
18758 * @param {SelectionModel} this
18760 "afterselectionchange" : true,
18762 * @event beforerowselect
18763 * Fires when a row is selected being selected, return false to cancel.
18764 * @param {SelectionModel} this
18765 * @param {Number} rowIndex The selected index
18766 * @param {Boolean} keepExisting False if other selections will be cleared
18768 "beforerowselect" : true,
18771 * Fires when a row is selected.
18772 * @param {SelectionModel} this
18773 * @param {Number} rowIndex The selected index
18774 * @param {Roo.data.Record} r The record
18776 "rowselect" : true,
18778 * @event rowdeselect
18779 * Fires when a row is deselected.
18780 * @param {SelectionModel} this
18781 * @param {Number} rowIndex The selected index
18783 "rowdeselect" : true
18785 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18786 this.locked = false;
18789 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18791 * @cfg {Boolean} singleSelect
18792 * True to allow selection of only one row at a time (defaults to false)
18794 singleSelect : false,
18797 initEvents : function(){
18799 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18800 this.grid.on("mousedown", this.handleMouseDown, this);
18801 }else{ // allow click to work like normal
18802 this.grid.on("rowclick", this.handleDragableRowClick, this);
18805 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18806 "up" : function(e){
18808 this.selectPrevious(e.shiftKey);
18809 }else if(this.last !== false && this.lastActive !== false){
18810 var last = this.last;
18811 this.selectRange(this.last, this.lastActive-1);
18812 this.grid.getView().focusRow(this.lastActive);
18813 if(last !== false){
18817 this.selectFirstRow();
18819 this.fireEvent("afterselectionchange", this);
18821 "down" : function(e){
18823 this.selectNext(e.shiftKey);
18824 }else if(this.last !== false && this.lastActive !== false){
18825 var last = this.last;
18826 this.selectRange(this.last, this.lastActive+1);
18827 this.grid.getView().focusRow(this.lastActive);
18828 if(last !== false){
18832 this.selectFirstRow();
18834 this.fireEvent("afterselectionchange", this);
18839 var view = this.grid.view;
18840 view.on("refresh", this.onRefresh, this);
18841 view.on("rowupdated", this.onRowUpdated, this);
18842 view.on("rowremoved", this.onRemove, this);
18846 onRefresh : function(){
18847 var ds = this.grid.dataSource, i, v = this.grid.view;
18848 var s = this.selections;
18849 s.each(function(r){
18850 if((i = ds.indexOfId(r.id)) != -1){
18859 onRemove : function(v, index, r){
18860 this.selections.remove(r);
18864 onRowUpdated : function(v, index, r){
18865 if(this.isSelected(r)){
18866 v.onRowSelect(index);
18872 * @param {Array} records The records to select
18873 * @param {Boolean} keepExisting (optional) True to keep existing selections
18875 selectRecords : function(records, keepExisting){
18877 this.clearSelections();
18879 var ds = this.grid.dataSource;
18880 for(var i = 0, len = records.length; i < len; i++){
18881 this.selectRow(ds.indexOf(records[i]), true);
18886 * Gets the number of selected rows.
18889 getCount : function(){
18890 return this.selections.length;
18894 * Selects the first row in the grid.
18896 selectFirstRow : function(){
18901 * Select the last row.
18902 * @param {Boolean} keepExisting (optional) True to keep existing selections
18904 selectLastRow : function(keepExisting){
18905 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18909 * Selects the row immediately following the last selected row.
18910 * @param {Boolean} keepExisting (optional) True to keep existing selections
18912 selectNext : function(keepExisting){
18913 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18914 this.selectRow(this.last+1, keepExisting);
18915 this.grid.getView().focusRow(this.last);
18920 * Selects the row that precedes the last selected row.
18921 * @param {Boolean} keepExisting (optional) True to keep existing selections
18923 selectPrevious : function(keepExisting){
18925 this.selectRow(this.last-1, keepExisting);
18926 this.grid.getView().focusRow(this.last);
18931 * Returns the selected records
18932 * @return {Array} Array of selected records
18934 getSelections : function(){
18935 return [].concat(this.selections.items);
18939 * Returns the first selected record.
18942 getSelected : function(){
18943 return this.selections.itemAt(0);
18948 * Clears all selections.
18950 clearSelections : function(fast){
18951 if(this.locked) return;
18953 var ds = this.grid.dataSource;
18954 var s = this.selections;
18955 s.each(function(r){
18956 this.deselectRow(ds.indexOfId(r.id));
18960 this.selections.clear();
18967 * Selects all rows.
18969 selectAll : function(){
18970 if(this.locked) return;
18971 this.selections.clear();
18972 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18973 this.selectRow(i, true);
18978 * Returns True if there is a selection.
18979 * @return {Boolean}
18981 hasSelection : function(){
18982 return this.selections.length > 0;
18986 * Returns True if the specified row is selected.
18987 * @param {Number/Record} record The record or index of the record to check
18988 * @return {Boolean}
18990 isSelected : function(index){
18991 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18992 return (r && this.selections.key(r.id) ? true : false);
18996 * Returns True if the specified record id is selected.
18997 * @param {String} id The id of record to check
18998 * @return {Boolean}
19000 isIdSelected : function(id){
19001 return (this.selections.key(id) ? true : false);
19005 handleMouseDown : function(e, t){
19006 var view = this.grid.getView(), rowIndex;
19007 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19010 if(e.shiftKey && this.last !== false){
19011 var last = this.last;
19012 this.selectRange(last, rowIndex, e.ctrlKey);
19013 this.last = last; // reset the last
19014 view.focusRow(rowIndex);
19016 var isSelected = this.isSelected(rowIndex);
19017 if(e.button !== 0 && isSelected){
19018 view.focusRow(rowIndex);
19019 }else if(e.ctrlKey && isSelected){
19020 this.deselectRow(rowIndex);
19021 }else if(!isSelected){
19022 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19023 view.focusRow(rowIndex);
19026 this.fireEvent("afterselectionchange", this);
19029 handleDragableRowClick : function(grid, rowIndex, e)
19031 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19032 this.selectRow(rowIndex, false);
19033 grid.view.focusRow(rowIndex);
19034 this.fireEvent("afterselectionchange", this);
19039 * Selects multiple rows.
19040 * @param {Array} rows Array of the indexes of the row to select
19041 * @param {Boolean} keepExisting (optional) True to keep existing selections
19043 selectRows : function(rows, keepExisting){
19045 this.clearSelections();
19047 for(var i = 0, len = rows.length; i < len; i++){
19048 this.selectRow(rows[i], true);
19053 * Selects a range of rows. All rows in between startRow and endRow are also selected.
19054 * @param {Number} startRow The index of the first row in the range
19055 * @param {Number} endRow The index of the last row in the range
19056 * @param {Boolean} keepExisting (optional) True to retain existing selections
19058 selectRange : function(startRow, endRow, keepExisting){
19059 if(this.locked) return;
19061 this.clearSelections();
19063 if(startRow <= endRow){
19064 for(var i = startRow; i <= endRow; i++){
19065 this.selectRow(i, true);
19068 for(var i = startRow; i >= endRow; i--){
19069 this.selectRow(i, true);
19075 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19076 * @param {Number} startRow The index of the first row in the range
19077 * @param {Number} endRow The index of the last row in the range
19079 deselectRange : function(startRow, endRow, preventViewNotify){
19080 if(this.locked) return;
19081 for(var i = startRow; i <= endRow; i++){
19082 this.deselectRow(i, preventViewNotify);
19088 * @param {Number} row The index of the row to select
19089 * @param {Boolean} keepExisting (optional) True to keep existing selections
19091 selectRow : function(index, keepExisting, preventViewNotify){
19092 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19093 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19094 if(!keepExisting || this.singleSelect){
19095 this.clearSelections();
19097 var r = this.grid.dataSource.getAt(index);
19098 this.selections.add(r);
19099 this.last = this.lastActive = index;
19100 if(!preventViewNotify){
19101 this.grid.getView().onRowSelect(index);
19103 this.fireEvent("rowselect", this, index, r);
19104 this.fireEvent("selectionchange", this);
19110 * @param {Number} row The index of the row to deselect
19112 deselectRow : function(index, preventViewNotify){
19113 if(this.locked) return;
19114 if(this.last == index){
19117 if(this.lastActive == index){
19118 this.lastActive = false;
19120 var r = this.grid.dataSource.getAt(index);
19121 this.selections.remove(r);
19122 if(!preventViewNotify){
19123 this.grid.getView().onRowDeselect(index);
19125 this.fireEvent("rowdeselect", this, index);
19126 this.fireEvent("selectionchange", this);
19130 restoreLast : function(){
19132 this.last = this._last;
19137 acceptsNav : function(row, col, cm){
19138 return !cm.isHidden(col) && cm.isCellEditable(col, row);
19142 onEditorKey : function(field, e){
19143 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19148 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19150 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19152 }else if(k == e.ENTER && !e.ctrlKey){
19156 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19158 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19160 }else if(k == e.ESC){
19164 g.startEditing(newCell[0], newCell[1]);
19169 * Ext JS Library 1.1.1
19170 * Copyright(c) 2006-2007, Ext JS, LLC.
19172 * Originally Released Under LGPL - original licence link has changed is not relivant.
19175 * <script type="text/javascript">
19179 * @class Roo.bootstrap.PagingToolbar
19181 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19183 * Create a new PagingToolbar
19184 * @param {Object} config The config object
19186 Roo.bootstrap.PagingToolbar = function(config)
19188 // old args format still supported... - xtype is prefered..
19189 // created from xtype...
19190 var ds = config.dataSource;
19191 this.toolbarItems = [];
19192 if (config.items) {
19193 this.toolbarItems = config.items;
19194 // config.items = [];
19197 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19204 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19208 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19210 * @cfg {Roo.data.Store} dataSource
19211 * The underlying data store providing the paged data
19214 * @cfg {String/HTMLElement/Element} container
19215 * container The id or element that will contain the toolbar
19218 * @cfg {Boolean} displayInfo
19219 * True to display the displayMsg (defaults to false)
19222 * @cfg {Number} pageSize
19223 * The number of records to display per page (defaults to 20)
19227 * @cfg {String} displayMsg
19228 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19230 displayMsg : 'Displaying {0} - {1} of {2}',
19232 * @cfg {String} emptyMsg
19233 * The message to display when no records are found (defaults to "No data to display")
19235 emptyMsg : 'No data to display',
19237 * Customizable piece of the default paging text (defaults to "Page")
19240 beforePageText : "Page",
19242 * Customizable piece of the default paging text (defaults to "of %0")
19245 afterPageText : "of {0}",
19247 * Customizable piece of the default paging text (defaults to "First Page")
19250 firstText : "First Page",
19252 * Customizable piece of the default paging text (defaults to "Previous Page")
19255 prevText : "Previous Page",
19257 * Customizable piece of the default paging text (defaults to "Next Page")
19260 nextText : "Next Page",
19262 * Customizable piece of the default paging text (defaults to "Last Page")
19265 lastText : "Last Page",
19267 * Customizable piece of the default paging text (defaults to "Refresh")
19270 refreshText : "Refresh",
19274 onRender : function(ct, position)
19276 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19277 this.navgroup.parentId = this.id;
19278 this.navgroup.onRender(this.el, null);
19279 // add the buttons to the navgroup
19281 if(this.displayInfo){
19282 Roo.log(this.el.select('ul.navbar-nav',true).first());
19283 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19284 this.displayEl = this.el.select('.x-paging-info', true).first();
19285 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19286 // this.displayEl = navel.el.select('span',true).first();
19292 Roo.each(_this.buttons, function(e){
19293 Roo.factory(e).onRender(_this.el, null);
19297 Roo.each(_this.toolbarItems, function(e) {
19298 _this.navgroup.addItem(e);
19301 this.first = this.navgroup.addItem({
19302 tooltip: this.firstText,
19304 icon : 'fa fa-backward',
19306 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19309 this.prev = this.navgroup.addItem({
19310 tooltip: this.prevText,
19312 icon : 'fa fa-step-backward',
19314 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
19316 //this.addSeparator();
19319 var field = this.navgroup.addItem( {
19321 cls : 'x-paging-position',
19323 html : this.beforePageText +
19324 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19325 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19328 this.field = field.el.select('input', true).first();
19329 this.field.on("keydown", this.onPagingKeydown, this);
19330 this.field.on("focus", function(){this.dom.select();});
19333 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19334 //this.field.setHeight(18);
19335 //this.addSeparator();
19336 this.next = this.navgroup.addItem({
19337 tooltip: this.nextText,
19339 html : ' <i class="fa fa-step-forward">',
19341 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19343 this.last = this.navgroup.addItem({
19344 tooltip: this.lastText,
19345 icon : 'fa fa-forward',
19348 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19350 //this.addSeparator();
19351 this.loading = this.navgroup.addItem({
19352 tooltip: this.refreshText,
19353 icon: 'fa fa-refresh',
19355 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19361 updateInfo : function(){
19362 if(this.displayEl){
19363 var count = this.ds.getCount();
19364 var msg = count == 0 ?
19368 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19370 this.displayEl.update(msg);
19375 onLoad : function(ds, r, o){
19376 this.cursor = o.params ? o.params.start : 0;
19377 var d = this.getPageData(),
19381 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19382 this.field.dom.value = ap;
19383 this.first.setDisabled(ap == 1);
19384 this.prev.setDisabled(ap == 1);
19385 this.next.setDisabled(ap == ps);
19386 this.last.setDisabled(ap == ps);
19387 this.loading.enable();
19392 getPageData : function(){
19393 var total = this.ds.getTotalCount();
19396 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19397 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19402 onLoadError : function(){
19403 this.loading.enable();
19407 onPagingKeydown : function(e){
19408 var k = e.getKey();
19409 var d = this.getPageData();
19411 var v = this.field.dom.value, pageNum;
19412 if(!v || isNaN(pageNum = parseInt(v, 10))){
19413 this.field.dom.value = d.activePage;
19416 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19417 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19420 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))
19422 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19423 this.field.dom.value = pageNum;
19424 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19427 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19429 var v = this.field.dom.value, pageNum;
19430 var increment = (e.shiftKey) ? 10 : 1;
19431 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19433 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19434 this.field.dom.value = d.activePage;
19437 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19439 this.field.dom.value = parseInt(v, 10) + increment;
19440 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19441 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19448 beforeLoad : function(){
19450 this.loading.disable();
19455 onClick : function(which){
19462 ds.load({params:{start: 0, limit: this.pageSize}});
19465 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19468 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19471 var total = ds.getTotalCount();
19472 var extra = total % this.pageSize;
19473 var lastStart = extra ? (total - extra) : total-this.pageSize;
19474 ds.load({params:{start: lastStart, limit: this.pageSize}});
19477 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19483 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19484 * @param {Roo.data.Store} store The data store to unbind
19486 unbind : function(ds){
19487 ds.un("beforeload", this.beforeLoad, this);
19488 ds.un("load", this.onLoad, this);
19489 ds.un("loadexception", this.onLoadError, this);
19490 ds.un("remove", this.updateInfo, this);
19491 ds.un("add", this.updateInfo, this);
19492 this.ds = undefined;
19496 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19497 * @param {Roo.data.Store} store The data store to bind
19499 bind : function(ds){
19500 ds.on("beforeload", this.beforeLoad, this);
19501 ds.on("load", this.onLoad, this);
19502 ds.on("loadexception", this.onLoadError, this);
19503 ds.on("remove", this.updateInfo, this);
19504 ds.on("add", this.updateInfo, this);
19515 * @class Roo.bootstrap.MessageBar
19516 * @extends Roo.bootstrap.Component
19517 * Bootstrap MessageBar class
19518 * @cfg {String} html contents of the MessageBar
19519 * @cfg {String} weight (info | success | warning | danger) default info
19520 * @cfg {String} beforeClass insert the bar before the given class
19521 * @cfg {Boolean} closable (true | false) default false
19522 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19525 * Create a new Element
19526 * @param {Object} config The config object
19529 Roo.bootstrap.MessageBar = function(config){
19530 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19533 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19539 beforeClass: 'bootstrap-sticky-wrap',
19541 getAutoCreate : function(){
19545 cls: 'alert alert-dismissable alert-' + this.weight,
19550 html: this.html || ''
19556 cfg.cls += ' alert-messages-fixed';
19570 onRender : function(ct, position)
19572 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19575 var cfg = Roo.apply({}, this.getAutoCreate());
19579 cfg.cls += ' ' + this.cls;
19582 cfg.style = this.style;
19584 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19586 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19589 this.el.select('>button.close').on('click', this.hide, this);
19595 if (!this.rendered) {
19601 this.fireEvent('show', this);
19607 if (!this.rendered) {
19613 this.fireEvent('hide', this);
19616 update : function()
19618 // var e = this.el.dom.firstChild;
19620 // if(this.closable){
19621 // e = e.nextSibling;
19624 // e.data = this.html || '';
19626 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19642 * @class Roo.bootstrap.Graph
19643 * @extends Roo.bootstrap.Component
19644 * Bootstrap Graph class
19648 @cfg {String} graphtype bar | vbar | pie
19649 @cfg {number} g_x coodinator | centre x (pie)
19650 @cfg {number} g_y coodinator | centre y (pie)
19651 @cfg {number} g_r radius (pie)
19652 @cfg {number} g_height height of the chart (respected by all elements in the set)
19653 @cfg {number} g_width width of the chart (respected by all elements in the set)
19654 @cfg {Object} title The title of the chart
19657 -opts (object) options for the chart
19659 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19660 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19662 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.
19663 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19665 o stretch (boolean)
19667 -opts (object) options for the pie
19670 o startAngle (number)
19671 o endAngle (number)
19675 * Create a new Input
19676 * @param {Object} config The config object
19679 Roo.bootstrap.Graph = function(config){
19680 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19686 * The img click event for the img.
19687 * @param {Roo.EventObject} e
19693 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19704 //g_colors: this.colors,
19711 getAutoCreate : function(){
19722 onRender : function(ct,position){
19723 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19724 this.raphael = Raphael(this.el.dom);
19726 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19727 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19728 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19729 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19731 r.text(160, 10, "Single Series Chart").attr(txtattr);
19732 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19733 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19734 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19736 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19737 r.barchart(330, 10, 300, 220, data1);
19738 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19739 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19742 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19743 // r.barchart(30, 30, 560, 250, xdata, {
19744 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19745 // axis : "0 0 1 1",
19746 // axisxlabels : xdata
19747 // //yvalues : cols,
19750 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19752 // this.load(null,xdata,{
19753 // axis : "0 0 1 1",
19754 // axisxlabels : xdata
19759 load : function(graphtype,xdata,opts){
19760 this.raphael.clear();
19762 graphtype = this.graphtype;
19767 var r = this.raphael,
19768 fin = function () {
19769 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19771 fout = function () {
19772 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19774 pfin = function() {
19775 this.sector.stop();
19776 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19779 this.label[0].stop();
19780 this.label[0].attr({ r: 7.5 });
19781 this.label[1].attr({ "font-weight": 800 });
19784 pfout = function() {
19785 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19788 this.label[0].animate({ r: 5 }, 500, "bounce");
19789 this.label[1].attr({ "font-weight": 400 });
19795 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19798 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19801 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19802 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19804 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19811 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19816 setTitle: function(o)
19821 initEvents: function() {
19824 this.el.on('click', this.onClick, this);
19828 onClick : function(e)
19830 Roo.log('img onclick');
19831 this.fireEvent('click', this, e);
19843 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19846 * @class Roo.bootstrap.dash.NumberBox
19847 * @extends Roo.bootstrap.Component
19848 * Bootstrap NumberBox class
19849 * @cfg {String} headline Box headline
19850 * @cfg {String} content Box content
19851 * @cfg {String} icon Box icon
19852 * @cfg {String} footer Footer text
19853 * @cfg {String} fhref Footer href
19856 * Create a new NumberBox
19857 * @param {Object} config The config object
19861 Roo.bootstrap.dash.NumberBox = function(config){
19862 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19866 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19875 getAutoCreate : function(){
19879 cls : 'small-box ',
19887 cls : 'roo-headline',
19888 html : this.headline
19892 cls : 'roo-content',
19893 html : this.content
19907 cls : 'ion ' + this.icon
19916 cls : 'small-box-footer',
19917 href : this.fhref || '#',
19921 cfg.cn.push(footer);
19928 onRender : function(ct,position){
19929 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19936 setHeadline: function (value)
19938 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19941 setFooter: function (value, href)
19943 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19946 this.el.select('a.small-box-footer',true).first().attr('href', href);
19951 setContent: function (value)
19953 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19956 initEvents: function()
19970 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19973 * @class Roo.bootstrap.dash.TabBox
19974 * @extends Roo.bootstrap.Component
19975 * Bootstrap TabBox class
19976 * @cfg {String} title Title of the TabBox
19977 * @cfg {String} icon Icon of the TabBox
19978 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19979 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
19982 * Create a new TabBox
19983 * @param {Object} config The config object
19987 Roo.bootstrap.dash.TabBox = function(config){
19988 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19993 * When a pane is added
19994 * @param {Roo.bootstrap.dash.TabPane} pane
19998 * @event activatepane
19999 * When a pane is activated
20000 * @param {Roo.bootstrap.dash.TabPane} pane
20002 "activatepane" : true
20010 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
20015 tabScrollable : false,
20017 getChildContainer : function()
20019 return this.el.select('.tab-content', true).first();
20022 getAutoCreate : function(){
20026 cls: 'pull-left header',
20034 cls: 'fa ' + this.icon
20040 cls: 'nav nav-tabs pull-right',
20046 if(this.tabScrollable){
20053 cls: 'nav nav-tabs pull-right',
20064 cls: 'nav-tabs-custom',
20069 cls: 'tab-content no-padding',
20077 initEvents : function()
20079 //Roo.log('add add pane handler');
20080 this.on('addpane', this.onAddPane, this);
20083 * Updates the box title
20084 * @param {String} html to set the title to.
20086 setTitle : function(value)
20088 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20090 onAddPane : function(pane)
20092 this.panes.push(pane);
20093 //Roo.log('addpane');
20095 // tabs are rendere left to right..
20096 if(!this.showtabs){
20100 var ctr = this.el.select('.nav-tabs', true).first();
20103 var existing = ctr.select('.nav-tab',true);
20104 var qty = existing.getCount();;
20107 var tab = ctr.createChild({
20109 cls : 'nav-tab' + (qty ? '' : ' active'),
20117 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20120 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20122 pane.el.addClass('active');
20127 onTabClick : function(ev,un,ob,pane)
20129 //Roo.log('tab - prev default');
20130 ev.preventDefault();
20133 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20134 pane.tab.addClass('active');
20135 //Roo.log(pane.title);
20136 this.getChildContainer().select('.tab-pane',true).removeClass('active');
20137 // technically we should have a deactivate event.. but maybe add later.
20138 // and it should not de-activate the selected tab...
20139 this.fireEvent('activatepane', pane);
20140 pane.el.addClass('active');
20141 pane.fireEvent('activate');
20146 getActivePane : function()
20149 Roo.each(this.panes, function(p) {
20150 if(p.el.hasClass('active')){
20171 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20173 * @class Roo.bootstrap.TabPane
20174 * @extends Roo.bootstrap.Component
20175 * Bootstrap TabPane class
20176 * @cfg {Boolean} active (false | true) Default false
20177 * @cfg {String} title title of panel
20181 * Create a new TabPane
20182 * @param {Object} config The config object
20185 Roo.bootstrap.dash.TabPane = function(config){
20186 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20192 * When a pane is activated
20193 * @param {Roo.bootstrap.dash.TabPane} pane
20200 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
20205 // the tabBox that this is attached to.
20208 getAutoCreate : function()
20216 cfg.cls += ' active';
20221 initEvents : function()
20223 //Roo.log('trigger add pane handler');
20224 this.parent().fireEvent('addpane', this)
20228 * Updates the tab title
20229 * @param {String} html to set the title to.
20231 setTitle: function(str)
20237 this.tab.select('a', true).first().dom.innerHTML = str;
20254 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20257 * @class Roo.bootstrap.menu.Menu
20258 * @extends Roo.bootstrap.Component
20259 * Bootstrap Menu class - container for Menu
20260 * @cfg {String} html Text of the menu
20261 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20262 * @cfg {String} icon Font awesome icon
20263 * @cfg {String} pos Menu align to (top | bottom) default bottom
20267 * Create a new Menu
20268 * @param {Object} config The config object
20272 Roo.bootstrap.menu.Menu = function(config){
20273 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20277 * @event beforeshow
20278 * Fires before this menu is displayed
20279 * @param {Roo.bootstrap.menu.Menu} this
20283 * @event beforehide
20284 * Fires before this menu is hidden
20285 * @param {Roo.bootstrap.menu.Menu} this
20290 * Fires after this menu is displayed
20291 * @param {Roo.bootstrap.menu.Menu} this
20296 * Fires after this menu is hidden
20297 * @param {Roo.bootstrap.menu.Menu} this
20302 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20303 * @param {Roo.bootstrap.menu.Menu} this
20304 * @param {Roo.EventObject} e
20311 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
20315 weight : 'default',
20320 getChildContainer : function() {
20321 if(this.isSubMenu){
20325 return this.el.select('ul.dropdown-menu', true).first();
20328 getAutoCreate : function()
20333 cls : 'roo-menu-text',
20341 cls : 'fa ' + this.icon
20352 cls : 'dropdown-button btn btn-' + this.weight,
20357 cls : 'dropdown-toggle btn btn-' + this.weight,
20367 cls : 'dropdown-menu'
20373 if(this.pos == 'top'){
20374 cfg.cls += ' dropup';
20377 if(this.isSubMenu){
20380 cls : 'dropdown-menu'
20387 onRender : function(ct, position)
20389 this.isSubMenu = ct.hasClass('dropdown-submenu');
20391 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20394 initEvents : function()
20396 if(this.isSubMenu){
20400 this.hidden = true;
20402 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20403 this.triggerEl.on('click', this.onTriggerPress, this);
20405 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20406 this.buttonEl.on('click', this.onClick, this);
20412 if(this.isSubMenu){
20416 return this.el.select('ul.dropdown-menu', true).first();
20419 onClick : function(e)
20421 this.fireEvent("click", this, e);
20424 onTriggerPress : function(e)
20426 if (this.isVisible()) {
20433 isVisible : function(){
20434 return !this.hidden;
20439 this.fireEvent("beforeshow", this);
20441 this.hidden = false;
20442 this.el.addClass('open');
20444 Roo.get(document).on("mouseup", this.onMouseUp, this);
20446 this.fireEvent("show", this);
20453 this.fireEvent("beforehide", this);
20455 this.hidden = true;
20456 this.el.removeClass('open');
20458 Roo.get(document).un("mouseup", this.onMouseUp);
20460 this.fireEvent("hide", this);
20463 onMouseUp : function()
20477 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20480 * @class Roo.bootstrap.menu.Item
20481 * @extends Roo.bootstrap.Component
20482 * Bootstrap MenuItem class
20483 * @cfg {Boolean} submenu (true | false) default false
20484 * @cfg {String} html text of the item
20485 * @cfg {String} href the link
20486 * @cfg {Boolean} disable (true | false) default false
20487 * @cfg {Boolean} preventDefault (true | false) default true
20488 * @cfg {String} icon Font awesome icon
20489 * @cfg {String} pos Submenu align to (left | right) default right
20493 * Create a new Item
20494 * @param {Object} config The config object
20498 Roo.bootstrap.menu.Item = function(config){
20499 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20503 * Fires when the mouse is hovering over this menu
20504 * @param {Roo.bootstrap.menu.Item} this
20505 * @param {Roo.EventObject} e
20510 * Fires when the mouse exits this menu
20511 * @param {Roo.bootstrap.menu.Item} this
20512 * @param {Roo.EventObject} e
20518 * The raw click event for the entire grid.
20519 * @param {Roo.EventObject} e
20525 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20530 preventDefault: true,
20535 getAutoCreate : function()
20540 cls : 'roo-menu-item-text',
20548 cls : 'fa ' + this.icon
20557 href : this.href || '#',
20564 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20568 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20570 if(this.pos == 'left'){
20571 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20578 initEvents : function()
20580 this.el.on('mouseover', this.onMouseOver, this);
20581 this.el.on('mouseout', this.onMouseOut, this);
20583 this.el.select('a', true).first().on('click', this.onClick, this);
20587 onClick : function(e)
20589 if(this.preventDefault){
20590 e.preventDefault();
20593 this.fireEvent("click", this, e);
20596 onMouseOver : function(e)
20598 if(this.submenu && this.pos == 'left'){
20599 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20602 this.fireEvent("mouseover", this, e);
20605 onMouseOut : function(e)
20607 this.fireEvent("mouseout", this, e);
20619 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20622 * @class Roo.bootstrap.menu.Separator
20623 * @extends Roo.bootstrap.Component
20624 * Bootstrap Separator class
20627 * Create a new Separator
20628 * @param {Object} config The config object
20632 Roo.bootstrap.menu.Separator = function(config){
20633 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20636 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20638 getAutoCreate : function(){
20659 * @class Roo.bootstrap.Tooltip
20660 * Bootstrap Tooltip class
20661 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20662 * to determine which dom element triggers the tooltip.
20664 * It needs to add support for additional attributes like tooltip-position
20667 * Create a new Toolti
20668 * @param {Object} config The config object
20671 Roo.bootstrap.Tooltip = function(config){
20672 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20675 Roo.apply(Roo.bootstrap.Tooltip, {
20677 * @function init initialize tooltip monitoring.
20681 currentTip : false,
20682 currentRegion : false,
20688 Roo.get(document).on('mouseover', this.enter ,this);
20689 Roo.get(document).on('mouseout', this.leave, this);
20692 this.currentTip = new Roo.bootstrap.Tooltip();
20695 enter : function(ev)
20697 var dom = ev.getTarget();
20698 //Roo.log(['enter',dom]);
20699 var el = Roo.fly(dom);
20700 if (this.currentEl) {
20702 //Roo.log(this.currentEl);
20703 //Roo.log(this.currentEl.contains(dom));
20704 if (this.currentEl == el) {
20707 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20715 if (this.currentTip.el) {
20716 this.currentTip.el.hide(); // force hiding...
20719 if (!el.attr('tooltip')) { // parents who have tip?
20722 this.currentEl = el;
20723 this.currentTip.bind(el);
20724 this.currentRegion = Roo.lib.Region.getRegion(dom);
20725 this.currentTip.enter();
20728 leave : function(ev)
20730 var dom = ev.getTarget();
20731 //Roo.log(['leave',dom]);
20732 if (!this.currentEl) {
20737 if (dom != this.currentEl.dom) {
20740 var xy = ev.getXY();
20741 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
20744 // only activate leave if mouse cursor is outside... bounding box..
20749 if (this.currentTip) {
20750 this.currentTip.leave();
20752 //Roo.log('clear currentEl');
20753 this.currentEl = false;
20758 'left' : ['r-l', [-2,0], 'right'],
20759 'right' : ['l-r', [2,0], 'left'],
20760 'bottom' : ['t-b', [0,2], 'top'],
20761 'top' : [ 'b-t', [0,-2], 'bottom']
20767 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
20772 delay : null, // can be { show : 300 , hide: 500}
20776 hoverState : null, //???
20778 placement : 'bottom',
20780 getAutoCreate : function(){
20787 cls : 'tooltip-arrow'
20790 cls : 'tooltip-inner'
20797 bind : function(el)
20803 enter : function () {
20805 if (this.timeout != null) {
20806 clearTimeout(this.timeout);
20809 this.hoverState = 'in'
20810 //Roo.log("enter - show");
20811 if (!this.delay || !this.delay.show) {
20816 this.timeout = setTimeout(function () {
20817 if (_t.hoverState == 'in') {
20820 }, this.delay.show);
20824 clearTimeout(this.timeout);
20826 this.hoverState = 'out'
20827 if (!this.delay || !this.delay.hide) {
20833 this.timeout = setTimeout(function () {
20834 //Roo.log("leave - timeout");
20836 if (_t.hoverState == 'out') {
20838 Roo.bootstrap.Tooltip.currentEl = false;
20846 this.render(document.body);
20849 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
20850 this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
20852 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
20854 var placement = typeof this.placement == 'function' ?
20855 this.placement.call(this, this.el, on_el) :
20858 var autoToken = /\s?auto?\s?/i;
20859 var autoPlace = autoToken.test(placement);
20861 placement = placement.replace(autoToken, '') || 'top';
20865 //this.el.setXY([0,0]);
20867 //this.el.dom.style.display='block';
20868 this.el.addClass(placement);
20870 //this.el.appendTo(on_el);
20872 var p = this.getPosition();
20873 var box = this.el.getBox();
20878 var align = Roo.bootstrap.Tooltip.alignment[placement]
20879 this.el.alignTo(this.bindEl, align[0],align[1]);
20880 //var arrow = this.el.select('.arrow',true).first();
20881 //arrow.set(align[2],
20883 this.el.addClass('in fade');
20884 this.hoverState = null;
20886 if (this.el.hasClass('fade')) {
20897 //this.el.setXY([0,0]);
20898 this.el.removeClass('in');
20914 * @class Roo.bootstrap.LocationPicker
20915 * @extends Roo.bootstrap.Component
20916 * Bootstrap LocationPicker class
20917 * @cfg {Number} latitude Position when init default 0
20918 * @cfg {Number} longitude Position when init default 0
20919 * @cfg {Number} zoom default 15
20920 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
20921 * @cfg {Boolean} mapTypeControl default false
20922 * @cfg {Boolean} disableDoubleClickZoom default false
20923 * @cfg {Boolean} scrollwheel default true
20924 * @cfg {Boolean} streetViewControl default false
20925 * @cfg {Number} radius default 0
20926 * @cfg {String} locationName
20927 * @cfg {Boolean} draggable default true
20928 * @cfg {Boolean} enableAutocomplete default false
20929 * @cfg {Boolean} enableReverseGeocode default true
20930 * @cfg {String} markerTitle
20933 * Create a new LocationPicker
20934 * @param {Object} config The config object
20937 Roo.bootstrap.LocationPicker = function(config){
20938 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
20942 * @event positionchanged
20943 * Fires when the picker initialized.
20944 * @param {Roo.bootstrap.LocationPicker} this
20945 * @param {Google Location} location
20947 positionchanged : true
20952 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
20954 gMapContext: false,
20959 mapTypeId: google.maps.MapTypeId.ROADMAP,
20960 mapTypeControl: false,
20961 disableDoubleClickZoom: false,
20963 streetViewControl: false,
20967 enableAutocomplete: false,
20968 enableReverseGeocode: true,
20971 getAutoCreate: function()
20975 cls: 'roo-location-picker'
20981 initEvents: function(ct, position)
20986 initial: function()
20988 if (this.isApplied()){
20992 this.gMapContext = this.GMapContext();
20996 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
20997 _this.setPosition(_this.gMapContext.marker.position);
21000 this.setPosition(this.gMapContext.location);
21003 isApplied: function()
21005 return this.getGmapContext() == false ? false : true;
21008 getGmapContext: function()
21010 return this.gMapContext
21013 GMapContext: function()
21015 var _map = new google.maps.Map(this.el.dom, this);
21016 var _marker = new google.maps.Marker({
21017 position: new google.maps.LatLng(this.latitude, this.longitude),
21019 title: this.markerTitle,
21020 draggable: this.draggable
21027 location: _marker.position,
21028 radius: this.radius,
21029 locationName: this.locationName,
21030 addressComponents: {
21031 formatted_address: null,
21032 addressLine1: null,
21033 addressLine2: null,
21035 streetNumber: null,
21039 stateOrProvince: null
21042 domContainer: this.el.dom,
21043 geodecoder: new google.maps.Geocoder()
21047 drawCircle: function(center, radius, options)
21049 if (this.gMapContext.circle != null) {
21050 this.gMapContext.circle.setMap(null);
21054 options = Roo.apply({}, options, {
21055 strokeColor: "#0000FF",
21056 strokeOpacity: .35,
21058 fillColor: "#0000FF",
21062 options.map = this.gMapContext.map;
21063 options.radius = radius;
21064 options.center = center;
21065 this.gMapContext.circle = new google.maps.Circle(options);
21066 return this.gMapContext.circle;
21072 setPosition: function(location)
21074 this.gMapContext.location = location;
21075 this.gMapContext.marker.setPosition(location);
21076 this.gMapContext.map.panTo(location);
21077 this.drawCircle(location, this.gMapContext.radius, {});
21081 if (this.gMapContext.settings.enableReverseGeocode) {
21082 this.gMapContext.geodecoder.geocode({
21083 latLng: this.gMapContext.location
21084 }, function(results, status) {
21085 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21086 _this.gMapContext.locationName = results[0].formatted_address;
21087 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21092 this.fireEvent('positionchanged', this, location);
21095 setPositionByLatLng: function(latitude, longitude)
21097 this.setPosition(new google.maps.LatLng(latitude, longitude));
21100 getCurrentPosition: function()
21103 latitude: this.gMapContext.location.lat(),
21104 longitude: this.gMapContext.location.lng()
21108 getAddressName: function()
21110 return this.gMapContext.locationName;
21113 getAddressComponents: function()
21115 return this.gMapContext.addressComponents;
21118 address_component_from_google_geocode: function(address_components)
21121 for (var i = address_components.length - 1; i >= 0; i--) {
21122 var component = address_components[i];
21123 if (component.types.indexOf("postal_code") >= 0) {
21124 result.postalCode = component.short_name;
21125 } else if (component.types.indexOf("street_number") >= 0) {
21126 result.streetNumber = component.short_name;
21127 } else if (component.types.indexOf("route") >= 0) {
21128 result.streetName = component.short_name;
21129 } else if (component.types.indexOf("locality") >= 0) {
21130 result.city = component.short_name;
21131 } else if (component.types.indexOf("neighborhood") >= 0) {
21132 result.city = component.short_name;
21133 } else if (component.types.indexOf("sublocality") >= 0) {
21134 result.district = component.short_name;
21135 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
21136 result.stateOrProvince = component.short_name;
21137 } else if (component.types.indexOf("country") >= 0) {
21138 result.country = component.short_name;
21141 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
21142 result.addressLine2 = "";