4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
104 cfg.id = this.id || Roo.id();
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
129 this.el = ct.createChild(cfg, position);
132 this.tooltipEl().attr('tooltip', this.tooltip);
135 if(this.tabIndex !== undefined){
136 this.el.dom.setAttribute('tabIndex', this.tabIndex);
143 * Fetch the element to add children to
144 * @return {Roo.Element} defaults to this.el
146 getChildContainer : function()
151 * Fetch the element to display the tooltip on.
152 * @return {Roo.Element} defaults to this.el
154 tooltipEl : function()
159 addxtype : function(tree,cntr)
163 cn = Roo.factory(tree);
165 cn.parentType = this.xtype; //??
166 cn.parentId = this.id;
168 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
169 if (typeof(cn.container_method) == 'string') {
170 cntr = cn.container_method;
174 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
176 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
178 var build_from_html = Roo.XComponent.build_from_html;
180 var is_body = (tree.xtype == 'Body') ;
182 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
184 var self_cntr_el = Roo.get(this[cntr](false));
186 // do not try and build conditional elements
187 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
192 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
193 return this.addxtypeChild(tree,cntr);
196 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202 Roo.log('skipping render');
208 if (!build_from_html) {
212 // this i think handles overlaying multiple children of the same type
213 // with the sam eelement.. - which might be buggy..
215 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
221 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
230 addxtypeChild : function (tree, cntr)
232 Roo.debug && Roo.log('addxtypeChild:' + cntr);
234 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
237 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
238 (typeof(tree['flexy:foreach']) != 'undefined');
242 skip_children = false;
243 // render the element if it's not BODY.
244 if (tree.xtype != 'Body') {
246 cn = Roo.factory(tree);
248 cn.parentType = this.xtype; //??
249 cn.parentId = this.id;
251 var build_from_html = Roo.XComponent.build_from_html;
254 // does the container contain child eleemnts with 'xtype' attributes.
255 // that match this xtype..
256 // note - when we render we create these as well..
257 // so we should check to see if body has xtype set.
258 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
260 var self_cntr_el = Roo.get(this[cntr](false));
261 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
263 //Roo.log(Roo.XComponent.build_from_html);
264 //Roo.log("got echild:");
267 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
268 // and are not displayed -this causes this to use up the wrong element when matching.
269 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
272 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
273 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
279 //echild.dom.removeAttribute('xtype');
281 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
282 Roo.debug && Roo.log(self_cntr_el);
283 Roo.debug && Roo.log(echild);
284 Roo.debug && Roo.log(cn);
290 // if object has flexy:if - then it may or may not be rendered.
291 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
292 // skip a flexy if element.
293 Roo.debug && Roo.log('skipping render');
294 Roo.debug && Roo.log(tree);
296 Roo.debug && Roo.log('skipping all children');
297 skip_children = true;
302 // actually if flexy:foreach is found, we really want to create
303 // multiple copies here...
305 //Roo.log(this[cntr]());
306 cn.render(this[cntr](true));
308 // then add the element..
316 if (typeof (tree.menu) != 'undefined') {
317 tree.menu.parentType = cn.xtype;
318 tree.menu.triggerEl = cn.el;
319 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
323 if (!tree.items || !tree.items.length) {
327 var items = tree.items;
330 //Roo.log(items.length);
332 if (!skip_children) {
333 for(var i =0;i < items.length;i++) {
334 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
340 this.fireEvent('childrenrendered', this);
345 * Show a component - removes 'hidden' class
350 this.el.removeClass('hidden');
354 * Hide a component - adds 'hidden' class
358 if (this.el && !this.el.hasClass('hidden')) {
359 this.el.addClass('hidden');
373 * @class Roo.bootstrap.Body
374 * @extends Roo.bootstrap.Component
375 * Bootstrap Body class
379 * @param {Object} config The config object
382 Roo.bootstrap.Body = function(config){
383 Roo.bootstrap.Body.superclass.constructor.call(this, config);
384 this.el = Roo.get(document.body);
385 if (this.cls && this.cls.length) {
386 Roo.get(document.body).addClass(this.cls);
390 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
395 onRender : function(ct, position)
397 /* Roo.log("Roo.bootstrap.Body - onRender");
398 if (this.cls && this.cls.length) {
399 Roo.get(document.body).addClass(this.cls);
419 * @class Roo.bootstrap.ButtonGroup
420 * @extends Roo.bootstrap.Component
421 * Bootstrap ButtonGroup class
422 * @cfg {String} size lg | sm | xs (default empty normal)
423 * @cfg {String} align vertical | justified (default none)
424 * @cfg {String} direction up | down (default down)
425 * @cfg {Boolean} toolbar false | true
426 * @cfg {Boolean} btn true | false
431 * @param {Object} config The config object
434 Roo.bootstrap.ButtonGroup = function(config){
435 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
438 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
446 getAutoCreate : function(){
452 cfg.html = this.html || cfg.html;
463 if (['vertical','justified'].indexOf(this.align)!==-1) {
464 cfg.cls = 'btn-group-' + this.align;
466 if (this.align == 'justified') {
467 console.log(this.items);
471 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
472 cfg.cls += ' btn-group-' + this.size;
475 if (this.direction == 'up') {
476 cfg.cls += ' dropup' ;
492 * @class Roo.bootstrap.Button
493 * @extends Roo.bootstrap.Component
494 * Bootstrap Button class
495 * @cfg {String} html The button content
496 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
497 * @cfg {String} size ( lg | sm | xs)
498 * @cfg {String} tag ( a | input | submit)
499 * @cfg {String} href empty or href
500 * @cfg {Boolean} disabled default false;
501 * @cfg {Boolean} isClose default false;
502 * @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)
503 * @cfg {String} badge text for badge
504 * @cfg {String} theme default
505 * @cfg {Boolean} inverse
506 * @cfg {Boolean} toggle
507 * @cfg {String} ontext text for on toggle state
508 * @cfg {String} offtext text for off toggle state
509 * @cfg {Boolean} defaulton
510 * @cfg {Boolean} preventDefault default true
511 * @cfg {Boolean} removeClass remove the standard class..
512 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
515 * Create a new button
516 * @param {Object} config The config object
520 Roo.bootstrap.Button = function(config){
521 Roo.bootstrap.Button.superclass.constructor.call(this, config);
526 * When a butotn is pressed
527 * @param {Roo.bootstrap.Button} this
528 * @param {Roo.EventObject} e
533 * After the button has been toggles
534 * @param {Roo.EventObject} e
535 * @param {boolean} pressed (also available as button.pressed)
541 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
559 preventDefault: true,
568 getAutoCreate : function(){
576 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
577 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
582 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
584 if (this.toggle == true) {
587 cls: 'slider-frame roo-button',
592 'data-off-text':'OFF',
593 cls: 'slider-button',
599 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
600 cfg.cls += ' '+this.weight;
609 cfg["aria-hidden"] = true;
611 cfg.html = "×";
617 if (this.theme==='default') {
618 cfg.cls = 'btn roo-button';
620 //if (this.parentType != 'Navbar') {
621 this.weight = this.weight.length ? this.weight : 'default';
623 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
625 cfg.cls += ' btn-' + this.weight;
627 } else if (this.theme==='glow') {
630 cfg.cls = 'btn-glow roo-button';
632 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
634 cfg.cls += ' ' + this.weight;
640 this.cls += ' inverse';
645 cfg.cls += ' active';
649 cfg.disabled = 'disabled';
653 Roo.log('changing to ul' );
655 this.glyphicon = 'caret';
658 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
660 //gsRoo.log(this.parentType);
661 if (this.parentType === 'Navbar' && !this.parent().bar) {
662 Roo.log('changing to li?');
671 href : this.href || '#'
674 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
675 cfg.cls += ' dropdown';
682 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
684 if (this.glyphicon) {
685 cfg.html = ' ' + cfg.html;
690 cls: 'glyphicon glyphicon-' + this.glyphicon
700 // cfg.cls='btn roo-button';
704 var value = cfg.html;
709 cls: 'glyphicon glyphicon-' + this.glyphicon,
728 cfg.cls += ' dropdown';
729 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
732 if (cfg.tag !== 'a' && this.href !== '') {
733 throw "Tag must be a to set href.";
734 } else if (this.href.length > 0) {
735 cfg.href = this.href;
738 if(this.removeClass){
743 cfg.target = this.target;
748 initEvents: function() {
749 // Roo.log('init events?');
750 // Roo.log(this.el.dom);
753 if (typeof (this.menu) != 'undefined') {
754 this.menu.parentType = this.xtype;
755 this.menu.triggerEl = this.el;
756 this.addxtype(Roo.apply({}, this.menu));
760 if (this.el.hasClass('roo-button')) {
761 this.el.on('click', this.onClick, this);
763 this.el.select('.roo-button').on('click', this.onClick, this);
766 if(this.removeClass){
767 this.el.on('click', this.onClick, this);
770 this.el.enableDisplayMode();
773 onClick : function(e)
780 Roo.log('button on click ');
781 if(this.preventDefault){
784 if (this.pressed === true || this.pressed === false) {
785 this.pressed = !this.pressed;
786 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
787 this.fireEvent('toggle', this, e, this.pressed);
791 this.fireEvent('click', this, e);
795 * Enables this button
799 this.disabled = false;
800 this.el.removeClass('disabled');
804 * Disable this button
808 this.disabled = true;
809 this.el.addClass('disabled');
812 * sets the active state on/off,
813 * @param {Boolean} state (optional) Force a particular state
815 setActive : function(v) {
817 this.el[v ? 'addClass' : 'removeClass']('active');
820 * toggles the current active state
822 toggleActive : function()
824 var active = this.el.hasClass('active');
825 this.setActive(!active);
829 setText : function(str)
831 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
835 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
858 * @class Roo.bootstrap.Column
859 * @extends Roo.bootstrap.Component
860 * Bootstrap Column class
861 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
862 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
863 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
864 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
865 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
866 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
867 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
868 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
871 * @cfg {Boolean} hidden (true|false) hide the element
872 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
873 * @cfg {String} fa (ban|check|...) font awesome icon
874 * @cfg {Number} fasize (1|2|....) font awsome size
876 * @cfg {String} icon (info-sign|check|...) glyphicon name
878 * @cfg {String} html content of column.
881 * Create a new Column
882 * @param {Object} config The config object
885 Roo.bootstrap.Column = function(config){
886 Roo.bootstrap.Column.superclass.constructor.call(this, config);
889 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
907 getAutoCreate : function(){
908 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
916 ['xs','sm','md','lg'].map(function(size){
917 //Roo.log( size + ':' + settings[size]);
919 if (settings[size+'off'] !== false) {
920 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
923 if (settings[size] === false) {
926 Roo.log(settings[size]);
927 if (!settings[size]) { // 0 = hidden
928 cfg.cls += ' hidden-' + size;
931 cfg.cls += ' col-' + size + '-' + settings[size];
936 cfg.cls += ' hidden';
939 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
940 cfg.cls +=' alert alert-' + this.alert;
944 if (this.html.length) {
945 cfg.html = this.html;
949 if (this.fasize > 1) {
950 fasize = ' fa-' + this.fasize + 'x';
952 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
957 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
976 * @class Roo.bootstrap.Container
977 * @extends Roo.bootstrap.Component
978 * Bootstrap Container class
979 * @cfg {Boolean} jumbotron is it a jumbotron element
980 * @cfg {String} html content of element
981 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
982 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
983 * @cfg {String} header content of header (for panel)
984 * @cfg {String} footer content of footer (for panel)
985 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
986 * @cfg {String} tag (header|aside|section) type of HTML tag.
987 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
988 * @cfg {String} fa (ban|check|...) font awesome icon
989 * @cfg {String} icon (info-sign|check|...) glyphicon name
990 * @cfg {Boolean} hidden (true|false) hide the element
991 * @cfg {Boolean} expandable (true|false) default false
992 * @cfg {String} rheader contet on the right of header
996 * Create a new Container
997 * @param {Object} config The config object
1000 Roo.bootstrap.Container = function(config){
1001 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1007 * After the panel has been expand
1009 * @param {Roo.bootstrap.Container} this
1014 * After the panel has been collapsed
1016 * @param {Roo.bootstrap.Container} this
1022 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1039 getChildContainer : function() {
1045 if (this.panel.length) {
1046 return this.el.select('.panel-body',true).first();
1053 getAutoCreate : function(){
1056 tag : this.tag || 'div',
1060 if (this.jumbotron) {
1061 cfg.cls = 'jumbotron';
1066 // - this is applied by the parent..
1068 // cfg.cls = this.cls + '';
1071 if (this.sticky.length) {
1073 var bd = Roo.get(document.body);
1074 if (!bd.hasClass('bootstrap-sticky')) {
1075 bd.addClass('bootstrap-sticky');
1076 Roo.select('html',true).setStyle('height', '100%');
1079 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1083 if (this.well.length) {
1084 switch (this.well) {
1087 cfg.cls +=' well well-' +this.well;
1096 cfg.cls += ' hidden';
1100 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1101 cfg.cls +=' alert alert-' + this.alert;
1106 if (this.panel.length) {
1107 cfg.cls += ' panel panel-' + this.panel;
1109 if (this.header.length) {
1113 if(this.expandable){
1115 cfg.cls = cfg.cls + ' expandable';
1126 cls : 'panel-title',
1131 cls: 'panel-header-right',
1137 cls : 'panel-heading',
1150 if (this.footer.length) {
1152 cls : 'panel-footer',
1161 body.html = this.html || cfg.html;
1162 // prefix with the icons..
1164 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1167 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1172 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1173 cfg.cls = 'container';
1179 initEvents: function()
1181 if(!this.expandable){
1185 var headerEl = this.headerEl();
1191 headerEl.on('click', this.onToggleClick, this);
1195 onToggleClick : function()
1197 var headerEl = this.headerEl();
1213 if(this.fireEvent('expand', this)) {
1215 this.expanded = true;
1217 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1219 var toggleEl = this.toggleEl();
1225 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1230 collapse : function()
1232 if(this.fireEvent('collapse', this)) {
1234 this.expanded = false;
1236 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1238 var toggleEl = this.toggleEl();
1244 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1248 toggleEl : function()
1250 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1254 return this.el.select('.panel-heading .fa',true).first();
1257 headerEl : function()
1259 if(!this.el || !this.panel.length || !this.header.length){
1263 return this.el.select('.panel-heading',true).first()
1266 titleEl : function()
1268 if(!this.el || !this.panel.length || !this.header.length){
1272 return this.el.select('.panel-title',true).first();
1275 setTitle : function(v)
1277 var titleEl = this.titleEl();
1283 titleEl.dom.innerHTML = v;
1286 getTitle : function()
1289 var titleEl = this.titleEl();
1295 return titleEl.dom.innerHTML;
1298 setRightTitle : function(v)
1300 var t = this.el.select('.panel-header-right',true).first();
1306 t.dom.innerHTML = v;
1320 * @class Roo.bootstrap.Img
1321 * @extends Roo.bootstrap.Component
1322 * Bootstrap Img class
1323 * @cfg {Boolean} imgResponsive false | true
1324 * @cfg {String} border rounded | circle | thumbnail
1325 * @cfg {String} src image source
1326 * @cfg {String} alt image alternative text
1327 * @cfg {String} href a tag href
1328 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1329 * @cfg {String} xsUrl xs image source
1330 * @cfg {String} smUrl sm image source
1331 * @cfg {String} mdUrl md image source
1332 * @cfg {String} lgUrl lg image source
1335 * Create a new Input
1336 * @param {Object} config The config object
1339 Roo.bootstrap.Img = function(config){
1340 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1346 * The img click event for the img.
1347 * @param {Roo.EventObject} e
1353 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1355 imgResponsive: true,
1365 getAutoCreate : function()
1367 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1368 return this.createSingleImg();
1373 cls: 'roo-image-responsive-group',
1378 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1380 if(!_this[size + 'Url']){
1386 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1387 html: _this.html || cfg.html,
1388 src: _this[size + 'Url']
1391 img.cls += ' roo-image-responsive-' + size;
1393 var s = ['xs', 'sm', 'md', 'lg'];
1395 s.splice(s.indexOf(size), 1);
1397 Roo.each(s, function(ss){
1398 img.cls += ' hidden-' + ss;
1401 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1402 cfg.cls += ' img-' + _this.border;
1406 cfg.alt = _this.alt;
1419 a.target = _this.target;
1423 cfg.cn.push((_this.href) ? a : img);
1430 createSingleImg : function()
1434 cls: (this.imgResponsive) ? 'img-responsive' : '',
1438 cfg.html = this.html || cfg.html;
1440 cfg.src = this.src || cfg.src;
1442 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1443 cfg.cls += ' img-' + this.border;
1460 a.target = this.target;
1465 return (this.href) ? a : cfg;
1468 initEvents: function()
1471 this.el.on('click', this.onClick, this);
1476 onClick : function(e)
1478 Roo.log('img onclick');
1479 this.fireEvent('click', this, e);
1493 * @class Roo.bootstrap.Link
1494 * @extends Roo.bootstrap.Component
1495 * Bootstrap Link Class
1496 * @cfg {String} alt image alternative text
1497 * @cfg {String} href a tag href
1498 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1499 * @cfg {String} html the content of the link.
1500 * @cfg {String} anchor name for the anchor link
1502 * @cfg {Boolean} preventDefault (true | false) default false
1506 * Create a new Input
1507 * @param {Object} config The config object
1510 Roo.bootstrap.Link = function(config){
1511 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1517 * The img click event for the img.
1518 * @param {Roo.EventObject} e
1524 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1528 preventDefault: false,
1532 getAutoCreate : function()
1538 // anchor's do not require html/href...
1539 if (this.anchor === false) {
1540 cfg.html = this.html || '';
1541 cfg.href = this.href || '#';
1543 cfg.name = this.anchor;
1544 if (this.html !== false) {
1545 cfg.html = this.html;
1547 if (this.href !== false) {
1548 cfg.href = this.href;
1552 if(this.alt !== false){
1557 if(this.target !== false) {
1558 cfg.target = this.target;
1564 initEvents: function() {
1566 if(!this.href || this.preventDefault){
1567 this.el.on('click', this.onClick, this);
1571 onClick : function(e)
1573 if(this.preventDefault){
1576 //Roo.log('img onclick');
1577 this.fireEvent('click', this, e);
1590 * @class Roo.bootstrap.Header
1591 * @extends Roo.bootstrap.Component
1592 * Bootstrap Header class
1593 * @cfg {String} html content of header
1594 * @cfg {Number} level (1|2|3|4|5|6) default 1
1597 * Create a new Header
1598 * @param {Object} config The config object
1602 Roo.bootstrap.Header = function(config){
1603 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1606 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1614 getAutoCreate : function(){
1619 tag: 'h' + (1 *this.level),
1620 html: this.html || ''
1632 * Ext JS Library 1.1.1
1633 * Copyright(c) 2006-2007, Ext JS, LLC.
1635 * Originally Released Under LGPL - original licence link has changed is not relivant.
1638 * <script type="text/javascript">
1642 * @class Roo.bootstrap.MenuMgr
1643 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1646 Roo.bootstrap.MenuMgr = function(){
1647 var menus, active, groups = {}, attached = false, lastShow = new Date();
1649 // private - called when first menu is created
1652 active = new Roo.util.MixedCollection();
1653 Roo.get(document).addKeyListener(27, function(){
1654 if(active.length > 0){
1662 if(active && active.length > 0){
1663 var c = active.clone();
1673 if(active.length < 1){
1674 Roo.get(document).un("mouseup", onMouseDown);
1682 var last = active.last();
1683 lastShow = new Date();
1686 Roo.get(document).on("mouseup", onMouseDown);
1691 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1692 m.parentMenu.activeChild = m;
1693 }else if(last && last.isVisible()){
1694 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1699 function onBeforeHide(m){
1701 m.activeChild.hide();
1703 if(m.autoHideTimer){
1704 clearTimeout(m.autoHideTimer);
1705 delete m.autoHideTimer;
1710 function onBeforeShow(m){
1711 var pm = m.parentMenu;
1712 if(!pm && !m.allowOtherMenus){
1714 }else if(pm && pm.activeChild && active != m){
1715 pm.activeChild.hide();
1719 // private this should really trigger on mouseup..
1720 function onMouseDown(e){
1721 Roo.log("on Mouse Up");
1722 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1732 function onBeforeCheck(mi, state){
1734 var g = groups[mi.group];
1735 for(var i = 0, l = g.length; i < l; i++){
1737 g[i].setChecked(false);
1746 * Hides all menus that are currently visible
1748 hideAll : function(){
1753 register : function(menu){
1757 menus[menu.id] = menu;
1758 menu.on("beforehide", onBeforeHide);
1759 menu.on("hide", onHide);
1760 menu.on("beforeshow", onBeforeShow);
1761 menu.on("show", onShow);
1763 if(g && menu.events["checkchange"]){
1767 groups[g].push(menu);
1768 menu.on("checkchange", onCheck);
1773 * Returns a {@link Roo.menu.Menu} object
1774 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1775 * be used to generate and return a new Menu instance.
1777 get : function(menu){
1778 if(typeof menu == "string"){ // menu id
1780 }else if(menu.events){ // menu instance
1783 /*else if(typeof menu.length == 'number'){ // array of menu items?
1784 return new Roo.bootstrap.Menu({items:menu});
1785 }else{ // otherwise, must be a config
1786 return new Roo.bootstrap.Menu(menu);
1793 unregister : function(menu){
1794 delete menus[menu.id];
1795 menu.un("beforehide", onBeforeHide);
1796 menu.un("hide", onHide);
1797 menu.un("beforeshow", onBeforeShow);
1798 menu.un("show", onShow);
1800 if(g && menu.events["checkchange"]){
1801 groups[g].remove(menu);
1802 menu.un("checkchange", onCheck);
1807 registerCheckable : function(menuItem){
1808 var g = menuItem.group;
1813 groups[g].push(menuItem);
1814 menuItem.on("beforecheckchange", onBeforeCheck);
1819 unregisterCheckable : function(menuItem){
1820 var g = menuItem.group;
1822 groups[g].remove(menuItem);
1823 menuItem.un("beforecheckchange", onBeforeCheck);
1835 * @class Roo.bootstrap.Menu
1836 * @extends Roo.bootstrap.Component
1837 * Bootstrap Menu class - container for MenuItems
1838 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1842 * @param {Object} config The config object
1846 Roo.bootstrap.Menu = function(config){
1847 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1848 if (this.registerMenu) {
1849 Roo.bootstrap.MenuMgr.register(this);
1854 * Fires before this menu is displayed
1855 * @param {Roo.menu.Menu} this
1860 * Fires before this menu is hidden
1861 * @param {Roo.menu.Menu} this
1866 * Fires after this menu is displayed
1867 * @param {Roo.menu.Menu} this
1872 * Fires after this menu is hidden
1873 * @param {Roo.menu.Menu} this
1878 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1879 * @param {Roo.menu.Menu} this
1880 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1881 * @param {Roo.EventObject} e
1886 * Fires when the mouse is hovering over this menu
1887 * @param {Roo.menu.Menu} this
1888 * @param {Roo.EventObject} e
1889 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1894 * Fires when the mouse exits this menu
1895 * @param {Roo.menu.Menu} this
1896 * @param {Roo.EventObject} e
1897 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1902 * Fires when a menu item contained in this menu is clicked
1903 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1904 * @param {Roo.EventObject} e
1908 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1911 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1915 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1918 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1920 registerMenu : true,
1922 menuItems :false, // stores the menu items..
1928 getChildContainer : function() {
1932 getAutoCreate : function(){
1934 //if (['right'].indexOf(this.align)!==-1) {
1935 // cfg.cn[1].cls += ' pull-right'
1941 cls : 'dropdown-menu' ,
1942 style : 'z-index:1000'
1946 if (this.type === 'submenu') {
1947 cfg.cls = 'submenu active';
1949 if (this.type === 'treeview') {
1950 cfg.cls = 'treeview-menu';
1955 initEvents : function() {
1957 // Roo.log("ADD event");
1958 // Roo.log(this.triggerEl.dom);
1959 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1961 this.triggerEl.addClass('dropdown-toggle');
1962 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1964 this.el.on("mouseover", this.onMouseOver, this);
1965 this.el.on("mouseout", this.onMouseOut, this);
1969 findTargetItem : function(e){
1970 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1974 //Roo.log(t); Roo.log(t.id);
1976 //Roo.log(this.menuitems);
1977 return this.menuitems.get(t.id);
1979 //return this.items.get(t.menuItemId);
1984 onClick : function(e){
1985 Roo.log("menu.onClick");
1986 var t = this.findTargetItem(e);
1987 if(!t || t.isContainer){
1992 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1993 if(t == this.activeItem && t.shouldDeactivate(e)){
1994 this.activeItem.deactivate();
1995 delete this.activeItem;
1999 this.setActiveItem(t, true);
2007 Roo.log('pass click event');
2011 this.fireEvent("click", this, t, e);
2015 onMouseOver : function(e){
2016 var t = this.findTargetItem(e);
2019 // if(t.canActivate && !t.disabled){
2020 // this.setActiveItem(t, true);
2024 this.fireEvent("mouseover", this, e, t);
2026 isVisible : function(){
2027 return !this.hidden;
2029 onMouseOut : function(e){
2030 var t = this.findTargetItem(e);
2033 // if(t == this.activeItem && t.shouldDeactivate(e)){
2034 // this.activeItem.deactivate();
2035 // delete this.activeItem;
2038 this.fireEvent("mouseout", this, e, t);
2043 * Displays this menu relative to another element
2044 * @param {String/HTMLElement/Roo.Element} element The element to align to
2045 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2046 * the element (defaults to this.defaultAlign)
2047 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2049 show : function(el, pos, parentMenu){
2050 this.parentMenu = parentMenu;
2054 this.fireEvent("beforeshow", this);
2055 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2058 * Displays this menu at a specific xy position
2059 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2060 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2062 showAt : function(xy, parentMenu, /* private: */_e){
2063 this.parentMenu = parentMenu;
2068 this.fireEvent("beforeshow", this);
2069 //xy = this.el.adjustForConstraints(xy);
2073 this.hideMenuItems();
2074 this.hidden = false;
2075 this.triggerEl.addClass('open');
2077 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2078 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2083 this.fireEvent("show", this);
2089 this.doFocus.defer(50, this);
2093 doFocus : function(){
2095 this.focusEl.focus();
2100 * Hides this menu and optionally all parent menus
2101 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2103 hide : function(deep){
2105 this.hideMenuItems();
2106 if(this.el && this.isVisible()){
2107 this.fireEvent("beforehide", this);
2108 if(this.activeItem){
2109 this.activeItem.deactivate();
2110 this.activeItem = null;
2112 this.triggerEl.removeClass('open');;
2114 this.fireEvent("hide", this);
2116 if(deep === true && this.parentMenu){
2117 this.parentMenu.hide(true);
2121 onTriggerPress : function(e)
2124 Roo.log('trigger press');
2125 //Roo.log(e.getTarget());
2126 // Roo.log(this.triggerEl.dom);
2127 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2131 if (this.isVisible()) {
2136 this.show(this.triggerEl, false, false);
2145 hideMenuItems : function()
2147 //$(backdrop).remove()
2148 Roo.select('.open',true).each(function(aa) {
2150 aa.removeClass('open');
2151 //var parent = getParent($(this))
2152 //var relatedTarget = { relatedTarget: this }
2154 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2155 //if (e.isDefaultPrevented()) return
2156 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2159 addxtypeChild : function (tree, cntr) {
2160 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2162 this.menuitems.add(comp);
2183 * @class Roo.bootstrap.MenuItem
2184 * @extends Roo.bootstrap.Component
2185 * Bootstrap MenuItem class
2186 * @cfg {String} html the menu label
2187 * @cfg {String} href the link
2188 * @cfg {Boolean} preventDefault (true | false) default true
2189 * @cfg {Boolean} isContainer (true | false) default false
2193 * Create a new MenuItem
2194 * @param {Object} config The config object
2198 Roo.bootstrap.MenuItem = function(config){
2199 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2204 * The raw click event for the entire grid.
2205 * @param {Roo.bootstrap.MenuItem} this
2206 * @param {Roo.EventObject} e
2212 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2216 preventDefault: true,
2217 isContainer : false,
2219 getAutoCreate : function(){
2221 if(this.isContainer){
2224 cls: 'dropdown-menu-item'
2230 cls: 'dropdown-menu-item',
2239 if (this.parent().type == 'treeview') {
2240 cfg.cls = 'treeview-menu';
2243 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2244 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2248 initEvents: function() {
2250 //this.el.select('a').on('click', this.onClick, this);
2253 onClick : function(e)
2255 Roo.log('item on click ');
2256 //if(this.preventDefault){
2257 // e.preventDefault();
2259 //this.parent().hideMenuItems();
2261 this.fireEvent('click', this, e);
2280 * @class Roo.bootstrap.MenuSeparator
2281 * @extends Roo.bootstrap.Component
2282 * Bootstrap MenuSeparator class
2285 * Create a new MenuItem
2286 * @param {Object} config The config object
2290 Roo.bootstrap.MenuSeparator = function(config){
2291 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2294 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2296 getAutoCreate : function(){
2315 * @class Roo.bootstrap.Modal
2316 * @extends Roo.bootstrap.Component
2317 * Bootstrap Modal class
2318 * @cfg {String} title Title of dialog
2319 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2320 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2321 * @cfg {Boolean} specificTitle default false
2322 * @cfg {Array} buttons Array of buttons or standard button set..
2323 * @cfg {String} buttonPosition (left|right|center) default right
2324 * @cfg {Boolean} animate default true
2325 * @cfg {Boolean} allow_close default true
2328 * Create a new Modal Dialog
2329 * @param {Object} config The config object
2332 Roo.bootstrap.Modal = function(config){
2333 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2338 * The raw btnclick event for the button
2339 * @param {Roo.EventObject} e
2343 this.buttons = this.buttons || [];
2346 this.tmpl = Roo.factory(this.tmpl);
2351 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2353 title : 'test dialog',
2363 specificTitle: false,
2365 buttonPosition: 'right',
2379 onRender : function(ct, position)
2381 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2384 var cfg = Roo.apply({}, this.getAutoCreate());
2387 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2389 //if (!cfg.name.length) {
2393 cfg.cls += ' ' + this.cls;
2396 cfg.style = this.style;
2398 this.el = Roo.get(document.body).createChild(cfg, position);
2400 //var type = this.el.dom.type;
2405 if(this.tabIndex !== undefined){
2406 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2410 this.bodyEl = this.el.select('.modal-body',true).first();
2411 this.closeEl = this.el.select('.modal-header .close', true).first();
2412 this.footerEl = this.el.select('.modal-footer',true).first();
2413 this.titleEl = this.el.select('.modal-title',true).first();
2417 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2418 this.maskEl.enableDisplayMode("block");
2420 //this.el.addClass("x-dlg-modal");
2422 if (this.buttons.length) {
2423 Roo.each(this.buttons, function(bb) {
2424 b = Roo.apply({}, bb);
2425 b.xns = b.xns || Roo.bootstrap;
2426 b.xtype = b.xtype || 'Button';
2427 if (typeof(b.listeners) == 'undefined') {
2428 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2431 var btn = Roo.factory(b);
2433 btn.onRender(this.el.select('.modal-footer div').first());
2437 // render the children.
2440 if(typeof(this.items) != 'undefined'){
2441 var items = this.items;
2444 for(var i =0;i < items.length;i++) {
2445 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2449 this.items = nitems;
2451 // where are these used - they used to be body/close/footer
2455 //this.el.addClass([this.fieldClass, this.cls]);
2459 getAutoCreate : function(){
2464 html : this.html || ''
2469 cls : 'modal-title',
2473 if(this.specificTitle){
2479 if (this.allow_close) {
2490 style : 'display: none',
2493 cls: "modal-dialog",
2496 cls : "modal-content",
2499 cls : 'modal-header',
2504 cls : 'modal-footer',
2508 cls: 'btn-' + this.buttonPosition
2525 modal.cls += ' fade';
2531 getChildContainer : function() {
2536 getButtonContainer : function() {
2537 return this.el.select('.modal-footer div',true).first();
2540 initEvents : function()
2542 if (this.allow_close) {
2543 this.closeEl.on('click', this.hide, this);
2549 if (!this.rendered) {
2553 this.el.setStyle('display', 'block');
2557 (function(){ _this.el.addClass('in'); }).defer(50);
2559 this.el.addClass('in');
2562 // not sure how we can show data in here..
2564 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2567 Roo.get(document.body).addClass("x-body-masked");
2568 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2570 this.el.setStyle('zIndex', '10001');
2572 this.fireEvent('show', this);
2579 Roo.get(document.body).removeClass("x-body-masked");
2580 this.el.removeClass('in');
2584 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2586 this.el.setStyle('display', 'none');
2589 this.fireEvent('hide', this);
2592 addButton : function(str, cb)
2596 var b = Roo.apply({}, { html : str } );
2597 b.xns = b.xns || Roo.bootstrap;
2598 b.xtype = b.xtype || 'Button';
2599 if (typeof(b.listeners) == 'undefined') {
2600 b.listeners = { click : cb.createDelegate(this) };
2603 var btn = Roo.factory(b);
2605 btn.onRender(this.el.select('.modal-footer div').first());
2611 setDefaultButton : function(btn)
2613 //this.el.select('.modal-footer').()
2615 resizeTo: function(w,h)
2619 setContentSize : function(w, h)
2623 onButtonClick: function(btn,e)
2626 this.fireEvent('btnclick', btn.name, e);
2629 * Set the title of the Dialog
2630 * @param {String} str new Title
2632 setTitle: function(str) {
2633 this.titleEl.dom.innerHTML = str;
2636 * Set the body of the Dialog
2637 * @param {String} str new Title
2639 setBody: function(str) {
2640 this.bodyEl.dom.innerHTML = str;
2643 * Set the body of the Dialog using the template
2644 * @param {Obj} data - apply this data to the template and replace the body contents.
2646 applyBody: function(obj)
2649 Roo.log("Error - using apply Body without a template");
2652 this.tmpl.overwrite(this.bodyEl, obj);
2658 Roo.apply(Roo.bootstrap.Modal, {
2660 * Button config that displays a single OK button
2669 * Button config that displays Yes and No buttons
2685 * Button config that displays OK and Cancel buttons
2700 * Button config that displays Yes, No and Cancel buttons
2723 * messagebox - can be used as a replace
2727 * @class Roo.MessageBox
2728 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2732 Roo.Msg.alert('Status', 'Changes saved successfully.');
2734 // Prompt for user data:
2735 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2737 // process text value...
2741 // Show a dialog using config options:
2743 title:'Save Changes?',
2744 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2745 buttons: Roo.Msg.YESNOCANCEL,
2752 Roo.bootstrap.MessageBox = function(){
2753 var dlg, opt, mask, waitTimer;
2754 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2755 var buttons, activeTextEl, bwidth;
2759 var handleButton = function(button){
2761 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2765 var handleHide = function(){
2767 dlg.el.removeClass(opt.cls);
2770 // Roo.TaskMgr.stop(waitTimer);
2771 // waitTimer = null;
2776 var updateButtons = function(b){
2779 buttons["ok"].hide();
2780 buttons["cancel"].hide();
2781 buttons["yes"].hide();
2782 buttons["no"].hide();
2783 //dlg.footer.dom.style.display = 'none';
2786 dlg.footerEl.dom.style.display = '';
2787 for(var k in buttons){
2788 if(typeof buttons[k] != "function"){
2791 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2792 width += buttons[k].el.getWidth()+15;
2802 var handleEsc = function(d, k, e){
2803 if(opt && opt.closable !== false){
2813 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2814 * @return {Roo.BasicDialog} The BasicDialog element
2816 getDialog : function(){
2818 dlg = new Roo.bootstrap.Modal( {
2821 //constraintoviewport:false,
2823 //collapsible : false,
2828 //buttonAlign:"center",
2829 closeClick : function(){
2830 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2833 handleButton("cancel");
2838 dlg.on("hide", handleHide);
2840 //dlg.addKeyListener(27, handleEsc);
2842 this.buttons = buttons;
2843 var bt = this.buttonText;
2844 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2845 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2846 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2847 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2849 bodyEl = dlg.bodyEl.createChild({
2851 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2852 '<textarea class="roo-mb-textarea"></textarea>' +
2853 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2855 msgEl = bodyEl.dom.firstChild;
2856 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2857 textboxEl.enableDisplayMode();
2858 textboxEl.addKeyListener([10,13], function(){
2859 if(dlg.isVisible() && opt && opt.buttons){
2862 }else if(opt.buttons.yes){
2863 handleButton("yes");
2867 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2868 textareaEl.enableDisplayMode();
2869 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2870 progressEl.enableDisplayMode();
2871 var pf = progressEl.dom.firstChild;
2873 pp = Roo.get(pf.firstChild);
2874 pp.setHeight(pf.offsetHeight);
2882 * Updates the message box body text
2883 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2884 * the XHTML-compliant non-breaking space character '&#160;')
2885 * @return {Roo.MessageBox} This message box
2887 updateText : function(text){
2888 if(!dlg.isVisible() && !opt.width){
2889 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2891 msgEl.innerHTML = text || ' ';
2893 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2894 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2896 Math.min(opt.width || cw , this.maxWidth),
2897 Math.max(opt.minWidth || this.minWidth, bwidth)
2900 activeTextEl.setWidth(w);
2902 if(dlg.isVisible()){
2903 dlg.fixedcenter = false;
2905 // to big, make it scroll. = But as usual stupid IE does not support
2908 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2909 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2910 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2912 bodyEl.dom.style.height = '';
2913 bodyEl.dom.style.overflowY = '';
2916 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2918 bodyEl.dom.style.overflowX = '';
2921 dlg.setContentSize(w, bodyEl.getHeight());
2922 if(dlg.isVisible()){
2923 dlg.fixedcenter = true;
2929 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2930 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2931 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2932 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2933 * @return {Roo.MessageBox} This message box
2935 updateProgress : function(value, text){
2937 this.updateText(text);
2939 if (pp) { // weird bug on my firefox - for some reason this is not defined
2940 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2946 * Returns true if the message box is currently displayed
2947 * @return {Boolean} True if the message box is visible, else false
2949 isVisible : function(){
2950 return dlg && dlg.isVisible();
2954 * Hides the message box if it is displayed
2957 if(this.isVisible()){
2963 * Displays a new message box, or reinitializes an existing message box, based on the config options
2964 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2965 * The following config object properties are supported:
2967 Property Type Description
2968 ---------- --------------- ------------------------------------------------------------------------------------
2969 animEl String/Element An id or Element from which the message box should animate as it opens and
2970 closes (defaults to undefined)
2971 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2972 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2973 closable Boolean False to hide the top-right close button (defaults to true). Note that
2974 progress and wait dialogs will ignore this property and always hide the
2975 close button as they can only be closed programmatically.
2976 cls String A custom CSS class to apply to the message box element
2977 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2978 displayed (defaults to 75)
2979 fn Function A callback function to execute after closing the dialog. The arguments to the
2980 function will be btn (the name of the button that was clicked, if applicable,
2981 e.g. "ok"), and text (the value of the active text field, if applicable).
2982 Progress and wait dialogs will ignore this option since they do not respond to
2983 user actions and can only be closed programmatically, so any required function
2984 should be called by the same code after it closes the dialog.
2985 icon String A CSS class that provides a background image to be used as an icon for
2986 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2987 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2988 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2989 modal Boolean False to allow user interaction with the page while the message box is
2990 displayed (defaults to true)
2991 msg String A string that will replace the existing message box body text (defaults
2992 to the XHTML-compliant non-breaking space character ' ')
2993 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2994 progress Boolean True to display a progress bar (defaults to false)
2995 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2996 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2997 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2998 title String The title text
2999 value String The string value to set into the active textbox element if displayed
3000 wait Boolean True to display a progress bar (defaults to false)
3001 width Number The width of the dialog in pixels
3008 msg: 'Please enter your address:',
3010 buttons: Roo.MessageBox.OKCANCEL,
3013 animEl: 'addAddressBtn'
3016 * @param {Object} config Configuration options
3017 * @return {Roo.MessageBox} This message box
3019 show : function(options)
3022 // this causes nightmares if you show one dialog after another
3023 // especially on callbacks..
3025 if(this.isVisible()){
3028 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3029 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3030 Roo.log("New Dialog Message:" + options.msg )
3031 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3032 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3035 var d = this.getDialog();
3037 d.setTitle(opt.title || " ");
3038 d.closeEl.setDisplayed(opt.closable !== false);
3039 activeTextEl = textboxEl;
3040 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3045 textareaEl.setHeight(typeof opt.multiline == "number" ?
3046 opt.multiline : this.defaultTextHeight);
3047 activeTextEl = textareaEl;
3056 progressEl.setDisplayed(opt.progress === true);
3057 this.updateProgress(0);
3058 activeTextEl.dom.value = opt.value || "";
3060 dlg.setDefaultButton(activeTextEl);
3062 var bs = opt.buttons;
3066 }else if(bs && bs.yes){
3067 db = buttons["yes"];
3069 dlg.setDefaultButton(db);
3071 bwidth = updateButtons(opt.buttons);
3072 this.updateText(opt.msg);
3074 d.el.addClass(opt.cls);
3076 d.proxyDrag = opt.proxyDrag === true;
3077 d.modal = opt.modal !== false;
3078 d.mask = opt.modal !== false ? mask : false;
3080 // force it to the end of the z-index stack so it gets a cursor in FF
3081 document.body.appendChild(dlg.el.dom);
3082 d.animateTarget = null;
3083 d.show(options.animEl);
3089 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3090 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3091 * and closing the message box when the process is complete.
3092 * @param {String} title The title bar text
3093 * @param {String} msg The message box body text
3094 * @return {Roo.MessageBox} This message box
3096 progress : function(title, msg){
3103 minWidth: this.minProgressWidth,
3110 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3111 * If a callback function is passed it will be called after the user clicks the button, and the
3112 * id of the button that was clicked will be passed as the only parameter to the callback
3113 * (could also be the top-right close button).
3114 * @param {String} title The title bar text
3115 * @param {String} msg The message box body text
3116 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3117 * @param {Object} scope (optional) The scope of the callback function
3118 * @return {Roo.MessageBox} This message box
3120 alert : function(title, msg, fn, scope){
3133 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3134 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3135 * You are responsible for closing the message box when the process is complete.
3136 * @param {String} msg The message box body text
3137 * @param {String} title (optional) The title bar text
3138 * @return {Roo.MessageBox} This message box
3140 wait : function(msg, title){
3151 waitTimer = Roo.TaskMgr.start({
3153 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3161 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3162 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3163 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3164 * @param {String} title The title bar text
3165 * @param {String} msg The message box body text
3166 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3167 * @param {Object} scope (optional) The scope of the callback function
3168 * @return {Roo.MessageBox} This message box
3170 confirm : function(title, msg, fn, scope){
3174 buttons: this.YESNO,
3183 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3184 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3185 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3186 * (could also be the top-right close button) and the text that was entered will be passed as the two
3187 * parameters to the callback.
3188 * @param {String} title The title bar text
3189 * @param {String} msg The message box body text
3190 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3191 * @param {Object} scope (optional) The scope of the callback function
3192 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3193 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3194 * @return {Roo.MessageBox} This message box
3196 prompt : function(title, msg, fn, scope, multiline){
3200 buttons: this.OKCANCEL,
3205 multiline: multiline,
3212 * Button config that displays a single OK button
3217 * Button config that displays Yes and No buttons
3220 YESNO : {yes:true, no:true},
3222 * Button config that displays OK and Cancel buttons
3225 OKCANCEL : {ok:true, cancel:true},
3227 * Button config that displays Yes, No and Cancel buttons
3230 YESNOCANCEL : {yes:true, no:true, cancel:true},
3233 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3236 defaultTextHeight : 75,
3238 * The maximum width in pixels of the message box (defaults to 600)
3243 * The minimum width in pixels of the message box (defaults to 100)
3248 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3249 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3252 minProgressWidth : 250,
3254 * An object containing the default button text strings that can be overriden for localized language support.
3255 * Supported properties are: ok, cancel, yes and no.
3256 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3269 * Shorthand for {@link Roo.MessageBox}
3271 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3272 Roo.Msg = Roo.Msg || Roo.MessageBox;
3281 * @class Roo.bootstrap.Navbar
3282 * @extends Roo.bootstrap.Component
3283 * Bootstrap Navbar class
3286 * Create a new Navbar
3287 * @param {Object} config The config object
3291 Roo.bootstrap.Navbar = function(config){
3292 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3296 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3305 getAutoCreate : function(){
3308 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3312 initEvents :function ()
3314 //Roo.log(this.el.select('.navbar-toggle',true));
3315 this.el.select('.navbar-toggle',true).on('click', function() {
3316 // Roo.log('click');
3317 this.el.select('.navbar-collapse',true).toggleClass('in');
3325 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3327 var size = this.el.getSize();
3328 this.maskEl.setSize(size.width, size.height);
3329 this.maskEl.enableDisplayMode("block");
3338 getChildContainer : function()
3340 if (this.el.select('.collapse').getCount()) {
3341 return this.el.select('.collapse',true).first();
3374 * @class Roo.bootstrap.NavSimplebar
3375 * @extends Roo.bootstrap.Navbar
3376 * Bootstrap Sidebar class
3378 * @cfg {Boolean} inverse is inverted color
3380 * @cfg {String} type (nav | pills | tabs)
3381 * @cfg {Boolean} arrangement stacked | justified
3382 * @cfg {String} align (left | right) alignment
3384 * @cfg {Boolean} main (true|false) main nav bar? default false
3385 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3387 * @cfg {String} tag (header|footer|nav|div) default is nav
3393 * Create a new Sidebar
3394 * @param {Object} config The config object
3398 Roo.bootstrap.NavSimplebar = function(config){
3399 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3402 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3418 getAutoCreate : function(){
3422 tag : this.tag || 'div',
3435 this.type = this.type || 'nav';
3436 if (['tabs','pills'].indexOf(this.type)!==-1) {
3437 cfg.cn[0].cls += ' nav-' + this.type
3441 if (this.type!=='nav') {
3442 Roo.log('nav type must be nav/tabs/pills')
3444 cfg.cn[0].cls += ' navbar-nav'
3450 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3451 cfg.cn[0].cls += ' nav-' + this.arrangement;
3455 if (this.align === 'right') {
3456 cfg.cn[0].cls += ' navbar-right';
3460 cfg.cls += ' navbar-inverse';
3487 * @class Roo.bootstrap.NavHeaderbar
3488 * @extends Roo.bootstrap.NavSimplebar
3489 * Bootstrap Sidebar class
3491 * @cfg {String} brand what is brand
3492 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3493 * @cfg {String} brand_href href of the brand
3494 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3495 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3496 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3497 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3500 * Create a new Sidebar
3501 * @param {Object} config The config object
3505 Roo.bootstrap.NavHeaderbar = function(config){
3506 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3510 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3517 desktopCenter : false,
3520 getAutoCreate : function(){
3523 tag: this.nav || 'nav',
3530 if (this.desktopCenter) {
3531 cn.push({cls : 'container', cn : []});
3538 cls: 'navbar-header',
3543 cls: 'navbar-toggle',
3544 'data-toggle': 'collapse',
3549 html: 'Toggle navigation'
3571 cls: 'collapse navbar-collapse',
3575 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3577 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3578 cfg.cls += ' navbar-' + this.position;
3580 // tag can override this..
3582 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3585 if (this.brand !== '') {
3588 href: this.brand_href ? this.brand_href : '#',
3589 cls: 'navbar-brand',
3597 cfg.cls += ' main-nav';
3605 getHeaderChildContainer : function()
3607 if (this.el.select('.navbar-header').getCount()) {
3608 return this.el.select('.navbar-header',true).first();
3611 return this.getChildContainer();
3615 initEvents : function()
3617 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3619 if (this.autohide) {
3624 Roo.get(document).on('scroll',function(e) {
3625 var ns = Roo.get(document).getScroll().top;
3626 var os = prevScroll;
3630 ft.removeClass('slideDown');
3631 ft.addClass('slideUp');
3634 ft.removeClass('slideUp');
3635 ft.addClass('slideDown');
3656 * @class Roo.bootstrap.NavSidebar
3657 * @extends Roo.bootstrap.Navbar
3658 * Bootstrap Sidebar class
3661 * Create a new Sidebar
3662 * @param {Object} config The config object
3666 Roo.bootstrap.NavSidebar = function(config){
3667 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3670 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3672 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3674 getAutoCreate : function(){
3679 cls: 'sidebar sidebar-nav'
3701 * @class Roo.bootstrap.NavGroup
3702 * @extends Roo.bootstrap.Component
3703 * Bootstrap NavGroup class
3704 * @cfg {String} align (left|right)
3705 * @cfg {Boolean} inverse
3706 * @cfg {String} type (nav|pills|tab) default nav
3707 * @cfg {String} navId - reference Id for navbar.
3711 * Create a new nav group
3712 * @param {Object} config The config object
3715 Roo.bootstrap.NavGroup = function(config){
3716 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3719 Roo.bootstrap.NavGroup.register(this);
3723 * Fires when the active item changes
3724 * @param {Roo.bootstrap.NavGroup} this
3725 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3726 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3733 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3744 getAutoCreate : function()
3746 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3753 if (['tabs','pills'].indexOf(this.type)!==-1) {
3754 cfg.cls += ' nav-' + this.type
3756 if (this.type!=='nav') {
3757 Roo.log('nav type must be nav/tabs/pills')
3759 cfg.cls += ' navbar-nav'
3762 if (this.parent().sidebar) {
3765 cls: 'dashboard-menu sidebar-menu'
3771 if (this.form === true) {
3777 if (this.align === 'right') {
3778 cfg.cls += ' navbar-right';
3780 cfg.cls += ' navbar-left';
3784 if (this.align === 'right') {
3785 cfg.cls += ' navbar-right';
3789 cfg.cls += ' navbar-inverse';
3797 * sets the active Navigation item
3798 * @param {Roo.bootstrap.NavItem} the new current navitem
3800 setActiveItem : function(item)
3803 Roo.each(this.navItems, function(v){
3808 v.setActive(false, true);
3815 item.setActive(true, true);
3816 this.fireEvent('changed', this, item, prev);
3821 * gets the active Navigation item
3822 * @return {Roo.bootstrap.NavItem} the current navitem
3824 getActive : function()
3828 Roo.each(this.navItems, function(v){
3839 indexOfNav : function()
3843 Roo.each(this.navItems, function(v,i){
3854 * adds a Navigation item
3855 * @param {Roo.bootstrap.NavItem} the navitem to add
3857 addItem : function(cfg)
3859 var cn = new Roo.bootstrap.NavItem(cfg);
3861 cn.parentId = this.id;
3862 cn.onRender(this.el, null);
3866 * register a Navigation item
3867 * @param {Roo.bootstrap.NavItem} the navitem to add
3869 register : function(item)
3871 this.navItems.push( item);
3872 item.navId = this.navId;
3877 * clear all the Navigation item
3880 clearAll : function()
3883 this.el.dom.innerHTML = '';
3886 getNavItem: function(tabId)
3889 Roo.each(this.navItems, function(e) {
3890 if (e.tabId == tabId) {
3900 setActiveNext : function()
3902 var i = this.indexOfNav(this.getActive());
3903 if (i > this.navItems.length) {
3906 this.setActiveItem(this.navItems[i+1]);
3908 setActivePrev : function()
3910 var i = this.indexOfNav(this.getActive());
3914 this.setActiveItem(this.navItems[i-1]);
3916 clearWasActive : function(except) {
3917 Roo.each(this.navItems, function(e) {
3918 if (e.tabId != except.tabId && e.was_active) {
3919 e.was_active = false;
3926 getWasActive : function ()
3929 Roo.each(this.navItems, function(e) {
3944 Roo.apply(Roo.bootstrap.NavGroup, {
3948 * register a Navigation Group
3949 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3951 register : function(navgrp)
3953 this.groups[navgrp.navId] = navgrp;
3957 * fetch a Navigation Group based on the navigation ID
3958 * @param {string} the navgroup to add
3959 * @returns {Roo.bootstrap.NavGroup} the navgroup
3961 get: function(navId) {
3962 if (typeof(this.groups[navId]) == 'undefined') {
3964 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3966 return this.groups[navId] ;
3981 * @class Roo.bootstrap.NavItem
3982 * @extends Roo.bootstrap.Component
3983 * Bootstrap Navbar.NavItem class
3984 * @cfg {String} href link to
3985 * @cfg {String} html content of button
3986 * @cfg {String} badge text inside badge
3987 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3988 * @cfg {String} glyphicon name of glyphicon
3989 * @cfg {String} icon name of font awesome icon
3990 * @cfg {Boolean} active Is item active
3991 * @cfg {Boolean} disabled Is item disabled
3993 * @cfg {Boolean} preventDefault (true | false) default false
3994 * @cfg {String} tabId the tab that this item activates.
3995 * @cfg {String} tagtype (a|span) render as a href or span?
3996 * @cfg {Boolean} animateRef (true|false) link to element default false
3999 * Create a new Navbar Item
4000 * @param {Object} config The config object
4002 Roo.bootstrap.NavItem = function(config){
4003 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4008 * The raw click event for the entire grid.
4009 * @param {Roo.EventObject} e
4014 * Fires when the active item active state changes
4015 * @param {Roo.bootstrap.NavItem} this
4016 * @param {boolean} state the new state
4022 * Fires when scroll to element
4023 * @param {Roo.bootstrap.NavItem} this
4024 * @param {Object} options
4025 * @param {Roo.EventObject} e
4033 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4041 preventDefault : false,
4048 getAutoCreate : function(){
4056 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4058 if (this.disabled) {
4059 cfg.cls += ' disabled';
4062 if (this.href || this.html || this.glyphicon || this.icon) {
4066 href : this.href || "#",
4067 html: this.html || ''
4072 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4075 if(this.glyphicon) {
4076 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4081 cfg.cn[0].html += " <span class='caret'></span>";
4085 if (this.badge !== '') {
4087 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4095 initEvents: function()
4097 if (typeof (this.menu) != 'undefined') {
4098 this.menu.parentType = this.xtype;
4099 this.menu.triggerEl = this.el;
4100 this.menu = this.addxtype(Roo.apply({}, this.menu));
4103 this.el.select('a',true).on('click', this.onClick, this);
4105 if(this.tagtype == 'span'){
4106 this.el.select('span',true).on('click', this.onClick, this);
4109 // at this point parent should be available..
4110 this.parent().register(this);
4113 onClick : function(e)
4116 this.preventDefault ||
4123 if (this.disabled) {
4127 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4128 if (tg && tg.transition) {
4129 Roo.log("waiting for the transitionend");
4135 //Roo.log("fire event clicked");
4136 if(this.fireEvent('click', this, e) === false){
4140 if(this.tagtype == 'span'){
4144 //Roo.log(this.href);
4145 var ael = this.el.select('a',true).first();
4148 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4149 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4150 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4151 return; // ignore... - it's a 'hash' to another page.
4155 this.scrollToElement(e);
4159 var p = this.parent();
4161 if (['tabs','pills'].indexOf(p.type)!==-1) {
4162 if (typeof(p.setActiveItem) !== 'undefined') {
4163 p.setActiveItem(this);
4167 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4168 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4169 // remove the collapsed menu expand...
4170 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4174 isActive: function () {
4177 setActive : function(state, fire, is_was_active)
4179 if (this.active && !state & this.navId) {
4180 this.was_active = true;
4181 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4183 nv.clearWasActive(this);
4187 this.active = state;
4190 this.el.removeClass('active');
4191 } else if (!this.el.hasClass('active')) {
4192 this.el.addClass('active');
4195 this.fireEvent('changed', this, state);
4198 // show a panel if it's registered and related..
4200 if (!this.navId || !this.tabId || !state || is_was_active) {
4204 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4208 var pan = tg.getPanelByName(this.tabId);
4212 // if we can not flip to new panel - go back to old nav highlight..
4213 if (false == tg.showPanel(pan)) {
4214 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4216 var onav = nv.getWasActive();
4218 onav.setActive(true, false, true);
4227 // this should not be here...
4228 setDisabled : function(state)
4230 this.disabled = state;
4232 this.el.removeClass('disabled');
4233 } else if (!this.el.hasClass('disabled')) {
4234 this.el.addClass('disabled');
4240 * Fetch the element to display the tooltip on.
4241 * @return {Roo.Element} defaults to this.el
4243 tooltipEl : function()
4245 return this.el.select('' + this.tagtype + '', true).first();
4248 scrollToElement : function(e)
4250 var c = document.body;
4253 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4255 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4256 c = document.documentElement;
4259 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4265 var o = target.calcOffsetsTo(c);
4272 this.fireEvent('scrollto', this, options, e);
4274 Roo.get(c).scrollTo('top', options.value, true);
4287 * <span> icon </span>
4288 * <span> text </span>
4289 * <span>badge </span>
4293 * @class Roo.bootstrap.NavSidebarItem
4294 * @extends Roo.bootstrap.NavItem
4295 * Bootstrap Navbar.NavSidebarItem class
4297 * Create a new Navbar Button
4298 * @param {Object} config The config object
4300 Roo.bootstrap.NavSidebarItem = function(config){
4301 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4306 * The raw click event for the entire grid.
4307 * @param {Roo.EventObject} e
4312 * Fires when the active item active state changes
4313 * @param {Roo.bootstrap.NavSidebarItem} this
4314 * @param {boolean} state the new state
4322 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4325 getAutoCreate : function(){
4330 href : this.href || '#',
4342 html : this.html || ''
4347 cfg.cls += ' active';
4351 if (this.glyphicon || this.icon) {
4352 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4353 a.cn.push({ tag : 'i', cls : c }) ;
4358 if (this.badge !== '') {
4359 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4363 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4364 a.cls += 'dropdown-toggle treeview' ;
4388 * @class Roo.bootstrap.Row
4389 * @extends Roo.bootstrap.Component
4390 * Bootstrap Row class (contains columns...)
4394 * @param {Object} config The config object
4397 Roo.bootstrap.Row = function(config){
4398 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4401 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4403 getAutoCreate : function(){
4422 * @class Roo.bootstrap.Element
4423 * @extends Roo.bootstrap.Component
4424 * Bootstrap Element class
4425 * @cfg {String} html contents of the element
4426 * @cfg {String} tag tag of the element
4427 * @cfg {String} cls class of the element
4428 * @cfg {Boolean} preventDefault (true|false) default false
4429 * @cfg {Boolean} clickable (true|false) default false
4432 * Create a new Element
4433 * @param {Object} config The config object
4436 Roo.bootstrap.Element = function(config){
4437 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4443 * When a element is chick
4444 * @param {Roo.bootstrap.Element} this
4445 * @param {Roo.EventObject} e
4451 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4456 preventDefault: false,
4459 getAutoCreate : function(){
4470 initEvents: function()
4472 Roo.bootstrap.Element.superclass.initEvents.call(this);
4475 this.el.on('click', this.onClick, this);
4480 onClick : function(e)
4482 if(this.preventDefault){
4486 this.fireEvent('click', this, e);
4489 getValue : function()
4491 return this.el.dom.innerHTML;
4494 setValue : function(value)
4496 this.el.dom.innerHTML = value;
4511 * @class Roo.bootstrap.Pagination
4512 * @extends Roo.bootstrap.Component
4513 * Bootstrap Pagination class
4514 * @cfg {String} size xs | sm | md | lg
4515 * @cfg {Boolean} inverse false | true
4518 * Create a new Pagination
4519 * @param {Object} config The config object
4522 Roo.bootstrap.Pagination = function(config){
4523 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4526 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4532 getAutoCreate : function(){
4538 cfg.cls += ' inverse';
4544 cfg.cls += " " + this.cls;
4562 * @class Roo.bootstrap.PaginationItem
4563 * @extends Roo.bootstrap.Component
4564 * Bootstrap PaginationItem class
4565 * @cfg {String} html text
4566 * @cfg {String} href the link
4567 * @cfg {Boolean} preventDefault (true | false) default true
4568 * @cfg {Boolean} active (true | false) default false
4569 * @cfg {Boolean} disabled default false
4573 * Create a new PaginationItem
4574 * @param {Object} config The config object
4578 Roo.bootstrap.PaginationItem = function(config){
4579 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4584 * The raw click event for the entire grid.
4585 * @param {Roo.EventObject} e
4591 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4595 preventDefault: true,
4600 getAutoCreate : function(){
4606 href : this.href ? this.href : '#',
4607 html : this.html ? this.html : ''
4617 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4621 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4627 initEvents: function() {
4629 this.el.on('click', this.onClick, this);
4632 onClick : function(e)
4634 Roo.log('PaginationItem on click ');
4635 if(this.preventDefault){
4643 this.fireEvent('click', this, e);
4659 * @class Roo.bootstrap.Slider
4660 * @extends Roo.bootstrap.Component
4661 * Bootstrap Slider class
4664 * Create a new Slider
4665 * @param {Object} config The config object
4668 Roo.bootstrap.Slider = function(config){
4669 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4672 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4674 getAutoCreate : function(){
4678 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4682 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4694 * Ext JS Library 1.1.1
4695 * Copyright(c) 2006-2007, Ext JS, LLC.
4697 * Originally Released Under LGPL - original licence link has changed is not relivant.
4700 * <script type="text/javascript">
4705 * @class Roo.grid.ColumnModel
4706 * @extends Roo.util.Observable
4707 * This is the default implementation of a ColumnModel used by the Grid. It defines
4708 * the columns in the grid.
4711 var colModel = new Roo.grid.ColumnModel([
4712 {header: "Ticker", width: 60, sortable: true, locked: true},
4713 {header: "Company Name", width: 150, sortable: true},
4714 {header: "Market Cap.", width: 100, sortable: true},
4715 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4716 {header: "Employees", width: 100, sortable: true, resizable: false}
4721 * The config options listed for this class are options which may appear in each
4722 * individual column definition.
4723 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4725 * @param {Object} config An Array of column config objects. See this class's
4726 * config objects for details.
4728 Roo.grid.ColumnModel = function(config){
4730 * The config passed into the constructor
4732 this.config = config;
4735 // if no id, create one
4736 // if the column does not have a dataIndex mapping,
4737 // map it to the order it is in the config
4738 for(var i = 0, len = config.length; i < len; i++){
4740 if(typeof c.dataIndex == "undefined"){
4743 if(typeof c.renderer == "string"){
4744 c.renderer = Roo.util.Format[c.renderer];
4746 if(typeof c.id == "undefined"){
4749 if(c.editor && c.editor.xtype){
4750 c.editor = Roo.factory(c.editor, Roo.grid);
4752 if(c.editor && c.editor.isFormField){
4753 c.editor = new Roo.grid.GridEditor(c.editor);
4755 this.lookup[c.id] = c;
4759 * The width of columns which have no width specified (defaults to 100)
4762 this.defaultWidth = 100;
4765 * Default sortable of columns which have no sortable specified (defaults to false)
4768 this.defaultSortable = false;
4772 * @event widthchange
4773 * Fires when the width of a column changes.
4774 * @param {ColumnModel} this
4775 * @param {Number} columnIndex The column index
4776 * @param {Number} newWidth The new width
4778 "widthchange": true,
4780 * @event headerchange
4781 * Fires when the text of a header changes.
4782 * @param {ColumnModel} this
4783 * @param {Number} columnIndex The column index
4784 * @param {Number} newText The new header text
4786 "headerchange": true,
4788 * @event hiddenchange
4789 * Fires when a column is hidden or "unhidden".
4790 * @param {ColumnModel} this
4791 * @param {Number} columnIndex The column index
4792 * @param {Boolean} hidden true if hidden, false otherwise
4794 "hiddenchange": true,
4796 * @event columnmoved
4797 * Fires when a column is moved.
4798 * @param {ColumnModel} this
4799 * @param {Number} oldIndex
4800 * @param {Number} newIndex
4802 "columnmoved" : true,
4804 * @event columlockchange
4805 * Fires when a column's locked state is changed
4806 * @param {ColumnModel} this
4807 * @param {Number} colIndex
4808 * @param {Boolean} locked true if locked
4810 "columnlockchange" : true
4812 Roo.grid.ColumnModel.superclass.constructor.call(this);
4814 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4816 * @cfg {String} header The header text to display in the Grid view.
4819 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4820 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4821 * specified, the column's index is used as an index into the Record's data Array.
4824 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4825 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4828 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4829 * Defaults to the value of the {@link #defaultSortable} property.
4830 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4833 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4836 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4839 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4842 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4845 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4846 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4847 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4848 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4851 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4854 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4857 * @cfg {String} cursor (Optional)
4860 * @cfg {String} tooltip (Optional)
4863 * Returns the id of the column at the specified index.
4864 * @param {Number} index The column index
4865 * @return {String} the id
4867 getColumnId : function(index){
4868 return this.config[index].id;
4872 * Returns the column for a specified id.
4873 * @param {String} id The column id
4874 * @return {Object} the column
4876 getColumnById : function(id){
4877 return this.lookup[id];
4882 * Returns the column for a specified dataIndex.
4883 * @param {String} dataIndex The column dataIndex
4884 * @return {Object|Boolean} the column or false if not found
4886 getColumnByDataIndex: function(dataIndex){
4887 var index = this.findColumnIndex(dataIndex);
4888 return index > -1 ? this.config[index] : false;
4892 * Returns the index for a specified column id.
4893 * @param {String} id The column id
4894 * @return {Number} the index, or -1 if not found
4896 getIndexById : function(id){
4897 for(var i = 0, len = this.config.length; i < len; i++){
4898 if(this.config[i].id == id){
4906 * Returns the index for a specified column dataIndex.
4907 * @param {String} dataIndex The column dataIndex
4908 * @return {Number} the index, or -1 if not found
4911 findColumnIndex : function(dataIndex){
4912 for(var i = 0, len = this.config.length; i < len; i++){
4913 if(this.config[i].dataIndex == dataIndex){
4921 moveColumn : function(oldIndex, newIndex){
4922 var c = this.config[oldIndex];
4923 this.config.splice(oldIndex, 1);
4924 this.config.splice(newIndex, 0, c);
4925 this.dataMap = null;
4926 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4929 isLocked : function(colIndex){
4930 return this.config[colIndex].locked === true;
4933 setLocked : function(colIndex, value, suppressEvent){
4934 if(this.isLocked(colIndex) == value){
4937 this.config[colIndex].locked = value;
4939 this.fireEvent("columnlockchange", this, colIndex, value);
4943 getTotalLockedWidth : function(){
4945 for(var i = 0; i < this.config.length; i++){
4946 if(this.isLocked(i) && !this.isHidden(i)){
4947 this.totalWidth += this.getColumnWidth(i);
4953 getLockedCount : function(){
4954 for(var i = 0, len = this.config.length; i < len; i++){
4955 if(!this.isLocked(i)){
4962 * Returns the number of columns.
4965 getColumnCount : function(visibleOnly){
4966 if(visibleOnly === true){
4968 for(var i = 0, len = this.config.length; i < len; i++){
4969 if(!this.isHidden(i)){
4975 return this.config.length;
4979 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4980 * @param {Function} fn
4981 * @param {Object} scope (optional)
4982 * @return {Array} result
4984 getColumnsBy : function(fn, scope){
4986 for(var i = 0, len = this.config.length; i < len; i++){
4987 var c = this.config[i];
4988 if(fn.call(scope||this, c, i) === true){
4996 * Returns true if the specified column is sortable.
4997 * @param {Number} col The column index
5000 isSortable : function(col){
5001 if(typeof this.config[col].sortable == "undefined"){
5002 return this.defaultSortable;
5004 return this.config[col].sortable;
5008 * Returns the rendering (formatting) function defined for the column.
5009 * @param {Number} col The column index.
5010 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5012 getRenderer : function(col){
5013 if(!this.config[col].renderer){
5014 return Roo.grid.ColumnModel.defaultRenderer;
5016 return this.config[col].renderer;
5020 * Sets the rendering (formatting) function for a column.
5021 * @param {Number} col The column index
5022 * @param {Function} fn The function to use to process the cell's raw data
5023 * to return HTML markup for the grid view. The render function is called with
5024 * the following parameters:<ul>
5025 * <li>Data value.</li>
5026 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5027 * <li>css A CSS style string to apply to the table cell.</li>
5028 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5029 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5030 * <li>Row index</li>
5031 * <li>Column index</li>
5032 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5034 setRenderer : function(col, fn){
5035 this.config[col].renderer = fn;
5039 * Returns the width for the specified column.
5040 * @param {Number} col The column index
5043 getColumnWidth : function(col){
5044 return this.config[col].width * 1 || this.defaultWidth;
5048 * Sets the width for a column.
5049 * @param {Number} col The column index
5050 * @param {Number} width The new width
5052 setColumnWidth : function(col, width, suppressEvent){
5053 this.config[col].width = width;
5054 this.totalWidth = null;
5056 this.fireEvent("widthchange", this, col, width);
5061 * Returns the total width of all columns.
5062 * @param {Boolean} includeHidden True to include hidden column widths
5065 getTotalWidth : function(includeHidden){
5066 if(!this.totalWidth){
5067 this.totalWidth = 0;
5068 for(var i = 0, len = this.config.length; i < len; i++){
5069 if(includeHidden || !this.isHidden(i)){
5070 this.totalWidth += this.getColumnWidth(i);
5074 return this.totalWidth;
5078 * Returns the header for the specified column.
5079 * @param {Number} col The column index
5082 getColumnHeader : function(col){
5083 return this.config[col].header;
5087 * Sets the header for a column.
5088 * @param {Number} col The column index
5089 * @param {String} header The new header
5091 setColumnHeader : function(col, header){
5092 this.config[col].header = header;
5093 this.fireEvent("headerchange", this, col, header);
5097 * Returns the tooltip for the specified column.
5098 * @param {Number} col The column index
5101 getColumnTooltip : function(col){
5102 return this.config[col].tooltip;
5105 * Sets the tooltip for a column.
5106 * @param {Number} col The column index
5107 * @param {String} tooltip The new tooltip
5109 setColumnTooltip : function(col, tooltip){
5110 this.config[col].tooltip = tooltip;
5114 * Returns the dataIndex for the specified column.
5115 * @param {Number} col The column index
5118 getDataIndex : function(col){
5119 return this.config[col].dataIndex;
5123 * Sets the dataIndex for a column.
5124 * @param {Number} col The column index
5125 * @param {Number} dataIndex The new dataIndex
5127 setDataIndex : function(col, dataIndex){
5128 this.config[col].dataIndex = dataIndex;
5134 * Returns true if the cell is editable.
5135 * @param {Number} colIndex The column index
5136 * @param {Number} rowIndex The row index
5139 isCellEditable : function(colIndex, rowIndex){
5140 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5144 * Returns the editor defined for the cell/column.
5145 * return false or null to disable editing.
5146 * @param {Number} colIndex The column index
5147 * @param {Number} rowIndex The row index
5150 getCellEditor : function(colIndex, rowIndex){
5151 return this.config[colIndex].editor;
5155 * Sets if a column is editable.
5156 * @param {Number} col The column index
5157 * @param {Boolean} editable True if the column is editable
5159 setEditable : function(col, editable){
5160 this.config[col].editable = editable;
5165 * Returns true if the column is hidden.
5166 * @param {Number} colIndex The column index
5169 isHidden : function(colIndex){
5170 return this.config[colIndex].hidden;
5175 * Returns true if the column width cannot be changed
5177 isFixed : function(colIndex){
5178 return this.config[colIndex].fixed;
5182 * Returns true if the column can be resized
5185 isResizable : function(colIndex){
5186 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5189 * Sets if a column is hidden.
5190 * @param {Number} colIndex The column index
5191 * @param {Boolean} hidden True if the column is hidden
5193 setHidden : function(colIndex, hidden){
5194 this.config[colIndex].hidden = hidden;
5195 this.totalWidth = null;
5196 this.fireEvent("hiddenchange", this, colIndex, hidden);
5200 * Sets the editor for a column.
5201 * @param {Number} col The column index
5202 * @param {Object} editor The editor object
5204 setEditor : function(col, editor){
5205 this.config[col].editor = editor;
5209 Roo.grid.ColumnModel.defaultRenderer = function(value){
5210 if(typeof value == "string" && value.length < 1){
5216 // Alias for backwards compatibility
5217 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5220 * Ext JS Library 1.1.1
5221 * Copyright(c) 2006-2007, Ext JS, LLC.
5223 * Originally Released Under LGPL - original licence link has changed is not relivant.
5226 * <script type="text/javascript">
5230 * @class Roo.LoadMask
5231 * A simple utility class for generically masking elements while loading data. If the element being masked has
5232 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5233 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5234 * element's UpdateManager load indicator and will be destroyed after the initial load.
5236 * Create a new LoadMask
5237 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5238 * @param {Object} config The config object
5240 Roo.LoadMask = function(el, config){
5241 this.el = Roo.get(el);
5242 Roo.apply(this, config);
5244 this.store.on('beforeload', this.onBeforeLoad, this);
5245 this.store.on('load', this.onLoad, this);
5246 this.store.on('loadexception', this.onLoadException, this);
5247 this.removeMask = false;
5249 var um = this.el.getUpdateManager();
5250 um.showLoadIndicator = false; // disable the default indicator
5251 um.on('beforeupdate', this.onBeforeLoad, this);
5252 um.on('update', this.onLoad, this);
5253 um.on('failure', this.onLoad, this);
5254 this.removeMask = true;
5258 Roo.LoadMask.prototype = {
5260 * @cfg {Boolean} removeMask
5261 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5262 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5266 * The text to display in a centered loading message box (defaults to 'Loading...')
5270 * @cfg {String} msgCls
5271 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5273 msgCls : 'x-mask-loading',
5276 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5282 * Disables the mask to prevent it from being displayed
5284 disable : function(){
5285 this.disabled = true;
5289 * Enables the mask so that it can be displayed
5291 enable : function(){
5292 this.disabled = false;
5295 onLoadException : function()
5299 if (typeof(arguments[3]) != 'undefined') {
5300 Roo.MessageBox.alert("Error loading",arguments[3]);
5304 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5305 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5314 this.el.unmask(this.removeMask);
5319 this.el.unmask(this.removeMask);
5323 onBeforeLoad : function(){
5325 this.el.mask(this.msg, this.msgCls);
5330 destroy : function(){
5332 this.store.un('beforeload', this.onBeforeLoad, this);
5333 this.store.un('load', this.onLoad, this);
5334 this.store.un('loadexception', this.onLoadException, this);
5336 var um = this.el.getUpdateManager();
5337 um.un('beforeupdate', this.onBeforeLoad, this);
5338 um.un('update', this.onLoad, this);
5339 um.un('failure', this.onLoad, this);
5350 * @class Roo.bootstrap.Table
5351 * @extends Roo.bootstrap.Component
5352 * Bootstrap Table class
5353 * @cfg {String} cls table class
5354 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5355 * @cfg {String} bgcolor Specifies the background color for a table
5356 * @cfg {Number} border Specifies whether the table cells should have borders or not
5357 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5358 * @cfg {Number} cellspacing Specifies the space between cells
5359 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5360 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5361 * @cfg {String} sortable Specifies that the table should be sortable
5362 * @cfg {String} summary Specifies a summary of the content of a table
5363 * @cfg {Number} width Specifies the width of a table
5364 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5366 * @cfg {boolean} striped Should the rows be alternative striped
5367 * @cfg {boolean} bordered Add borders to the table
5368 * @cfg {boolean} hover Add hover highlighting
5369 * @cfg {boolean} condensed Format condensed
5370 * @cfg {boolean} responsive Format condensed
5371 * @cfg {Boolean} loadMask (true|false) default false
5372 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5373 * @cfg {Boolean} thead (true|false) generate thead, default true
5374 * @cfg {Boolean} RowSelection (true|false) default false
5375 * @cfg {Boolean} CellSelection (true|false) default false
5376 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5380 * Create a new Table
5381 * @param {Object} config The config object
5384 Roo.bootstrap.Table = function(config){
5385 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5388 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5389 this.sm = this.selModel;
5390 this.sm.xmodule = this.xmodule || false;
5392 if (this.cm && typeof(this.cm.config) == 'undefined') {
5393 this.colModel = new Roo.grid.ColumnModel(this.cm);
5394 this.cm = this.colModel;
5395 this.cm.xmodule = this.xmodule || false;
5398 this.store= Roo.factory(this.store, Roo.data);
5399 this.ds = this.store;
5400 this.ds.xmodule = this.xmodule || false;
5403 if (this.footer && this.store) {
5404 this.footer.dataSource = this.ds;
5405 this.footer = Roo.factory(this.footer);
5412 * Fires when a cell is clicked
5413 * @param {Roo.bootstrap.Table} this
5414 * @param {Roo.Element} el
5415 * @param {Number} rowIndex
5416 * @param {Number} columnIndex
5417 * @param {Roo.EventObject} e
5421 * @event celldblclick
5422 * Fires when a cell is double clicked
5423 * @param {Roo.bootstrap.Table} this
5424 * @param {Roo.Element} el
5425 * @param {Number} rowIndex
5426 * @param {Number} columnIndex
5427 * @param {Roo.EventObject} e
5429 "celldblclick" : true,
5432 * Fires when a row is clicked
5433 * @param {Roo.bootstrap.Table} this
5434 * @param {Roo.Element} el
5435 * @param {Number} rowIndex
5436 * @param {Roo.EventObject} e
5440 * @event rowdblclick
5441 * Fires when a row is double clicked
5442 * @param {Roo.bootstrap.Table} this
5443 * @param {Roo.Element} el
5444 * @param {Number} rowIndex
5445 * @param {Roo.EventObject} e
5447 "rowdblclick" : true,
5450 * Fires when a mouseover occur
5451 * @param {Roo.bootstrap.Table} this
5452 * @param {Roo.Element} el
5453 * @param {Number} rowIndex
5454 * @param {Number} columnIndex
5455 * @param {Roo.EventObject} e
5460 * Fires when a mouseout occur
5461 * @param {Roo.bootstrap.Table} this
5462 * @param {Roo.Element} el
5463 * @param {Number} rowIndex
5464 * @param {Number} columnIndex
5465 * @param {Roo.EventObject} e
5470 * Fires when a row is rendered, so you can change add a style to it.
5471 * @param {Roo.bootstrap.Table} this
5472 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5476 * @event rowsrendered
5477 * Fires when all the rows have been rendered
5478 * @param {Roo.bootstrap.Table} this
5480 'rowsrendered' : true
5485 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5509 RowSelection : false,
5510 CellSelection : false,
5513 // Roo.Element - the tbody
5516 getAutoCreate : function(){
5517 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5526 cfg.cls += ' table-striped';
5530 cfg.cls += ' table-hover';
5532 if (this.bordered) {
5533 cfg.cls += ' table-bordered';
5535 if (this.condensed) {
5536 cfg.cls += ' table-condensed';
5538 if (this.responsive) {
5539 cfg.cls += ' table-responsive';
5543 cfg.cls+= ' ' +this.cls;
5546 // this lot should be simplifed...
5549 cfg.align=this.align;
5552 cfg.bgcolor=this.bgcolor;
5555 cfg.border=this.border;
5557 if (this.cellpadding) {
5558 cfg.cellpadding=this.cellpadding;
5560 if (this.cellspacing) {
5561 cfg.cellspacing=this.cellspacing;
5564 cfg.frame=this.frame;
5567 cfg.rules=this.rules;
5569 if (this.sortable) {
5570 cfg.sortable=this.sortable;
5573 cfg.summary=this.summary;
5576 cfg.width=this.width;
5579 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5582 if(this.store || this.cm){
5584 cfg.cn.push(this.renderHeader());
5587 cfg.cn.push(this.renderBody());
5590 cfg.cn.push(this.renderFooter());
5593 cfg.cls+= ' TableGrid';
5596 return { cn : [ cfg ] };
5599 initEvents : function()
5601 if(!this.store || !this.cm){
5605 //Roo.log('initEvents with ds!!!!');
5607 this.mainBody = this.el.select('tbody', true).first();
5612 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5613 e.on('click', _this.sort, _this);
5616 this.el.on("click", this.onClick, this);
5617 this.el.on("dblclick", this.onDblClick, this);
5619 // why is this done????? = it breaks dialogs??
5620 //this.parent().el.setStyle('position', 'relative');
5624 this.footer.parentId = this.id;
5625 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5628 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5630 this.store.on('load', this.onLoad, this);
5631 this.store.on('beforeload', this.onBeforeLoad, this);
5632 this.store.on('update', this.onUpdate, this);
5633 this.store.on('add', this.onAdd, this);
5637 onMouseover : function(e, el)
5639 var cell = Roo.get(el);
5645 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5646 cell = cell.findParent('td', false, true);
5649 var row = cell.findParent('tr', false, true);
5650 var cellIndex = cell.dom.cellIndex;
5651 var rowIndex = row.dom.rowIndex - 1; // start from 0
5653 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5657 onMouseout : function(e, el)
5659 var cell = Roo.get(el);
5665 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5666 cell = cell.findParent('td', false, true);
5669 var row = cell.findParent('tr', false, true);
5670 var cellIndex = cell.dom.cellIndex;
5671 var rowIndex = row.dom.rowIndex - 1; // start from 0
5673 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5677 onClick : function(e, el)
5679 var cell = Roo.get(el);
5681 if(!cell || (!this.CellSelection && !this.RowSelection)){
5685 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5686 cell = cell.findParent('td', false, true);
5689 if(!cell || typeof(cell) == 'undefined'){
5693 var row = cell.findParent('tr', false, true);
5695 if(!row || typeof(row) == 'undefined'){
5699 var cellIndex = cell.dom.cellIndex;
5700 var rowIndex = this.getRowIndex(row);
5702 if(this.CellSelection){
5703 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5706 if(this.RowSelection){
5707 this.fireEvent('rowclick', this, row, rowIndex, e);
5713 onDblClick : function(e,el)
5715 var cell = Roo.get(el);
5717 if(!cell || (!this.CellSelection && !this.RowSelection)){
5721 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5722 cell = cell.findParent('td', false, true);
5725 if(!cell || typeof(cell) == 'undefined'){
5729 var row = cell.findParent('tr', false, true);
5731 if(!row || typeof(row) == 'undefined'){
5735 var cellIndex = cell.dom.cellIndex;
5736 var rowIndex = this.getRowIndex(row);
5738 if(this.CellSelection){
5739 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5742 if(this.RowSelection){
5743 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5747 sort : function(e,el)
5749 var col = Roo.get(el);
5751 if(!col.hasClass('sortable')){
5755 var sort = col.attr('sort');
5758 if(col.hasClass('glyphicon-arrow-up')){
5762 this.store.sortInfo = {field : sort, direction : dir};
5765 Roo.log("calling footer first");
5766 this.footer.onClick('first');
5769 this.store.load({ params : { start : 0 } });
5773 renderHeader : function()
5782 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5784 var config = cm.config[i];
5789 html: cm.getColumnHeader(i)
5792 if(typeof(config.tooltip) != 'undefined'){
5793 c.tooltip = config.tooltip;
5796 if(typeof(config.colspan) != 'undefined'){
5797 c.colspan = config.colspan;
5800 if(typeof(config.hidden) != 'undefined' && config.hidden){
5801 c.style += ' display:none;';
5804 if(typeof(config.dataIndex) != 'undefined'){
5805 c.sort = config.dataIndex;
5808 if(typeof(config.sortable) != 'undefined' && config.sortable){
5812 if(typeof(config.align) != 'undefined' && config.align.length){
5813 c.style += ' text-align:' + config.align + ';';
5816 if(typeof(config.width) != 'undefined'){
5817 c.style += ' width:' + config.width + 'px;';
5820 if(typeof(config.cls) != 'undefined'){
5821 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5830 renderBody : function()
5840 colspan : this.cm.getColumnCount()
5850 renderFooter : function()
5860 colspan : this.cm.getColumnCount()
5874 Roo.log('ds onload');
5879 var ds = this.store;
5881 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5882 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5884 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5885 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5888 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5889 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5893 var tbody = this.mainBody;
5895 if(ds.getCount() > 0){
5896 ds.data.each(function(d,rowIndex){
5897 var row = this.renderRow(cm, ds, rowIndex);
5899 tbody.createChild(row);
5903 if(row.cellObjects.length){
5904 Roo.each(row.cellObjects, function(r){
5905 _this.renderCellObject(r);
5912 Roo.each(this.el.select('tbody td', true).elements, function(e){
5913 e.on('mouseover', _this.onMouseover, _this);
5916 Roo.each(this.el.select('tbody td', true).elements, function(e){
5917 e.on('mouseout', _this.onMouseout, _this);
5919 this.fireEvent('rowsrendered', this);
5920 //if(this.loadMask){
5921 // this.maskEl.hide();
5926 onUpdate : function(ds,record)
5928 this.refreshRow(record);
5931 onRemove : function(ds, record, index, isUpdate){
5932 if(isUpdate !== true){
5933 this.fireEvent("beforerowremoved", this, index, record);
5935 var bt = this.mainBody.dom;
5937 var rows = this.el.select('tbody > tr', true).elements;
5939 if(typeof(rows[index]) != 'undefined'){
5940 bt.removeChild(rows[index].dom);
5943 // if(bt.rows[index]){
5944 // bt.removeChild(bt.rows[index]);
5947 if(isUpdate !== true){
5948 //this.stripeRows(index);
5949 //this.syncRowHeights(index, index);
5951 this.fireEvent("rowremoved", this, index, record);
5955 onAdd : function(ds, records, rowIndex)
5957 //Roo.log('on Add called');
5958 // - note this does not handle multiple adding very well..
5959 var bt = this.mainBody.dom;
5960 for (var i =0 ; i < records.length;i++) {
5961 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5962 //Roo.log(records[i]);
5963 //Roo.log(this.store.getAt(rowIndex+i));
5964 this.insertRow(this.store, rowIndex + i, false);
5971 refreshRow : function(record){
5972 var ds = this.store, index;
5973 if(typeof record == 'number'){
5975 record = ds.getAt(index);
5977 index = ds.indexOf(record);
5979 this.insertRow(ds, index, true);
5980 this.onRemove(ds, record, index+1, true);
5981 //this.syncRowHeights(index, index);
5983 this.fireEvent("rowupdated", this, index, record);
5986 insertRow : function(dm, rowIndex, isUpdate){
5989 this.fireEvent("beforerowsinserted", this, rowIndex);
5991 //var s = this.getScrollState();
5992 var row = this.renderRow(this.cm, this.store, rowIndex);
5993 // insert before rowIndex..
5994 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5998 if(row.cellObjects.length){
5999 Roo.each(row.cellObjects, function(r){
6000 _this.renderCellObject(r);
6005 this.fireEvent("rowsinserted", this, rowIndex);
6006 //this.syncRowHeights(firstRow, lastRow);
6007 //this.stripeRows(firstRow);
6014 getRowDom : function(rowIndex)
6016 var rows = this.el.select('tbody > tr', true).elements;
6018 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6021 // returns the object tree for a tr..
6024 renderRow : function(cm, ds, rowIndex)
6027 var d = ds.getAt(rowIndex);
6034 var cellObjects = [];
6036 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6037 var config = cm.config[i];
6039 var renderer = cm.getRenderer(i);
6043 if(typeof(renderer) !== 'undefined'){
6044 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6046 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6047 // and are rendered into the cells after the row is rendered - using the id for the element.
6049 if(typeof(value) === 'object'){
6059 rowIndex : rowIndex,
6064 this.fireEvent('rowclass', this, rowcfg);
6068 cls : rowcfg.rowClass,
6070 html: (typeof(value) === 'object') ? '' : value
6077 if(typeof(config.colspan) != 'undefined'){
6078 td.colspan = config.colspan;
6081 if(typeof(config.hidden) != 'undefined' && config.hidden){
6082 td.style += ' display:none;';
6085 if(typeof(config.align) != 'undefined' && config.align.length){
6086 td.style += ' text-align:' + config.align + ';';
6089 if(typeof(config.width) != 'undefined'){
6090 td.style += ' width:' + config.width + 'px;';
6093 if(typeof(config.cursor) != 'undefined'){
6094 td.style += ' cursor:' + config.cursor + ';';
6097 if(typeof(config.cls) != 'undefined'){
6098 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6105 row.cellObjects = cellObjects;
6113 onBeforeLoad : function()
6115 //Roo.log('ds onBeforeLoad');
6119 //if(this.loadMask){
6120 // this.maskEl.show();
6128 this.el.select('tbody', true).first().dom.innerHTML = '';
6131 * Show or hide a row.
6132 * @param {Number} rowIndex to show or hide
6133 * @param {Boolean} state hide
6135 setRowVisibility : function(rowIndex, state)
6137 var bt = this.mainBody.dom;
6139 var rows = this.el.select('tbody > tr', true).elements;
6141 if(typeof(rows[rowIndex]) == 'undefined'){
6144 rows[rowIndex].dom.style.display = state ? '' : 'none';
6148 getSelectionModel : function(){
6150 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6152 return this.selModel;
6155 * Render the Roo.bootstrap object from renderder
6157 renderCellObject : function(r)
6161 var t = r.cfg.render(r.container);
6164 Roo.each(r.cfg.cn, function(c){
6166 container: t.getChildContainer(),
6169 _this.renderCellObject(child);
6174 getRowIndex : function(row)
6178 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6201 * @class Roo.bootstrap.TableCell
6202 * @extends Roo.bootstrap.Component
6203 * Bootstrap TableCell class
6204 * @cfg {String} html cell contain text
6205 * @cfg {String} cls cell class
6206 * @cfg {String} tag cell tag (td|th) default td
6207 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6208 * @cfg {String} align Aligns the content in a cell
6209 * @cfg {String} axis Categorizes cells
6210 * @cfg {String} bgcolor Specifies the background color of a cell
6211 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6212 * @cfg {Number} colspan Specifies the number of columns a cell should span
6213 * @cfg {String} headers Specifies one or more header cells a cell is related to
6214 * @cfg {Number} height Sets the height of a cell
6215 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6216 * @cfg {Number} rowspan Sets the number of rows a cell should span
6217 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6218 * @cfg {String} valign Vertical aligns the content in a cell
6219 * @cfg {Number} width Specifies the width of a cell
6222 * Create a new TableCell
6223 * @param {Object} config The config object
6226 Roo.bootstrap.TableCell = function(config){
6227 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6230 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6250 getAutoCreate : function(){
6251 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6271 cfg.align=this.align
6277 cfg.bgcolor=this.bgcolor
6280 cfg.charoff=this.charoff
6283 cfg.colspan=this.colspan
6286 cfg.headers=this.headers
6289 cfg.height=this.height
6292 cfg.nowrap=this.nowrap
6295 cfg.rowspan=this.rowspan
6298 cfg.scope=this.scope
6301 cfg.valign=this.valign
6304 cfg.width=this.width
6323 * @class Roo.bootstrap.TableRow
6324 * @extends Roo.bootstrap.Component
6325 * Bootstrap TableRow class
6326 * @cfg {String} cls row class
6327 * @cfg {String} align Aligns the content in a table row
6328 * @cfg {String} bgcolor Specifies a background color for a table row
6329 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6330 * @cfg {String} valign Vertical aligns the content in a table row
6333 * Create a new TableRow
6334 * @param {Object} config The config object
6337 Roo.bootstrap.TableRow = function(config){
6338 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6341 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6349 getAutoCreate : function(){
6350 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6360 cfg.align = this.align;
6363 cfg.bgcolor = this.bgcolor;
6366 cfg.charoff = this.charoff;
6369 cfg.valign = this.valign;
6387 * @class Roo.bootstrap.TableBody
6388 * @extends Roo.bootstrap.Component
6389 * Bootstrap TableBody class
6390 * @cfg {String} cls element class
6391 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6392 * @cfg {String} align Aligns the content inside the element
6393 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6394 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6397 * Create a new TableBody
6398 * @param {Object} config The config object
6401 Roo.bootstrap.TableBody = function(config){
6402 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6405 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6413 getAutoCreate : function(){
6414 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6428 cfg.align = this.align;
6431 cfg.charoff = this.charoff;
6434 cfg.valign = this.valign;
6441 // initEvents : function()
6448 // this.store = Roo.factory(this.store, Roo.data);
6449 // this.store.on('load', this.onLoad, this);
6451 // this.store.load();
6455 // onLoad: function ()
6457 // this.fireEvent('load', this);
6467 * Ext JS Library 1.1.1
6468 * Copyright(c) 2006-2007, Ext JS, LLC.
6470 * Originally Released Under LGPL - original licence link has changed is not relivant.
6473 * <script type="text/javascript">
6476 // as we use this in bootstrap.
6477 Roo.namespace('Roo.form');
6479 * @class Roo.form.Action
6480 * Internal Class used to handle form actions
6482 * @param {Roo.form.BasicForm} el The form element or its id
6483 * @param {Object} config Configuration options
6488 // define the action interface
6489 Roo.form.Action = function(form, options){
6491 this.options = options || {};
6494 * Client Validation Failed
6497 Roo.form.Action.CLIENT_INVALID = 'client';
6499 * Server Validation Failed
6502 Roo.form.Action.SERVER_INVALID = 'server';
6504 * Connect to Server Failed
6507 Roo.form.Action.CONNECT_FAILURE = 'connect';
6509 * Reading Data from Server Failed
6512 Roo.form.Action.LOAD_FAILURE = 'load';
6514 Roo.form.Action.prototype = {
6516 failureType : undefined,
6517 response : undefined,
6521 run : function(options){
6526 success : function(response){
6531 handleResponse : function(response){
6535 // default connection failure
6536 failure : function(response){
6538 this.response = response;
6539 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6540 this.form.afterAction(this, false);
6543 processResponse : function(response){
6544 this.response = response;
6545 if(!response.responseText){
6548 this.result = this.handleResponse(response);
6552 // utility functions used internally
6553 getUrl : function(appendParams){
6554 var url = this.options.url || this.form.url || this.form.el.dom.action;
6556 var p = this.getParams();
6558 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6564 getMethod : function(){
6565 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6568 getParams : function(){
6569 var bp = this.form.baseParams;
6570 var p = this.options.params;
6572 if(typeof p == "object"){
6573 p = Roo.urlEncode(Roo.applyIf(p, bp));
6574 }else if(typeof p == 'string' && bp){
6575 p += '&' + Roo.urlEncode(bp);
6578 p = Roo.urlEncode(bp);
6583 createCallback : function(){
6585 success: this.success,
6586 failure: this.failure,
6588 timeout: (this.form.timeout*1000),
6589 upload: this.form.fileUpload ? this.success : undefined
6594 Roo.form.Action.Submit = function(form, options){
6595 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6598 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6601 haveProgress : false,
6602 uploadComplete : false,
6604 // uploadProgress indicator.
6605 uploadProgress : function()
6607 if (!this.form.progressUrl) {
6611 if (!this.haveProgress) {
6612 Roo.MessageBox.progress("Uploading", "Uploading");
6614 if (this.uploadComplete) {
6615 Roo.MessageBox.hide();
6619 this.haveProgress = true;
6621 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6623 var c = new Roo.data.Connection();
6625 url : this.form.progressUrl,
6630 success : function(req){
6631 //console.log(data);
6635 rdata = Roo.decode(req.responseText)
6637 Roo.log("Invalid data from server..");
6641 if (!rdata || !rdata.success) {
6643 Roo.MessageBox.alert(Roo.encode(rdata));
6646 var data = rdata.data;
6648 if (this.uploadComplete) {
6649 Roo.MessageBox.hide();
6654 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6655 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6658 this.uploadProgress.defer(2000,this);
6661 failure: function(data) {
6662 Roo.log('progress url failed ');
6673 // run get Values on the form, so it syncs any secondary forms.
6674 this.form.getValues();
6676 var o = this.options;
6677 var method = this.getMethod();
6678 var isPost = method == 'POST';
6679 if(o.clientValidation === false || this.form.isValid()){
6681 if (this.form.progressUrl) {
6682 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6683 (new Date() * 1) + '' + Math.random());
6688 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6689 form:this.form.el.dom,
6690 url:this.getUrl(!isPost),
6692 params:isPost ? this.getParams() : null,
6693 isUpload: this.form.fileUpload
6696 this.uploadProgress();
6698 }else if (o.clientValidation !== false){ // client validation failed
6699 this.failureType = Roo.form.Action.CLIENT_INVALID;
6700 this.form.afterAction(this, false);
6704 success : function(response)
6706 this.uploadComplete= true;
6707 if (this.haveProgress) {
6708 Roo.MessageBox.hide();
6712 var result = this.processResponse(response);
6713 if(result === true || result.success){
6714 this.form.afterAction(this, true);
6718 this.form.markInvalid(result.errors);
6719 this.failureType = Roo.form.Action.SERVER_INVALID;
6721 this.form.afterAction(this, false);
6723 failure : function(response)
6725 this.uploadComplete= true;
6726 if (this.haveProgress) {
6727 Roo.MessageBox.hide();
6730 this.response = response;
6731 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6732 this.form.afterAction(this, false);
6735 handleResponse : function(response){
6736 if(this.form.errorReader){
6737 var rs = this.form.errorReader.read(response);
6740 for(var i = 0, len = rs.records.length; i < len; i++) {
6741 var r = rs.records[i];
6745 if(errors.length < 1){
6749 success : rs.success,
6755 ret = Roo.decode(response.responseText);
6759 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6769 Roo.form.Action.Load = function(form, options){
6770 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6771 this.reader = this.form.reader;
6774 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6779 Roo.Ajax.request(Roo.apply(
6780 this.createCallback(), {
6781 method:this.getMethod(),
6782 url:this.getUrl(false),
6783 params:this.getParams()
6787 success : function(response){
6789 var result = this.processResponse(response);
6790 if(result === true || !result.success || !result.data){
6791 this.failureType = Roo.form.Action.LOAD_FAILURE;
6792 this.form.afterAction(this, false);
6795 this.form.clearInvalid();
6796 this.form.setValues(result.data);
6797 this.form.afterAction(this, true);
6800 handleResponse : function(response){
6801 if(this.form.reader){
6802 var rs = this.form.reader.read(response);
6803 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6805 success : rs.success,
6809 return Roo.decode(response.responseText);
6813 Roo.form.Action.ACTION_TYPES = {
6814 'load' : Roo.form.Action.Load,
6815 'submit' : Roo.form.Action.Submit
6824 * @class Roo.bootstrap.Form
6825 * @extends Roo.bootstrap.Component
6826 * Bootstrap Form class
6827 * @cfg {String} method GET | POST (default POST)
6828 * @cfg {String} labelAlign top | left (default top)
6829 * @cfg {String} align left | right - for navbars
6830 * @cfg {Boolean} loadMask load mask when submit (default true)
6835 * @param {Object} config The config object
6839 Roo.bootstrap.Form = function(config){
6840 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6843 * @event clientvalidation
6844 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6845 * @param {Form} this
6846 * @param {Boolean} valid true if the form has passed client-side validation
6848 clientvalidation: true,
6850 * @event beforeaction
6851 * Fires before any action is performed. Return false to cancel the action.
6852 * @param {Form} this
6853 * @param {Action} action The action to be performed
6857 * @event actionfailed
6858 * Fires when an action fails.
6859 * @param {Form} this
6860 * @param {Action} action The action that failed
6862 actionfailed : true,
6864 * @event actioncomplete
6865 * Fires when an action is completed.
6866 * @param {Form} this
6867 * @param {Action} action The action that completed
6869 actioncomplete : true
6874 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6877 * @cfg {String} method
6878 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6883 * The URL to use for form actions if one isn't supplied in the action options.
6886 * @cfg {Boolean} fileUpload
6887 * Set to true if this form is a file upload.
6891 * @cfg {Object} baseParams
6892 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6896 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6900 * @cfg {Sting} align (left|right) for navbar forms
6905 activeAction : null,
6908 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6909 * element by passing it or its id or mask the form itself by passing in true.
6912 waitMsgTarget : false,
6916 getAutoCreate : function(){
6920 method : this.method || 'POST',
6921 id : this.id || Roo.id(),
6924 if (this.parent().xtype.match(/^Nav/)) {
6925 cfg.cls = 'navbar-form navbar-' + this.align;
6929 if (this.labelAlign == 'left' ) {
6930 cfg.cls += ' form-horizontal';
6936 initEvents : function()
6938 this.el.on('submit', this.onSubmit, this);
6939 // this was added as random key presses on the form where triggering form submit.
6940 this.el.on('keypress', function(e) {
6941 if (e.getCharCode() != 13) {
6944 // we might need to allow it for textareas.. and some other items.
6945 // check e.getTarget().
6947 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6951 Roo.log("keypress blocked");
6959 onSubmit : function(e){
6964 * Returns true if client-side validation on the form is successful.
6967 isValid : function(){
6968 var items = this.getItems();
6970 items.each(function(f){
6979 * Returns true if any fields in this form have changed since their original load.
6982 isDirty : function(){
6984 var items = this.getItems();
6985 items.each(function(f){
6995 * Performs a predefined action (submit or load) or custom actions you define on this form.
6996 * @param {String} actionName The name of the action type
6997 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6998 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6999 * accept other config options):
7001 Property Type Description
7002 ---------------- --------------- ----------------------------------------------------------------------------------
7003 url String The url for the action (defaults to the form's url)
7004 method String The form method to use (defaults to the form's method, or POST if not defined)
7005 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7006 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7007 validate the form on the client (defaults to false)
7009 * @return {BasicForm} this
7011 doAction : function(action, options){
7012 if(typeof action == 'string'){
7013 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7015 if(this.fireEvent('beforeaction', this, action) !== false){
7016 this.beforeAction(action);
7017 action.run.defer(100, action);
7023 beforeAction : function(action){
7024 var o = action.options;
7027 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7029 // not really supported yet.. ??
7031 //if(this.waitMsgTarget === true){
7032 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7033 //}else if(this.waitMsgTarget){
7034 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7035 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7037 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7043 afterAction : function(action, success){
7044 this.activeAction = null;
7045 var o = action.options;
7047 //if(this.waitMsgTarget === true){
7049 //}else if(this.waitMsgTarget){
7050 // this.waitMsgTarget.unmask();
7052 // Roo.MessageBox.updateProgress(1);
7053 // Roo.MessageBox.hide();
7060 Roo.callback(o.success, o.scope, [this, action]);
7061 this.fireEvent('actioncomplete', this, action);
7065 // failure condition..
7066 // we have a scenario where updates need confirming.
7067 // eg. if a locking scenario exists..
7068 // we look for { errors : { needs_confirm : true }} in the response.
7070 (typeof(action.result) != 'undefined') &&
7071 (typeof(action.result.errors) != 'undefined') &&
7072 (typeof(action.result.errors.needs_confirm) != 'undefined')
7075 Roo.log("not supported yet");
7078 Roo.MessageBox.confirm(
7079 "Change requires confirmation",
7080 action.result.errorMsg,
7085 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7095 Roo.callback(o.failure, o.scope, [this, action]);
7096 // show an error message if no failed handler is set..
7097 if (!this.hasListener('actionfailed')) {
7098 Roo.log("need to add dialog support");
7100 Roo.MessageBox.alert("Error",
7101 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7102 action.result.errorMsg :
7103 "Saving Failed, please check your entries or try again"
7108 this.fireEvent('actionfailed', this, action);
7113 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7114 * @param {String} id The value to search for
7117 findField : function(id){
7118 var items = this.getItems();
7119 var field = items.get(id);
7121 items.each(function(f){
7122 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7129 return field || null;
7132 * Mark fields in this form invalid in bulk.
7133 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7134 * @return {BasicForm} this
7136 markInvalid : function(errors){
7137 if(errors instanceof Array){
7138 for(var i = 0, len = errors.length; i < len; i++){
7139 var fieldError = errors[i];
7140 var f = this.findField(fieldError.id);
7142 f.markInvalid(fieldError.msg);
7148 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7149 field.markInvalid(errors[id]);
7153 //Roo.each(this.childForms || [], function (f) {
7154 // f.markInvalid(errors);
7161 * Set values for fields in this form in bulk.
7162 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7163 * @return {BasicForm} this
7165 setValues : function(values){
7166 if(values instanceof Array){ // array of objects
7167 for(var i = 0, len = values.length; i < len; i++){
7169 var f = this.findField(v.id);
7171 f.setValue(v.value);
7172 if(this.trackResetOnLoad){
7173 f.originalValue = f.getValue();
7177 }else{ // object hash
7180 if(typeof values[id] != 'function' && (field = this.findField(id))){
7182 if (field.setFromData &&
7184 field.displayField &&
7185 // combos' with local stores can
7186 // be queried via setValue()
7187 // to set their value..
7188 (field.store && !field.store.isLocal)
7192 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7193 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7194 field.setFromData(sd);
7197 field.setValue(values[id]);
7201 if(this.trackResetOnLoad){
7202 field.originalValue = field.getValue();
7208 //Roo.each(this.childForms || [], function (f) {
7209 // f.setValues(values);
7216 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7217 * they are returned as an array.
7218 * @param {Boolean} asString
7221 getValues : function(asString){
7222 //if (this.childForms) {
7223 // copy values from the child forms
7224 // Roo.each(this.childForms, function (f) {
7225 // this.setValues(f.getValues());
7231 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7232 if(asString === true){
7235 return Roo.urlDecode(fs);
7239 * Returns the fields in this form as an object with key/value pairs.
7240 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7243 getFieldValues : function(with_hidden)
7245 var items = this.getItems();
7247 items.each(function(f){
7251 var v = f.getValue();
7252 if (f.inputType =='radio') {
7253 if (typeof(ret[f.getName()]) == 'undefined') {
7254 ret[f.getName()] = ''; // empty..
7257 if (!f.el.dom.checked) {
7265 // not sure if this supported any more..
7266 if ((typeof(v) == 'object') && f.getRawValue) {
7267 v = f.getRawValue() ; // dates..
7269 // combo boxes where name != hiddenName...
7270 if (f.name != f.getName()) {
7271 ret[f.name] = f.getRawValue();
7273 ret[f.getName()] = v;
7280 * Clears all invalid messages in this form.
7281 * @return {BasicForm} this
7283 clearInvalid : function(){
7284 var items = this.getItems();
7286 items.each(function(f){
7297 * @return {BasicForm} this
7300 var items = this.getItems();
7301 items.each(function(f){
7305 Roo.each(this.childForms || [], function (f) {
7312 getItems : function()
7314 var r=new Roo.util.MixedCollection(false, function(o){
7315 return o.id || (o.id = Roo.id());
7317 var iter = function(el) {
7324 Roo.each(el.items,function(e) {
7344 * Ext JS Library 1.1.1
7345 * Copyright(c) 2006-2007, Ext JS, LLC.
7347 * Originally Released Under LGPL - original licence link has changed is not relivant.
7350 * <script type="text/javascript">
7353 * @class Roo.form.VTypes
7354 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7357 Roo.form.VTypes = function(){
7358 // closure these in so they are only created once.
7359 var alpha = /^[a-zA-Z_]+$/;
7360 var alphanum = /^[a-zA-Z0-9_]+$/;
7361 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7362 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7364 // All these messages and functions are configurable
7367 * The function used to validate email addresses
7368 * @param {String} value The email address
7370 'email' : function(v){
7371 return email.test(v);
7374 * The error text to display when the email validation function returns false
7377 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7379 * The keystroke filter mask to be applied on email input
7382 'emailMask' : /[a-z0-9_\.\-@]/i,
7385 * The function used to validate URLs
7386 * @param {String} value The URL
7388 'url' : function(v){
7392 * The error text to display when the url validation function returns false
7395 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7398 * The function used to validate alpha values
7399 * @param {String} value The value
7401 'alpha' : function(v){
7402 return alpha.test(v);
7405 * The error text to display when the alpha validation function returns false
7408 'alphaText' : 'This field should only contain letters and _',
7410 * The keystroke filter mask to be applied on alpha input
7413 'alphaMask' : /[a-z_]/i,
7416 * The function used to validate alphanumeric values
7417 * @param {String} value The value
7419 'alphanum' : function(v){
7420 return alphanum.test(v);
7423 * The error text to display when the alphanumeric validation function returns false
7426 'alphanumText' : 'This field should only contain letters, numbers and _',
7428 * The keystroke filter mask to be applied on alphanumeric input
7431 'alphanumMask' : /[a-z0-9_]/i
7441 * @class Roo.bootstrap.Input
7442 * @extends Roo.bootstrap.Component
7443 * Bootstrap Input class
7444 * @cfg {Boolean} disabled is it disabled
7445 * @cfg {String} fieldLabel - the label associated
7446 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7447 * @cfg {String} name name of the input
7448 * @cfg {string} fieldLabel - the label associated
7449 * @cfg {string} inputType - input / file submit ...
7450 * @cfg {string} placeholder - placeholder to put in text.
7451 * @cfg {string} before - input group add on before
7452 * @cfg {string} after - input group add on after
7453 * @cfg {string} size - (lg|sm) or leave empty..
7454 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7455 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7456 * @cfg {Number} md colspan out of 12 for computer-sized screens
7457 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7458 * @cfg {string} value default value of the input
7459 * @cfg {Number} labelWidth set the width of label (0-12)
7460 * @cfg {String} labelAlign (top|left)
7461 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7462 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7464 * @cfg {String} align (left|center|right) Default left
7469 * Create a new Input
7470 * @param {Object} config The config object
7473 Roo.bootstrap.Input = function(config){
7474 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7479 * Fires when this field receives input focus.
7480 * @param {Roo.form.Field} this
7485 * Fires when this field loses input focus.
7486 * @param {Roo.form.Field} this
7491 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7492 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7493 * @param {Roo.form.Field} this
7494 * @param {Roo.EventObject} e The event object
7499 * Fires just before the field blurs if the field value has changed.
7500 * @param {Roo.form.Field} this
7501 * @param {Mixed} newValue The new value
7502 * @param {Mixed} oldValue The original value
7507 * Fires after the field has been marked as invalid.
7508 * @param {Roo.form.Field} this
7509 * @param {String} msg The validation message
7514 * Fires after the field has been validated with no errors.
7515 * @param {Roo.form.Field} this
7520 * Fires after the key up
7521 * @param {Roo.form.Field} this
7522 * @param {Roo.EventObject} e The event Object
7528 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7530 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7531 automatic validation (defaults to "keyup").
7533 validationEvent : "keyup",
7535 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7537 validateOnBlur : true,
7539 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7541 validationDelay : 250,
7543 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7545 focusClass : "x-form-focus", // not needed???
7549 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7551 invalidClass : "has-warning",
7554 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7556 validClass : "has-success",
7559 * @cfg {Boolean} hasFeedback (true|false) default true
7564 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7566 invalidFeedbackClass : "glyphicon-warning-sign",
7569 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7571 validFeedbackClass : "glyphicon-ok",
7574 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7576 selectOnFocus : false,
7579 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7583 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7588 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7590 disableKeyFilter : false,
7593 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7597 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7601 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7603 blankText : "This field is required",
7606 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7610 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7612 maxLength : Number.MAX_VALUE,
7614 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7616 minLengthText : "The minimum length for this field is {0}",
7618 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7620 maxLengthText : "The maximum length for this field is {0}",
7624 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7625 * If available, this function will be called only after the basic validators all return true, and will be passed the
7626 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7630 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7631 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7632 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7636 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7640 autocomplete: false,
7659 formatedValue : false,
7661 parentLabelAlign : function()
7664 while (parent.parent()) {
7665 parent = parent.parent();
7666 if (typeof(parent.labelAlign) !='undefined') {
7667 return parent.labelAlign;
7674 getAutoCreate : function(){
7676 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7682 if(this.inputType != 'hidden'){
7683 cfg.cls = 'form-group' //input-group
7689 type : this.inputType,
7691 cls : 'form-control',
7692 placeholder : this.placeholder || '',
7693 autocomplete : this.autocomplete || 'new-password'
7698 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7701 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7702 input.maxLength = this.maxLength;
7705 if (this.disabled) {
7706 input.disabled=true;
7709 if (this.readOnly) {
7710 input.readonly=true;
7714 input.name = this.name;
7717 input.cls += ' input-' + this.size;
7720 ['xs','sm','md','lg'].map(function(size){
7721 if (settings[size]) {
7722 cfg.cls += ' col-' + size + '-' + settings[size];
7726 var inputblock = input;
7730 cls: 'glyphicon form-control-feedback'
7733 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7736 cls : 'has-feedback',
7744 if (this.before || this.after) {
7747 cls : 'input-group',
7751 if (this.before && typeof(this.before) == 'string') {
7753 inputblock.cn.push({
7755 cls : 'roo-input-before input-group-addon',
7759 if (this.before && typeof(this.before) == 'object') {
7760 this.before = Roo.factory(this.before);
7761 Roo.log(this.before);
7762 inputblock.cn.push({
7764 cls : 'roo-input-before input-group-' +
7765 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7769 inputblock.cn.push(input);
7771 if (this.after && typeof(this.after) == 'string') {
7772 inputblock.cn.push({
7774 cls : 'roo-input-after input-group-addon',
7778 if (this.after && typeof(this.after) == 'object') {
7779 this.after = Roo.factory(this.after);
7780 Roo.log(this.after);
7781 inputblock.cn.push({
7783 cls : 'roo-input-after input-group-' +
7784 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7788 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7789 inputblock.cls += ' has-feedback';
7790 inputblock.cn.push(feedback);
7794 if (align ==='left' && this.fieldLabel.length) {
7795 Roo.log("left and has label");
7801 cls : 'control-label col-sm-' + this.labelWidth,
7802 html : this.fieldLabel
7806 cls : "col-sm-" + (12 - this.labelWidth),
7813 } else if ( this.fieldLabel.length) {
7819 //cls : 'input-group-addon',
7820 html : this.fieldLabel
7830 Roo.log(" no label && no align");
7839 Roo.log('input-parentType: ' + this.parentType);
7841 if (this.parentType === 'Navbar' && this.parent().bar) {
7842 cfg.cls += ' navbar-form';
7850 * return the real input element.
7852 inputEl: function ()
7854 return this.el.select('input.form-control',true).first();
7857 tooltipEl : function()
7859 return this.inputEl();
7862 setDisabled : function(v)
7864 var i = this.inputEl().dom;
7866 i.removeAttribute('disabled');
7870 i.setAttribute('disabled','true');
7872 initEvents : function()
7875 this.inputEl().on("keydown" , this.fireKey, this);
7876 this.inputEl().on("focus", this.onFocus, this);
7877 this.inputEl().on("blur", this.onBlur, this);
7879 this.inputEl().relayEvent('keyup', this);
7881 // reference to original value for reset
7882 this.originalValue = this.getValue();
7883 //Roo.form.TextField.superclass.initEvents.call(this);
7884 if(this.validationEvent == 'keyup'){
7885 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7886 this.inputEl().on('keyup', this.filterValidation, this);
7888 else if(this.validationEvent !== false){
7889 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7892 if(this.selectOnFocus){
7893 this.on("focus", this.preFocus, this);
7896 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7897 this.inputEl().on("keypress", this.filterKeys, this);
7900 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7901 this.el.on("click", this.autoSize, this);
7904 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7905 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7908 if (typeof(this.before) == 'object') {
7909 this.before.render(this.el.select('.roo-input-before',true).first());
7911 if (typeof(this.after) == 'object') {
7912 this.after.render(this.el.select('.roo-input-after',true).first());
7917 filterValidation : function(e){
7918 if(!e.isNavKeyPress()){
7919 this.validationTask.delay(this.validationDelay);
7923 * Validates the field value
7924 * @return {Boolean} True if the value is valid, else false
7926 validate : function(){
7927 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7928 if(this.disabled || this.validateValue(this.getRawValue())){
7939 * Validates a value according to the field's validation rules and marks the field as invalid
7940 * if the validation fails
7941 * @param {Mixed} value The value to validate
7942 * @return {Boolean} True if the value is valid, else false
7944 validateValue : function(value){
7945 if(value.length < 1) { // if it's blank
7946 if(this.allowBlank){
7952 if(value.length < this.minLength){
7955 if(value.length > this.maxLength){
7959 var vt = Roo.form.VTypes;
7960 if(!vt[this.vtype](value, this)){
7964 if(typeof this.validator == "function"){
7965 var msg = this.validator(value);
7971 if(this.regex && !this.regex.test(value)){
7981 fireKey : function(e){
7982 //Roo.log('field ' + e.getKey());
7983 if(e.isNavKeyPress()){
7984 this.fireEvent("specialkey", this, e);
7987 focus : function (selectText){
7989 this.inputEl().focus();
7990 if(selectText === true){
7991 this.inputEl().dom.select();
7997 onFocus : function(){
7998 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7999 // this.el.addClass(this.focusClass);
8002 this.hasFocus = true;
8003 this.startValue = this.getValue();
8004 this.fireEvent("focus", this);
8008 beforeBlur : Roo.emptyFn,
8012 onBlur : function(){
8014 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8015 //this.el.removeClass(this.focusClass);
8017 this.hasFocus = false;
8018 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8021 var v = this.getValue();
8022 if(String(v) !== String(this.startValue)){
8023 this.fireEvent('change', this, v, this.startValue);
8025 this.fireEvent("blur", this);
8029 * Resets the current field value to the originally loaded value and clears any validation messages
8032 this.setValue(this.originalValue);
8036 * Returns the name of the field
8037 * @return {Mixed} name The name field
8039 getName: function(){
8043 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8044 * @return {Mixed} value The field value
8046 getValue : function(){
8048 var v = this.inputEl().getValue();
8053 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8054 * @return {Mixed} value The field value
8056 getRawValue : function(){
8057 var v = this.inputEl().getValue();
8063 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8064 * @param {Mixed} value The value to set
8066 setRawValue : function(v){
8067 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8070 selectText : function(start, end){
8071 var v = this.getRawValue();
8073 start = start === undefined ? 0 : start;
8074 end = end === undefined ? v.length : end;
8075 var d = this.inputEl().dom;
8076 if(d.setSelectionRange){
8077 d.setSelectionRange(start, end);
8078 }else if(d.createTextRange){
8079 var range = d.createTextRange();
8080 range.moveStart("character", start);
8081 range.moveEnd("character", v.length-end);
8088 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8089 * @param {Mixed} value The value to set
8091 setValue : function(v){
8094 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8100 processValue : function(value){
8101 if(this.stripCharsRe){
8102 var newValue = value.replace(this.stripCharsRe, '');
8103 if(newValue !== value){
8104 this.setRawValue(newValue);
8111 preFocus : function(){
8113 if(this.selectOnFocus){
8114 this.inputEl().dom.select();
8117 filterKeys : function(e){
8119 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8122 var c = e.getCharCode(), cc = String.fromCharCode(c);
8123 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8126 if(!this.maskRe.test(cc)){
8131 * Clear any invalid styles/messages for this field
8133 clearInvalid : function(){
8135 if(!this.el || this.preventMark){ // not rendered
8138 this.el.removeClass(this.invalidClass);
8140 this.fireEvent('valid', this);
8144 * Mark this field as valid
8146 markValid : function(){
8147 if(!this.el || this.preventMark){ // not rendered
8151 this.el.removeClass([this.invalidClass, this.validClass]);
8153 if(this.disabled || this.allowBlank){
8157 this.el.addClass(this.validClass);
8159 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8161 var feedback = this.el.select('.form-control-feedback', true).first();
8164 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8165 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8170 this.fireEvent('valid', this);
8174 * Mark this field as invalid
8175 * @param {String} msg The validation message
8177 markInvalid : function(msg){
8178 if(!this.el || this.preventMark){ // not rendered
8182 this.el.removeClass([this.invalidClass, this.validClass]);
8184 if(this.disabled || this.allowBlank){
8188 this.el.addClass(this.invalidClass);
8190 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8192 var feedback = this.el.select('.form-control-feedback', true).first();
8195 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8197 if(this.getValue().length){
8198 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8205 this.fireEvent('invalid', this, msg);
8208 SafariOnKeyDown : function(event)
8210 // this is a workaround for a password hang bug on chrome/ webkit.
8212 var isSelectAll = false;
8214 if(this.inputEl().dom.selectionEnd > 0){
8215 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8217 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8218 event.preventDefault();
8223 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8225 event.preventDefault();
8226 // this is very hacky as keydown always get's upper case.
8228 var cc = String.fromCharCode(event.getCharCode());
8229 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8233 adjustWidth : function(tag, w){
8234 tag = tag.toLowerCase();
8235 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8236 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8240 if(tag == 'textarea'){
8243 }else if(Roo.isOpera){
8247 if(tag == 'textarea'){
8266 * @class Roo.bootstrap.TextArea
8267 * @extends Roo.bootstrap.Input
8268 * Bootstrap TextArea class
8269 * @cfg {Number} cols Specifies the visible width of a text area
8270 * @cfg {Number} rows Specifies the visible number of lines in a text area
8271 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8272 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8273 * @cfg {string} html text
8276 * Create a new TextArea
8277 * @param {Object} config The config object
8280 Roo.bootstrap.TextArea = function(config){
8281 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8285 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8295 getAutoCreate : function(){
8297 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8308 value : this.value || '',
8309 html: this.html || '',
8310 cls : 'form-control',
8311 placeholder : this.placeholder || ''
8315 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8316 input.maxLength = this.maxLength;
8320 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8324 input.cols = this.cols;
8327 if (this.readOnly) {
8328 input.readonly = true;
8332 input.name = this.name;
8336 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8340 ['xs','sm','md','lg'].map(function(size){
8341 if (settings[size]) {
8342 cfg.cls += ' col-' + size + '-' + settings[size];
8346 var inputblock = input;
8348 if(this.hasFeedback && !this.allowBlank){
8352 cls: 'glyphicon form-control-feedback'
8356 cls : 'has-feedback',
8365 if (this.before || this.after) {
8368 cls : 'input-group',
8372 inputblock.cn.push({
8374 cls : 'input-group-addon',
8379 inputblock.cn.push(input);
8381 if(this.hasFeedback && !this.allowBlank){
8382 inputblock.cls += ' has-feedback';
8383 inputblock.cn.push(feedback);
8387 inputblock.cn.push({
8389 cls : 'input-group-addon',
8396 if (align ==='left' && this.fieldLabel.length) {
8397 Roo.log("left and has label");
8403 cls : 'control-label col-sm-' + this.labelWidth,
8404 html : this.fieldLabel
8408 cls : "col-sm-" + (12 - this.labelWidth),
8415 } else if ( this.fieldLabel.length) {
8421 //cls : 'input-group-addon',
8422 html : this.fieldLabel
8432 Roo.log(" no label && no align");
8442 if (this.disabled) {
8443 input.disabled=true;
8450 * return the real textarea element.
8452 inputEl: function ()
8454 return this.el.select('textarea.form-control',true).first();
8462 * trigger field - base class for combo..
8467 * @class Roo.bootstrap.TriggerField
8468 * @extends Roo.bootstrap.Input
8469 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8470 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8471 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8472 * for which you can provide a custom implementation. For example:
8474 var trigger = new Roo.bootstrap.TriggerField();
8475 trigger.onTriggerClick = myTriggerFn;
8476 trigger.applyTo('my-field');
8479 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8480 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8481 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8482 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8483 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8486 * Create a new TriggerField.
8487 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8488 * to the base TextField)
8490 Roo.bootstrap.TriggerField = function(config){
8491 this.mimicing = false;
8492 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8495 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8497 * @cfg {String} triggerClass A CSS class to apply to the trigger
8500 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8505 * @cfg {Boolean} removable (true|false) special filter default false
8509 /** @cfg {Boolean} grow @hide */
8510 /** @cfg {Number} growMin @hide */
8511 /** @cfg {Number} growMax @hide */
8517 autoSize: Roo.emptyFn,
8524 actionMode : 'wrap',
8529 getAutoCreate : function(){
8531 var align = this.labelAlign || this.parentLabelAlign();
8536 cls: 'form-group' //input-group
8543 type : this.inputType,
8544 cls : 'form-control',
8545 autocomplete: 'new-password',
8546 placeholder : this.placeholder || ''
8550 input.name = this.name;
8553 input.cls += ' input-' + this.size;
8556 if (this.disabled) {
8557 input.disabled=true;
8560 var inputblock = input;
8562 if(this.hasFeedback && !this.allowBlank){
8566 cls: 'glyphicon form-control-feedback'
8569 if(this.removable && !this.editable && !this.tickable){
8571 cls : 'has-feedback',
8577 cls : 'roo-combo-removable-btn close'
8584 cls : 'has-feedback',
8593 if(this.removable && !this.editable && !this.tickable){
8595 cls : 'roo-removable',
8601 cls : 'roo-combo-removable-btn close'
8608 if (this.before || this.after) {
8611 cls : 'input-group',
8615 inputblock.cn.push({
8617 cls : 'input-group-addon',
8622 inputblock.cn.push(input);
8624 if(this.hasFeedback && !this.allowBlank){
8625 inputblock.cls += ' has-feedback';
8626 inputblock.cn.push(feedback);
8630 inputblock.cn.push({
8632 cls : 'input-group-addon',
8645 cls: 'form-hidden-field'
8653 Roo.log('multiple');
8661 cls: 'form-hidden-field'
8665 cls: 'select2-choices',
8669 cls: 'select2-search-field',
8682 cls: 'select2-container input-group',
8687 // cls: 'typeahead typeahead-long dropdown-menu',
8688 // style: 'display:none'
8693 if(!this.multiple && this.showToggleBtn){
8699 if (this.caret != false) {
8702 cls: 'fa fa-' + this.caret
8709 cls : 'input-group-addon btn dropdown-toggle',
8714 cls: 'combobox-clear',
8728 combobox.cls += ' select2-container-multi';
8731 if (align ==='left' && this.fieldLabel.length) {
8733 Roo.log("left and has label");
8739 cls : 'control-label col-sm-' + this.labelWidth,
8740 html : this.fieldLabel
8744 cls : "col-sm-" + (12 - this.labelWidth),
8751 } else if ( this.fieldLabel.length) {
8757 //cls : 'input-group-addon',
8758 html : this.fieldLabel
8768 Roo.log(" no label && no align");
8775 ['xs','sm','md','lg'].map(function(size){
8776 if (settings[size]) {
8777 cfg.cls += ' col-' + size + '-' + settings[size];
8788 onResize : function(w, h){
8789 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8790 // if(typeof w == 'number'){
8791 // var x = w - this.trigger.getWidth();
8792 // this.inputEl().setWidth(this.adjustWidth('input', x));
8793 // this.trigger.setStyle('left', x+'px');
8798 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8801 getResizeEl : function(){
8802 return this.inputEl();
8806 getPositionEl : function(){
8807 return this.inputEl();
8811 alignErrorIcon : function(){
8812 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8816 initEvents : function(){
8820 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8821 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8822 if(!this.multiple && this.showToggleBtn){
8823 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8824 if(this.hideTrigger){
8825 this.trigger.setDisplayed(false);
8827 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8831 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8834 if(this.removable && !this.editable && !this.tickable){
8835 var close = this.closeTriggerEl();
8838 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
8839 close.on('click', this.removeBtnClick, this, close);
8843 //this.trigger.addClassOnOver('x-form-trigger-over');
8844 //this.trigger.addClassOnClick('x-form-trigger-click');
8847 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8851 closeTriggerEl : function()
8853 var close = this.el.select('.roo-combo-removable-btn', true).first();
8854 return close ? close : false;
8857 removeBtnClick : function(e, h, el)
8861 if(this.fireEvent("remove", this) !== false){
8866 createList : function()
8868 this.list = Roo.get(document.body).createChild({
8870 cls: 'typeahead typeahead-long dropdown-menu',
8871 style: 'display:none'
8874 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8879 initTrigger : function(){
8884 onDestroy : function(){
8886 this.trigger.removeAllListeners();
8887 // this.trigger.remove();
8890 // this.wrap.remove();
8892 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8896 onFocus : function(){
8897 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8900 this.wrap.addClass('x-trigger-wrap-focus');
8901 this.mimicing = true;
8902 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8903 if(this.monitorTab){
8904 this.el.on("keydown", this.checkTab, this);
8911 checkTab : function(e){
8912 if(e.getKey() == e.TAB){
8918 onBlur : function(){
8923 mimicBlur : function(e, t){
8925 if(!this.wrap.contains(t) && this.validateBlur()){
8932 triggerBlur : function(){
8933 this.mimicing = false;
8934 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8935 if(this.monitorTab){
8936 this.el.un("keydown", this.checkTab, this);
8938 //this.wrap.removeClass('x-trigger-wrap-focus');
8939 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8943 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8944 validateBlur : function(e, t){
8949 onDisable : function(){
8950 this.inputEl().dom.disabled = true;
8951 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8953 // this.wrap.addClass('x-item-disabled');
8958 onEnable : function(){
8959 this.inputEl().dom.disabled = false;
8960 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8962 // this.el.removeClass('x-item-disabled');
8967 onShow : function(){
8968 var ae = this.getActionEl();
8971 ae.dom.style.display = '';
8972 ae.dom.style.visibility = 'visible';
8978 onHide : function(){
8979 var ae = this.getActionEl();
8980 ae.dom.style.display = 'none';
8984 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8985 * by an implementing function.
8987 * @param {EventObject} e
8989 onTriggerClick : Roo.emptyFn
8993 * Ext JS Library 1.1.1
8994 * Copyright(c) 2006-2007, Ext JS, LLC.
8996 * Originally Released Under LGPL - original licence link has changed is not relivant.
8999 * <script type="text/javascript">
9004 * @class Roo.data.SortTypes
9006 * Defines the default sorting (casting?) comparison functions used when sorting data.
9008 Roo.data.SortTypes = {
9010 * Default sort that does nothing
9011 * @param {Mixed} s The value being converted
9012 * @return {Mixed} The comparison value
9019 * The regular expression used to strip tags
9023 stripTagsRE : /<\/?[^>]+>/gi,
9026 * Strips all HTML tags to sort on text only
9027 * @param {Mixed} s The value being converted
9028 * @return {String} The comparison value
9030 asText : function(s){
9031 return String(s).replace(this.stripTagsRE, "");
9035 * Strips all HTML tags to sort on text only - Case insensitive
9036 * @param {Mixed} s The value being converted
9037 * @return {String} The comparison value
9039 asUCText : function(s){
9040 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9044 * Case insensitive string
9045 * @param {Mixed} s The value being converted
9046 * @return {String} The comparison value
9048 asUCString : function(s) {
9049 return String(s).toUpperCase();
9054 * @param {Mixed} s The value being converted
9055 * @return {Number} The comparison value
9057 asDate : function(s) {
9061 if(s instanceof Date){
9064 return Date.parse(String(s));
9069 * @param {Mixed} s The value being converted
9070 * @return {Float} The comparison value
9072 asFloat : function(s) {
9073 var val = parseFloat(String(s).replace(/,/g, ""));
9074 if(isNaN(val)) val = 0;
9080 * @param {Mixed} s The value being converted
9081 * @return {Number} The comparison value
9083 asInt : function(s) {
9084 var val = parseInt(String(s).replace(/,/g, ""));
9085 if(isNaN(val)) val = 0;
9090 * Ext JS Library 1.1.1
9091 * Copyright(c) 2006-2007, Ext JS, LLC.
9093 * Originally Released Under LGPL - original licence link has changed is not relivant.
9096 * <script type="text/javascript">
9100 * @class Roo.data.Record
9101 * Instances of this class encapsulate both record <em>definition</em> information, and record
9102 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9103 * to access Records cached in an {@link Roo.data.Store} object.<br>
9105 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9106 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9109 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9111 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9112 * {@link #create}. The parameters are the same.
9113 * @param {Array} data An associative Array of data values keyed by the field name.
9114 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9115 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9116 * not specified an integer id is generated.
9118 Roo.data.Record = function(data, id){
9119 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9124 * Generate a constructor for a specific record layout.
9125 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9126 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9127 * Each field definition object may contain the following properties: <ul>
9128 * <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,
9129 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9130 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9131 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9132 * is being used, then this is a string containing the javascript expression to reference the data relative to
9133 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9134 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9135 * this may be omitted.</p></li>
9136 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9137 * <ul><li>auto (Default, implies no conversion)</li>
9142 * <li>date</li></ul></p></li>
9143 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9144 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9145 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9146 * by the Reader into an object that will be stored in the Record. It is passed the
9147 * following parameters:<ul>
9148 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9150 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9152 * <br>usage:<br><pre><code>
9153 var TopicRecord = Roo.data.Record.create(
9154 {name: 'title', mapping: 'topic_title'},
9155 {name: 'author', mapping: 'username'},
9156 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9157 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9158 {name: 'lastPoster', mapping: 'user2'},
9159 {name: 'excerpt', mapping: 'post_text'}
9162 var myNewRecord = new TopicRecord({
9163 title: 'Do my job please',
9166 lastPost: new Date(),
9167 lastPoster: 'Animal',
9168 excerpt: 'No way dude!'
9170 myStore.add(myNewRecord);
9175 Roo.data.Record.create = function(o){
9177 f.superclass.constructor.apply(this, arguments);
9179 Roo.extend(f, Roo.data.Record);
9180 var p = f.prototype;
9181 p.fields = new Roo.util.MixedCollection(false, function(field){
9184 for(var i = 0, len = o.length; i < len; i++){
9185 p.fields.add(new Roo.data.Field(o[i]));
9187 f.getField = function(name){
9188 return p.fields.get(name);
9193 Roo.data.Record.AUTO_ID = 1000;
9194 Roo.data.Record.EDIT = 'edit';
9195 Roo.data.Record.REJECT = 'reject';
9196 Roo.data.Record.COMMIT = 'commit';
9198 Roo.data.Record.prototype = {
9200 * Readonly flag - true if this record has been modified.
9209 join : function(store){
9214 * Set the named field to the specified value.
9215 * @param {String} name The name of the field to set.
9216 * @param {Object} value The value to set the field to.
9218 set : function(name, value){
9219 if(this.data[name] == value){
9226 if(typeof this.modified[name] == 'undefined'){
9227 this.modified[name] = this.data[name];
9229 this.data[name] = value;
9230 if(!this.editing && this.store){
9231 this.store.afterEdit(this);
9236 * Get the value of the named field.
9237 * @param {String} name The name of the field to get the value of.
9238 * @return {Object} The value of the field.
9240 get : function(name){
9241 return this.data[name];
9245 beginEdit : function(){
9246 this.editing = true;
9251 cancelEdit : function(){
9252 this.editing = false;
9253 delete this.modified;
9257 endEdit : function(){
9258 this.editing = false;
9259 if(this.dirty && this.store){
9260 this.store.afterEdit(this);
9265 * Usually called by the {@link Roo.data.Store} which owns the Record.
9266 * Rejects all changes made to the Record since either creation, or the last commit operation.
9267 * Modified fields are reverted to their original values.
9269 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9270 * of reject operations.
9272 reject : function(){
9273 var m = this.modified;
9275 if(typeof m[n] != "function"){
9276 this.data[n] = m[n];
9280 delete this.modified;
9281 this.editing = false;
9283 this.store.afterReject(this);
9288 * Usually called by the {@link Roo.data.Store} which owns the Record.
9289 * Commits all changes made to the Record since either creation, or the last commit operation.
9291 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9292 * of commit operations.
9294 commit : function(){
9296 delete this.modified;
9297 this.editing = false;
9299 this.store.afterCommit(this);
9304 hasError : function(){
9305 return this.error != null;
9309 clearError : function(){
9314 * Creates a copy of this record.
9315 * @param {String} id (optional) A new record id if you don't want to use this record's id
9318 copy : function(newId) {
9319 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9323 * Ext JS Library 1.1.1
9324 * Copyright(c) 2006-2007, Ext JS, LLC.
9326 * Originally Released Under LGPL - original licence link has changed is not relivant.
9329 * <script type="text/javascript">
9335 * @class Roo.data.Store
9336 * @extends Roo.util.Observable
9337 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9338 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9340 * 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
9341 * has no knowledge of the format of the data returned by the Proxy.<br>
9343 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9344 * instances from the data object. These records are cached and made available through accessor functions.
9346 * Creates a new Store.
9347 * @param {Object} config A config object containing the objects needed for the Store to access data,
9348 * and read the data into Records.
9350 Roo.data.Store = function(config){
9351 this.data = new Roo.util.MixedCollection(false);
9352 this.data.getKey = function(o){
9355 this.baseParams = {};
9362 "multisort" : "_multisort"
9365 if(config && config.data){
9366 this.inlineData = config.data;
9370 Roo.apply(this, config);
9372 if(this.reader){ // reader passed
9373 this.reader = Roo.factory(this.reader, Roo.data);
9374 this.reader.xmodule = this.xmodule || false;
9375 if(!this.recordType){
9376 this.recordType = this.reader.recordType;
9378 if(this.reader.onMetaChange){
9379 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9383 if(this.recordType){
9384 this.fields = this.recordType.prototype.fields;
9390 * @event datachanged
9391 * Fires when the data cache has changed, and a widget which is using this Store
9392 * as a Record cache should refresh its view.
9393 * @param {Store} this
9398 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9399 * @param {Store} this
9400 * @param {Object} meta The JSON metadata
9405 * Fires when Records have been added to the Store
9406 * @param {Store} this
9407 * @param {Roo.data.Record[]} records The array of Records added
9408 * @param {Number} index The index at which the record(s) were added
9413 * Fires when a Record has been removed from the Store
9414 * @param {Store} this
9415 * @param {Roo.data.Record} record The Record that was removed
9416 * @param {Number} index The index at which the record was removed
9421 * Fires when a Record has been updated
9422 * @param {Store} this
9423 * @param {Roo.data.Record} record The Record that was updated
9424 * @param {String} operation The update operation being performed. Value may be one of:
9426 Roo.data.Record.EDIT
9427 Roo.data.Record.REJECT
9428 Roo.data.Record.COMMIT
9434 * Fires when the data cache has been cleared.
9435 * @param {Store} this
9440 * Fires before a request is made for a new data object. If the beforeload handler returns false
9441 * the load action will be canceled.
9442 * @param {Store} this
9443 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9447 * @event beforeloadadd
9448 * Fires after a new set of Records has been loaded.
9449 * @param {Store} this
9450 * @param {Roo.data.Record[]} records The Records that were loaded
9451 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9453 beforeloadadd : true,
9456 * Fires after a new set of Records has been loaded, before they are added to the store.
9457 * @param {Store} this
9458 * @param {Roo.data.Record[]} records The Records that were loaded
9459 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9460 * @params {Object} return from reader
9464 * @event loadexception
9465 * Fires if an exception occurs in the Proxy during loading.
9466 * Called with the signature of the Proxy's "loadexception" event.
9467 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9470 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9471 * @param {Object} load options
9472 * @param {Object} jsonData from your request (normally this contains the Exception)
9474 loadexception : true
9478 this.proxy = Roo.factory(this.proxy, Roo.data);
9479 this.proxy.xmodule = this.xmodule || false;
9480 this.relayEvents(this.proxy, ["loadexception"]);
9482 this.sortToggle = {};
9483 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9485 Roo.data.Store.superclass.constructor.call(this);
9487 if(this.inlineData){
9488 this.loadData(this.inlineData);
9489 delete this.inlineData;
9493 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9495 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9496 * without a remote query - used by combo/forms at present.
9500 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9503 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9506 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9507 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9510 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9511 * on any HTTP request
9514 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9517 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9521 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9522 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9527 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9528 * loaded or when a record is removed. (defaults to false).
9530 pruneModifiedRecords : false,
9536 * Add Records to the Store and fires the add event.
9537 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9539 add : function(records){
9540 records = [].concat(records);
9541 for(var i = 0, len = records.length; i < len; i++){
9542 records[i].join(this);
9544 var index = this.data.length;
9545 this.data.addAll(records);
9546 this.fireEvent("add", this, records, index);
9550 * Remove a Record from the Store and fires the remove event.
9551 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9553 remove : function(record){
9554 var index = this.data.indexOf(record);
9555 this.data.removeAt(index);
9556 if(this.pruneModifiedRecords){
9557 this.modified.remove(record);
9559 this.fireEvent("remove", this, record, index);
9563 * Remove all Records from the Store and fires the clear event.
9565 removeAll : function(){
9567 if(this.pruneModifiedRecords){
9570 this.fireEvent("clear", this);
9574 * Inserts Records to the Store at the given index and fires the add event.
9575 * @param {Number} index The start index at which to insert the passed Records.
9576 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9578 insert : function(index, records){
9579 records = [].concat(records);
9580 for(var i = 0, len = records.length; i < len; i++){
9581 this.data.insert(index, records[i]);
9582 records[i].join(this);
9584 this.fireEvent("add", this, records, index);
9588 * Get the index within the cache of the passed Record.
9589 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9590 * @return {Number} The index of the passed Record. Returns -1 if not found.
9592 indexOf : function(record){
9593 return this.data.indexOf(record);
9597 * Get the index within the cache of the Record with the passed id.
9598 * @param {String} id The id of the Record to find.
9599 * @return {Number} The index of the Record. Returns -1 if not found.
9601 indexOfId : function(id){
9602 return this.data.indexOfKey(id);
9606 * Get the Record with the specified id.
9607 * @param {String} id The id of the Record to find.
9608 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9610 getById : function(id){
9611 return this.data.key(id);
9615 * Get the Record at the specified index.
9616 * @param {Number} index The index of the Record to find.
9617 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9619 getAt : function(index){
9620 return this.data.itemAt(index);
9624 * Returns a range of Records between specified indices.
9625 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9626 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9627 * @return {Roo.data.Record[]} An array of Records
9629 getRange : function(start, end){
9630 return this.data.getRange(start, end);
9634 storeOptions : function(o){
9635 o = Roo.apply({}, o);
9638 this.lastOptions = o;
9642 * Loads the Record cache from the configured Proxy using the configured Reader.
9644 * If using remote paging, then the first load call must specify the <em>start</em>
9645 * and <em>limit</em> properties in the options.params property to establish the initial
9646 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9648 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9649 * and this call will return before the new data has been loaded. Perform any post-processing
9650 * in a callback function, or in a "load" event handler.</strong>
9652 * @param {Object} options An object containing properties which control loading options:<ul>
9653 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9654 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9655 * passed the following arguments:<ul>
9656 * <li>r : Roo.data.Record[]</li>
9657 * <li>options: Options object from the load call</li>
9658 * <li>success: Boolean success indicator</li></ul></li>
9659 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9660 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9663 load : function(options){
9664 options = options || {};
9665 if(this.fireEvent("beforeload", this, options) !== false){
9666 this.storeOptions(options);
9667 var p = Roo.apply(options.params || {}, this.baseParams);
9668 // if meta was not loaded from remote source.. try requesting it.
9669 if (!this.reader.metaFromRemote) {
9672 if(this.sortInfo && this.remoteSort){
9673 var pn = this.paramNames;
9674 p[pn["sort"]] = this.sortInfo.field;
9675 p[pn["dir"]] = this.sortInfo.direction;
9677 if (this.multiSort) {
9678 var pn = this.paramNames;
9679 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9682 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9687 * Reloads the Record cache from the configured Proxy using the configured Reader and
9688 * the options from the last load operation performed.
9689 * @param {Object} options (optional) An object containing properties which may override the options
9690 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9691 * the most recently used options are reused).
9693 reload : function(options){
9694 this.load(Roo.applyIf(options||{}, this.lastOptions));
9698 // Called as a callback by the Reader during a load operation.
9699 loadRecords : function(o, options, success){
9700 if(!o || success === false){
9701 if(success !== false){
9702 this.fireEvent("load", this, [], options, o);
9704 if(options.callback){
9705 options.callback.call(options.scope || this, [], options, false);
9709 // if data returned failure - throw an exception.
9710 if (o.success === false) {
9711 // show a message if no listener is registered.
9712 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9713 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9715 // loadmask wil be hooked into this..
9716 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9719 var r = o.records, t = o.totalRecords || r.length;
9721 this.fireEvent("beforeloadadd", this, r, options, o);
9723 if(!options || options.add !== true){
9724 if(this.pruneModifiedRecords){
9727 for(var i = 0, len = r.length; i < len; i++){
9731 this.data = this.snapshot;
9732 delete this.snapshot;
9735 this.data.addAll(r);
9736 this.totalLength = t;
9738 this.fireEvent("datachanged", this);
9740 this.totalLength = Math.max(t, this.data.length+r.length);
9743 this.fireEvent("load", this, r, options, o);
9744 if(options.callback){
9745 options.callback.call(options.scope || this, r, options, true);
9751 * Loads data from a passed data block. A Reader which understands the format of the data
9752 * must have been configured in the constructor.
9753 * @param {Object} data The data block from which to read the Records. The format of the data expected
9754 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9755 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9757 loadData : function(o, append){
9758 var r = this.reader.readRecords(o);
9759 this.loadRecords(r, {add: append}, true);
9763 * Gets the number of cached records.
9765 * <em>If using paging, this may not be the total size of the dataset. If the data object
9766 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9767 * the data set size</em>
9769 getCount : function(){
9770 return this.data.length || 0;
9774 * Gets the total number of records in the dataset as returned by the server.
9776 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9777 * the dataset size</em>
9779 getTotalCount : function(){
9780 return this.totalLength || 0;
9784 * Returns the sort state of the Store as an object with two properties:
9786 field {String} The name of the field by which the Records are sorted
9787 direction {String} The sort order, "ASC" or "DESC"
9790 getSortState : function(){
9791 return this.sortInfo;
9795 applySort : function(){
9796 if(this.sortInfo && !this.remoteSort){
9797 var s = this.sortInfo, f = s.field;
9798 var st = this.fields.get(f).sortType;
9799 var fn = function(r1, r2){
9800 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9801 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9803 this.data.sort(s.direction, fn);
9804 if(this.snapshot && this.snapshot != this.data){
9805 this.snapshot.sort(s.direction, fn);
9811 * Sets the default sort column and order to be used by the next load operation.
9812 * @param {String} fieldName The name of the field to sort by.
9813 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9815 setDefaultSort : function(field, dir){
9816 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9821 * If remote sorting is used, the sort is performed on the server, and the cache is
9822 * reloaded. If local sorting is used, the cache is sorted internally.
9823 * @param {String} fieldName The name of the field to sort by.
9824 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9826 sort : function(fieldName, dir){
9827 var f = this.fields.get(fieldName);
9829 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9831 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9832 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9837 this.sortToggle[f.name] = dir;
9838 this.sortInfo = {field: f.name, direction: dir};
9839 if(!this.remoteSort){
9841 this.fireEvent("datachanged", this);
9843 this.load(this.lastOptions);
9848 * Calls the specified function for each of the Records in the cache.
9849 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9850 * Returning <em>false</em> aborts and exits the iteration.
9851 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9853 each : function(fn, scope){
9854 this.data.each(fn, scope);
9858 * Gets all records modified since the last commit. Modified records are persisted across load operations
9859 * (e.g., during paging).
9860 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9862 getModifiedRecords : function(){
9863 return this.modified;
9867 createFilterFn : function(property, value, anyMatch){
9868 if(!value.exec){ // not a regex
9869 value = String(value);
9870 if(value.length == 0){
9873 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9876 return value.test(r.data[property]);
9881 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9882 * @param {String} property A field on your records
9883 * @param {Number} start The record index to start at (defaults to 0)
9884 * @param {Number} end The last record index to include (defaults to length - 1)
9885 * @return {Number} The sum
9887 sum : function(property, start, end){
9888 var rs = this.data.items, v = 0;
9890 end = (end || end === 0) ? end : rs.length-1;
9892 for(var i = start; i <= end; i++){
9893 v += (rs[i].data[property] || 0);
9899 * Filter the records by a specified property.
9900 * @param {String} field A field on your records
9901 * @param {String/RegExp} value Either a string that the field
9902 * should start with or a RegExp to test against the field
9903 * @param {Boolean} anyMatch True to match any part not just the beginning
9905 filter : function(property, value, anyMatch){
9906 var fn = this.createFilterFn(property, value, anyMatch);
9907 return fn ? this.filterBy(fn) : this.clearFilter();
9911 * Filter by a function. The specified function will be called with each
9912 * record in this data source. If the function returns true the record is included,
9913 * otherwise it is filtered.
9914 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9915 * @param {Object} scope (optional) The scope of the function (defaults to this)
9917 filterBy : function(fn, scope){
9918 this.snapshot = this.snapshot || this.data;
9919 this.data = this.queryBy(fn, scope||this);
9920 this.fireEvent("datachanged", this);
9924 * Query the records by a specified property.
9925 * @param {String} field A field on your records
9926 * @param {String/RegExp} value Either a string that the field
9927 * should start with or a RegExp to test against the field
9928 * @param {Boolean} anyMatch True to match any part not just the beginning
9929 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9931 query : function(property, value, anyMatch){
9932 var fn = this.createFilterFn(property, value, anyMatch);
9933 return fn ? this.queryBy(fn) : this.data.clone();
9937 * Query by a function. The specified function will be called with each
9938 * record in this data source. If the function returns true the record is included
9940 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9941 * @param {Object} scope (optional) The scope of the function (defaults to this)
9942 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9944 queryBy : function(fn, scope){
9945 var data = this.snapshot || this.data;
9946 return data.filterBy(fn, scope||this);
9950 * Collects unique values for a particular dataIndex from this store.
9951 * @param {String} dataIndex The property to collect
9952 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9953 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9954 * @return {Array} An array of the unique values
9956 collect : function(dataIndex, allowNull, bypassFilter){
9957 var d = (bypassFilter === true && this.snapshot) ?
9958 this.snapshot.items : this.data.items;
9959 var v, sv, r = [], l = {};
9960 for(var i = 0, len = d.length; i < len; i++){
9961 v = d[i].data[dataIndex];
9963 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9972 * Revert to a view of the Record cache with no filtering applied.
9973 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9975 clearFilter : function(suppressEvent){
9976 if(this.snapshot && this.snapshot != this.data){
9977 this.data = this.snapshot;
9978 delete this.snapshot;
9979 if(suppressEvent !== true){
9980 this.fireEvent("datachanged", this);
9986 afterEdit : function(record){
9987 if(this.modified.indexOf(record) == -1){
9988 this.modified.push(record);
9990 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9994 afterReject : function(record){
9995 this.modified.remove(record);
9996 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10000 afterCommit : function(record){
10001 this.modified.remove(record);
10002 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10006 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10007 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10009 commitChanges : function(){
10010 var m = this.modified.slice(0);
10011 this.modified = [];
10012 for(var i = 0, len = m.length; i < len; i++){
10018 * Cancel outstanding changes on all changed records.
10020 rejectChanges : function(){
10021 var m = this.modified.slice(0);
10022 this.modified = [];
10023 for(var i = 0, len = m.length; i < len; i++){
10028 onMetaChange : function(meta, rtype, o){
10029 this.recordType = rtype;
10030 this.fields = rtype.prototype.fields;
10031 delete this.snapshot;
10032 this.sortInfo = meta.sortInfo || this.sortInfo;
10033 this.modified = [];
10034 this.fireEvent('metachange', this, this.reader.meta);
10037 moveIndex : function(data, type)
10039 var index = this.indexOf(data);
10041 var newIndex = index + type;
10045 this.insert(newIndex, data);
10050 * Ext JS Library 1.1.1
10051 * Copyright(c) 2006-2007, Ext JS, LLC.
10053 * Originally Released Under LGPL - original licence link has changed is not relivant.
10056 * <script type="text/javascript">
10060 * @class Roo.data.SimpleStore
10061 * @extends Roo.data.Store
10062 * Small helper class to make creating Stores from Array data easier.
10063 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10064 * @cfg {Array} fields An array of field definition objects, or field name strings.
10065 * @cfg {Array} data The multi-dimensional array of data
10067 * @param {Object} config
10069 Roo.data.SimpleStore = function(config){
10070 Roo.data.SimpleStore.superclass.constructor.call(this, {
10072 reader: new Roo.data.ArrayReader({
10075 Roo.data.Record.create(config.fields)
10077 proxy : new Roo.data.MemoryProxy(config.data)
10081 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10083 * Ext JS Library 1.1.1
10084 * Copyright(c) 2006-2007, Ext JS, LLC.
10086 * Originally Released Under LGPL - original licence link has changed is not relivant.
10089 * <script type="text/javascript">
10094 * @extends Roo.data.Store
10095 * @class Roo.data.JsonStore
10096 * Small helper class to make creating Stores for JSON data easier. <br/>
10098 var store = new Roo.data.JsonStore({
10099 url: 'get-images.php',
10101 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10104 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10105 * JsonReader and HttpProxy (unless inline data is provided).</b>
10106 * @cfg {Array} fields An array of field definition objects, or field name strings.
10108 * @param {Object} config
10110 Roo.data.JsonStore = function(c){
10111 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10112 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10113 reader: new Roo.data.JsonReader(c, c.fields)
10116 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10118 * Ext JS Library 1.1.1
10119 * Copyright(c) 2006-2007, Ext JS, LLC.
10121 * Originally Released Under LGPL - original licence link has changed is not relivant.
10124 * <script type="text/javascript">
10128 Roo.data.Field = function(config){
10129 if(typeof config == "string"){
10130 config = {name: config};
10132 Roo.apply(this, config);
10135 this.type = "auto";
10138 var st = Roo.data.SortTypes;
10139 // named sortTypes are supported, here we look them up
10140 if(typeof this.sortType == "string"){
10141 this.sortType = st[this.sortType];
10144 // set default sortType for strings and dates
10145 if(!this.sortType){
10148 this.sortType = st.asUCString;
10151 this.sortType = st.asDate;
10154 this.sortType = st.none;
10159 var stripRe = /[\$,%]/g;
10161 // prebuilt conversion function for this field, instead of
10162 // switching every time we're reading a value
10164 var cv, dateFormat = this.dateFormat;
10169 cv = function(v){ return v; };
10172 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10176 return v !== undefined && v !== null && v !== '' ?
10177 parseInt(String(v).replace(stripRe, ""), 10) : '';
10182 return v !== undefined && v !== null && v !== '' ?
10183 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10188 cv = function(v){ return v === true || v === "true" || v == 1; };
10195 if(v instanceof Date){
10199 if(dateFormat == "timestamp"){
10200 return new Date(v*1000);
10202 return Date.parseDate(v, dateFormat);
10204 var parsed = Date.parse(v);
10205 return parsed ? new Date(parsed) : null;
10214 Roo.data.Field.prototype = {
10222 * Ext JS Library 1.1.1
10223 * Copyright(c) 2006-2007, Ext JS, LLC.
10225 * Originally Released Under LGPL - original licence link has changed is not relivant.
10228 * <script type="text/javascript">
10231 // Base class for reading structured data from a data source. This class is intended to be
10232 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10235 * @class Roo.data.DataReader
10236 * Base class for reading structured data from a data source. This class is intended to be
10237 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10240 Roo.data.DataReader = function(meta, recordType){
10244 this.recordType = recordType instanceof Array ?
10245 Roo.data.Record.create(recordType) : recordType;
10248 Roo.data.DataReader.prototype = {
10250 * Create an empty record
10251 * @param {Object} data (optional) - overlay some values
10252 * @return {Roo.data.Record} record created.
10254 newRow : function(d) {
10256 this.recordType.prototype.fields.each(function(c) {
10258 case 'int' : da[c.name] = 0; break;
10259 case 'date' : da[c.name] = new Date(); break;
10260 case 'float' : da[c.name] = 0.0; break;
10261 case 'boolean' : da[c.name] = false; break;
10262 default : da[c.name] = ""; break;
10266 return new this.recordType(Roo.apply(da, d));
10271 * Ext JS Library 1.1.1
10272 * Copyright(c) 2006-2007, Ext JS, LLC.
10274 * Originally Released Under LGPL - original licence link has changed is not relivant.
10277 * <script type="text/javascript">
10281 * @class Roo.data.DataProxy
10282 * @extends Roo.data.Observable
10283 * This class is an abstract base class for implementations which provide retrieval of
10284 * unformatted data objects.<br>
10286 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10287 * (of the appropriate type which knows how to parse the data object) to provide a block of
10288 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10290 * Custom implementations must implement the load method as described in
10291 * {@link Roo.data.HttpProxy#load}.
10293 Roo.data.DataProxy = function(){
10296 * @event beforeload
10297 * Fires before a network request is made to retrieve a data object.
10298 * @param {Object} This DataProxy object.
10299 * @param {Object} params The params parameter to the load function.
10304 * Fires before the load method's callback is called.
10305 * @param {Object} This DataProxy object.
10306 * @param {Object} o The data object.
10307 * @param {Object} arg The callback argument object passed to the load function.
10311 * @event loadexception
10312 * Fires if an Exception occurs during data retrieval.
10313 * @param {Object} This DataProxy object.
10314 * @param {Object} o The data object.
10315 * @param {Object} arg The callback argument object passed to the load function.
10316 * @param {Object} e The Exception.
10318 loadexception : true
10320 Roo.data.DataProxy.superclass.constructor.call(this);
10323 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10326 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10330 * Ext JS Library 1.1.1
10331 * Copyright(c) 2006-2007, Ext JS, LLC.
10333 * Originally Released Under LGPL - original licence link has changed is not relivant.
10336 * <script type="text/javascript">
10339 * @class Roo.data.MemoryProxy
10340 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10341 * to the Reader when its load method is called.
10343 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10345 Roo.data.MemoryProxy = function(data){
10349 Roo.data.MemoryProxy.superclass.constructor.call(this);
10353 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10355 * Load data from the requested source (in this case an in-memory
10356 * data object passed to the constructor), read the data object into
10357 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10358 * process that block using the passed callback.
10359 * @param {Object} params This parameter is not used by the MemoryProxy class.
10360 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10361 * object into a block of Roo.data.Records.
10362 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10363 * The function must be passed <ul>
10364 * <li>The Record block object</li>
10365 * <li>The "arg" argument from the load function</li>
10366 * <li>A boolean success indicator</li>
10368 * @param {Object} scope The scope in which to call the callback
10369 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10371 load : function(params, reader, callback, scope, arg){
10372 params = params || {};
10375 result = reader.readRecords(this.data);
10377 this.fireEvent("loadexception", this, arg, null, e);
10378 callback.call(scope, null, arg, false);
10381 callback.call(scope, result, arg, true);
10385 update : function(params, records){
10390 * Ext JS Library 1.1.1
10391 * Copyright(c) 2006-2007, Ext JS, LLC.
10393 * Originally Released Under LGPL - original licence link has changed is not relivant.
10396 * <script type="text/javascript">
10399 * @class Roo.data.HttpProxy
10400 * @extends Roo.data.DataProxy
10401 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10402 * configured to reference a certain URL.<br><br>
10404 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10405 * from which the running page was served.<br><br>
10407 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10409 * Be aware that to enable the browser to parse an XML document, the server must set
10410 * the Content-Type header in the HTTP response to "text/xml".
10412 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10413 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10414 * will be used to make the request.
10416 Roo.data.HttpProxy = function(conn){
10417 Roo.data.HttpProxy.superclass.constructor.call(this);
10418 // is conn a conn config or a real conn?
10420 this.useAjax = !conn || !conn.events;
10424 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10425 // thse are take from connection...
10428 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10431 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10432 * extra parameters to each request made by this object. (defaults to undefined)
10435 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10436 * to each request made by this object. (defaults to undefined)
10439 * @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)
10442 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10445 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10451 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10455 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10456 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10457 * a finer-grained basis than the DataProxy events.
10459 getConnection : function(){
10460 return this.useAjax ? Roo.Ajax : this.conn;
10464 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10465 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10466 * process that block using the passed callback.
10467 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10468 * for the request to the remote server.
10469 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10470 * object into a block of Roo.data.Records.
10471 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10472 * The function must be passed <ul>
10473 * <li>The Record block object</li>
10474 * <li>The "arg" argument from the load function</li>
10475 * <li>A boolean success indicator</li>
10477 * @param {Object} scope The scope in which to call the callback
10478 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10480 load : function(params, reader, callback, scope, arg){
10481 if(this.fireEvent("beforeload", this, params) !== false){
10483 params : params || {},
10485 callback : callback,
10490 callback : this.loadResponse,
10494 Roo.applyIf(o, this.conn);
10495 if(this.activeRequest){
10496 Roo.Ajax.abort(this.activeRequest);
10498 this.activeRequest = Roo.Ajax.request(o);
10500 this.conn.request(o);
10503 callback.call(scope||this, null, arg, false);
10508 loadResponse : function(o, success, response){
10509 delete this.activeRequest;
10511 this.fireEvent("loadexception", this, o, response);
10512 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10517 result = o.reader.read(response);
10519 this.fireEvent("loadexception", this, o, response, e);
10520 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10524 this.fireEvent("load", this, o, o.request.arg);
10525 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10529 update : function(dataSet){
10534 updateResponse : function(dataSet){
10539 * Ext JS Library 1.1.1
10540 * Copyright(c) 2006-2007, Ext JS, LLC.
10542 * Originally Released Under LGPL - original licence link has changed is not relivant.
10545 * <script type="text/javascript">
10549 * @class Roo.data.ScriptTagProxy
10550 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10551 * other than the originating domain of the running page.<br><br>
10553 * <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
10554 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10556 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10557 * source code that is used as the source inside a <script> tag.<br><br>
10559 * In order for the browser to process the returned data, the server must wrap the data object
10560 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10561 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10562 * depending on whether the callback name was passed:
10565 boolean scriptTag = false;
10566 String cb = request.getParameter("callback");
10569 response.setContentType("text/javascript");
10571 response.setContentType("application/x-json");
10573 Writer out = response.getWriter();
10575 out.write(cb + "(");
10577 out.print(dataBlock.toJsonString());
10584 * @param {Object} config A configuration object.
10586 Roo.data.ScriptTagProxy = function(config){
10587 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10588 Roo.apply(this, config);
10589 this.head = document.getElementsByTagName("head")[0];
10592 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10594 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10596 * @cfg {String} url The URL from which to request the data object.
10599 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10603 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10604 * the server the name of the callback function set up by the load call to process the returned data object.
10605 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10606 * javascript output which calls this named function passing the data object as its only parameter.
10608 callbackParam : "callback",
10610 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10611 * name to the request.
10616 * Load data from the configured URL, read the data object into
10617 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10618 * process that block using the passed callback.
10619 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10620 * for the request to the remote server.
10621 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10622 * object into a block of Roo.data.Records.
10623 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10624 * The function must be passed <ul>
10625 * <li>The Record block object</li>
10626 * <li>The "arg" argument from the load function</li>
10627 * <li>A boolean success indicator</li>
10629 * @param {Object} scope The scope in which to call the callback
10630 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10632 load : function(params, reader, callback, scope, arg){
10633 if(this.fireEvent("beforeload", this, params) !== false){
10635 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10637 var url = this.url;
10638 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10640 url += "&_dc=" + (new Date().getTime());
10642 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10645 cb : "stcCallback"+transId,
10646 scriptId : "stcScript"+transId,
10650 callback : callback,
10656 window[trans.cb] = function(o){
10657 conn.handleResponse(o, trans);
10660 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10662 if(this.autoAbort !== false){
10666 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10668 var script = document.createElement("script");
10669 script.setAttribute("src", url);
10670 script.setAttribute("type", "text/javascript");
10671 script.setAttribute("id", trans.scriptId);
10672 this.head.appendChild(script);
10674 this.trans = trans;
10676 callback.call(scope||this, null, arg, false);
10681 isLoading : function(){
10682 return this.trans ? true : false;
10686 * Abort the current server request.
10688 abort : function(){
10689 if(this.isLoading()){
10690 this.destroyTrans(this.trans);
10695 destroyTrans : function(trans, isLoaded){
10696 this.head.removeChild(document.getElementById(trans.scriptId));
10697 clearTimeout(trans.timeoutId);
10699 window[trans.cb] = undefined;
10701 delete window[trans.cb];
10704 // if hasn't been loaded, wait for load to remove it to prevent script error
10705 window[trans.cb] = function(){
10706 window[trans.cb] = undefined;
10708 delete window[trans.cb];
10715 handleResponse : function(o, trans){
10716 this.trans = false;
10717 this.destroyTrans(trans, true);
10720 result = trans.reader.readRecords(o);
10722 this.fireEvent("loadexception", this, o, trans.arg, e);
10723 trans.callback.call(trans.scope||window, null, trans.arg, false);
10726 this.fireEvent("load", this, o, trans.arg);
10727 trans.callback.call(trans.scope||window, result, trans.arg, true);
10731 handleFailure : function(trans){
10732 this.trans = false;
10733 this.destroyTrans(trans, false);
10734 this.fireEvent("loadexception", this, null, trans.arg);
10735 trans.callback.call(trans.scope||window, null, trans.arg, false);
10739 * Ext JS Library 1.1.1
10740 * Copyright(c) 2006-2007, Ext JS, LLC.
10742 * Originally Released Under LGPL - original licence link has changed is not relivant.
10745 * <script type="text/javascript">
10749 * @class Roo.data.JsonReader
10750 * @extends Roo.data.DataReader
10751 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10752 * based on mappings in a provided Roo.data.Record constructor.
10754 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10755 * in the reply previously.
10760 var RecordDef = Roo.data.Record.create([
10761 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10762 {name: 'occupation'} // This field will use "occupation" as the mapping.
10764 var myReader = new Roo.data.JsonReader({
10765 totalProperty: "results", // The property which contains the total dataset size (optional)
10766 root: "rows", // The property which contains an Array of row objects
10767 id: "id" // The property within each row object that provides an ID for the record (optional)
10771 * This would consume a JSON file like this:
10773 { 'results': 2, 'rows': [
10774 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10775 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10778 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10779 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10780 * paged from the remote server.
10781 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10782 * @cfg {String} root name of the property which contains the Array of row objects.
10783 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10784 * @cfg {Array} fields Array of field definition objects
10786 * Create a new JsonReader
10787 * @param {Object} meta Metadata configuration options
10788 * @param {Object} recordType Either an Array of field definition objects,
10789 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10791 Roo.data.JsonReader = function(meta, recordType){
10794 // set some defaults:
10795 Roo.applyIf(meta, {
10796 totalProperty: 'total',
10797 successProperty : 'success',
10802 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10804 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10807 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10808 * Used by Store query builder to append _requestMeta to params.
10811 metaFromRemote : false,
10813 * This method is only used by a DataProxy which has retrieved data from a remote server.
10814 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10815 * @return {Object} data A data block which is used by an Roo.data.Store object as
10816 * a cache of Roo.data.Records.
10818 read : function(response){
10819 var json = response.responseText;
10821 var o = /* eval:var:o */ eval("("+json+")");
10823 throw {message: "JsonReader.read: Json object not found"};
10829 this.metaFromRemote = true;
10830 this.meta = o.metaData;
10831 this.recordType = Roo.data.Record.create(o.metaData.fields);
10832 this.onMetaChange(this.meta, this.recordType, o);
10834 return this.readRecords(o);
10837 // private function a store will implement
10838 onMetaChange : function(meta, recordType, o){
10845 simpleAccess: function(obj, subsc) {
10852 getJsonAccessor: function(){
10854 return function(expr) {
10856 return(re.test(expr))
10857 ? new Function("obj", "return obj." + expr)
10862 return Roo.emptyFn;
10867 * Create a data block containing Roo.data.Records from an XML document.
10868 * @param {Object} o An object which contains an Array of row objects in the property specified
10869 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10870 * which contains the total size of the dataset.
10871 * @return {Object} data A data block which is used by an Roo.data.Store object as
10872 * a cache of Roo.data.Records.
10874 readRecords : function(o){
10876 * After any data loads, the raw JSON data is available for further custom processing.
10880 var s = this.meta, Record = this.recordType,
10881 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10883 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10885 if(s.totalProperty) {
10886 this.getTotal = this.getJsonAccessor(s.totalProperty);
10888 if(s.successProperty) {
10889 this.getSuccess = this.getJsonAccessor(s.successProperty);
10891 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10893 var g = this.getJsonAccessor(s.id);
10894 this.getId = function(rec) {
10896 return (r === undefined || r === "") ? null : r;
10899 this.getId = function(){return null;};
10902 for(var jj = 0; jj < fl; jj++){
10904 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10905 this.ef[jj] = this.getJsonAccessor(map);
10909 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10910 if(s.totalProperty){
10911 var vt = parseInt(this.getTotal(o), 10);
10916 if(s.successProperty){
10917 var vs = this.getSuccess(o);
10918 if(vs === false || vs === 'false'){
10923 for(var i = 0; i < c; i++){
10926 var id = this.getId(n);
10927 for(var j = 0; j < fl; j++){
10929 var v = this.ef[j](n);
10931 Roo.log('missing convert for ' + f.name);
10935 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10937 var record = new Record(values, id);
10939 records[i] = record;
10945 totalRecords : totalRecords
10950 * Ext JS Library 1.1.1
10951 * Copyright(c) 2006-2007, Ext JS, LLC.
10953 * Originally Released Under LGPL - original licence link has changed is not relivant.
10956 * <script type="text/javascript">
10960 * @class Roo.data.ArrayReader
10961 * @extends Roo.data.DataReader
10962 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10963 * Each element of that Array represents a row of data fields. The
10964 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10965 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10969 var RecordDef = Roo.data.Record.create([
10970 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10971 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10973 var myReader = new Roo.data.ArrayReader({
10974 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10978 * This would consume an Array like this:
10980 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10982 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10984 * Create a new JsonReader
10985 * @param {Object} meta Metadata configuration options.
10986 * @param {Object} recordType Either an Array of field definition objects
10987 * as specified to {@link Roo.data.Record#create},
10988 * or an {@link Roo.data.Record} object
10989 * created using {@link Roo.data.Record#create}.
10991 Roo.data.ArrayReader = function(meta, recordType){
10992 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10995 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10997 * Create a data block containing Roo.data.Records from an XML document.
10998 * @param {Object} o An Array of row objects which represents the dataset.
10999 * @return {Object} data A data block which is used by an Roo.data.Store object as
11000 * a cache of Roo.data.Records.
11002 readRecords : function(o){
11003 var sid = this.meta ? this.meta.id : null;
11004 var recordType = this.recordType, fields = recordType.prototype.fields;
11007 for(var i = 0; i < root.length; i++){
11010 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11011 for(var j = 0, jlen = fields.length; j < jlen; j++){
11012 var f = fields.items[j];
11013 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11014 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11016 values[f.name] = v;
11018 var record = new recordType(values, id);
11020 records[records.length] = record;
11024 totalRecords : records.length
11033 * @class Roo.bootstrap.ComboBox
11034 * @extends Roo.bootstrap.TriggerField
11035 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11036 * @cfg {Boolean} append (true|false) default false
11037 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11038 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11039 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11040 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11041 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11042 * @cfg {Boolean} animate default true
11043 * @cfg {Boolean} emptyResultText only for touch device
11045 * Create a new ComboBox.
11046 * @param {Object} config Configuration options
11048 Roo.bootstrap.ComboBox = function(config){
11049 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11053 * Fires when the dropdown list is expanded
11054 * @param {Roo.bootstrap.ComboBox} combo This combo box
11059 * Fires when the dropdown list is collapsed
11060 * @param {Roo.bootstrap.ComboBox} combo This combo box
11064 * @event beforeselect
11065 * Fires before a list item is selected. Return false to cancel the selection.
11066 * @param {Roo.bootstrap.ComboBox} combo This combo box
11067 * @param {Roo.data.Record} record The data record returned from the underlying store
11068 * @param {Number} index The index of the selected item in the dropdown list
11070 'beforeselect' : true,
11073 * Fires when a list item is selected
11074 * @param {Roo.bootstrap.ComboBox} combo This combo box
11075 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11076 * @param {Number} index The index of the selected item in the dropdown list
11080 * @event beforequery
11081 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11082 * The event object passed has these properties:
11083 * @param {Roo.bootstrap.ComboBox} combo This combo box
11084 * @param {String} query The query
11085 * @param {Boolean} forceAll true to force "all" query
11086 * @param {Boolean} cancel true to cancel the query
11087 * @param {Object} e The query event object
11089 'beforequery': true,
11092 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11093 * @param {Roo.bootstrap.ComboBox} combo This combo box
11098 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11099 * @param {Roo.bootstrap.ComboBox} combo This combo box
11100 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11105 * Fires when the remove value from the combobox array
11106 * @param {Roo.bootstrap.ComboBox} combo This combo box
11110 * @event specialfilter
11111 * Fires when specialfilter
11112 * @param {Roo.bootstrap.ComboBox} combo This combo box
11114 'specialfilter' : true
11119 this.tickItems = [];
11121 this.selectedIndex = -1;
11122 if(this.mode == 'local'){
11123 if(config.queryDelay === undefined){
11124 this.queryDelay = 10;
11126 if(config.minChars === undefined){
11132 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11135 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11136 * rendering into an Roo.Editor, defaults to false)
11139 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11140 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11143 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11146 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11147 * the dropdown list (defaults to undefined, with no header element)
11151 * @cfg {String/Roo.Template} tpl The template to use to render the output
11155 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11157 listWidth: undefined,
11159 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11160 * mode = 'remote' or 'text' if mode = 'local')
11162 displayField: undefined,
11165 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11166 * mode = 'remote' or 'value' if mode = 'local').
11167 * Note: use of a valueField requires the user make a selection
11168 * in order for a value to be mapped.
11170 valueField: undefined,
11174 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11175 * field's data value (defaults to the underlying DOM element's name)
11177 hiddenName: undefined,
11179 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11183 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11185 selectedClass: 'active',
11188 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11192 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11193 * anchor positions (defaults to 'tl-bl')
11195 listAlign: 'tl-bl?',
11197 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11201 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11202 * query specified by the allQuery config option (defaults to 'query')
11204 triggerAction: 'query',
11206 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11207 * (defaults to 4, does not apply if editable = false)
11211 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11212 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11216 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11217 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11221 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11222 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11226 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11227 * when editable = true (defaults to false)
11229 selectOnFocus:false,
11231 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11233 queryParam: 'query',
11235 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11236 * when mode = 'remote' (defaults to 'Loading...')
11238 loadingText: 'Loading...',
11240 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11244 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11248 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11249 * traditional select (defaults to true)
11253 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11257 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11261 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11262 * listWidth has a higher value)
11266 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11267 * allow the user to set arbitrary text into the field (defaults to false)
11269 forceSelection:false,
11271 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11272 * if typeAhead = true (defaults to 250)
11274 typeAheadDelay : 250,
11276 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11277 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11279 valueNotFoundText : undefined,
11281 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11283 blockFocus : false,
11286 * @cfg {Boolean} disableClear Disable showing of clear button.
11288 disableClear : false,
11290 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11292 alwaysQuery : false,
11295 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11300 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11302 invalidClass : "has-warning",
11305 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11307 validClass : "has-success",
11310 * @cfg {Boolean} specialFilter (true|false) special filter default false
11312 specialFilter : false,
11315 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
11317 mobileTouchView : true,
11329 btnPosition : 'right',
11330 triggerList : true,
11331 showToggleBtn : true,
11333 emptyResultText: 'Empty',
11334 // element that contains real text value.. (when hidden is used..)
11336 getAutoCreate : function()
11344 if(Roo.isTouch && this.mobileTouchView){
11345 cfg = this.getAutoCreateTouchView();
11352 if(!this.tickable){
11353 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11358 * ComboBox with tickable selections
11361 var align = this.labelAlign || this.parentLabelAlign();
11364 cls : 'form-group roo-combobox-tickable' //input-group
11369 cls : 'tickable-buttons',
11374 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11381 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11388 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11395 buttons.cn.unshift({
11397 cls: 'select2-search-field-input'
11403 Roo.each(buttons.cn, function(c){
11405 c.cls += ' btn-' + _this.size;
11408 if (_this.disabled) {
11419 cls: 'form-hidden-field'
11423 cls: 'select2-choices',
11427 cls: 'select2-search-field',
11439 cls: 'select2-container input-group select2-container-multi',
11444 // cls: 'typeahead typeahead-long dropdown-menu',
11445 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11450 if(this.hasFeedback && !this.allowBlank){
11454 cls: 'glyphicon form-control-feedback'
11457 combobox.cn.push(feedback);
11460 if (align ==='left' && this.fieldLabel.length) {
11462 Roo.log("left and has label");
11468 cls : 'control-label col-sm-' + this.labelWidth,
11469 html : this.fieldLabel
11473 cls : "col-sm-" + (12 - this.labelWidth),
11480 } else if ( this.fieldLabel.length) {
11486 //cls : 'input-group-addon',
11487 html : this.fieldLabel
11497 Roo.log(" no label && no align");
11504 ['xs','sm','md','lg'].map(function(size){
11505 if (settings[size]) {
11506 cfg.cls += ' col-' + size + '-' + settings[size];
11515 initEvents: function()
11519 throw "can not find store for combo";
11522 this.store = Roo.factory(this.store, Roo.data);
11528 if(Roo.isTouch && this.mobileTouchView){
11529 this.initTouchView();
11534 this.initTickableEvents();
11538 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11540 if(this.hiddenName){
11542 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11544 this.hiddenField.dom.value =
11545 this.hiddenValue !== undefined ? this.hiddenValue :
11546 this.value !== undefined ? this.value : '';
11548 // prevent input submission
11549 this.el.dom.removeAttribute('name');
11550 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11555 // this.el.dom.setAttribute('autocomplete', 'off');
11558 var cls = 'x-combo-list';
11560 //this.list = new Roo.Layer({
11561 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11567 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11568 _this.list.setWidth(lw);
11571 this.list.on('mouseover', this.onViewOver, this);
11572 this.list.on('mousemove', this.onViewMove, this);
11574 this.list.on('scroll', this.onViewScroll, this);
11577 this.list.swallowEvent('mousewheel');
11578 this.assetHeight = 0;
11581 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11582 this.assetHeight += this.header.getHeight();
11585 this.innerList = this.list.createChild({cls:cls+'-inner'});
11586 this.innerList.on('mouseover', this.onViewOver, this);
11587 this.innerList.on('mousemove', this.onViewMove, this);
11588 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11590 if(this.allowBlank && !this.pageSize && !this.disableClear){
11591 this.footer = this.list.createChild({cls:cls+'-ft'});
11592 this.pageTb = new Roo.Toolbar(this.footer);
11596 this.footer = this.list.createChild({cls:cls+'-ft'});
11597 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11598 {pageSize: this.pageSize});
11602 if (this.pageTb && this.allowBlank && !this.disableClear) {
11604 this.pageTb.add(new Roo.Toolbar.Fill(), {
11605 cls: 'x-btn-icon x-btn-clear',
11607 handler: function()
11610 _this.clearValue();
11611 _this.onSelect(false, -1);
11616 this.assetHeight += this.footer.getHeight();
11621 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11624 this.view = new Roo.View(this.list, this.tpl, {
11625 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11627 //this.view.wrapEl.setDisplayed(false);
11628 this.view.on('click', this.onViewClick, this);
11632 this.store.on('beforeload', this.onBeforeLoad, this);
11633 this.store.on('load', this.onLoad, this);
11634 this.store.on('loadexception', this.onLoadException, this);
11636 if(this.resizable){
11637 this.resizer = new Roo.Resizable(this.list, {
11638 pinned:true, handles:'se'
11640 this.resizer.on('resize', function(r, w, h){
11641 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11642 this.listWidth = w;
11643 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11644 this.restrictHeight();
11646 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11649 if(!this.editable){
11650 this.editable = true;
11651 this.setEditable(false);
11656 if (typeof(this.events.add.listeners) != 'undefined') {
11658 this.addicon = this.wrap.createChild(
11659 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11661 this.addicon.on('click', function(e) {
11662 this.fireEvent('add', this);
11665 if (typeof(this.events.edit.listeners) != 'undefined') {
11667 this.editicon = this.wrap.createChild(
11668 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11669 if (this.addicon) {
11670 this.editicon.setStyle('margin-left', '40px');
11672 this.editicon.on('click', function(e) {
11674 // we fire even if inothing is selected..
11675 this.fireEvent('edit', this, this.lastData );
11681 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11682 "up" : function(e){
11683 this.inKeyMode = true;
11687 "down" : function(e){
11688 if(!this.isExpanded()){
11689 this.onTriggerClick();
11691 this.inKeyMode = true;
11696 "enter" : function(e){
11697 // this.onViewClick();
11701 if(this.fireEvent("specialkey", this, e)){
11702 this.onViewClick(false);
11708 "esc" : function(e){
11712 "tab" : function(e){
11715 if(this.fireEvent("specialkey", this, e)){
11716 this.onViewClick(false);
11724 doRelay : function(foo, bar, hname){
11725 if(hname == 'down' || this.scope.isExpanded()){
11726 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11735 this.queryDelay = Math.max(this.queryDelay || 10,
11736 this.mode == 'local' ? 10 : 250);
11739 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11741 if(this.typeAhead){
11742 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11744 if(this.editable !== false){
11745 this.inputEl().on("keyup", this.onKeyUp, this);
11747 if(this.forceSelection){
11748 this.inputEl().on('blur', this.doForce, this);
11752 this.choices = this.el.select('ul.select2-choices', true).first();
11753 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11757 initTickableEvents: function()
11761 if(this.hiddenName){
11763 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11765 this.hiddenField.dom.value =
11766 this.hiddenValue !== undefined ? this.hiddenValue :
11767 this.value !== undefined ? this.value : '';
11769 // prevent input submission
11770 this.el.dom.removeAttribute('name');
11771 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11776 // this.list = this.el.select('ul.dropdown-menu',true).first();
11778 this.choices = this.el.select('ul.select2-choices', true).first();
11779 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11780 if(this.triggerList){
11781 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11784 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11785 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11787 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11788 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11790 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11791 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11793 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11794 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11795 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11798 this.cancelBtn.hide();
11803 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11804 _this.list.setWidth(lw);
11807 this.list.on('mouseover', this.onViewOver, this);
11808 this.list.on('mousemove', this.onViewMove, this);
11810 this.list.on('scroll', this.onViewScroll, this);
11813 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>';
11816 this.view = new Roo.View(this.list, this.tpl, {
11817 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11820 //this.view.wrapEl.setDisplayed(false);
11821 this.view.on('click', this.onViewClick, this);
11825 this.store.on('beforeload', this.onBeforeLoad, this);
11826 this.store.on('load', this.onLoad, this);
11827 this.store.on('loadexception', this.onLoadException, this);
11830 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11831 "up" : function(e){
11832 this.inKeyMode = true;
11836 "down" : function(e){
11837 this.inKeyMode = true;
11841 "enter" : function(e){
11842 if(this.fireEvent("specialkey", this, e)){
11843 this.onViewClick(false);
11849 "esc" : function(e){
11850 this.onTickableFooterButtonClick(e, false, false);
11853 "tab" : function(e){
11854 this.fireEvent("specialkey", this, e);
11856 this.onTickableFooterButtonClick(e, false, false);
11863 doRelay : function(e, fn, key){
11864 if(this.scope.isExpanded()){
11865 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11874 this.queryDelay = Math.max(this.queryDelay || 10,
11875 this.mode == 'local' ? 10 : 250);
11878 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11880 if(this.typeAhead){
11881 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11884 if(this.editable !== false){
11885 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11890 onDestroy : function(){
11892 this.view.setStore(null);
11893 this.view.el.removeAllListeners();
11894 this.view.el.remove();
11895 this.view.purgeListeners();
11898 this.list.dom.innerHTML = '';
11902 this.store.un('beforeload', this.onBeforeLoad, this);
11903 this.store.un('load', this.onLoad, this);
11904 this.store.un('loadexception', this.onLoadException, this);
11906 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11910 fireKey : function(e){
11911 if(e.isNavKeyPress() && !this.list.isVisible()){
11912 this.fireEvent("specialkey", this, e);
11917 onResize: function(w, h){
11918 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11920 // if(typeof w != 'number'){
11921 // // we do not handle it!?!?
11924 // var tw = this.trigger.getWidth();
11925 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11926 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11928 // this.inputEl().setWidth( this.adjustWidth('input', x));
11930 // //this.trigger.setStyle('left', x+'px');
11932 // if(this.list && this.listWidth === undefined){
11933 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11934 // this.list.setWidth(lw);
11935 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11943 * Allow or prevent the user from directly editing the field text. If false is passed,
11944 * the user will only be able to select from the items defined in the dropdown list. This method
11945 * is the runtime equivalent of setting the 'editable' config option at config time.
11946 * @param {Boolean} value True to allow the user to directly edit the field text
11948 setEditable : function(value){
11949 if(value == this.editable){
11952 this.editable = value;
11954 this.inputEl().dom.setAttribute('readOnly', true);
11955 this.inputEl().on('mousedown', this.onTriggerClick, this);
11956 this.inputEl().addClass('x-combo-noedit');
11958 this.inputEl().dom.setAttribute('readOnly', false);
11959 this.inputEl().un('mousedown', this.onTriggerClick, this);
11960 this.inputEl().removeClass('x-combo-noedit');
11966 onBeforeLoad : function(combo,opts){
11967 if(!this.hasFocus){
11971 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11973 this.restrictHeight();
11974 this.selectedIndex = -1;
11978 onLoad : function(){
11980 this.hasQuery = false;
11982 if(!this.hasFocus){
11986 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11987 this.loading.hide();
11990 if(this.store.getCount() > 0){
11992 this.restrictHeight();
11993 if(this.lastQuery == this.allQuery){
11994 if(this.editable && !this.tickable){
11995 this.inputEl().dom.select();
11999 !this.selectByValue(this.value, true) &&
12002 !this.store.lastOptions ||
12003 typeof(this.store.lastOptions.add) == 'undefined' ||
12004 this.store.lastOptions.add != true
12007 this.select(0, true);
12010 if(this.autoFocus){
12013 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12014 this.taTask.delay(this.typeAheadDelay);
12018 this.onEmptyResults();
12024 onLoadException : function()
12026 this.hasQuery = false;
12028 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12029 this.loading.hide();
12032 if(this.tickable && this.editable){
12038 Roo.log(this.store.reader.jsonData);
12039 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12041 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12047 onTypeAhead : function(){
12048 if(this.store.getCount() > 0){
12049 var r = this.store.getAt(0);
12050 var newValue = r.data[this.displayField];
12051 var len = newValue.length;
12052 var selStart = this.getRawValue().length;
12054 if(selStart != len){
12055 this.setRawValue(newValue);
12056 this.selectText(selStart, newValue.length);
12062 onSelect : function(record, index){
12064 if(this.fireEvent('beforeselect', this, record, index) !== false){
12066 this.setFromData(index > -1 ? record.data : false);
12069 this.fireEvent('select', this, record, index);
12074 * Returns the currently selected field value or empty string if no value is set.
12075 * @return {String} value The selected value
12077 getValue : function(){
12080 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12083 if(this.valueField){
12084 return typeof this.value != 'undefined' ? this.value : '';
12086 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12091 * Clears any text/value currently set in the field
12093 clearValue : function(){
12094 if(this.hiddenField){
12095 this.hiddenField.dom.value = '';
12098 this.setRawValue('');
12099 this.lastSelectionText = '';
12100 this.lastData = false;
12102 var close = this.closeTriggerEl();
12111 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12112 * will be displayed in the field. If the value does not match the data value of an existing item,
12113 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12114 * Otherwise the field will be blank (although the value will still be set).
12115 * @param {String} value The value to match
12117 setValue : function(v){
12124 if(this.valueField){
12125 var r = this.findRecord(this.valueField, v);
12127 text = r.data[this.displayField];
12128 }else if(this.valueNotFoundText !== undefined){
12129 text = this.valueNotFoundText;
12132 this.lastSelectionText = text;
12133 if(this.hiddenField){
12134 this.hiddenField.dom.value = v;
12136 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12139 var close = this.closeTriggerEl();
12142 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
12146 * @property {Object} the last set data for the element
12151 * Sets the value of the field based on a object which is related to the record format for the store.
12152 * @param {Object} value the value to set as. or false on reset?
12154 setFromData : function(o){
12161 var dv = ''; // display value
12162 var vv = ''; // value value..
12164 if (this.displayField) {
12165 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12167 // this is an error condition!!!
12168 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12171 if(this.valueField){
12172 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12175 var close = this.closeTriggerEl();
12178 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12181 if(this.hiddenField){
12182 this.hiddenField.dom.value = vv;
12184 this.lastSelectionText = dv;
12185 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12189 // no hidden field.. - we store the value in 'value', but still display
12190 // display field!!!!
12191 this.lastSelectionText = dv;
12192 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12199 reset : function(){
12200 // overridden so that last data is reset..
12207 this.setValue(this.originalValue);
12208 this.clearInvalid();
12209 this.lastData = false;
12211 this.view.clearSelections();
12215 findRecord : function(prop, value){
12217 if(this.store.getCount() > 0){
12218 this.store.each(function(r){
12219 if(r.data[prop] == value){
12229 getName: function()
12231 // returns hidden if it's set..
12232 if (!this.rendered) {return ''};
12233 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12237 onViewMove : function(e, t){
12238 this.inKeyMode = false;
12242 onViewOver : function(e, t){
12243 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12246 var item = this.view.findItemFromChild(t);
12249 var index = this.view.indexOf(item);
12250 this.select(index, false);
12255 onViewClick : function(view, doFocus, el, e)
12257 var index = this.view.getSelectedIndexes()[0];
12259 var r = this.store.getAt(index);
12263 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12270 Roo.each(this.tickItems, function(v,k){
12272 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12273 _this.tickItems.splice(k, 1);
12275 if(typeof(e) == 'undefined' && view == false){
12276 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12288 this.tickItems.push(r.data);
12290 if(typeof(e) == 'undefined' && view == false){
12291 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12298 this.onSelect(r, index);
12300 if(doFocus !== false && !this.blockFocus){
12301 this.inputEl().focus();
12306 restrictHeight : function(){
12307 //this.innerList.dom.style.height = '';
12308 //var inner = this.innerList.dom;
12309 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12310 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12311 //this.list.beginUpdate();
12312 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12313 this.list.alignTo(this.inputEl(), this.listAlign);
12314 this.list.alignTo(this.inputEl(), this.listAlign);
12315 //this.list.endUpdate();
12319 onEmptyResults : function(){
12321 if(this.tickable && this.editable){
12322 this.restrictHeight();
12330 * Returns true if the dropdown list is expanded, else false.
12332 isExpanded : function(){
12333 return this.list.isVisible();
12337 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12338 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12339 * @param {String} value The data value of the item to select
12340 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12341 * selected item if it is not currently in view (defaults to true)
12342 * @return {Boolean} True if the value matched an item in the list, else false
12344 selectByValue : function(v, scrollIntoView){
12345 if(v !== undefined && v !== null){
12346 var r = this.findRecord(this.valueField || this.displayField, v);
12348 this.select(this.store.indexOf(r), scrollIntoView);
12356 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12357 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12358 * @param {Number} index The zero-based index of the list item to select
12359 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12360 * selected item if it is not currently in view (defaults to true)
12362 select : function(index, scrollIntoView){
12363 this.selectedIndex = index;
12364 this.view.select(index);
12365 if(scrollIntoView !== false){
12366 var el = this.view.getNode(index);
12368 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12371 this.list.scrollChildIntoView(el, false);
12377 selectNext : function(){
12378 var ct = this.store.getCount();
12380 if(this.selectedIndex == -1){
12382 }else if(this.selectedIndex < ct-1){
12383 this.select(this.selectedIndex+1);
12389 selectPrev : function(){
12390 var ct = this.store.getCount();
12392 if(this.selectedIndex == -1){
12394 }else if(this.selectedIndex != 0){
12395 this.select(this.selectedIndex-1);
12401 onKeyUp : function(e){
12402 if(this.editable !== false && !e.isSpecialKey()){
12403 this.lastKey = e.getKey();
12404 this.dqTask.delay(this.queryDelay);
12409 validateBlur : function(){
12410 return !this.list || !this.list.isVisible();
12414 initQuery : function(){
12416 var v = this.getRawValue();
12418 if(this.tickable && this.editable){
12419 v = this.tickableInputEl().getValue();
12426 doForce : function(){
12427 if(this.inputEl().dom.value.length > 0){
12428 this.inputEl().dom.value =
12429 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12435 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12436 * query allowing the query action to be canceled if needed.
12437 * @param {String} query The SQL query to execute
12438 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12439 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12440 * saved in the current store (defaults to false)
12442 doQuery : function(q, forceAll){
12444 if(q === undefined || q === null){
12449 forceAll: forceAll,
12453 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12458 forceAll = qe.forceAll;
12459 if(forceAll === true || (q.length >= this.minChars)){
12461 this.hasQuery = true;
12463 if(this.lastQuery != q || this.alwaysQuery){
12464 this.lastQuery = q;
12465 if(this.mode == 'local'){
12466 this.selectedIndex = -1;
12468 this.store.clearFilter();
12471 if(this.specialFilter){
12472 this.fireEvent('specialfilter', this);
12477 this.store.filter(this.displayField, q);
12480 this.store.fireEvent("datachanged", this.store);
12487 this.store.baseParams[this.queryParam] = q;
12489 var options = {params : this.getParams(q)};
12492 options.add = true;
12493 options.params.start = this.page * this.pageSize;
12496 this.store.load(options);
12499 * this code will make the page width larger, at the beginning, the list not align correctly,
12500 * we should expand the list on onLoad
12501 * so command out it
12506 this.selectedIndex = -1;
12511 this.loadNext = false;
12515 getParams : function(q){
12517 //p[this.queryParam] = q;
12521 p.limit = this.pageSize;
12527 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12529 collapse : function(){
12530 if(!this.isExpanded()){
12537 this.hasFocus = false;
12539 this.cancelBtn.hide();
12540 this.trigger.show();
12543 this.tickableInputEl().dom.value = '';
12544 this.tickableInputEl().blur();
12549 Roo.get(document).un('mousedown', this.collapseIf, this);
12550 Roo.get(document).un('mousewheel', this.collapseIf, this);
12551 if (!this.editable) {
12552 Roo.get(document).un('keydown', this.listKeyPress, this);
12554 this.fireEvent('collapse', this);
12558 collapseIf : function(e){
12559 var in_combo = e.within(this.el);
12560 var in_list = e.within(this.list);
12561 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12563 if (in_combo || in_list || is_list) {
12564 //e.stopPropagation();
12569 this.onTickableFooterButtonClick(e, false, false);
12577 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12579 expand : function(){
12581 if(this.isExpanded() || !this.hasFocus){
12585 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12586 this.list.setWidth(lw);
12593 this.restrictHeight();
12597 this.tickItems = Roo.apply([], this.item);
12600 this.cancelBtn.show();
12601 this.trigger.hide();
12604 this.tickableInputEl().focus();
12609 Roo.get(document).on('mousedown', this.collapseIf, this);
12610 Roo.get(document).on('mousewheel', this.collapseIf, this);
12611 if (!this.editable) {
12612 Roo.get(document).on('keydown', this.listKeyPress, this);
12615 this.fireEvent('expand', this);
12619 // Implements the default empty TriggerField.onTriggerClick function
12620 onTriggerClick : function(e)
12622 Roo.log('trigger click');
12624 if(this.disabled || !this.triggerList){
12629 this.loadNext = false;
12631 if(this.isExpanded()){
12633 if (!this.blockFocus) {
12634 this.inputEl().focus();
12638 this.hasFocus = true;
12639 if(this.triggerAction == 'all') {
12640 this.doQuery(this.allQuery, true);
12642 this.doQuery(this.getRawValue());
12644 if (!this.blockFocus) {
12645 this.inputEl().focus();
12650 onTickableTriggerClick : function(e)
12657 this.loadNext = false;
12658 this.hasFocus = true;
12660 if(this.triggerAction == 'all') {
12661 this.doQuery(this.allQuery, true);
12663 this.doQuery(this.getRawValue());
12667 onSearchFieldClick : function(e)
12669 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12670 this.onTickableFooterButtonClick(e, false, false);
12674 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12679 this.loadNext = false;
12680 this.hasFocus = true;
12682 if(this.triggerAction == 'all') {
12683 this.doQuery(this.allQuery, true);
12685 this.doQuery(this.getRawValue());
12689 listKeyPress : function(e)
12691 //Roo.log('listkeypress');
12692 // scroll to first matching element based on key pres..
12693 if (e.isSpecialKey()) {
12696 var k = String.fromCharCode(e.getKey()).toUpperCase();
12699 var csel = this.view.getSelectedNodes();
12700 var cselitem = false;
12702 var ix = this.view.indexOf(csel[0]);
12703 cselitem = this.store.getAt(ix);
12704 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12710 this.store.each(function(v) {
12712 // start at existing selection.
12713 if (cselitem.id == v.id) {
12719 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12720 match = this.store.indexOf(v);
12726 if (match === false) {
12727 return true; // no more action?
12730 this.view.select(match);
12731 var sn = Roo.get(this.view.getSelectedNodes()[0])
12732 sn.scrollIntoView(sn.dom.parentNode, false);
12735 onViewScroll : function(e, t){
12737 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){
12741 this.hasQuery = true;
12743 this.loading = this.list.select('.loading', true).first();
12745 if(this.loading === null){
12746 this.list.createChild({
12748 cls: 'loading select2-more-results select2-active',
12749 html: 'Loading more results...'
12752 this.loading = this.list.select('.loading', true).first();
12754 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12756 this.loading.hide();
12759 this.loading.show();
12764 this.loadNext = true;
12766 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12771 addItem : function(o)
12773 var dv = ''; // display value
12775 if (this.displayField) {
12776 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12778 // this is an error condition!!!
12779 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12786 var choice = this.choices.createChild({
12788 cls: 'select2-search-choice',
12797 cls: 'select2-search-choice-close',
12802 }, this.searchField);
12804 var close = choice.select('a.select2-search-choice-close', true).first()
12806 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12814 this.inputEl().dom.value = '';
12819 onRemoveItem : function(e, _self, o)
12821 e.preventDefault();
12823 this.lastItem = Roo.apply([], this.item);
12825 var index = this.item.indexOf(o.data) * 1;
12828 Roo.log('not this item?!');
12832 this.item.splice(index, 1);
12837 this.fireEvent('remove', this, e);
12843 syncValue : function()
12845 if(!this.item.length){
12852 Roo.each(this.item, function(i){
12853 if(_this.valueField){
12854 value.push(i[_this.valueField]);
12861 this.value = value.join(',');
12863 if(this.hiddenField){
12864 this.hiddenField.dom.value = this.value;
12867 this.store.fireEvent("datachanged", this.store);
12870 clearItem : function()
12872 if(!this.multiple){
12878 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12887 inputEl: function ()
12889 if(Roo.isTouch && this.mobileTouchView){
12890 return this.el.select('input.form-control',true).first();
12894 return this.searchField;
12897 return this.el.select('input.form-control',true).first();
12901 onTickableFooterButtonClick : function(e, btn, el)
12903 e.preventDefault();
12905 this.lastItem = Roo.apply([], this.item);
12907 if(btn && btn.name == 'cancel'){
12908 this.tickItems = Roo.apply([], this.item);
12917 Roo.each(this.tickItems, function(o){
12925 validate : function()
12927 var v = this.getRawValue();
12930 v = this.getValue();
12933 if(this.disabled || this.allowBlank || v.length){
12938 this.markInvalid();
12942 tickableInputEl : function()
12944 if(!this.tickable || !this.editable){
12945 return this.inputEl();
12948 return this.inputEl().select('.select2-search-field-input', true).first();
12952 getAutoCreateTouchView : function()
12957 cls: 'form-group' //input-group
12963 type : this.inputType,
12964 cls : 'form-control x-combo-noedit',
12965 autocomplete: 'new-password',
12966 placeholder : this.placeholder || '',
12971 input.name = this.name;
12975 input.cls += ' input-' + this.size;
12978 if (this.disabled) {
12979 input.disabled = true;
12990 inputblock.cls += ' input-group';
12992 inputblock.cn.unshift({
12994 cls : 'input-group-addon',
12999 if(this.removable && !this.multiple){
13000 inputblock.cls += ' roo-removable';
13002 inputblock.cn.push({
13005 cls : 'roo-combo-removable-btn close'
13009 if(this.hasFeedback && !this.allowBlank){
13011 inputblock.cls += ' has-feedback';
13013 inputblock.cn.push({
13015 cls: 'glyphicon form-control-feedback'
13022 inputblock.cls += (this.before) ? '' : ' input-group';
13024 inputblock.cn.push({
13026 cls : 'input-group-addon',
13037 cls: 'form-hidden-field'
13051 cls: 'form-hidden-field'
13055 cls: 'select2-choices',
13059 cls: 'select2-search-field',
13072 cls: 'select2-container input-group',
13079 combobox.cls += ' select2-container-multi';
13082 var align = this.labelAlign || this.parentLabelAlign();
13086 if(this.fieldLabel.length){
13088 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13089 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13094 cls : 'control-label ' + lw,
13095 html : this.fieldLabel
13107 var settings = this;
13109 ['xs','sm','md','lg'].map(function(size){
13110 if (settings[size]) {
13111 cfg.cls += ' col-' + size + '-' + settings[size];
13118 initTouchView : function()
13120 this.renderTouchView();
13122 this.touchViewEl.on('scroll', function(){
13123 this.el.dom.scrollTop = 0;
13126 this.inputEl().on("click", this.showTouchView, this);
13127 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13128 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13130 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13132 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13133 this.store.on('load', this.onTouchViewLoad, this);
13134 this.store.on('loadexception', this.onTouchViewLoadException, this);
13136 if(this.hiddenName){
13138 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13140 this.hiddenField.dom.value =
13141 this.hiddenValue !== undefined ? this.hiddenValue :
13142 this.value !== undefined ? this.value : '';
13144 this.el.dom.removeAttribute('name');
13145 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13149 this.choices = this.el.select('ul.select2-choices', true).first();
13150 this.searchField = this.el.select('ul li.select2-search-field', true).first();
13153 if(this.removable && !this.multiple){
13154 var close = this.closeTriggerEl();
13156 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
13157 close.on('click', this.removeBtnClick, this, close);
13166 renderTouchView : function()
13168 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13169 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13171 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13172 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13174 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13175 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13176 this.touchViewBodyEl.setStyle('overflow', 'auto');
13178 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13179 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13181 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13182 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13186 showTouchView : function()
13188 this.touchViewHeaderEl.hide();
13190 if(this.fieldLabel.length){
13191 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
13192 this.touchViewHeaderEl.show();
13195 this.touchViewEl.show();
13197 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
13198 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13200 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
13202 if(this.fieldLabel.length){
13203 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
13206 this.touchViewBodyEl.setHeight(bodyHeight);
13210 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
13212 this.touchViewEl.addClass('in');
13215 this.doTouchViewQuery();
13219 hideTouchView : function()
13221 this.touchViewEl.removeClass('in');
13225 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
13227 this.touchViewEl.setStyle('display', 'none');
13232 setTouchViewValue : function()
13239 Roo.each(this.tickItems, function(o){
13244 this.hideTouchView();
13247 doTouchViewQuery : function()
13256 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
13260 if(!this.alwaysQuery || this.mode == 'local'){
13261 this.onTouchViewLoad();
13268 onTouchViewBeforeLoad : function(combo,opts)
13274 onTouchViewLoad : function()
13276 if(this.store.getCount() < 1){
13277 this.onTouchViewEmptyResults();
13281 this.clearTouchView();
13283 var rawValue = this.getRawValue();
13285 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
13287 this.tickItems = [];
13289 this.store.data.each(function(d, rowIndex){
13290 var row = this.touchViewListGroup.createChild(template);
13292 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
13293 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = d.data[this.displayField];
13296 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
13297 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13300 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
13301 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13302 this.tickItems.push(d.data);
13305 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
13309 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
13311 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
13313 if(this.fieldLabel.length){
13314 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
13317 var listHeight = this.touchViewListGroup.getHeight();
13319 if(firstChecked && listHeight > bodyHeight){
13320 (function() { firstChecked.findParent('li').scrollIntoView(this.touchViewListGroup.dom); }).defer(500);
13325 onTouchViewLoadException : function()
13327 this.hideTouchView();
13330 onTouchViewEmptyResults : function()
13332 this.clearTouchView();
13334 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
13336 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
13340 clearTouchView : function()
13342 this.touchViewListGroup.dom.innerHTML = '';
13345 onTouchViewClick : function(e, el, o)
13347 e.preventDefault();
13350 var rowIndex = o.rowIndex;
13352 var r = this.store.getAt(rowIndex);
13354 if(!this.multiple){
13355 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
13356 c.dom.removeAttribute('checked');
13359 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13361 this.setFromData(r.data);
13363 var close = this.closeTriggerEl();
13369 this.hideTouchView();
13374 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
13375 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
13376 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
13380 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
13381 this.addItem(r.data);
13382 this.tickItems.push(r.data);
13390 * @cfg {Boolean} grow
13394 * @cfg {Number} growMin
13398 * @cfg {Number} growMax
13407 Roo.apply(Roo.bootstrap.ComboBox, {
13411 cls: 'modal-header',
13433 cls: 'list-group-item',
13437 cls: 'roo-combobox-list-group-item-value'
13441 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
13455 listItemCheckbox : {
13457 cls: 'list-group-item',
13461 cls: 'roo-combobox-list-group-item-value'
13465 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
13481 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
13486 cls: 'modal-footer',
13494 cls: 'col-xs-6 text-left',
13497 cls: 'btn btn-danger roo-touch-view-cancel',
13503 cls: 'col-xs-6 text-right',
13506 cls: 'btn btn-success roo-touch-view-ok',
13517 Roo.apply(Roo.bootstrap.ComboBox, {
13519 touchViewTemplate : {
13521 cls: 'modal fade roo-combobox-touch-view',
13525 cls: 'modal-dialog',
13529 cls: 'modal-content',
13531 Roo.bootstrap.ComboBox.header,
13532 Roo.bootstrap.ComboBox.body,
13533 Roo.bootstrap.ComboBox.footer
13542 * Ext JS Library 1.1.1
13543 * Copyright(c) 2006-2007, Ext JS, LLC.
13545 * Originally Released Under LGPL - original licence link has changed is not relivant.
13548 * <script type="text/javascript">
13553 * @extends Roo.util.Observable
13554 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
13555 * This class also supports single and multi selection modes. <br>
13556 * Create a data model bound view:
13558 var store = new Roo.data.Store(...);
13560 var view = new Roo.View({
13562 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
13564 singleSelect: true,
13565 selectedClass: "ydataview-selected",
13569 // listen for node click?
13570 view.on("click", function(vw, index, node, e){
13571 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
13575 dataModel.load("foobar.xml");
13577 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
13579 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
13580 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
13582 * Note: old style constructor is still suported (container, template, config)
13585 * Create a new View
13586 * @param {Object} config The config object
13589 Roo.View = function(config, depreciated_tpl, depreciated_config){
13591 this.parent = false;
13593 if (typeof(depreciated_tpl) == 'undefined') {
13594 // new way.. - universal constructor.
13595 Roo.apply(this, config);
13596 this.el = Roo.get(this.el);
13599 this.el = Roo.get(config);
13600 this.tpl = depreciated_tpl;
13601 Roo.apply(this, depreciated_config);
13603 this.wrapEl = this.el.wrap().wrap();
13604 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
13607 if(typeof(this.tpl) == "string"){
13608 this.tpl = new Roo.Template(this.tpl);
13610 // support xtype ctors..
13611 this.tpl = new Roo.factory(this.tpl, Roo);
13615 this.tpl.compile();
13620 * @event beforeclick
13621 * Fires before a click is processed. Returns false to cancel the default action.
13622 * @param {Roo.View} this
13623 * @param {Number} index The index of the target node
13624 * @param {HTMLElement} node The target node
13625 * @param {Roo.EventObject} e The raw event object
13627 "beforeclick" : true,
13630 * Fires when a template node is clicked.
13631 * @param {Roo.View} this
13632 * @param {Number} index The index of the target node
13633 * @param {HTMLElement} node The target node
13634 * @param {Roo.EventObject} e The raw event object
13639 * Fires when a template node is double clicked.
13640 * @param {Roo.View} this
13641 * @param {Number} index The index of the target node
13642 * @param {HTMLElement} node The target node
13643 * @param {Roo.EventObject} e The raw event object
13647 * @event contextmenu
13648 * Fires when a template node is right clicked.
13649 * @param {Roo.View} this
13650 * @param {Number} index The index of the target node
13651 * @param {HTMLElement} node The target node
13652 * @param {Roo.EventObject} e The raw event object
13654 "contextmenu" : true,
13656 * @event selectionchange
13657 * Fires when the selected nodes change.
13658 * @param {Roo.View} this
13659 * @param {Array} selections Array of the selected nodes
13661 "selectionchange" : true,
13664 * @event beforeselect
13665 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
13666 * @param {Roo.View} this
13667 * @param {HTMLElement} node The node to be selected
13668 * @param {Array} selections Array of currently selected nodes
13670 "beforeselect" : true,
13672 * @event preparedata
13673 * Fires on every row to render, to allow you to change the data.
13674 * @param {Roo.View} this
13675 * @param {Object} data to be rendered (change this)
13677 "preparedata" : true
13685 "click": this.onClick,
13686 "dblclick": this.onDblClick,
13687 "contextmenu": this.onContextMenu,
13691 this.selections = [];
13693 this.cmp = new Roo.CompositeElementLite([]);
13695 this.store = Roo.factory(this.store, Roo.data);
13696 this.setStore(this.store, true);
13699 if ( this.footer && this.footer.xtype) {
13701 var fctr = this.wrapEl.appendChild(document.createElement("div"));
13703 this.footer.dataSource = this.store
13704 this.footer.container = fctr;
13705 this.footer = Roo.factory(this.footer, Roo);
13706 fctr.insertFirst(this.el);
13708 // this is a bit insane - as the paging toolbar seems to detach the el..
13709 // dom.parentNode.parentNode.parentNode
13710 // they get detached?
13714 Roo.View.superclass.constructor.call(this);
13719 Roo.extend(Roo.View, Roo.util.Observable, {
13722 * @cfg {Roo.data.Store} store Data store to load data from.
13727 * @cfg {String|Roo.Element} el The container element.
13732 * @cfg {String|Roo.Template} tpl The template used by this View
13736 * @cfg {String} dataName the named area of the template to use as the data area
13737 * Works with domtemplates roo-name="name"
13741 * @cfg {String} selectedClass The css class to add to selected nodes
13743 selectedClass : "x-view-selected",
13745 * @cfg {String} emptyText The empty text to show when nothing is loaded.
13750 * @cfg {String} text to display on mask (default Loading)
13754 * @cfg {Boolean} multiSelect Allow multiple selection
13756 multiSelect : false,
13758 * @cfg {Boolean} singleSelect Allow single selection
13760 singleSelect: false,
13763 * @cfg {Boolean} toggleSelect - selecting
13765 toggleSelect : false,
13768 * @cfg {Boolean} tickable - selecting
13773 * Returns the element this view is bound to.
13774 * @return {Roo.Element}
13776 getEl : function(){
13777 return this.wrapEl;
13783 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13785 refresh : function(){
13786 //Roo.log('refresh');
13789 // if we are using something like 'domtemplate', then
13790 // the what gets used is:
13791 // t.applySubtemplate(NAME, data, wrapping data..)
13792 // the outer template then get' applied with
13793 // the store 'extra data'
13794 // and the body get's added to the
13795 // roo-name="data" node?
13796 // <span class='roo-tpl-{name}'></span> ?????
13800 this.clearSelections();
13801 this.el.update("");
13803 var records = this.store.getRange();
13804 if(records.length < 1) {
13806 // is this valid?? = should it render a template??
13808 this.el.update(this.emptyText);
13812 if (this.dataName) {
13813 this.el.update(t.apply(this.store.meta)); //????
13814 el = this.el.child('.roo-tpl-' + this.dataName);
13817 for(var i = 0, len = records.length; i < len; i++){
13818 var data = this.prepareData(records[i].data, i, records[i]);
13819 this.fireEvent("preparedata", this, data, i, records[i]);
13821 var d = Roo.apply({}, data);
13824 Roo.apply(d, {'roo-id' : Roo.id()});
13828 Roo.each(this.parent.item, function(item){
13829 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13832 Roo.apply(d, {'roo-data-checked' : 'checked'});
13836 html[html.length] = Roo.util.Format.trim(
13838 t.applySubtemplate(this.dataName, d, this.store.meta) :
13845 el.update(html.join(""));
13846 this.nodes = el.dom.childNodes;
13847 this.updateIndexes(0);
13852 * Function to override to reformat the data that is sent to
13853 * the template for each node.
13854 * DEPRICATED - use the preparedata event handler.
13855 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13856 * a JSON object for an UpdateManager bound view).
13858 prepareData : function(data, index, record)
13860 this.fireEvent("preparedata", this, data, index, record);
13864 onUpdate : function(ds, record){
13865 // Roo.log('on update');
13866 this.clearSelections();
13867 var index = this.store.indexOf(record);
13868 var n = this.nodes[index];
13869 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13870 n.parentNode.removeChild(n);
13871 this.updateIndexes(index, index);
13877 onAdd : function(ds, records, index)
13879 //Roo.log(['on Add', ds, records, index] );
13880 this.clearSelections();
13881 if(this.nodes.length == 0){
13885 var n = this.nodes[index];
13886 for(var i = 0, len = records.length; i < len; i++){
13887 var d = this.prepareData(records[i].data, i, records[i]);
13889 this.tpl.insertBefore(n, d);
13892 this.tpl.append(this.el, d);
13895 this.updateIndexes(index);
13898 onRemove : function(ds, record, index){
13899 // Roo.log('onRemove');
13900 this.clearSelections();
13901 var el = this.dataName ?
13902 this.el.child('.roo-tpl-' + this.dataName) :
13905 el.dom.removeChild(this.nodes[index]);
13906 this.updateIndexes(index);
13910 * Refresh an individual node.
13911 * @param {Number} index
13913 refreshNode : function(index){
13914 this.onUpdate(this.store, this.store.getAt(index));
13917 updateIndexes : function(startIndex, endIndex){
13918 var ns = this.nodes;
13919 startIndex = startIndex || 0;
13920 endIndex = endIndex || ns.length - 1;
13921 for(var i = startIndex; i <= endIndex; i++){
13922 ns[i].nodeIndex = i;
13927 * Changes the data store this view uses and refresh the view.
13928 * @param {Store} store
13930 setStore : function(store, initial){
13931 if(!initial && this.store){
13932 this.store.un("datachanged", this.refresh);
13933 this.store.un("add", this.onAdd);
13934 this.store.un("remove", this.onRemove);
13935 this.store.un("update", this.onUpdate);
13936 this.store.un("clear", this.refresh);
13937 this.store.un("beforeload", this.onBeforeLoad);
13938 this.store.un("load", this.onLoad);
13939 this.store.un("loadexception", this.onLoad);
13943 store.on("datachanged", this.refresh, this);
13944 store.on("add", this.onAdd, this);
13945 store.on("remove", this.onRemove, this);
13946 store.on("update", this.onUpdate, this);
13947 store.on("clear", this.refresh, this);
13948 store.on("beforeload", this.onBeforeLoad, this);
13949 store.on("load", this.onLoad, this);
13950 store.on("loadexception", this.onLoad, this);
13958 * onbeforeLoad - masks the loading area.
13961 onBeforeLoad : function(store,opts)
13963 //Roo.log('onBeforeLoad');
13965 this.el.update("");
13967 this.el.mask(this.mask ? this.mask : "Loading" );
13969 onLoad : function ()
13976 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13977 * @param {HTMLElement} node
13978 * @return {HTMLElement} The template node
13980 findItemFromChild : function(node){
13981 var el = this.dataName ?
13982 this.el.child('.roo-tpl-' + this.dataName,true) :
13985 if(!node || node.parentNode == el){
13988 var p = node.parentNode;
13989 while(p && p != el){
13990 if(p.parentNode == el){
13999 onClick : function(e){
14000 var item = this.findItemFromChild(e.getTarget());
14002 var index = this.indexOf(item);
14003 if(this.onItemClick(item, index, e) !== false){
14004 this.fireEvent("click", this, index, item, e);
14007 this.clearSelections();
14012 onContextMenu : function(e){
14013 var item = this.findItemFromChild(e.getTarget());
14015 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
14020 onDblClick : function(e){
14021 var item = this.findItemFromChild(e.getTarget());
14023 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
14027 onItemClick : function(item, index, e)
14029 if(this.fireEvent("beforeclick", this, index, item, e) === false){
14032 if (this.toggleSelect) {
14033 var m = this.isSelected(item) ? 'unselect' : 'select';
14036 _t[m](item, true, false);
14039 if(this.multiSelect || this.singleSelect){
14040 if(this.multiSelect && e.shiftKey && this.lastSelection){
14041 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
14043 this.select(item, this.multiSelect && e.ctrlKey);
14044 this.lastSelection = item;
14047 if(!this.tickable){
14048 e.preventDefault();
14056 * Get the number of selected nodes.
14059 getSelectionCount : function(){
14060 return this.selections.length;
14064 * Get the currently selected nodes.
14065 * @return {Array} An array of HTMLElements
14067 getSelectedNodes : function(){
14068 return this.selections;
14072 * Get the indexes of the selected nodes.
14075 getSelectedIndexes : function(){
14076 var indexes = [], s = this.selections;
14077 for(var i = 0, len = s.length; i < len; i++){
14078 indexes.push(s[i].nodeIndex);
14084 * Clear all selections
14085 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
14087 clearSelections : function(suppressEvent){
14088 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
14089 this.cmp.elements = this.selections;
14090 this.cmp.removeClass(this.selectedClass);
14091 this.selections = [];
14092 if(!suppressEvent){
14093 this.fireEvent("selectionchange", this, this.selections);
14099 * Returns true if the passed node is selected
14100 * @param {HTMLElement/Number} node The node or node index
14101 * @return {Boolean}
14103 isSelected : function(node){
14104 var s = this.selections;
14108 node = this.getNode(node);
14109 return s.indexOf(node) !== -1;
14114 * @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
14115 * @param {Boolean} keepExisting (optional) true to keep existing selections
14116 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14118 select : function(nodeInfo, keepExisting, suppressEvent){
14119 if(nodeInfo instanceof Array){
14121 this.clearSelections(true);
14123 for(var i = 0, len = nodeInfo.length; i < len; i++){
14124 this.select(nodeInfo[i], true, true);
14128 var node = this.getNode(nodeInfo);
14129 if(!node || this.isSelected(node)){
14130 return; // already selected.
14133 this.clearSelections(true);
14136 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
14137 Roo.fly(node).addClass(this.selectedClass);
14138 this.selections.push(node);
14139 if(!suppressEvent){
14140 this.fireEvent("selectionchange", this, this.selections);
14148 * @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
14149 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
14150 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14152 unselect : function(nodeInfo, keepExisting, suppressEvent)
14154 if(nodeInfo instanceof Array){
14155 Roo.each(this.selections, function(s) {
14156 this.unselect(s, nodeInfo);
14160 var node = this.getNode(nodeInfo);
14161 if(!node || !this.isSelected(node)){
14162 //Roo.log("not selected");
14163 return; // not selected.
14167 Roo.each(this.selections, function(s) {
14169 Roo.fly(node).removeClass(this.selectedClass);
14176 this.selections= ns;
14177 this.fireEvent("selectionchange", this, this.selections);
14181 * Gets a template node.
14182 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14183 * @return {HTMLElement} The node or null if it wasn't found
14185 getNode : function(nodeInfo){
14186 if(typeof nodeInfo == "string"){
14187 return document.getElementById(nodeInfo);
14188 }else if(typeof nodeInfo == "number"){
14189 return this.nodes[nodeInfo];
14195 * Gets a range template nodes.
14196 * @param {Number} startIndex
14197 * @param {Number} endIndex
14198 * @return {Array} An array of nodes
14200 getNodes : function(start, end){
14201 var ns = this.nodes;
14202 start = start || 0;
14203 end = typeof end == "undefined" ? ns.length - 1 : end;
14206 for(var i = start; i <= end; i++){
14210 for(var i = start; i >= end; i--){
14218 * Finds the index of the passed node
14219 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14220 * @return {Number} The index of the node or -1
14222 indexOf : function(node){
14223 node = this.getNode(node);
14224 if(typeof node.nodeIndex == "number"){
14225 return node.nodeIndex;
14227 var ns = this.nodes;
14228 for(var i = 0, len = ns.length; i < len; i++){
14239 * based on jquery fullcalendar
14243 Roo.bootstrap = Roo.bootstrap || {};
14245 * @class Roo.bootstrap.Calendar
14246 * @extends Roo.bootstrap.Component
14247 * Bootstrap Calendar class
14248 * @cfg {Boolean} loadMask (true|false) default false
14249 * @cfg {Object} header generate the user specific header of the calendar, default false
14252 * Create a new Container
14253 * @param {Object} config The config object
14258 Roo.bootstrap.Calendar = function(config){
14259 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
14263 * Fires when a date is selected
14264 * @param {DatePicker} this
14265 * @param {Date} date The selected date
14269 * @event monthchange
14270 * Fires when the displayed month changes
14271 * @param {DatePicker} this
14272 * @param {Date} date The selected month
14274 'monthchange': true,
14276 * @event evententer
14277 * Fires when mouse over an event
14278 * @param {Calendar} this
14279 * @param {event} Event
14281 'evententer': true,
14283 * @event eventleave
14284 * Fires when the mouse leaves an
14285 * @param {Calendar} this
14288 'eventleave': true,
14290 * @event eventclick
14291 * Fires when the mouse click an
14292 * @param {Calendar} this
14301 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
14304 * @cfg {Number} startDay
14305 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
14313 getAutoCreate : function(){
14316 var fc_button = function(name, corner, style, content ) {
14317 return Roo.apply({},{
14319 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
14321 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
14324 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
14335 style : 'width:100%',
14342 cls : 'fc-header-left',
14344 fc_button('prev', 'left', 'arrow', '‹' ),
14345 fc_button('next', 'right', 'arrow', '›' ),
14346 { tag: 'span', cls: 'fc-header-space' },
14347 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
14355 cls : 'fc-header-center',
14359 cls: 'fc-header-title',
14362 html : 'month / year'
14370 cls : 'fc-header-right',
14372 /* fc_button('month', 'left', '', 'month' ),
14373 fc_button('week', '', '', 'week' ),
14374 fc_button('day', 'right', '', 'day' )
14386 header = this.header;
14389 var cal_heads = function() {
14391 // fixme - handle this.
14393 for (var i =0; i < Date.dayNames.length; i++) {
14394 var d = Date.dayNames[i];
14397 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
14398 html : d.substring(0,3)
14402 ret[0].cls += ' fc-first';
14403 ret[6].cls += ' fc-last';
14406 var cal_cell = function(n) {
14409 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
14414 cls: 'fc-day-number',
14418 cls: 'fc-day-content',
14422 style: 'position: relative;' // height: 17px;
14434 var cal_rows = function() {
14437 for (var r = 0; r < 6; r++) {
14444 for (var i =0; i < Date.dayNames.length; i++) {
14445 var d = Date.dayNames[i];
14446 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
14449 row.cn[0].cls+=' fc-first';
14450 row.cn[0].cn[0].style = 'min-height:90px';
14451 row.cn[6].cls+=' fc-last';
14455 ret[0].cls += ' fc-first';
14456 ret[4].cls += ' fc-prev-last';
14457 ret[5].cls += ' fc-last';
14464 cls: 'fc-border-separate',
14465 style : 'width:100%',
14473 cls : 'fc-first fc-last',
14491 cls : 'fc-content',
14492 style : "position: relative;",
14495 cls : 'fc-view fc-view-month fc-grid',
14496 style : 'position: relative',
14497 unselectable : 'on',
14500 cls : 'fc-event-container',
14501 style : 'position:absolute;z-index:8;top:0;left:0;'
14519 initEvents : function()
14522 throw "can not find store for calendar";
14528 style: "text-align:center",
14532 style: "background-color:white;width:50%;margin:250 auto",
14536 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
14547 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
14549 var size = this.el.select('.fc-content', true).first().getSize();
14550 this.maskEl.setSize(size.width, size.height);
14551 this.maskEl.enableDisplayMode("block");
14552 if(!this.loadMask){
14553 this.maskEl.hide();
14556 this.store = Roo.factory(this.store, Roo.data);
14557 this.store.on('load', this.onLoad, this);
14558 this.store.on('beforeload', this.onBeforeLoad, this);
14562 this.cells = this.el.select('.fc-day',true);
14563 //Roo.log(this.cells);
14564 this.textNodes = this.el.query('.fc-day-number');
14565 this.cells.addClassOnOver('fc-state-hover');
14567 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
14568 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
14569 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
14570 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
14572 this.on('monthchange', this.onMonthChange, this);
14574 this.update(new Date().clearTime());
14577 resize : function() {
14578 var sz = this.el.getSize();
14580 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
14581 this.el.select('.fc-day-content div',true).setHeight(34);
14586 showPrevMonth : function(e){
14587 this.update(this.activeDate.add("mo", -1));
14589 showToday : function(e){
14590 this.update(new Date().clearTime());
14593 showNextMonth : function(e){
14594 this.update(this.activeDate.add("mo", 1));
14598 showPrevYear : function(){
14599 this.update(this.activeDate.add("y", -1));
14603 showNextYear : function(){
14604 this.update(this.activeDate.add("y", 1));
14609 update : function(date)
14611 var vd = this.activeDate;
14612 this.activeDate = date;
14613 // if(vd && this.el){
14614 // var t = date.getTime();
14615 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
14616 // Roo.log('using add remove');
14618 // this.fireEvent('monthchange', this, date);
14620 // this.cells.removeClass("fc-state-highlight");
14621 // this.cells.each(function(c){
14622 // if(c.dateValue == t){
14623 // c.addClass("fc-state-highlight");
14624 // setTimeout(function(){
14625 // try{c.dom.firstChild.focus();}catch(e){}
14635 var days = date.getDaysInMonth();
14637 var firstOfMonth = date.getFirstDateOfMonth();
14638 var startingPos = firstOfMonth.getDay()-this.startDay;
14640 if(startingPos < this.startDay){
14644 var pm = date.add(Date.MONTH, -1);
14645 var prevStart = pm.getDaysInMonth()-startingPos;
14647 this.cells = this.el.select('.fc-day',true);
14648 this.textNodes = this.el.query('.fc-day-number');
14649 this.cells.addClassOnOver('fc-state-hover');
14651 var cells = this.cells.elements;
14652 var textEls = this.textNodes;
14654 Roo.each(cells, function(cell){
14655 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
14658 days += startingPos;
14660 // convert everything to numbers so it's fast
14661 var day = 86400000;
14662 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
14665 //Roo.log(prevStart);
14667 var today = new Date().clearTime().getTime();
14668 var sel = date.clearTime().getTime();
14669 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
14670 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
14671 var ddMatch = this.disabledDatesRE;
14672 var ddText = this.disabledDatesText;
14673 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
14674 var ddaysText = this.disabledDaysText;
14675 var format = this.format;
14677 var setCellClass = function(cal, cell){
14681 //Roo.log('set Cell Class');
14683 var t = d.getTime();
14687 cell.dateValue = t;
14689 cell.className += " fc-today";
14690 cell.className += " fc-state-highlight";
14691 cell.title = cal.todayText;
14694 // disable highlight in other month..
14695 //cell.className += " fc-state-highlight";
14700 cell.className = " fc-state-disabled";
14701 cell.title = cal.minText;
14705 cell.className = " fc-state-disabled";
14706 cell.title = cal.maxText;
14710 if(ddays.indexOf(d.getDay()) != -1){
14711 cell.title = ddaysText;
14712 cell.className = " fc-state-disabled";
14715 if(ddMatch && format){
14716 var fvalue = d.dateFormat(format);
14717 if(ddMatch.test(fvalue)){
14718 cell.title = ddText.replace("%0", fvalue);
14719 cell.className = " fc-state-disabled";
14723 if (!cell.initialClassName) {
14724 cell.initialClassName = cell.dom.className;
14727 cell.dom.className = cell.initialClassName + ' ' + cell.className;
14732 for(; i < startingPos; i++) {
14733 textEls[i].innerHTML = (++prevStart);
14734 d.setDate(d.getDate()+1);
14736 cells[i].className = "fc-past fc-other-month";
14737 setCellClass(this, cells[i]);
14742 for(; i < days; i++){
14743 intDay = i - startingPos + 1;
14744 textEls[i].innerHTML = (intDay);
14745 d.setDate(d.getDate()+1);
14747 cells[i].className = ''; // "x-date-active";
14748 setCellClass(this, cells[i]);
14752 for(; i < 42; i++) {
14753 textEls[i].innerHTML = (++extraDays);
14754 d.setDate(d.getDate()+1);
14756 cells[i].className = "fc-future fc-other-month";
14757 setCellClass(this, cells[i]);
14760 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14762 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14764 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14765 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14767 if(totalRows != 6){
14768 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14769 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14772 this.fireEvent('monthchange', this, date);
14776 if(!this.internalRender){
14777 var main = this.el.dom.firstChild;
14778 var w = main.offsetWidth;
14779 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14780 Roo.fly(main).setWidth(w);
14781 this.internalRender = true;
14782 // opera does not respect the auto grow header center column
14783 // then, after it gets a width opera refuses to recalculate
14784 // without a second pass
14785 if(Roo.isOpera && !this.secondPass){
14786 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14787 this.secondPass = true;
14788 this.update.defer(10, this, [date]);
14795 findCell : function(dt) {
14796 dt = dt.clearTime().getTime();
14798 this.cells.each(function(c){
14799 //Roo.log("check " +c.dateValue + '?=' + dt);
14800 if(c.dateValue == dt){
14810 findCells : function(ev) {
14811 var s = ev.start.clone().clearTime().getTime();
14813 var e= ev.end.clone().clearTime().getTime();
14816 this.cells.each(function(c){
14817 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14819 if(c.dateValue > e){
14822 if(c.dateValue < s){
14831 // findBestRow: function(cells)
14835 // for (var i =0 ; i < cells.length;i++) {
14836 // ret = Math.max(cells[i].rows || 0,ret);
14843 addItem : function(ev)
14845 // look for vertical location slot in
14846 var cells = this.findCells(ev);
14848 // ev.row = this.findBestRow(cells);
14850 // work out the location.
14854 for(var i =0; i < cells.length; i++) {
14856 cells[i].row = cells[0].row;
14859 cells[i].row = cells[i].row + 1;
14869 if (crow.start.getY() == cells[i].getY()) {
14871 crow.end = cells[i];
14888 cells[0].events.push(ev);
14890 this.calevents.push(ev);
14893 clearEvents: function() {
14895 if(!this.calevents){
14899 Roo.each(this.cells.elements, function(c){
14905 Roo.each(this.calevents, function(e) {
14906 Roo.each(e.els, function(el) {
14907 el.un('mouseenter' ,this.onEventEnter, this);
14908 el.un('mouseleave' ,this.onEventLeave, this);
14913 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14919 renderEvents: function()
14923 this.cells.each(function(c) {
14932 if(c.row != c.events.length){
14933 r = 4 - (4 - (c.row - c.events.length));
14936 c.events = ev.slice(0, r);
14937 c.more = ev.slice(r);
14939 if(c.more.length && c.more.length == 1){
14940 c.events.push(c.more.pop());
14943 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14947 this.cells.each(function(c) {
14949 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14952 for (var e = 0; e < c.events.length; e++){
14953 var ev = c.events[e];
14954 var rows = ev.rows;
14956 for(var i = 0; i < rows.length; i++) {
14958 // how many rows should it span..
14961 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14962 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14964 unselectable : "on",
14967 cls: 'fc-event-inner',
14971 // cls: 'fc-event-time',
14972 // html : cells.length > 1 ? '' : ev.time
14976 cls: 'fc-event-title',
14977 html : String.format('{0}', ev.title)
14984 cls: 'ui-resizable-handle ui-resizable-e',
14985 html : '  '
14992 cfg.cls += ' fc-event-start';
14994 if ((i+1) == rows.length) {
14995 cfg.cls += ' fc-event-end';
14998 var ctr = _this.el.select('.fc-event-container',true).first();
14999 var cg = ctr.createChild(cfg);
15001 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
15002 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
15004 var r = (c.more.length) ? 1 : 0;
15005 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
15006 cg.setWidth(ebox.right - sbox.x -2);
15008 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
15009 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
15010 cg.on('click', _this.onEventClick, _this, ev);
15021 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
15022 style : 'position: absolute',
15023 unselectable : "on",
15026 cls: 'fc-event-inner',
15030 cls: 'fc-event-title',
15038 cls: 'ui-resizable-handle ui-resizable-e',
15039 html : '  '
15045 var ctr = _this.el.select('.fc-event-container',true).first();
15046 var cg = ctr.createChild(cfg);
15048 var sbox = c.select('.fc-day-content',true).first().getBox();
15049 var ebox = c.select('.fc-day-content',true).first().getBox();
15051 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
15052 cg.setWidth(ebox.right - sbox.x -2);
15054 cg.on('click', _this.onMoreEventClick, _this, c.more);
15064 onEventEnter: function (e, el,event,d) {
15065 this.fireEvent('evententer', this, el, event);
15068 onEventLeave: function (e, el,event,d) {
15069 this.fireEvent('eventleave', this, el, event);
15072 onEventClick: function (e, el,event,d) {
15073 this.fireEvent('eventclick', this, el, event);
15076 onMonthChange: function () {
15080 onMoreEventClick: function(e, el, more)
15084 this.calpopover.placement = 'right';
15085 this.calpopover.setTitle('More');
15087 this.calpopover.setContent('');
15089 var ctr = this.calpopover.el.select('.popover-content', true).first();
15091 Roo.each(more, function(m){
15093 cls : 'fc-event-hori fc-event-draggable',
15096 var cg = ctr.createChild(cfg);
15098 cg.on('click', _this.onEventClick, _this, m);
15101 this.calpopover.show(el);
15106 onLoad: function ()
15108 this.calevents = [];
15111 if(this.store.getCount() > 0){
15112 this.store.data.each(function(d){
15115 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
15116 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
15117 time : d.data.start_time,
15118 title : d.data.title,
15119 description : d.data.description,
15120 venue : d.data.venue
15125 this.renderEvents();
15127 if(this.calevents.length && this.loadMask){
15128 this.maskEl.hide();
15132 onBeforeLoad: function()
15134 this.clearEvents();
15136 this.maskEl.show();
15150 * @class Roo.bootstrap.Popover
15151 * @extends Roo.bootstrap.Component
15152 * Bootstrap Popover class
15153 * @cfg {String} html contents of the popover (or false to use children..)
15154 * @cfg {String} title of popover (or false to hide)
15155 * @cfg {String} placement how it is placed
15156 * @cfg {String} trigger click || hover (or false to trigger manually)
15157 * @cfg {String} over what (parent or false to trigger manually.)
15158 * @cfg {Number} delay - delay before showing
15161 * Create a new Popover
15162 * @param {Object} config The config object
15165 Roo.bootstrap.Popover = function(config){
15166 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
15169 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
15171 title: 'Fill in a title',
15174 placement : 'right',
15175 trigger : 'hover', // hover
15181 can_build_overlaid : false,
15183 getChildContainer : function()
15185 return this.el.select('.popover-content',true).first();
15188 getAutoCreate : function(){
15189 Roo.log('make popover?');
15191 cls : 'popover roo-dynamic',
15192 style: 'display:block',
15198 cls : 'popover-inner',
15202 cls: 'popover-title',
15206 cls : 'popover-content',
15217 setTitle: function(str)
15219 this.el.select('.popover-title',true).first().dom.innerHTML = str;
15221 setContent: function(str)
15223 this.el.select('.popover-content',true).first().dom.innerHTML = str;
15225 // as it get's added to the bottom of the page.
15226 onRender : function(ct, position)
15228 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
15230 var cfg = Roo.apply({}, this.getAutoCreate());
15234 cfg.cls += ' ' + this.cls;
15237 cfg.style = this.style;
15239 Roo.log("adding to ")
15240 this.el = Roo.get(document.body).createChild(cfg, position);
15246 initEvents : function()
15248 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
15249 this.el.enableDisplayMode('block');
15251 if (this.over === false) {
15254 if (this.triggers === false) {
15257 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15258 var triggers = this.trigger ? this.trigger.split(' ') : [];
15259 Roo.each(triggers, function(trigger) {
15261 if (trigger == 'click') {
15262 on_el.on('click', this.toggle, this);
15263 } else if (trigger != 'manual') {
15264 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
15265 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
15267 on_el.on(eventIn ,this.enter, this);
15268 on_el.on(eventOut, this.leave, this);
15279 toggle : function () {
15280 this.hoverState == 'in' ? this.leave() : this.enter();
15283 enter : function () {
15286 clearTimeout(this.timeout);
15288 this.hoverState = 'in';
15290 if (!this.delay || !this.delay.show) {
15295 this.timeout = setTimeout(function () {
15296 if (_t.hoverState == 'in') {
15299 }, this.delay.show)
15301 leave : function() {
15302 clearTimeout(this.timeout);
15304 this.hoverState = 'out';
15306 if (!this.delay || !this.delay.hide) {
15311 this.timeout = setTimeout(function () {
15312 if (_t.hoverState == 'out') {
15315 }, this.delay.hide)
15318 show : function (on_el)
15321 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15324 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
15325 if (this.html !== false) {
15326 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
15328 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
15329 if (!this.title.length) {
15330 this.el.select('.popover-title',true).hide();
15333 var placement = typeof this.placement == 'function' ?
15334 this.placement.call(this, this.el, on_el) :
15337 var autoToken = /\s?auto?\s?/i;
15338 var autoPlace = autoToken.test(placement);
15340 placement = placement.replace(autoToken, '') || 'top';
15344 //this.el.setXY([0,0]);
15346 this.el.dom.style.display='block';
15347 this.el.addClass(placement);
15349 //this.el.appendTo(on_el);
15351 var p = this.getPosition();
15352 var box = this.el.getBox();
15357 var align = Roo.bootstrap.Popover.alignment[placement];
15358 this.el.alignTo(on_el, align[0],align[1]);
15359 //var arrow = this.el.select('.arrow',true).first();
15360 //arrow.set(align[2],
15362 this.el.addClass('in');
15363 this.hoverState = null;
15365 if (this.el.hasClass('fade')) {
15372 this.el.setXY([0,0]);
15373 this.el.removeClass('in');
15380 Roo.bootstrap.Popover.alignment = {
15381 'left' : ['r-l', [-10,0], 'right'],
15382 'right' : ['l-r', [10,0], 'left'],
15383 'bottom' : ['t-b', [0,10], 'top'],
15384 'top' : [ 'b-t', [0,-10], 'bottom']
15395 * @class Roo.bootstrap.Progress
15396 * @extends Roo.bootstrap.Component
15397 * Bootstrap Progress class
15398 * @cfg {Boolean} striped striped of the progress bar
15399 * @cfg {Boolean} active animated of the progress bar
15403 * Create a new Progress
15404 * @param {Object} config The config object
15407 Roo.bootstrap.Progress = function(config){
15408 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
15411 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
15416 getAutoCreate : function(){
15424 cfg.cls += ' progress-striped';
15428 cfg.cls += ' active';
15447 * @class Roo.bootstrap.ProgressBar
15448 * @extends Roo.bootstrap.Component
15449 * Bootstrap ProgressBar class
15450 * @cfg {Number} aria_valuenow aria-value now
15451 * @cfg {Number} aria_valuemin aria-value min
15452 * @cfg {Number} aria_valuemax aria-value max
15453 * @cfg {String} label label for the progress bar
15454 * @cfg {String} panel (success | info | warning | danger )
15455 * @cfg {String} role role of the progress bar
15456 * @cfg {String} sr_only text
15460 * Create a new ProgressBar
15461 * @param {Object} config The config object
15464 Roo.bootstrap.ProgressBar = function(config){
15465 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
15468 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
15472 aria_valuemax : 100,
15478 getAutoCreate : function()
15483 cls: 'progress-bar',
15484 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
15496 cfg.role = this.role;
15499 if(this.aria_valuenow){
15500 cfg['aria-valuenow'] = this.aria_valuenow;
15503 if(this.aria_valuemin){
15504 cfg['aria-valuemin'] = this.aria_valuemin;
15507 if(this.aria_valuemax){
15508 cfg['aria-valuemax'] = this.aria_valuemax;
15511 if(this.label && !this.sr_only){
15512 cfg.html = this.label;
15516 cfg.cls += ' progress-bar-' + this.panel;
15522 update : function(aria_valuenow)
15524 this.aria_valuenow = aria_valuenow;
15526 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
15541 * @class Roo.bootstrap.TabGroup
15542 * @extends Roo.bootstrap.Column
15543 * Bootstrap Column class
15544 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
15545 * @cfg {Boolean} carousel true to make the group behave like a carousel
15546 * @cfg {Number} bullets show the panel pointer.. default 0
15547 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
15548 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
15549 * @cfg {Number} timer auto slide timer .. default 0 millisecond
15552 * Create a new TabGroup
15553 * @param {Object} config The config object
15556 Roo.bootstrap.TabGroup = function(config){
15557 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
15559 this.navId = Roo.id();
15562 Roo.bootstrap.TabGroup.register(this);
15566 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
15569 transition : false,
15574 slideOnTouch : false,
15576 getAutoCreate : function()
15578 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
15580 cfg.cls += ' tab-content';
15582 Roo.log('get auto create...............');
15584 if (this.carousel) {
15585 cfg.cls += ' carousel slide';
15588 cls : 'carousel-inner'
15591 if(this.bullets > 0 && !Roo.isTouch){
15594 cls : 'carousel-bullets',
15598 if(this.bullets_cls){
15599 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
15602 for (var i = 0; i < this.bullets; i++){
15604 cls : 'bullet bullet-' + i
15612 cfg.cn[0].cn = bullets;
15619 initEvents: function()
15621 Roo.log('-------- init events on tab group ---------');
15623 if(this.bullets > 0 && !Roo.isTouch){
15629 if(Roo.isTouch && this.slideOnTouch){
15630 this.el.on("touchstart", this.onTouchStart, this);
15633 if(this.autoslide){
15636 this.slideFn = window.setInterval(function() {
15637 _this.showPanelNext();
15643 onTouchStart : function(e, el, o)
15645 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15649 this.showPanelNext();
15652 getChildContainer : function()
15654 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15658 * register a Navigation item
15659 * @param {Roo.bootstrap.NavItem} the navitem to add
15661 register : function(item)
15663 this.tabs.push( item);
15664 item.navId = this.navId; // not really needed..
15668 getActivePanel : function()
15671 Roo.each(this.tabs, function(t) {
15681 getPanelByName : function(n)
15684 Roo.each(this.tabs, function(t) {
15685 if (t.tabId == n) {
15693 indexOfPanel : function(p)
15696 Roo.each(this.tabs, function(t,i) {
15697 if (t.tabId == p.tabId) {
15706 * show a specific panel
15707 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15708 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15710 showPanel : function (pan)
15712 if(this.transition){
15713 Roo.log("waiting for the transitionend");
15717 if (typeof(pan) == 'number') {
15718 pan = this.tabs[pan];
15720 if (typeof(pan) == 'string') {
15721 pan = this.getPanelByName(pan);
15723 if (pan.tabId == this.getActivePanel().tabId) {
15726 var cur = this.getActivePanel();
15728 if (false === cur.fireEvent('beforedeactivate')) {
15732 if(this.bullets > 0 && !Roo.isTouch){
15733 this.setActiveBullet(this.indexOfPanel(pan));
15736 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15738 this.transition = true;
15739 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15740 var lr = dir == 'next' ? 'left' : 'right';
15741 pan.el.addClass(dir); // or prev
15742 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15743 cur.el.addClass(lr); // or right
15744 pan.el.addClass(lr);
15747 cur.el.on('transitionend', function() {
15748 Roo.log("trans end?");
15750 pan.el.removeClass([lr,dir]);
15751 pan.setActive(true);
15753 cur.el.removeClass([lr]);
15754 cur.setActive(false);
15756 _this.transition = false;
15758 }, this, { single: true } );
15763 cur.setActive(false);
15764 pan.setActive(true);
15769 showPanelNext : function()
15771 var i = this.indexOfPanel(this.getActivePanel());
15773 if (i >= this.tabs.length - 1 && !this.autoslide) {
15777 if (i >= this.tabs.length - 1 && this.autoslide) {
15781 this.showPanel(this.tabs[i+1]);
15784 showPanelPrev : function()
15786 var i = this.indexOfPanel(this.getActivePanel());
15788 if (i < 1 && !this.autoslide) {
15792 if (i < 1 && this.autoslide) {
15793 i = this.tabs.length;
15796 this.showPanel(this.tabs[i-1]);
15799 initBullet : function()
15807 for (var i = 0; i < this.bullets; i++){
15808 var bullet = this.el.select('.bullet-' + i, true).first();
15814 bullet.on('click', (function(e, el, o, ii, t){
15816 e.preventDefault();
15818 _this.showPanel(ii);
15820 if(_this.autoslide && _this.slideFn){
15821 clearInterval(_this.slideFn);
15822 _this.slideFn = window.setInterval(function() {
15823 _this.showPanelNext();
15827 }).createDelegate(this, [i, bullet], true));
15831 setActiveBullet : function(i)
15837 Roo.each(this.el.select('.bullet', true).elements, function(el){
15838 el.removeClass('selected');
15841 var bullet = this.el.select('.bullet-' + i, true).first();
15847 bullet.addClass('selected');
15858 Roo.apply(Roo.bootstrap.TabGroup, {
15862 * register a Navigation Group
15863 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15865 register : function(navgrp)
15867 this.groups[navgrp.navId] = navgrp;
15871 * fetch a Navigation Group based on the navigation ID
15872 * if one does not exist , it will get created.
15873 * @param {string} the navgroup to add
15874 * @returns {Roo.bootstrap.NavGroup} the navgroup
15876 get: function(navId) {
15877 if (typeof(this.groups[navId]) == 'undefined') {
15878 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15880 return this.groups[navId] ;
15895 * @class Roo.bootstrap.TabPanel
15896 * @extends Roo.bootstrap.Component
15897 * Bootstrap TabPanel class
15898 * @cfg {Boolean} active panel active
15899 * @cfg {String} html panel content
15900 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15901 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15905 * Create a new TabPanel
15906 * @param {Object} config The config object
15909 Roo.bootstrap.TabPanel = function(config){
15910 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15914 * Fires when the active status changes
15915 * @param {Roo.bootstrap.TabPanel} this
15916 * @param {Boolean} state the new state
15921 * @event beforedeactivate
15922 * Fires before a tab is de-activated - can be used to do validation on a form.
15923 * @param {Roo.bootstrap.TabPanel} this
15924 * @return {Boolean} false if there is an error
15927 'beforedeactivate': true
15930 this.tabId = this.tabId || Roo.id();
15934 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15941 getAutoCreate : function(){
15944 // item is needed for carousel - not sure if it has any effect otherwise
15945 cls: 'tab-pane item',
15946 html: this.html || ''
15950 cfg.cls += ' active';
15954 cfg.tabId = this.tabId;
15961 initEvents: function()
15963 Roo.log('-------- init events on tab panel ---------');
15965 var p = this.parent();
15966 this.navId = this.navId || p.navId;
15968 if (typeof(this.navId) != 'undefined') {
15969 // not really needed.. but just in case.. parent should be a NavGroup.
15970 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15971 Roo.log(['register', tg, this]);
15974 var i = tg.tabs.length - 1;
15976 if(this.active && tg.bullets > 0 && i < tg.bullets){
15977 tg.setActiveBullet(i);
15984 onRender : function(ct, position)
15986 // Roo.log("Call onRender: " + this.xtype);
15988 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15996 setActive: function(state)
15998 Roo.log("panel - set active " + this.tabId + "=" + state);
16000 this.active = state;
16002 this.el.removeClass('active');
16004 } else if (!this.el.hasClass('active')) {
16005 this.el.addClass('active');
16008 this.fireEvent('changed', this, state);
16025 * @class Roo.bootstrap.DateField
16026 * @extends Roo.bootstrap.Input
16027 * Bootstrap DateField class
16028 * @cfg {Number} weekStart default 0
16029 * @cfg {String} viewMode default empty, (months|years)
16030 * @cfg {String} minViewMode default empty, (months|years)
16031 * @cfg {Number} startDate default -Infinity
16032 * @cfg {Number} endDate default Infinity
16033 * @cfg {Boolean} todayHighlight default false
16034 * @cfg {Boolean} todayBtn default false
16035 * @cfg {Boolean} calendarWeeks default false
16036 * @cfg {Object} daysOfWeekDisabled default empty
16037 * @cfg {Boolean} singleMode default false (true | false)
16039 * @cfg {Boolean} keyboardNavigation default true
16040 * @cfg {String} language default en
16043 * Create a new DateField
16044 * @param {Object} config The config object
16047 Roo.bootstrap.DateField = function(config){
16048 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16052 * Fires when this field show.
16053 * @param {Roo.bootstrap.DateField} this
16054 * @param {Mixed} date The date value
16059 * Fires when this field hide.
16060 * @param {Roo.bootstrap.DateField} this
16061 * @param {Mixed} date The date value
16066 * Fires when select a date.
16067 * @param {Roo.bootstrap.DateField} this
16068 * @param {Mixed} date The date value
16074 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16077 * @cfg {String} format
16078 * The default date format string which can be overriden for localization support. The format must be
16079 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16083 * @cfg {String} altFormats
16084 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16085 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16087 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16095 todayHighlight : false,
16101 keyboardNavigation: true,
16103 calendarWeeks: false,
16105 startDate: -Infinity,
16109 daysOfWeekDisabled: [],
16113 singleMode : false,
16115 UTCDate: function()
16117 return new Date(Date.UTC.apply(Date, arguments));
16120 UTCToday: function()
16122 var today = new Date();
16123 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16126 getDate: function() {
16127 var d = this.getUTCDate();
16128 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16131 getUTCDate: function() {
16135 setDate: function(d) {
16136 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
16139 setUTCDate: function(d) {
16141 this.setValue(this.formatDate(this.date));
16144 onRender: function(ct, position)
16147 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
16149 this.language = this.language || 'en';
16150 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
16151 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
16153 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
16154 this.format = this.format || 'm/d/y';
16155 this.isInline = false;
16156 this.isInput = true;
16157 this.component = this.el.select('.add-on', true).first() || false;
16158 this.component = (this.component && this.component.length === 0) ? false : this.component;
16159 this.hasInput = this.component && this.inputEL().length;
16161 if (typeof(this.minViewMode === 'string')) {
16162 switch (this.minViewMode) {
16164 this.minViewMode = 1;
16167 this.minViewMode = 2;
16170 this.minViewMode = 0;
16175 if (typeof(this.viewMode === 'string')) {
16176 switch (this.viewMode) {
16189 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
16191 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
16193 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16195 this.picker().on('mousedown', this.onMousedown, this);
16196 this.picker().on('click', this.onClick, this);
16198 this.picker().addClass('datepicker-dropdown');
16200 this.startViewMode = this.viewMode;
16202 if(this.singleMode){
16203 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
16204 v.setVisibilityMode(Roo.Element.DISPLAY)
16208 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16209 v.setStyle('width', '189px');
16213 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
16214 if(!this.calendarWeeks){
16219 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16220 v.attr('colspan', function(i, val){
16221 return parseInt(val) + 1;
16226 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
16228 this.setStartDate(this.startDate);
16229 this.setEndDate(this.endDate);
16231 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
16238 if(this.isInline) {
16243 picker : function()
16245 return this.pickerEl;
16246 // return this.el.select('.datepicker', true).first();
16249 fillDow: function()
16251 var dowCnt = this.weekStart;
16260 if(this.calendarWeeks){
16268 while (dowCnt < this.weekStart + 7) {
16272 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
16276 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
16279 fillMonths: function()
16282 var months = this.picker().select('>.datepicker-months td', true).first();
16284 months.dom.innerHTML = '';
16290 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
16293 months.createChild(month);
16300 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;
16302 if (this.date < this.startDate) {
16303 this.viewDate = new Date(this.startDate);
16304 } else if (this.date > this.endDate) {
16305 this.viewDate = new Date(this.endDate);
16307 this.viewDate = new Date(this.date);
16315 var d = new Date(this.viewDate),
16316 year = d.getUTCFullYear(),
16317 month = d.getUTCMonth(),
16318 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
16319 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
16320 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
16321 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
16322 currentDate = this.date && this.date.valueOf(),
16323 today = this.UTCToday();
16325 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
16327 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16329 // this.picker.select('>tfoot th.today').
16330 // .text(dates[this.language].today)
16331 // .toggle(this.todayBtn !== false);
16333 this.updateNavArrows();
16336 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
16338 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
16340 prevMonth.setUTCDate(day);
16342 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
16344 var nextMonth = new Date(prevMonth);
16346 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
16348 nextMonth = nextMonth.valueOf();
16350 var fillMonths = false;
16352 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
16354 while(prevMonth.valueOf() < nextMonth) {
16357 if (prevMonth.getUTCDay() === this.weekStart) {
16359 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
16367 if(this.calendarWeeks){
16368 // ISO 8601: First week contains first thursday.
16369 // ISO also states week starts on Monday, but we can be more abstract here.
16371 // Start of current week: based on weekstart/current date
16372 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
16373 // Thursday of this week
16374 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
16375 // First Thursday of year, year from thursday
16376 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
16377 // Calendar week: ms between thursdays, div ms per day, div 7 days
16378 calWeek = (th - yth) / 864e5 / 7 + 1;
16380 fillMonths.cn.push({
16388 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
16390 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
16393 if (this.todayHighlight &&
16394 prevMonth.getUTCFullYear() == today.getFullYear() &&
16395 prevMonth.getUTCMonth() == today.getMonth() &&
16396 prevMonth.getUTCDate() == today.getDate()) {
16397 clsName += ' today';
16400 if (currentDate && prevMonth.valueOf() === currentDate) {
16401 clsName += ' active';
16404 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
16405 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
16406 clsName += ' disabled';
16409 fillMonths.cn.push({
16411 cls: 'day ' + clsName,
16412 html: prevMonth.getDate()
16415 prevMonth.setDate(prevMonth.getDate()+1);
16418 var currentYear = this.date && this.date.getUTCFullYear();
16419 var currentMonth = this.date && this.date.getUTCMonth();
16421 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
16423 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
16424 v.removeClass('active');
16426 if(currentYear === year && k === currentMonth){
16427 v.addClass('active');
16430 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
16431 v.addClass('disabled');
16437 year = parseInt(year/10, 10) * 10;
16439 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
16441 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
16444 for (var i = -1; i < 11; i++) {
16445 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
16447 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
16455 showMode: function(dir)
16458 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
16461 Roo.each(this.picker().select('>div',true).elements, function(v){
16462 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16465 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
16470 if(this.isInline) return;
16472 this.picker().removeClass(['bottom', 'top']);
16474 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16476 * place to the top of element!
16480 this.picker().addClass('top');
16481 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16486 this.picker().addClass('bottom');
16488 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16491 parseDate : function(value)
16493 if(!value || value instanceof Date){
16496 var v = Date.parseDate(value, this.format);
16497 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
16498 v = Date.parseDate(value, 'Y-m-d');
16500 if(!v && this.altFormats){
16501 if(!this.altFormatsArray){
16502 this.altFormatsArray = this.altFormats.split("|");
16504 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
16505 v = Date.parseDate(value, this.altFormatsArray[i]);
16511 formatDate : function(date, fmt)
16513 return (!date || !(date instanceof Date)) ?
16514 date : date.dateFormat(fmt || this.format);
16517 onFocus : function()
16519 Roo.bootstrap.DateField.superclass.onFocus.call(this);
16523 onBlur : function()
16525 Roo.bootstrap.DateField.superclass.onBlur.call(this);
16527 var d = this.inputEl().getValue();
16536 this.picker().show();
16540 this.fireEvent('show', this, this.date);
16545 if(this.isInline) return;
16546 this.picker().hide();
16547 this.viewMode = this.startViewMode;
16550 this.fireEvent('hide', this, this.date);
16554 onMousedown: function(e)
16556 e.stopPropagation();
16557 e.preventDefault();
16562 Roo.bootstrap.DateField.superclass.keyup.call(this);
16566 setValue: function(v)
16569 // v can be a string or a date..
16572 var d = new Date(this.parseDate(v) ).clearTime();
16574 if(isNaN(d.getTime())){
16575 this.date = this.viewDate = '';
16576 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
16580 v = this.formatDate(d);
16582 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
16584 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
16588 this.fireEvent('select', this, this.date);
16592 getValue: function()
16594 return this.formatDate(this.date);
16597 fireKey: function(e)
16599 if (!this.picker().isVisible()){
16600 if (e.keyCode == 27) // allow escape to hide and re-show picker
16605 var dateChanged = false,
16607 newDate, newViewDate;
16612 e.preventDefault();
16616 if (!this.keyboardNavigation) break;
16617 dir = e.keyCode == 37 ? -1 : 1;
16620 newDate = this.moveYear(this.date, dir);
16621 newViewDate = this.moveYear(this.viewDate, dir);
16622 } else if (e.shiftKey){
16623 newDate = this.moveMonth(this.date, dir);
16624 newViewDate = this.moveMonth(this.viewDate, dir);
16626 newDate = new Date(this.date);
16627 newDate.setUTCDate(this.date.getUTCDate() + dir);
16628 newViewDate = new Date(this.viewDate);
16629 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16631 if (this.dateWithinRange(newDate)){
16632 this.date = newDate;
16633 this.viewDate = newViewDate;
16634 this.setValue(this.formatDate(this.date));
16636 e.preventDefault();
16637 dateChanged = true;
16642 if (!this.keyboardNavigation) break;
16643 dir = e.keyCode == 38 ? -1 : 1;
16645 newDate = this.moveYear(this.date, dir);
16646 newViewDate = this.moveYear(this.viewDate, dir);
16647 } else if (e.shiftKey){
16648 newDate = this.moveMonth(this.date, dir);
16649 newViewDate = this.moveMonth(this.viewDate, dir);
16651 newDate = new Date(this.date);
16652 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16653 newViewDate = new Date(this.viewDate);
16654 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16656 if (this.dateWithinRange(newDate)){
16657 this.date = newDate;
16658 this.viewDate = newViewDate;
16659 this.setValue(this.formatDate(this.date));
16661 e.preventDefault();
16662 dateChanged = true;
16666 this.setValue(this.formatDate(this.date));
16668 e.preventDefault();
16671 this.setValue(this.formatDate(this.date));
16685 onClick: function(e)
16687 e.stopPropagation();
16688 e.preventDefault();
16690 var target = e.getTarget();
16692 if(target.nodeName.toLowerCase() === 'i'){
16693 target = Roo.get(target).dom.parentNode;
16696 var nodeName = target.nodeName;
16697 var className = target.className;
16698 var html = target.innerHTML;
16699 //Roo.log(nodeName);
16701 switch(nodeName.toLowerCase()) {
16703 switch(className) {
16709 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16710 switch(this.viewMode){
16712 this.viewDate = this.moveMonth(this.viewDate, dir);
16716 this.viewDate = this.moveYear(this.viewDate, dir);
16722 var date = new Date();
16723 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16725 this.setValue(this.formatDate(this.date));
16732 if (className.indexOf('disabled') < 0) {
16733 this.viewDate.setUTCDate(1);
16734 if (className.indexOf('month') > -1) {
16735 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16737 var year = parseInt(html, 10) || 0;
16738 this.viewDate.setUTCFullYear(year);
16742 if(this.singleMode){
16743 this.setValue(this.formatDate(this.viewDate));
16754 //Roo.log(className);
16755 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16756 var day = parseInt(html, 10) || 1;
16757 var year = this.viewDate.getUTCFullYear(),
16758 month = this.viewDate.getUTCMonth();
16760 if (className.indexOf('old') > -1) {
16767 } else if (className.indexOf('new') > -1) {
16775 //Roo.log([year,month,day]);
16776 this.date = this.UTCDate(year, month, day,0,0,0,0);
16777 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16779 //Roo.log(this.formatDate(this.date));
16780 this.setValue(this.formatDate(this.date));
16787 setStartDate: function(startDate)
16789 this.startDate = startDate || -Infinity;
16790 if (this.startDate !== -Infinity) {
16791 this.startDate = this.parseDate(this.startDate);
16794 this.updateNavArrows();
16797 setEndDate: function(endDate)
16799 this.endDate = endDate || Infinity;
16800 if (this.endDate !== Infinity) {
16801 this.endDate = this.parseDate(this.endDate);
16804 this.updateNavArrows();
16807 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16809 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16810 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16811 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16813 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16814 return parseInt(d, 10);
16817 this.updateNavArrows();
16820 updateNavArrows: function()
16822 if(this.singleMode){
16826 var d = new Date(this.viewDate),
16827 year = d.getUTCFullYear(),
16828 month = d.getUTCMonth();
16830 Roo.each(this.picker().select('.prev', true).elements, function(v){
16832 switch (this.viewMode) {
16835 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16841 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16848 Roo.each(this.picker().select('.next', true).elements, function(v){
16850 switch (this.viewMode) {
16853 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16859 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16867 moveMonth: function(date, dir)
16869 if (!dir) return date;
16870 var new_date = new Date(date.valueOf()),
16871 day = new_date.getUTCDate(),
16872 month = new_date.getUTCMonth(),
16873 mag = Math.abs(dir),
16875 dir = dir > 0 ? 1 : -1;
16878 // If going back one month, make sure month is not current month
16879 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16881 return new_date.getUTCMonth() == month;
16883 // If going forward one month, make sure month is as expected
16884 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16886 return new_date.getUTCMonth() != new_month;
16888 new_month = month + dir;
16889 new_date.setUTCMonth(new_month);
16890 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16891 if (new_month < 0 || new_month > 11)
16892 new_month = (new_month + 12) % 12;
16894 // For magnitudes >1, move one month at a time...
16895 for (var i=0; i<mag; i++)
16896 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16897 new_date = this.moveMonth(new_date, dir);
16898 // ...then reset the day, keeping it in the new month
16899 new_month = new_date.getUTCMonth();
16900 new_date.setUTCDate(day);
16902 return new_month != new_date.getUTCMonth();
16905 // Common date-resetting loop -- if date is beyond end of month, make it
16908 new_date.setUTCDate(--day);
16909 new_date.setUTCMonth(new_month);
16914 moveYear: function(date, dir)
16916 return this.moveMonth(date, dir*12);
16919 dateWithinRange: function(date)
16921 return date >= this.startDate && date <= this.endDate;
16927 this.picker().remove();
16932 Roo.apply(Roo.bootstrap.DateField, {
16943 html: '<i class="fa fa-arrow-left"/>'
16953 html: '<i class="fa fa-arrow-right"/>'
16995 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16996 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16997 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16998 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16999 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17012 navFnc: 'FullYear',
17017 navFnc: 'FullYear',
17022 Roo.apply(Roo.bootstrap.DateField, {
17026 cls: 'datepicker dropdown-menu roo-dynamic',
17030 cls: 'datepicker-days',
17034 cls: 'table-condensed',
17036 Roo.bootstrap.DateField.head,
17040 Roo.bootstrap.DateField.footer
17047 cls: 'datepicker-months',
17051 cls: 'table-condensed',
17053 Roo.bootstrap.DateField.head,
17054 Roo.bootstrap.DateField.content,
17055 Roo.bootstrap.DateField.footer
17062 cls: 'datepicker-years',
17066 cls: 'table-condensed',
17068 Roo.bootstrap.DateField.head,
17069 Roo.bootstrap.DateField.content,
17070 Roo.bootstrap.DateField.footer
17089 * @class Roo.bootstrap.TimeField
17090 * @extends Roo.bootstrap.Input
17091 * Bootstrap DateField class
17095 * Create a new TimeField
17096 * @param {Object} config The config object
17099 Roo.bootstrap.TimeField = function(config){
17100 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17104 * Fires when this field show.
17105 * @param {Roo.bootstrap.DateField} thisthis
17106 * @param {Mixed} date The date value
17111 * Fires when this field hide.
17112 * @param {Roo.bootstrap.DateField} this
17113 * @param {Mixed} date The date value
17118 * Fires when select a date.
17119 * @param {Roo.bootstrap.DateField} this
17120 * @param {Mixed} date The date value
17126 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
17129 * @cfg {String} format
17130 * The default time format string which can be overriden for localization support. The format must be
17131 * valid according to {@link Date#parseDate} (defaults to 'H:i').
17135 onRender: function(ct, position)
17138 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
17140 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
17142 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17144 this.pop = this.picker().select('>.datepicker-time',true).first();
17145 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17147 this.picker().on('mousedown', this.onMousedown, this);
17148 this.picker().on('click', this.onClick, this);
17150 this.picker().addClass('datepicker-dropdown');
17155 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
17156 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
17157 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
17158 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
17159 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
17160 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
17164 fireKey: function(e){
17165 if (!this.picker().isVisible()){
17166 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17172 e.preventDefault();
17180 this.onTogglePeriod();
17183 this.onIncrementMinutes();
17186 this.onDecrementMinutes();
17195 onClick: function(e) {
17196 e.stopPropagation();
17197 e.preventDefault();
17200 picker : function()
17202 return this.el.select('.datepicker', true).first();
17205 fillTime: function()
17207 var time = this.pop.select('tbody', true).first();
17209 time.dom.innerHTML = '';
17224 cls: 'hours-up glyphicon glyphicon-chevron-up'
17244 cls: 'minutes-up glyphicon glyphicon-chevron-up'
17265 cls: 'timepicker-hour',
17280 cls: 'timepicker-minute',
17295 cls: 'btn btn-primary period',
17317 cls: 'hours-down glyphicon glyphicon-chevron-down'
17337 cls: 'minutes-down glyphicon glyphicon-chevron-down'
17355 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
17362 var hours = this.time.getHours();
17363 var minutes = this.time.getMinutes();
17376 hours = hours - 12;
17380 hours = '0' + hours;
17384 minutes = '0' + minutes;
17387 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
17388 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
17389 this.pop.select('button', true).first().dom.innerHTML = period;
17395 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
17397 var cls = ['bottom'];
17399 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
17406 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
17411 this.picker().addClass(cls.join('-'));
17415 Roo.each(cls, function(c){
17417 _this.picker().setTop(_this.inputEl().getHeight());
17421 _this.picker().setTop(0 - _this.picker().getHeight());
17426 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
17430 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
17437 onFocus : function()
17439 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
17443 onBlur : function()
17445 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
17451 this.picker().show();
17456 this.fireEvent('show', this, this.date);
17461 this.picker().hide();
17464 this.fireEvent('hide', this, this.date);
17467 setTime : function()
17470 this.setValue(this.time.format(this.format));
17472 this.fireEvent('select', this, this.date);
17477 onMousedown: function(e){
17478 e.stopPropagation();
17479 e.preventDefault();
17482 onIncrementHours: function()
17484 Roo.log('onIncrementHours');
17485 this.time = this.time.add(Date.HOUR, 1);
17490 onDecrementHours: function()
17492 Roo.log('onDecrementHours');
17493 this.time = this.time.add(Date.HOUR, -1);
17497 onIncrementMinutes: function()
17499 Roo.log('onIncrementMinutes');
17500 this.time = this.time.add(Date.MINUTE, 1);
17504 onDecrementMinutes: function()
17506 Roo.log('onDecrementMinutes');
17507 this.time = this.time.add(Date.MINUTE, -1);
17511 onTogglePeriod: function()
17513 Roo.log('onTogglePeriod');
17514 this.time = this.time.add(Date.HOUR, 12);
17521 Roo.apply(Roo.bootstrap.TimeField, {
17551 cls: 'btn btn-info ok',
17563 Roo.apply(Roo.bootstrap.TimeField, {
17567 cls: 'datepicker dropdown-menu',
17571 cls: 'datepicker-time',
17575 cls: 'table-condensed',
17577 Roo.bootstrap.TimeField.content,
17578 Roo.bootstrap.TimeField.footer
17597 * @class Roo.bootstrap.MonthField
17598 * @extends Roo.bootstrap.Input
17599 * Bootstrap MonthField class
17601 * @cfg {String} language default en
17604 * Create a new MonthField
17605 * @param {Object} config The config object
17608 Roo.bootstrap.MonthField = function(config){
17609 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
17614 * Fires when this field show.
17615 * @param {Roo.bootstrap.MonthField} this
17616 * @param {Mixed} date The date value
17621 * Fires when this field hide.
17622 * @param {Roo.bootstrap.MonthField} this
17623 * @param {Mixed} date The date value
17628 * Fires when select a date.
17629 * @param {Roo.bootstrap.MonthField} this
17630 * @param {String} oldvalue The old value
17631 * @param {String} newvalue The new value
17637 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17639 onRender: function(ct, position)
17642 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17644 this.language = this.language || 'en';
17645 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17646 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17648 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17649 this.isInline = false;
17650 this.isInput = true;
17651 this.component = this.el.select('.add-on', true).first() || false;
17652 this.component = (this.component && this.component.length === 0) ? false : this.component;
17653 this.hasInput = this.component && this.inputEL().length;
17655 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17657 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17659 this.picker().on('mousedown', this.onMousedown, this);
17660 this.picker().on('click', this.onClick, this);
17662 this.picker().addClass('datepicker-dropdown');
17664 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17665 v.setStyle('width', '189px');
17672 if(this.isInline) {
17678 setValue: function(v, suppressEvent)
17680 var o = this.getValue();
17682 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17686 if(suppressEvent !== true){
17687 this.fireEvent('select', this, o, v);
17692 getValue: function()
17697 onClick: function(e)
17699 e.stopPropagation();
17700 e.preventDefault();
17702 var target = e.getTarget();
17704 if(target.nodeName.toLowerCase() === 'i'){
17705 target = Roo.get(target).dom.parentNode;
17708 var nodeName = target.nodeName;
17709 var className = target.className;
17710 var html = target.innerHTML;
17712 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17716 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17718 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17724 picker : function()
17726 return this.pickerEl;
17729 fillMonths: function()
17732 var months = this.picker().select('>.datepicker-months td', true).first();
17734 months.dom.innerHTML = '';
17740 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17743 months.createChild(month);
17752 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17753 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17756 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17757 e.removeClass('active');
17759 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17760 e.addClass('active');
17767 if(this.isInline) return;
17769 this.picker().removeClass(['bottom', 'top']);
17771 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17773 * place to the top of element!
17777 this.picker().addClass('top');
17778 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17783 this.picker().addClass('bottom');
17785 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17788 onFocus : function()
17790 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17794 onBlur : function()
17796 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17798 var d = this.inputEl().getValue();
17807 this.picker().show();
17808 this.picker().select('>.datepicker-months', true).first().show();
17812 this.fireEvent('show', this, this.date);
17817 if(this.isInline) return;
17818 this.picker().hide();
17819 this.fireEvent('hide', this, this.date);
17823 onMousedown: function(e)
17825 e.stopPropagation();
17826 e.preventDefault();
17831 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17835 fireKey: function(e)
17837 if (!this.picker().isVisible()){
17838 if (e.keyCode == 27) // allow escape to hide and re-show picker
17848 e.preventDefault();
17852 dir = e.keyCode == 37 ? -1 : 1;
17854 this.vIndex = this.vIndex + dir;
17856 if(this.vIndex < 0){
17860 if(this.vIndex > 11){
17864 if(isNaN(this.vIndex)){
17868 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17874 dir = e.keyCode == 38 ? -1 : 1;
17876 this.vIndex = this.vIndex + dir * 4;
17878 if(this.vIndex < 0){
17882 if(this.vIndex > 11){
17886 if(isNaN(this.vIndex)){
17890 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17895 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17896 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17900 e.preventDefault();
17903 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17904 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17920 this.picker().remove();
17925 Roo.apply(Roo.bootstrap.MonthField, {
17944 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17945 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17950 Roo.apply(Roo.bootstrap.MonthField, {
17954 cls: 'datepicker dropdown-menu roo-dynamic',
17958 cls: 'datepicker-months',
17962 cls: 'table-condensed',
17964 Roo.bootstrap.DateField.content
17984 * @class Roo.bootstrap.CheckBox
17985 * @extends Roo.bootstrap.Input
17986 * Bootstrap CheckBox class
17988 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17989 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17990 * @cfg {String} boxLabel The text that appears beside the checkbox
17991 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17992 * @cfg {Boolean} checked initnal the element
17993 * @cfg {Boolean} inline inline the element (default false)
17994 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17997 * Create a new CheckBox
17998 * @param {Object} config The config object
18001 Roo.bootstrap.CheckBox = function(config){
18002 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
18007 * Fires when the element is checked or unchecked.
18008 * @param {Roo.bootstrap.CheckBox} this This input
18009 * @param {Boolean} checked The new checked value
18016 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18018 inputType: 'checkbox',
18026 getAutoCreate : function()
18028 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18034 cfg.cls = 'form-group ' + this.inputType; //input-group
18037 cfg.cls += ' ' + this.inputType + '-inline';
18043 type : this.inputType,
18044 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18045 cls : 'roo-' + this.inputType, //'form-box',
18046 placeholder : this.placeholder || ''
18050 if (this.weight) { // Validity check?
18051 cfg.cls += " " + this.inputType + "-" + this.weight;
18054 if (this.disabled) {
18055 input.disabled=true;
18059 input.checked = this.checked;
18063 input.name = this.name;
18067 input.cls += ' input-' + this.size;
18072 ['xs','sm','md','lg'].map(function(size){
18073 if (settings[size]) {
18074 cfg.cls += ' col-' + size + '-' + settings[size];
18078 var inputblock = input;
18080 if (this.before || this.after) {
18083 cls : 'input-group',
18088 inputblock.cn.push({
18090 cls : 'input-group-addon',
18095 inputblock.cn.push(input);
18098 inputblock.cn.push({
18100 cls : 'input-group-addon',
18107 if (align ==='left' && this.fieldLabel.length) {
18108 Roo.log("left and has label");
18114 cls : 'control-label col-md-' + this.labelWidth,
18115 html : this.fieldLabel
18119 cls : "col-md-" + (12 - this.labelWidth),
18126 } else if ( this.fieldLabel.length) {
18131 tag: this.boxLabel ? 'span' : 'label',
18133 cls: 'control-label box-input-label',
18134 //cls : 'input-group-addon',
18135 html : this.fieldLabel
18145 Roo.log(" no label && no align");
18146 cfg.cn = [ inputblock ] ;
18151 var boxLabelCfg = {
18153 //'for': id, // box label is handled by onclick - so no for...
18155 html: this.boxLabel
18159 boxLabelCfg.tooltip = this.tooltip;
18162 cfg.cn.push(boxLabelCfg);
18172 * return the real input element.
18174 inputEl: function ()
18176 return this.el.select('input.roo-' + this.inputType,true).first();
18179 labelEl: function()
18181 return this.el.select('label.control-label',true).first();
18183 /* depricated... */
18187 return this.labelEl();
18190 initEvents : function()
18192 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18194 this.inputEl().on('click', this.onClick, this);
18196 if (this.boxLabel) {
18197 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
18200 this.startValue = this.getValue();
18203 Roo.bootstrap.CheckBox.register(this);
18207 onClick : function()
18209 this.setChecked(!this.checked);
18212 setChecked : function(state,suppressEvent)
18214 this.startValue = this.getValue();
18216 if(this.inputType == 'radio'){
18218 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18219 e.dom.checked = false;
18222 this.inputEl().dom.checked = true;
18224 this.inputEl().dom.value = this.inputValue;
18226 if(suppressEvent !== true){
18227 this.fireEvent('check', this, true);
18235 this.checked = state;
18237 this.inputEl().dom.checked = state;
18239 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18241 if(suppressEvent !== true){
18242 this.fireEvent('check', this, state);
18248 getValue : function()
18250 if(this.inputType == 'radio'){
18251 return this.getGroupValue();
18254 return this.inputEl().getValue();
18258 getGroupValue : function()
18260 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
18264 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
18267 setValue : function(v,suppressEvent)
18269 if(this.inputType == 'radio'){
18270 this.setGroupValue(v, suppressEvent);
18274 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
18279 setGroupValue : function(v, suppressEvent)
18281 this.startValue = this.getValue();
18283 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18284 e.dom.checked = false;
18286 if(e.dom.value == v){
18287 e.dom.checked = true;
18291 if(suppressEvent !== true){
18292 this.fireEvent('check', this, true);
18300 validate : function()
18304 (this.inputType == 'radio' && this.validateRadio()) ||
18305 (this.inputType == 'checkbox' && this.validateCheckbox())
18311 this.markInvalid();
18315 validateRadio : function()
18319 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18320 if(!e.dom.checked){
18332 validateCheckbox : function()
18335 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
18338 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18346 for(var i in group){
18351 r = (group[i].getValue() == group[i].inputValue) ? true : false;
18358 * Mark this field as valid
18360 markValid : function()
18362 if(this.allowBlank){
18368 this.fireEvent('valid', this);
18370 if(this.inputType == 'radio'){
18371 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18372 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
18373 e.findParent('.form-group', false, true).addClass(_this.validClass);
18380 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18381 this.el.findParent('.form-group', false, true).addClass(this.validClass);
18385 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18391 for(var i in group){
18392 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18393 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
18398 * Mark this field as invalid
18399 * @param {String} msg The validation message
18401 markInvalid : function(msg)
18403 if(this.allowBlank){
18409 this.fireEvent('invalid', this, msg);
18411 if(this.inputType == 'radio'){
18412 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18413 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
18414 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
18421 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18422 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
18426 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18432 for(var i in group){
18433 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18434 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
18441 Roo.apply(Roo.bootstrap.CheckBox, {
18446 * register a CheckBox Group
18447 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
18449 register : function(checkbox)
18451 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
18452 this.groups[checkbox.groupId] = {};
18455 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
18459 this.groups[checkbox.groupId][checkbox.name] = checkbox;
18463 * fetch a CheckBox Group based on the group ID
18464 * @param {string} the group ID
18465 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
18467 get: function(groupId) {
18468 if (typeof(this.groups[groupId]) == 'undefined') {
18472 return this.groups[groupId] ;
18484 *<div class="radio">
18486 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
18487 Option one is this and that—be sure to include why it's great
18494 *<label class="radio-inline">fieldLabel</label>
18495 *<label class="radio-inline">
18496 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
18504 * @class Roo.bootstrap.Radio
18505 * @extends Roo.bootstrap.CheckBox
18506 * Bootstrap Radio class
18509 * Create a new Radio
18510 * @param {Object} config The config object
18513 Roo.bootstrap.Radio = function(config){
18514 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
18518 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
18520 inputType: 'radio',
18524 getAutoCreate : function()
18526 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18527 align = align || 'left'; // default...
18534 tag : this.inline ? 'span' : 'div',
18539 var inline = this.inline ? ' radio-inline' : '';
18543 // does not need for, as we wrap the input with it..
18545 cls : 'control-label box-label' + inline,
18548 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
18552 //cls : 'control-label' + inline,
18553 html : this.fieldLabel,
18554 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
18563 type : this.inputType,
18564 //value : (!this.checked) ? this.valueOff : this.inputValue,
18565 value : this.inputValue,
18567 placeholder : this.placeholder || '' // ?? needed????
18570 if (this.weight) { // Validity check?
18571 input.cls += " radio-" + this.weight;
18573 if (this.disabled) {
18574 input.disabled=true;
18578 input.checked = this.checked;
18582 input.name = this.name;
18586 input.cls += ' input-' + this.size;
18589 //?? can span's inline have a width??
18592 ['xs','sm','md','lg'].map(function(size){
18593 if (settings[size]) {
18594 cfg.cls += ' col-' + size + '-' + settings[size];
18598 var inputblock = input;
18600 if (this.before || this.after) {
18603 cls : 'input-group',
18608 inputblock.cn.push({
18610 cls : 'input-group-addon',
18614 inputblock.cn.push(input);
18616 inputblock.cn.push({
18618 cls : 'input-group-addon',
18626 if (this.fieldLabel && this.fieldLabel.length) {
18627 cfg.cn.push(fieldLabel);
18630 // normal bootstrap puts the input inside the label.
18631 // however with our styled version - it has to go after the input.
18633 //lbl.cn.push(inputblock);
18637 cls: 'radio' + inline,
18644 cfg.cn.push( lblwrap);
18649 html: this.boxLabel
18658 initEvents : function()
18660 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18662 this.inputEl().on('click', this.onClick, this);
18663 if (this.boxLabel) {
18664 Roo.log('find label')
18665 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18670 inputEl: function ()
18672 return this.el.select('input.roo-radio',true).first();
18674 onClick : function()
18677 this.setChecked(true);
18680 setChecked : function(state,suppressEvent)
18683 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18684 v.dom.checked = false;
18687 Roo.log(this.inputEl().dom);
18688 this.checked = state;
18689 this.inputEl().dom.checked = state;
18691 if(suppressEvent !== true){
18692 this.fireEvent('check', this, state);
18695 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18699 getGroupValue : function()
18702 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18703 if(v.dom.checked == true){
18704 value = v.dom.value;
18712 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18713 * @return {Mixed} value The field value
18715 getValue : function(){
18716 return this.getGroupValue();
18722 //<script type="text/javascript">
18725 * Based Ext JS Library 1.1.1
18726 * Copyright(c) 2006-2007, Ext JS, LLC.
18732 * @class Roo.HtmlEditorCore
18733 * @extends Roo.Component
18734 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18736 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18739 Roo.HtmlEditorCore = function(config){
18742 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18747 * @event initialize
18748 * Fires when the editor is fully initialized (including the iframe)
18749 * @param {Roo.HtmlEditorCore} this
18754 * Fires when the editor is first receives the focus. Any insertion must wait
18755 * until after this event.
18756 * @param {Roo.HtmlEditorCore} this
18760 * @event beforesync
18761 * Fires before the textarea is updated with content from the editor iframe. Return false
18762 * to cancel the sync.
18763 * @param {Roo.HtmlEditorCore} this
18764 * @param {String} html
18768 * @event beforepush
18769 * Fires before the iframe editor is updated with content from the textarea. Return false
18770 * to cancel the push.
18771 * @param {Roo.HtmlEditorCore} this
18772 * @param {String} html
18777 * Fires when the textarea is updated with content from the editor iframe.
18778 * @param {Roo.HtmlEditorCore} this
18779 * @param {String} html
18784 * Fires when the iframe editor is updated with content from the textarea.
18785 * @param {Roo.HtmlEditorCore} this
18786 * @param {String} html
18791 * @event editorevent
18792 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18793 * @param {Roo.HtmlEditorCore} this
18799 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18801 // defaults : white / black...
18802 this.applyBlacklists();
18809 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18813 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18819 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18824 * @cfg {Number} height (in pixels)
18828 * @cfg {Number} width (in pixels)
18833 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18836 stylesheets: false,
18841 // private properties
18842 validationEvent : false,
18844 initialized : false,
18846 sourceEditMode : false,
18847 onFocus : Roo.emptyFn,
18849 hideMode:'offsets',
18853 // blacklist + whitelisted elements..
18860 * Protected method that will not generally be called directly. It
18861 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18862 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18864 getDocMarkup : function(){
18868 // inherit styels from page...??
18869 if (this.stylesheets === false) {
18871 Roo.get(document.head).select('style').each(function(node) {
18872 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18875 Roo.get(document.head).select('link').each(function(node) {
18876 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18879 } else if (!this.stylesheets.length) {
18881 st = '<style type="text/css">' +
18882 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18888 st += '<style type="text/css">' +
18889 'IMG { cursor: pointer } ' +
18893 return '<html><head>' + st +
18894 //<style type="text/css">' +
18895 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18897 ' </head><body class="roo-htmleditor-body"></body></html>';
18901 onRender : function(ct, position)
18904 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18905 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18908 this.el.dom.style.border = '0 none';
18909 this.el.dom.setAttribute('tabIndex', -1);
18910 this.el.addClass('x-hidden hide');
18914 if(Roo.isIE){ // fix IE 1px bogus margin
18915 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18919 this.frameId = Roo.id();
18923 var iframe = this.owner.wrap.createChild({
18925 cls: 'form-control', // bootstrap..
18927 name: this.frameId,
18928 frameBorder : 'no',
18929 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18934 this.iframe = iframe.dom;
18936 this.assignDocWin();
18938 this.doc.designMode = 'on';
18941 this.doc.write(this.getDocMarkup());
18945 var task = { // must defer to wait for browser to be ready
18947 //console.log("run task?" + this.doc.readyState);
18948 this.assignDocWin();
18949 if(this.doc.body || this.doc.readyState == 'complete'){
18951 this.doc.designMode="on";
18955 Roo.TaskMgr.stop(task);
18956 this.initEditor.defer(10, this);
18963 Roo.TaskMgr.start(task);
18968 onResize : function(w, h)
18970 Roo.log('resize: ' +w + ',' + h );
18971 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18975 if(typeof w == 'number'){
18977 this.iframe.style.width = w + 'px';
18979 if(typeof h == 'number'){
18981 this.iframe.style.height = h + 'px';
18983 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18990 * Toggles the editor between standard and source edit mode.
18991 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18993 toggleSourceEdit : function(sourceEditMode){
18995 this.sourceEditMode = sourceEditMode === true;
18997 if(this.sourceEditMode){
18999 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
19002 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
19003 //this.iframe.className = '';
19006 //this.setSize(this.owner.wrap.getSize());
19007 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19014 * Protected method that will not generally be called directly. If you need/want
19015 * custom HTML cleanup, this is the method you should override.
19016 * @param {String} html The HTML to be cleaned
19017 * return {String} The cleaned HTML
19019 cleanHtml : function(html){
19020 html = String(html);
19021 if(html.length > 5){
19022 if(Roo.isSafari){ // strip safari nonsense
19023 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19026 if(html == ' '){
19033 * HTML Editor -> Textarea
19034 * Protected method that will not generally be called directly. Syncs the contents
19035 * of the editor iframe with the textarea.
19037 syncValue : function(){
19038 if(this.initialized){
19039 var bd = (this.doc.body || this.doc.documentElement);
19040 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19041 var html = bd.innerHTML;
19043 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19044 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19046 html = '<div style="'+m[0]+'">' + html + '</div>';
19049 html = this.cleanHtml(html);
19050 // fix up the special chars.. normaly like back quotes in word...
19051 // however we do not want to do this with chinese..
19052 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19053 var cc = b.charCodeAt();
19055 (cc >= 0x4E00 && cc < 0xA000 ) ||
19056 (cc >= 0x3400 && cc < 0x4E00 ) ||
19057 (cc >= 0xf900 && cc < 0xfb00 )
19063 if(this.owner.fireEvent('beforesync', this, html) !== false){
19064 this.el.dom.value = html;
19065 this.owner.fireEvent('sync', this, html);
19071 * Protected method that will not generally be called directly. Pushes the value of the textarea
19072 * into the iframe editor.
19074 pushValue : function(){
19075 if(this.initialized){
19076 var v = this.el.dom.value.trim();
19078 // if(v.length < 1){
19082 if(this.owner.fireEvent('beforepush', this, v) !== false){
19083 var d = (this.doc.body || this.doc.documentElement);
19085 this.cleanUpPaste();
19086 this.el.dom.value = d.innerHTML;
19087 this.owner.fireEvent('push', this, v);
19093 deferFocus : function(){
19094 this.focus.defer(10, this);
19098 focus : function(){
19099 if(this.win && !this.sourceEditMode){
19106 assignDocWin: function()
19108 var iframe = this.iframe;
19111 this.doc = iframe.contentWindow.document;
19112 this.win = iframe.contentWindow;
19114 // if (!Roo.get(this.frameId)) {
19117 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19118 // this.win = Roo.get(this.frameId).dom.contentWindow;
19120 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
19124 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19125 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
19130 initEditor : function(){
19131 //console.log("INIT EDITOR");
19132 this.assignDocWin();
19136 this.doc.designMode="on";
19138 this.doc.write(this.getDocMarkup());
19141 var dbody = (this.doc.body || this.doc.documentElement);
19142 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
19143 // this copies styles from the containing element into thsi one..
19144 // not sure why we need all of this..
19145 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
19147 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
19148 //ss['background-attachment'] = 'fixed'; // w3c
19149 dbody.bgProperties = 'fixed'; // ie
19150 //Roo.DomHelper.applyStyles(dbody, ss);
19151 Roo.EventManager.on(this.doc, {
19152 //'mousedown': this.onEditorEvent,
19153 'mouseup': this.onEditorEvent,
19154 'dblclick': this.onEditorEvent,
19155 'click': this.onEditorEvent,
19156 'keyup': this.onEditorEvent,
19161 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
19163 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
19164 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
19166 this.initialized = true;
19168 this.owner.fireEvent('initialize', this);
19173 onDestroy : function(){
19179 //for (var i =0; i < this.toolbars.length;i++) {
19180 // // fixme - ask toolbars for heights?
19181 // this.toolbars[i].onDestroy();
19184 //this.wrap.dom.innerHTML = '';
19185 //this.wrap.remove();
19190 onFirstFocus : function(){
19192 this.assignDocWin();
19195 this.activated = true;
19198 if(Roo.isGecko){ // prevent silly gecko errors
19200 var s = this.win.getSelection();
19201 if(!s.focusNode || s.focusNode.nodeType != 3){
19202 var r = s.getRangeAt(0);
19203 r.selectNodeContents((this.doc.body || this.doc.documentElement));
19208 this.execCmd('useCSS', true);
19209 this.execCmd('styleWithCSS', false);
19212 this.owner.fireEvent('activate', this);
19216 adjustFont: function(btn){
19217 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
19218 //if(Roo.isSafari){ // safari
19221 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
19222 if(Roo.isSafari){ // safari
19223 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
19224 v = (v < 10) ? 10 : v;
19225 v = (v > 48) ? 48 : v;
19226 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
19231 v = Math.max(1, v+adjust);
19233 this.execCmd('FontSize', v );
19236 onEditorEvent : function(e)
19238 this.owner.fireEvent('editorevent', this, e);
19239 // this.updateToolbar();
19240 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
19243 insertTag : function(tg)
19245 // could be a bit smarter... -> wrap the current selected tRoo..
19246 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
19248 range = this.createRange(this.getSelection());
19249 var wrappingNode = this.doc.createElement(tg.toLowerCase());
19250 wrappingNode.appendChild(range.extractContents());
19251 range.insertNode(wrappingNode);
19258 this.execCmd("formatblock", tg);
19262 insertText : function(txt)
19266 var range = this.createRange();
19267 range.deleteContents();
19268 //alert(Sender.getAttribute('label'));
19270 range.insertNode(this.doc.createTextNode(txt));
19276 * Executes a Midas editor command on the editor document and performs necessary focus and
19277 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
19278 * @param {String} cmd The Midas command
19279 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
19281 relayCmd : function(cmd, value){
19283 this.execCmd(cmd, value);
19284 this.owner.fireEvent('editorevent', this);
19285 //this.updateToolbar();
19286 this.owner.deferFocus();
19290 * Executes a Midas editor command directly on the editor document.
19291 * For visual commands, you should use {@link #relayCmd} instead.
19292 * <b>This should only be called after the editor is initialized.</b>
19293 * @param {String} cmd The Midas command
19294 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
19296 execCmd : function(cmd, value){
19297 this.doc.execCommand(cmd, false, value === undefined ? null : value);
19304 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
19306 * @param {String} text | dom node..
19308 insertAtCursor : function(text)
19313 if(!this.activated){
19319 var r = this.doc.selection.createRange();
19330 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
19334 // from jquery ui (MIT licenced)
19336 var win = this.win;
19338 if (win.getSelection && win.getSelection().getRangeAt) {
19339 range = win.getSelection().getRangeAt(0);
19340 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
19341 range.insertNode(node);
19342 } else if (win.document.selection && win.document.selection.createRange) {
19343 // no firefox support
19344 var txt = typeof(text) == 'string' ? text : text.outerHTML;
19345 win.document.selection.createRange().pasteHTML(txt);
19347 // no firefox support
19348 var txt = typeof(text) == 'string' ? text : text.outerHTML;
19349 this.execCmd('InsertHTML', txt);
19358 mozKeyPress : function(e){
19360 var c = e.getCharCode(), cmd;
19363 c = String.fromCharCode(c).toLowerCase();
19377 this.cleanUpPaste.defer(100, this);
19385 e.preventDefault();
19393 fixKeys : function(){ // load time branching for fastest keydown performance
19395 return function(e){
19396 var k = e.getKey(), r;
19399 r = this.doc.selection.createRange();
19402 r.pasteHTML('    ');
19409 r = this.doc.selection.createRange();
19411 var target = r.parentElement();
19412 if(!target || target.tagName.toLowerCase() != 'li'){
19414 r.pasteHTML('<br />');
19420 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19421 this.cleanUpPaste.defer(100, this);
19427 }else if(Roo.isOpera){
19428 return function(e){
19429 var k = e.getKey();
19433 this.execCmd('InsertHTML','    ');
19436 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19437 this.cleanUpPaste.defer(100, this);
19442 }else if(Roo.isSafari){
19443 return function(e){
19444 var k = e.getKey();
19448 this.execCmd('InsertText','\t');
19452 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19453 this.cleanUpPaste.defer(100, this);
19461 getAllAncestors: function()
19463 var p = this.getSelectedNode();
19466 a.push(p); // push blank onto stack..
19467 p = this.getParentElement();
19471 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
19475 a.push(this.doc.body);
19479 lastSelNode : false,
19482 getSelection : function()
19484 this.assignDocWin();
19485 return Roo.isIE ? this.doc.selection : this.win.getSelection();
19488 getSelectedNode: function()
19490 // this may only work on Gecko!!!
19492 // should we cache this!!!!
19497 var range = this.createRange(this.getSelection()).cloneRange();
19500 var parent = range.parentElement();
19502 var testRange = range.duplicate();
19503 testRange.moveToElementText(parent);
19504 if (testRange.inRange(range)) {
19507 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
19510 parent = parent.parentElement;
19515 // is ancestor a text element.
19516 var ac = range.commonAncestorContainer;
19517 if (ac.nodeType == 3) {
19518 ac = ac.parentNode;
19521 var ar = ac.childNodes;
19524 var other_nodes = [];
19525 var has_other_nodes = false;
19526 for (var i=0;i<ar.length;i++) {
19527 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
19530 // fullly contained node.
19532 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
19537 // probably selected..
19538 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
19539 other_nodes.push(ar[i]);
19543 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
19548 has_other_nodes = true;
19550 if (!nodes.length && other_nodes.length) {
19551 nodes= other_nodes;
19553 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
19559 createRange: function(sel)
19561 // this has strange effects when using with
19562 // top toolbar - not sure if it's a great idea.
19563 //this.editor.contentWindow.focus();
19564 if (typeof sel != "undefined") {
19566 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
19568 return this.doc.createRange();
19571 return this.doc.createRange();
19574 getParentElement: function()
19577 this.assignDocWin();
19578 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
19580 var range = this.createRange(sel);
19583 var p = range.commonAncestorContainer;
19584 while (p.nodeType == 3) { // text node
19595 * Range intersection.. the hard stuff...
19599 * [ -- selected range --- ]
19603 * if end is before start or hits it. fail.
19604 * if start is after end or hits it fail.
19606 * if either hits (but other is outside. - then it's not
19612 // @see http://www.thismuchiknow.co.uk/?p=64.
19613 rangeIntersectsNode : function(range, node)
19615 var nodeRange = node.ownerDocument.createRange();
19617 nodeRange.selectNode(node);
19619 nodeRange.selectNodeContents(node);
19622 var rangeStartRange = range.cloneRange();
19623 rangeStartRange.collapse(true);
19625 var rangeEndRange = range.cloneRange();
19626 rangeEndRange.collapse(false);
19628 var nodeStartRange = nodeRange.cloneRange();
19629 nodeStartRange.collapse(true);
19631 var nodeEndRange = nodeRange.cloneRange();
19632 nodeEndRange.collapse(false);
19634 return rangeStartRange.compareBoundaryPoints(
19635 Range.START_TO_START, nodeEndRange) == -1 &&
19636 rangeEndRange.compareBoundaryPoints(
19637 Range.START_TO_START, nodeStartRange) == 1;
19641 rangeCompareNode : function(range, node)
19643 var nodeRange = node.ownerDocument.createRange();
19645 nodeRange.selectNode(node);
19647 nodeRange.selectNodeContents(node);
19651 range.collapse(true);
19653 nodeRange.collapse(true);
19655 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19656 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19658 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19660 var nodeIsBefore = ss == 1;
19661 var nodeIsAfter = ee == -1;
19663 if (nodeIsBefore && nodeIsAfter)
19665 if (!nodeIsBefore && nodeIsAfter)
19666 return 1; //right trailed.
19668 if (nodeIsBefore && !nodeIsAfter)
19669 return 2; // left trailed.
19674 // private? - in a new class?
19675 cleanUpPaste : function()
19677 // cleans up the whole document..
19678 Roo.log('cleanuppaste');
19680 this.cleanUpChildren(this.doc.body);
19681 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19682 if (clean != this.doc.body.innerHTML) {
19683 this.doc.body.innerHTML = clean;
19688 cleanWordChars : function(input) {// change the chars to hex code
19689 var he = Roo.HtmlEditorCore;
19691 var output = input;
19692 Roo.each(he.swapCodes, function(sw) {
19693 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19695 output = output.replace(swapper, sw[1]);
19702 cleanUpChildren : function (n)
19704 if (!n.childNodes.length) {
19707 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19708 this.cleanUpChild(n.childNodes[i]);
19715 cleanUpChild : function (node)
19718 //console.log(node);
19719 if (node.nodeName == "#text") {
19720 // clean up silly Windows -- stuff?
19723 if (node.nodeName == "#comment") {
19724 node.parentNode.removeChild(node);
19725 // clean up silly Windows -- stuff?
19728 var lcname = node.tagName.toLowerCase();
19729 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19730 // whitelist of tags..
19732 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19734 node.parentNode.removeChild(node);
19739 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19741 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19742 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19744 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19745 // remove_keep_children = true;
19748 if (remove_keep_children) {
19749 this.cleanUpChildren(node);
19750 // inserts everything just before this node...
19751 while (node.childNodes.length) {
19752 var cn = node.childNodes[0];
19753 node.removeChild(cn);
19754 node.parentNode.insertBefore(cn, node);
19756 node.parentNode.removeChild(node);
19760 if (!node.attributes || !node.attributes.length) {
19761 this.cleanUpChildren(node);
19765 function cleanAttr(n,v)
19768 if (v.match(/^\./) || v.match(/^\//)) {
19771 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19774 if (v.match(/^#/)) {
19777 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19778 node.removeAttribute(n);
19782 var cwhite = this.cwhite;
19783 var cblack = this.cblack;
19785 function cleanStyle(n,v)
19787 if (v.match(/expression/)) { //XSS?? should we even bother..
19788 node.removeAttribute(n);
19792 var parts = v.split(/;/);
19795 Roo.each(parts, function(p) {
19796 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19800 var l = p.split(':').shift().replace(/\s+/g,'');
19801 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19803 if ( cwhite.length && cblack.indexOf(l) > -1) {
19804 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19805 //node.removeAttribute(n);
19809 // only allow 'c whitelisted system attributes'
19810 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19811 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19812 //node.removeAttribute(n);
19822 if (clean.length) {
19823 node.setAttribute(n, clean.join(';'));
19825 node.removeAttribute(n);
19831 for (var i = node.attributes.length-1; i > -1 ; i--) {
19832 var a = node.attributes[i];
19835 if (a.name.toLowerCase().substr(0,2)=='on') {
19836 node.removeAttribute(a.name);
19839 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19840 node.removeAttribute(a.name);
19843 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19844 cleanAttr(a.name,a.value); // fixme..
19847 if (a.name == 'style') {
19848 cleanStyle(a.name,a.value);
19851 /// clean up MS crap..
19852 // tecnically this should be a list of valid class'es..
19855 if (a.name == 'class') {
19856 if (a.value.match(/^Mso/)) {
19857 node.className = '';
19860 if (a.value.match(/body/)) {
19861 node.className = '';
19872 this.cleanUpChildren(node);
19878 * Clean up MS wordisms...
19880 cleanWord : function(node)
19885 this.cleanWord(this.doc.body);
19888 if (node.nodeName == "#text") {
19889 // clean up silly Windows -- stuff?
19892 if (node.nodeName == "#comment") {
19893 node.parentNode.removeChild(node);
19894 // clean up silly Windows -- stuff?
19898 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19899 node.parentNode.removeChild(node);
19903 // remove - but keep children..
19904 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19905 while (node.childNodes.length) {
19906 var cn = node.childNodes[0];
19907 node.removeChild(cn);
19908 node.parentNode.insertBefore(cn, node);
19910 node.parentNode.removeChild(node);
19911 this.iterateChildren(node, this.cleanWord);
19915 if (node.className.length) {
19917 var cn = node.className.split(/\W+/);
19919 Roo.each(cn, function(cls) {
19920 if (cls.match(/Mso[a-zA-Z]+/)) {
19925 node.className = cna.length ? cna.join(' ') : '';
19927 node.removeAttribute("class");
19931 if (node.hasAttribute("lang")) {
19932 node.removeAttribute("lang");
19935 if (node.hasAttribute("style")) {
19937 var styles = node.getAttribute("style").split(";");
19939 Roo.each(styles, function(s) {
19940 if (!s.match(/:/)) {
19943 var kv = s.split(":");
19944 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19947 // what ever is left... we allow.
19950 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19951 if (!nstyle.length) {
19952 node.removeAttribute('style');
19955 this.iterateChildren(node, this.cleanWord);
19961 * iterateChildren of a Node, calling fn each time, using this as the scole..
19962 * @param {DomNode} node node to iterate children of.
19963 * @param {Function} fn method of this class to call on each item.
19965 iterateChildren : function(node, fn)
19967 if (!node.childNodes.length) {
19970 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19971 fn.call(this, node.childNodes[i])
19977 * cleanTableWidths.
19979 * Quite often pasting from word etc.. results in tables with column and widths.
19980 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19983 cleanTableWidths : function(node)
19988 this.cleanTableWidths(this.doc.body);
19993 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19996 Roo.log(node.tagName);
19997 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
19998 this.iterateChildren(node, this.cleanTableWidths);
20001 if (node.hasAttribute('width')) {
20002 node.removeAttribute('width');
20006 if (node.hasAttribute("style")) {
20009 var styles = node.getAttribute("style").split(";");
20011 Roo.each(styles, function(s) {
20012 if (!s.match(/:/)) {
20015 var kv = s.split(":");
20016 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20019 // what ever is left... we allow.
20022 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20023 if (!nstyle.length) {
20024 node.removeAttribute('style');
20028 this.iterateChildren(node, this.cleanTableWidths);
20036 domToHTML : function(currentElement, depth, nopadtext) {
20038 depth = depth || 0;
20039 nopadtext = nopadtext || false;
20041 if (!currentElement) {
20042 return this.domToHTML(this.doc.body);
20045 //Roo.log(currentElement);
20047 var allText = false;
20048 var nodeName = currentElement.nodeName;
20049 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20051 if (nodeName == '#text') {
20053 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20058 if (nodeName != 'BODY') {
20061 // Prints the node tagName, such as <A>, <IMG>, etc
20064 for(i = 0; i < currentElement.attributes.length;i++) {
20066 var aname = currentElement.attributes.item(i).name;
20067 if (!currentElement.attributes.item(i).value.length) {
20070 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20073 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20082 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20085 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20090 // Traverse the tree
20092 var currentElementChild = currentElement.childNodes.item(i);
20093 var allText = true;
20094 var innerHTML = '';
20096 while (currentElementChild) {
20097 // Formatting code (indent the tree so it looks nice on the screen)
20098 var nopad = nopadtext;
20099 if (lastnode == 'SPAN') {
20103 if (currentElementChild.nodeName == '#text') {
20104 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
20105 toadd = nopadtext ? toadd : toadd.trim();
20106 if (!nopad && toadd.length > 80) {
20107 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
20109 innerHTML += toadd;
20112 currentElementChild = currentElement.childNodes.item(i);
20118 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
20120 // Recursively traverse the tree structure of the child node
20121 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
20122 lastnode = currentElementChild.nodeName;
20124 currentElementChild=currentElement.childNodes.item(i);
20130 // The remaining code is mostly for formatting the tree
20131 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
20136 ret+= "</"+tagName+">";
20142 applyBlacklists : function()
20144 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
20145 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
20149 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
20150 if (b.indexOf(tag) > -1) {
20153 this.white.push(tag);
20157 Roo.each(w, function(tag) {
20158 if (b.indexOf(tag) > -1) {
20161 if (this.white.indexOf(tag) > -1) {
20164 this.white.push(tag);
20169 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
20170 if (w.indexOf(tag) > -1) {
20173 this.black.push(tag);
20177 Roo.each(b, function(tag) {
20178 if (w.indexOf(tag) > -1) {
20181 if (this.black.indexOf(tag) > -1) {
20184 this.black.push(tag);
20189 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
20190 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
20194 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
20195 if (b.indexOf(tag) > -1) {
20198 this.cwhite.push(tag);
20202 Roo.each(w, function(tag) {
20203 if (b.indexOf(tag) > -1) {
20206 if (this.cwhite.indexOf(tag) > -1) {
20209 this.cwhite.push(tag);
20214 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
20215 if (w.indexOf(tag) > -1) {
20218 this.cblack.push(tag);
20222 Roo.each(b, function(tag) {
20223 if (w.indexOf(tag) > -1) {
20226 if (this.cblack.indexOf(tag) > -1) {
20229 this.cblack.push(tag);
20234 setStylesheets : function(stylesheets)
20236 if(typeof(stylesheets) == 'string'){
20237 Roo.get(this.iframe.contentDocument.head).createChild({
20239 rel : 'stylesheet',
20248 Roo.each(stylesheets, function(s) {
20253 Roo.get(_this.iframe.contentDocument.head).createChild({
20255 rel : 'stylesheet',
20264 removeStylesheets : function()
20268 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
20273 // hide stuff that is not compatible
20287 * @event specialkey
20291 * @cfg {String} fieldClass @hide
20294 * @cfg {String} focusClass @hide
20297 * @cfg {String} autoCreate @hide
20300 * @cfg {String} inputType @hide
20303 * @cfg {String} invalidClass @hide
20306 * @cfg {String} invalidText @hide
20309 * @cfg {String} msgFx @hide
20312 * @cfg {String} validateOnBlur @hide
20316 Roo.HtmlEditorCore.white = [
20317 'area', 'br', 'img', 'input', 'hr', 'wbr',
20319 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
20320 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
20321 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
20322 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
20323 'table', 'ul', 'xmp',
20325 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
20328 'dir', 'menu', 'ol', 'ul', 'dl',
20334 Roo.HtmlEditorCore.black = [
20335 // 'embed', 'object', // enable - backend responsiblity to clean thiese
20337 'base', 'basefont', 'bgsound', 'blink', 'body',
20338 'frame', 'frameset', 'head', 'html', 'ilayer',
20339 'iframe', 'layer', 'link', 'meta', 'object',
20340 'script', 'style' ,'title', 'xml' // clean later..
20342 Roo.HtmlEditorCore.clean = [
20343 'script', 'style', 'title', 'xml'
20345 Roo.HtmlEditorCore.remove = [
20350 Roo.HtmlEditorCore.ablack = [
20354 Roo.HtmlEditorCore.aclean = [
20355 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
20359 Roo.HtmlEditorCore.pwhite= [
20360 'http', 'https', 'mailto'
20363 // white listed style attributes.
20364 Roo.HtmlEditorCore.cwhite= [
20365 // 'text-align', /// default is to allow most things..
20371 // black listed style attributes.
20372 Roo.HtmlEditorCore.cblack= [
20373 // 'font-size' -- this can be set by the project
20377 Roo.HtmlEditorCore.swapCodes =[
20396 * @class Roo.bootstrap.HtmlEditor
20397 * @extends Roo.bootstrap.TextArea
20398 * Bootstrap HtmlEditor class
20401 * Create a new HtmlEditor
20402 * @param {Object} config The config object
20405 Roo.bootstrap.HtmlEditor = function(config){
20406 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
20407 if (!this.toolbars) {
20408 this.toolbars = [];
20410 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
20413 * @event initialize
20414 * Fires when the editor is fully initialized (including the iframe)
20415 * @param {HtmlEditor} this
20420 * Fires when the editor is first receives the focus. Any insertion must wait
20421 * until after this event.
20422 * @param {HtmlEditor} this
20426 * @event beforesync
20427 * Fires before the textarea is updated with content from the editor iframe. Return false
20428 * to cancel the sync.
20429 * @param {HtmlEditor} this
20430 * @param {String} html
20434 * @event beforepush
20435 * Fires before the iframe editor is updated with content from the textarea. Return false
20436 * to cancel the push.
20437 * @param {HtmlEditor} this
20438 * @param {String} html
20443 * Fires when the textarea is updated with content from the editor iframe.
20444 * @param {HtmlEditor} this
20445 * @param {String} html
20450 * Fires when the iframe editor is updated with content from the textarea.
20451 * @param {HtmlEditor} this
20452 * @param {String} html
20456 * @event editmodechange
20457 * Fires when the editor switches edit modes
20458 * @param {HtmlEditor} this
20459 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
20461 editmodechange: true,
20463 * @event editorevent
20464 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20465 * @param {HtmlEditor} this
20469 * @event firstfocus
20470 * Fires when on first focus - needed by toolbars..
20471 * @param {HtmlEditor} this
20476 * Auto save the htmlEditor value as a file into Events
20477 * @param {HtmlEditor} this
20481 * @event savedpreview
20482 * preview the saved version of htmlEditor
20483 * @param {HtmlEditor} this
20490 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
20494 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
20499 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20504 * @cfg {Number} height (in pixels)
20508 * @cfg {Number} width (in pixels)
20513 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20516 stylesheets: false,
20521 // private properties
20522 validationEvent : false,
20524 initialized : false,
20527 onFocus : Roo.emptyFn,
20529 hideMode:'offsets',
20532 tbContainer : false,
20534 toolbarContainer :function() {
20535 return this.wrap.select('.x-html-editor-tb',true).first();
20539 * Protected method that will not generally be called directly. It
20540 * is called when the editor creates its toolbar. Override this method if you need to
20541 * add custom toolbar buttons.
20542 * @param {HtmlEditor} editor
20544 createToolbar : function(){
20546 Roo.log("create toolbars");
20548 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
20549 this.toolbars[0].render(this.toolbarContainer());
20553 // if (!editor.toolbars || !editor.toolbars.length) {
20554 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
20557 // for (var i =0 ; i < editor.toolbars.length;i++) {
20558 // editor.toolbars[i] = Roo.factory(
20559 // typeof(editor.toolbars[i]) == 'string' ?
20560 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
20561 // Roo.bootstrap.HtmlEditor);
20562 // editor.toolbars[i].init(editor);
20568 onRender : function(ct, position)
20570 // Roo.log("Call onRender: " + this.xtype);
20572 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
20574 this.wrap = this.inputEl().wrap({
20575 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
20578 this.editorcore.onRender(ct, position);
20580 if (this.resizable) {
20581 this.resizeEl = new Roo.Resizable(this.wrap, {
20585 minHeight : this.height,
20586 height: this.height,
20587 handles : this.resizable,
20590 resize : function(r, w, h) {
20591 _t.onResize(w,h); // -something
20597 this.createToolbar(this);
20600 if(!this.width && this.resizable){
20601 this.setSize(this.wrap.getSize());
20603 if (this.resizeEl) {
20604 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
20605 // should trigger onReize..
20611 onResize : function(w, h)
20613 Roo.log('resize: ' +w + ',' + h );
20614 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20618 if(this.inputEl() ){
20619 if(typeof w == 'number'){
20620 var aw = w - this.wrap.getFrameWidth('lr');
20621 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20624 if(typeof h == 'number'){
20625 var tbh = -11; // fixme it needs to tool bar size!
20626 for (var i =0; i < this.toolbars.length;i++) {
20627 // fixme - ask toolbars for heights?
20628 tbh += this.toolbars[i].el.getHeight();
20629 //if (this.toolbars[i].footer) {
20630 // tbh += this.toolbars[i].footer.el.getHeight();
20638 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20639 ah -= 5; // knock a few pixes off for look..
20640 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20644 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20645 this.editorcore.onResize(ew,eh);
20650 * Toggles the editor between standard and source edit mode.
20651 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20653 toggleSourceEdit : function(sourceEditMode)
20655 this.editorcore.toggleSourceEdit(sourceEditMode);
20657 if(this.editorcore.sourceEditMode){
20658 Roo.log('editor - showing textarea');
20661 // Roo.log(this.syncValue());
20663 this.inputEl().removeClass(['hide', 'x-hidden']);
20664 this.inputEl().dom.removeAttribute('tabIndex');
20665 this.inputEl().focus();
20667 Roo.log('editor - hiding textarea');
20669 // Roo.log(this.pushValue());
20672 this.inputEl().addClass(['hide', 'x-hidden']);
20673 this.inputEl().dom.setAttribute('tabIndex', -1);
20674 //this.deferFocus();
20677 if(this.resizable){
20678 this.setSize(this.wrap.getSize());
20681 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20684 // private (for BoxComponent)
20685 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20687 // private (for BoxComponent)
20688 getResizeEl : function(){
20692 // private (for BoxComponent)
20693 getPositionEl : function(){
20698 initEvents : function(){
20699 this.originalValue = this.getValue();
20703 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20706 // markInvalid : Roo.emptyFn,
20708 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20711 // clearInvalid : Roo.emptyFn,
20713 setValue : function(v){
20714 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20715 this.editorcore.pushValue();
20720 deferFocus : function(){
20721 this.focus.defer(10, this);
20725 focus : function(){
20726 this.editorcore.focus();
20732 onDestroy : function(){
20738 for (var i =0; i < this.toolbars.length;i++) {
20739 // fixme - ask toolbars for heights?
20740 this.toolbars[i].onDestroy();
20743 this.wrap.dom.innerHTML = '';
20744 this.wrap.remove();
20749 onFirstFocus : function(){
20750 //Roo.log("onFirstFocus");
20751 this.editorcore.onFirstFocus();
20752 for (var i =0; i < this.toolbars.length;i++) {
20753 this.toolbars[i].onFirstFocus();
20759 syncValue : function()
20761 this.editorcore.syncValue();
20764 pushValue : function()
20766 this.editorcore.pushValue();
20770 // hide stuff that is not compatible
20784 * @event specialkey
20788 * @cfg {String} fieldClass @hide
20791 * @cfg {String} focusClass @hide
20794 * @cfg {String} autoCreate @hide
20797 * @cfg {String} inputType @hide
20800 * @cfg {String} invalidClass @hide
20803 * @cfg {String} invalidText @hide
20806 * @cfg {String} msgFx @hide
20809 * @cfg {String} validateOnBlur @hide
20818 Roo.namespace('Roo.bootstrap.htmleditor');
20820 * @class Roo.bootstrap.HtmlEditorToolbar1
20825 new Roo.bootstrap.HtmlEditor({
20828 new Roo.bootstrap.HtmlEditorToolbar1({
20829 disable : { fonts: 1 , format: 1, ..., ... , ...],
20835 * @cfg {Object} disable List of elements to disable..
20836 * @cfg {Array} btns List of additional buttons.
20840 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20843 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20846 Roo.apply(this, config);
20848 // default disabled, based on 'good practice'..
20849 this.disable = this.disable || {};
20850 Roo.applyIf(this.disable, {
20853 specialElements : true
20855 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20857 this.editor = config.editor;
20858 this.editorcore = config.editor.editorcore;
20860 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20862 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20863 // dont call parent... till later.
20865 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20870 editorcore : false,
20875 "h1","h2","h3","h4","h5","h6",
20877 "abbr", "acronym", "address", "cite", "samp", "var",
20881 onRender : function(ct, position)
20883 // Roo.log("Call onRender: " + this.xtype);
20885 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20887 this.el.dom.style.marginBottom = '0';
20889 var editorcore = this.editorcore;
20890 var editor= this.editor;
20893 var btn = function(id,cmd , toggle, handler){
20895 var event = toggle ? 'toggle' : 'click';
20900 xns: Roo.bootstrap,
20903 enableToggle:toggle !== false,
20905 pressed : toggle ? false : null,
20908 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20909 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20918 xns: Roo.bootstrap,
20919 glyphicon : 'font',
20923 xns: Roo.bootstrap,
20927 Roo.each(this.formats, function(f) {
20928 style.menu.items.push({
20930 xns: Roo.bootstrap,
20931 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20936 editorcore.insertTag(this.tagname);
20943 children.push(style);
20946 btn('bold',false,true);
20947 btn('italic',false,true);
20948 btn('align-left', 'justifyleft',true);
20949 btn('align-center', 'justifycenter',true);
20950 btn('align-right' , 'justifyright',true);
20951 btn('link', false, false, function(btn) {
20952 //Roo.log("create link?");
20953 var url = prompt(this.createLinkText, this.defaultLinkValue);
20954 if(url && url != 'http:/'+'/'){
20955 this.editorcore.relayCmd('createlink', url);
20958 btn('list','insertunorderedlist',true);
20959 btn('pencil', false,true, function(btn){
20962 this.toggleSourceEdit(btn.pressed);
20968 xns: Roo.bootstrap,
20973 xns: Roo.bootstrap,
20978 cog.menu.items.push({
20980 xns: Roo.bootstrap,
20981 html : Clean styles,
20986 editorcore.insertTag(this.tagname);
20995 this.xtype = 'NavSimplebar';
20997 for(var i=0;i< children.length;i++) {
20999 this.buttons.add(this.addxtypeChild(children[i]));
21003 editor.on('editorevent', this.updateToolbar, this);
21005 onBtnClick : function(id)
21007 this.editorcore.relayCmd(id);
21008 this.editorcore.focus();
21012 * Protected method that will not generally be called directly. It triggers
21013 * a toolbar update by reading the markup state of the current selection in the editor.
21015 updateToolbar: function(){
21017 if(!this.editorcore.activated){
21018 this.editor.onFirstFocus(); // is this neeed?
21022 var btns = this.buttons;
21023 var doc = this.editorcore.doc;
21024 btns.get('bold').setActive(doc.queryCommandState('bold'));
21025 btns.get('italic').setActive(doc.queryCommandState('italic'));
21026 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21028 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21029 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21030 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21032 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21033 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21036 var ans = this.editorcore.getAllAncestors();
21037 if (this.formatCombo) {
21040 var store = this.formatCombo.store;
21041 this.formatCombo.setValue("");
21042 for (var i =0; i < ans.length;i++) {
21043 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21045 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21053 // hides menus... - so this cant be on a menu...
21054 Roo.bootstrap.MenuMgr.hideAll();
21056 Roo.bootstrap.MenuMgr.hideAll();
21057 //this.editorsyncValue();
21059 onFirstFocus: function() {
21060 this.buttons.each(function(item){
21064 toggleSourceEdit : function(sourceEditMode){
21067 if(sourceEditMode){
21068 Roo.log("disabling buttons");
21069 this.buttons.each( function(item){
21070 if(item.cmd != 'pencil'){
21076 Roo.log("enabling buttons");
21077 if(this.editorcore.initialized){
21078 this.buttons.each( function(item){
21084 Roo.log("calling toggole on editor");
21085 // tell the editor that it's been pressed..
21086 this.editor.toggleSourceEdit(sourceEditMode);
21096 * @class Roo.bootstrap.Table.AbstractSelectionModel
21097 * @extends Roo.util.Observable
21098 * Abstract base class for grid SelectionModels. It provides the interface that should be
21099 * implemented by descendant classes. This class should not be directly instantiated.
21102 Roo.bootstrap.Table.AbstractSelectionModel = function(){
21103 this.locked = false;
21104 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
21108 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
21109 /** @ignore Called by the grid automatically. Do not call directly. */
21110 init : function(grid){
21116 * Locks the selections.
21119 this.locked = true;
21123 * Unlocks the selections.
21125 unlock : function(){
21126 this.locked = false;
21130 * Returns true if the selections are locked.
21131 * @return {Boolean}
21133 isLocked : function(){
21134 return this.locked;
21138 * @extends Roo.bootstrap.Table.AbstractSelectionModel
21139 * @class Roo.bootstrap.Table.RowSelectionModel
21140 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
21141 * It supports multiple selections and keyboard selection/navigation.
21143 * @param {Object} config
21146 Roo.bootstrap.Table.RowSelectionModel = function(config){
21147 Roo.apply(this, config);
21148 this.selections = new Roo.util.MixedCollection(false, function(o){
21153 this.lastActive = false;
21157 * @event selectionchange
21158 * Fires when the selection changes
21159 * @param {SelectionModel} this
21161 "selectionchange" : true,
21163 * @event afterselectionchange
21164 * Fires after the selection changes (eg. by key press or clicking)
21165 * @param {SelectionModel} this
21167 "afterselectionchange" : true,
21169 * @event beforerowselect
21170 * Fires when a row is selected being selected, return false to cancel.
21171 * @param {SelectionModel} this
21172 * @param {Number} rowIndex The selected index
21173 * @param {Boolean} keepExisting False if other selections will be cleared
21175 "beforerowselect" : true,
21178 * Fires when a row is selected.
21179 * @param {SelectionModel} this
21180 * @param {Number} rowIndex The selected index
21181 * @param {Roo.data.Record} r The record
21183 "rowselect" : true,
21185 * @event rowdeselect
21186 * Fires when a row is deselected.
21187 * @param {SelectionModel} this
21188 * @param {Number} rowIndex The selected index
21190 "rowdeselect" : true
21192 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
21193 this.locked = false;
21196 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
21198 * @cfg {Boolean} singleSelect
21199 * True to allow selection of only one row at a time (defaults to false)
21201 singleSelect : false,
21204 initEvents : function(){
21206 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
21207 this.grid.on("mousedown", this.handleMouseDown, this);
21208 }else{ // allow click to work like normal
21209 this.grid.on("rowclick", this.handleDragableRowClick, this);
21212 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
21213 "up" : function(e){
21215 this.selectPrevious(e.shiftKey);
21216 }else if(this.last !== false && this.lastActive !== false){
21217 var last = this.last;
21218 this.selectRange(this.last, this.lastActive-1);
21219 this.grid.getView().focusRow(this.lastActive);
21220 if(last !== false){
21224 this.selectFirstRow();
21226 this.fireEvent("afterselectionchange", this);
21228 "down" : function(e){
21230 this.selectNext(e.shiftKey);
21231 }else if(this.last !== false && this.lastActive !== false){
21232 var last = this.last;
21233 this.selectRange(this.last, this.lastActive+1);
21234 this.grid.getView().focusRow(this.lastActive);
21235 if(last !== false){
21239 this.selectFirstRow();
21241 this.fireEvent("afterselectionchange", this);
21246 var view = this.grid.view;
21247 view.on("refresh", this.onRefresh, this);
21248 view.on("rowupdated", this.onRowUpdated, this);
21249 view.on("rowremoved", this.onRemove, this);
21253 onRefresh : function(){
21254 var ds = this.grid.dataSource, i, v = this.grid.view;
21255 var s = this.selections;
21256 s.each(function(r){
21257 if((i = ds.indexOfId(r.id)) != -1){
21266 onRemove : function(v, index, r){
21267 this.selections.remove(r);
21271 onRowUpdated : function(v, index, r){
21272 if(this.isSelected(r)){
21273 v.onRowSelect(index);
21279 * @param {Array} records The records to select
21280 * @param {Boolean} keepExisting (optional) True to keep existing selections
21282 selectRecords : function(records, keepExisting){
21284 this.clearSelections();
21286 var ds = this.grid.dataSource;
21287 for(var i = 0, len = records.length; i < len; i++){
21288 this.selectRow(ds.indexOf(records[i]), true);
21293 * Gets the number of selected rows.
21296 getCount : function(){
21297 return this.selections.length;
21301 * Selects the first row in the grid.
21303 selectFirstRow : function(){
21308 * Select the last row.
21309 * @param {Boolean} keepExisting (optional) True to keep existing selections
21311 selectLastRow : function(keepExisting){
21312 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
21316 * Selects the row immediately following the last selected row.
21317 * @param {Boolean} keepExisting (optional) True to keep existing selections
21319 selectNext : function(keepExisting){
21320 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
21321 this.selectRow(this.last+1, keepExisting);
21322 this.grid.getView().focusRow(this.last);
21327 * Selects the row that precedes the last selected row.
21328 * @param {Boolean} keepExisting (optional) True to keep existing selections
21330 selectPrevious : function(keepExisting){
21332 this.selectRow(this.last-1, keepExisting);
21333 this.grid.getView().focusRow(this.last);
21338 * Returns the selected records
21339 * @return {Array} Array of selected records
21341 getSelections : function(){
21342 return [].concat(this.selections.items);
21346 * Returns the first selected record.
21349 getSelected : function(){
21350 return this.selections.itemAt(0);
21355 * Clears all selections.
21357 clearSelections : function(fast){
21358 if(this.locked) return;
21360 var ds = this.grid.dataSource;
21361 var s = this.selections;
21362 s.each(function(r){
21363 this.deselectRow(ds.indexOfId(r.id));
21367 this.selections.clear();
21374 * Selects all rows.
21376 selectAll : function(){
21377 if(this.locked) return;
21378 this.selections.clear();
21379 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
21380 this.selectRow(i, true);
21385 * Returns True if there is a selection.
21386 * @return {Boolean}
21388 hasSelection : function(){
21389 return this.selections.length > 0;
21393 * Returns True if the specified row is selected.
21394 * @param {Number/Record} record The record or index of the record to check
21395 * @return {Boolean}
21397 isSelected : function(index){
21398 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
21399 return (r && this.selections.key(r.id) ? true : false);
21403 * Returns True if the specified record id is selected.
21404 * @param {String} id The id of record to check
21405 * @return {Boolean}
21407 isIdSelected : function(id){
21408 return (this.selections.key(id) ? true : false);
21412 handleMouseDown : function(e, t){
21413 var view = this.grid.getView(), rowIndex;
21414 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
21417 if(e.shiftKey && this.last !== false){
21418 var last = this.last;
21419 this.selectRange(last, rowIndex, e.ctrlKey);
21420 this.last = last; // reset the last
21421 view.focusRow(rowIndex);
21423 var isSelected = this.isSelected(rowIndex);
21424 if(e.button !== 0 && isSelected){
21425 view.focusRow(rowIndex);
21426 }else if(e.ctrlKey && isSelected){
21427 this.deselectRow(rowIndex);
21428 }else if(!isSelected){
21429 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
21430 view.focusRow(rowIndex);
21433 this.fireEvent("afterselectionchange", this);
21436 handleDragableRowClick : function(grid, rowIndex, e)
21438 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
21439 this.selectRow(rowIndex, false);
21440 grid.view.focusRow(rowIndex);
21441 this.fireEvent("afterselectionchange", this);
21446 * Selects multiple rows.
21447 * @param {Array} rows Array of the indexes of the row to select
21448 * @param {Boolean} keepExisting (optional) True to keep existing selections
21450 selectRows : function(rows, keepExisting){
21452 this.clearSelections();
21454 for(var i = 0, len = rows.length; i < len; i++){
21455 this.selectRow(rows[i], true);
21460 * Selects a range of rows. All rows in between startRow and endRow are also selected.
21461 * @param {Number} startRow The index of the first row in the range
21462 * @param {Number} endRow The index of the last row in the range
21463 * @param {Boolean} keepExisting (optional) True to retain existing selections
21465 selectRange : function(startRow, endRow, keepExisting){
21466 if(this.locked) return;
21468 this.clearSelections();
21470 if(startRow <= endRow){
21471 for(var i = startRow; i <= endRow; i++){
21472 this.selectRow(i, true);
21475 for(var i = startRow; i >= endRow; i--){
21476 this.selectRow(i, true);
21482 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
21483 * @param {Number} startRow The index of the first row in the range
21484 * @param {Number} endRow The index of the last row in the range
21486 deselectRange : function(startRow, endRow, preventViewNotify){
21487 if(this.locked) return;
21488 for(var i = startRow; i <= endRow; i++){
21489 this.deselectRow(i, preventViewNotify);
21495 * @param {Number} row The index of the row to select
21496 * @param {Boolean} keepExisting (optional) True to keep existing selections
21498 selectRow : function(index, keepExisting, preventViewNotify){
21499 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
21500 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
21501 if(!keepExisting || this.singleSelect){
21502 this.clearSelections();
21504 var r = this.grid.dataSource.getAt(index);
21505 this.selections.add(r);
21506 this.last = this.lastActive = index;
21507 if(!preventViewNotify){
21508 this.grid.getView().onRowSelect(index);
21510 this.fireEvent("rowselect", this, index, r);
21511 this.fireEvent("selectionchange", this);
21517 * @param {Number} row The index of the row to deselect
21519 deselectRow : function(index, preventViewNotify){
21520 if(this.locked) return;
21521 if(this.last == index){
21524 if(this.lastActive == index){
21525 this.lastActive = false;
21527 var r = this.grid.dataSource.getAt(index);
21528 this.selections.remove(r);
21529 if(!preventViewNotify){
21530 this.grid.getView().onRowDeselect(index);
21532 this.fireEvent("rowdeselect", this, index);
21533 this.fireEvent("selectionchange", this);
21537 restoreLast : function(){
21539 this.last = this._last;
21544 acceptsNav : function(row, col, cm){
21545 return !cm.isHidden(col) && cm.isCellEditable(col, row);
21549 onEditorKey : function(field, e){
21550 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
21555 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
21557 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
21559 }else if(k == e.ENTER && !e.ctrlKey){
21563 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
21565 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
21567 }else if(k == e.ESC){
21571 g.startEditing(newCell[0], newCell[1]);
21576 * Ext JS Library 1.1.1
21577 * Copyright(c) 2006-2007, Ext JS, LLC.
21579 * Originally Released Under LGPL - original licence link has changed is not relivant.
21582 * <script type="text/javascript">
21586 * @class Roo.bootstrap.PagingToolbar
21588 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
21590 * Create a new PagingToolbar
21591 * @param {Object} config The config object
21593 Roo.bootstrap.PagingToolbar = function(config)
21595 // old args format still supported... - xtype is prefered..
21596 // created from xtype...
21597 var ds = config.dataSource;
21598 this.toolbarItems = [];
21599 if (config.items) {
21600 this.toolbarItems = config.items;
21601 // config.items = [];
21604 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
21611 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
21615 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21617 * @cfg {Roo.data.Store} dataSource
21618 * The underlying data store providing the paged data
21621 * @cfg {String/HTMLElement/Element} container
21622 * container The id or element that will contain the toolbar
21625 * @cfg {Boolean} displayInfo
21626 * True to display the displayMsg (defaults to false)
21629 * @cfg {Number} pageSize
21630 * The number of records to display per page (defaults to 20)
21634 * @cfg {String} displayMsg
21635 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21637 displayMsg : 'Displaying {0} - {1} of {2}',
21639 * @cfg {String} emptyMsg
21640 * The message to display when no records are found (defaults to "No data to display")
21642 emptyMsg : 'No data to display',
21644 * Customizable piece of the default paging text (defaults to "Page")
21647 beforePageText : "Page",
21649 * Customizable piece of the default paging text (defaults to "of %0")
21652 afterPageText : "of {0}",
21654 * Customizable piece of the default paging text (defaults to "First Page")
21657 firstText : "First Page",
21659 * Customizable piece of the default paging text (defaults to "Previous Page")
21662 prevText : "Previous Page",
21664 * Customizable piece of the default paging text (defaults to "Next Page")
21667 nextText : "Next Page",
21669 * Customizable piece of the default paging text (defaults to "Last Page")
21672 lastText : "Last Page",
21674 * Customizable piece of the default paging text (defaults to "Refresh")
21677 refreshText : "Refresh",
21681 onRender : function(ct, position)
21683 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21684 this.navgroup.parentId = this.id;
21685 this.navgroup.onRender(this.el, null);
21686 // add the buttons to the navgroup
21688 if(this.displayInfo){
21689 Roo.log(this.el.select('ul.navbar-nav',true).first());
21690 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21691 this.displayEl = this.el.select('.x-paging-info', true).first();
21692 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21693 // this.displayEl = navel.el.select('span',true).first();
21699 Roo.each(_this.buttons, function(e){
21700 Roo.factory(e).onRender(_this.el, null);
21704 Roo.each(_this.toolbarItems, function(e) {
21705 _this.navgroup.addItem(e);
21709 this.first = this.navgroup.addItem({
21710 tooltip: this.firstText,
21712 icon : 'fa fa-backward',
21714 preventDefault: true,
21715 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21718 this.prev = this.navgroup.addItem({
21719 tooltip: this.prevText,
21721 icon : 'fa fa-step-backward',
21723 preventDefault: true,
21724 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21726 //this.addSeparator();
21729 var field = this.navgroup.addItem( {
21731 cls : 'x-paging-position',
21733 html : this.beforePageText +
21734 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21735 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21738 this.field = field.el.select('input', true).first();
21739 this.field.on("keydown", this.onPagingKeydown, this);
21740 this.field.on("focus", function(){this.dom.select();});
21743 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21744 //this.field.setHeight(18);
21745 //this.addSeparator();
21746 this.next = this.navgroup.addItem({
21747 tooltip: this.nextText,
21749 html : ' <i class="fa fa-step-forward">',
21751 preventDefault: true,
21752 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21754 this.last = this.navgroup.addItem({
21755 tooltip: this.lastText,
21756 icon : 'fa fa-forward',
21759 preventDefault: true,
21760 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21762 //this.addSeparator();
21763 this.loading = this.navgroup.addItem({
21764 tooltip: this.refreshText,
21765 icon: 'fa fa-refresh',
21766 preventDefault: true,
21767 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21773 updateInfo : function(){
21774 if(this.displayEl){
21775 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21776 var msg = count == 0 ?
21780 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21782 this.displayEl.update(msg);
21787 onLoad : function(ds, r, o){
21788 this.cursor = o.params ? o.params.start : 0;
21789 var d = this.getPageData(),
21793 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21794 this.field.dom.value = ap;
21795 this.first.setDisabled(ap == 1);
21796 this.prev.setDisabled(ap == 1);
21797 this.next.setDisabled(ap == ps);
21798 this.last.setDisabled(ap == ps);
21799 this.loading.enable();
21804 getPageData : function(){
21805 var total = this.ds.getTotalCount();
21808 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21809 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21814 onLoadError : function(){
21815 this.loading.enable();
21819 onPagingKeydown : function(e){
21820 var k = e.getKey();
21821 var d = this.getPageData();
21823 var v = this.field.dom.value, pageNum;
21824 if(!v || isNaN(pageNum = parseInt(v, 10))){
21825 this.field.dom.value = d.activePage;
21828 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21829 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21832 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))
21834 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21835 this.field.dom.value = pageNum;
21836 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21839 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21841 var v = this.field.dom.value, pageNum;
21842 var increment = (e.shiftKey) ? 10 : 1;
21843 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21845 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21846 this.field.dom.value = d.activePage;
21849 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21851 this.field.dom.value = parseInt(v, 10) + increment;
21852 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21853 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21860 beforeLoad : function(){
21862 this.loading.disable();
21867 onClick : function(which){
21876 ds.load({params:{start: 0, limit: this.pageSize}});
21879 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21882 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21885 var total = ds.getTotalCount();
21886 var extra = total % this.pageSize;
21887 var lastStart = extra ? (total - extra) : total-this.pageSize;
21888 ds.load({params:{start: lastStart, limit: this.pageSize}});
21891 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21897 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21898 * @param {Roo.data.Store} store The data store to unbind
21900 unbind : function(ds){
21901 ds.un("beforeload", this.beforeLoad, this);
21902 ds.un("load", this.onLoad, this);
21903 ds.un("loadexception", this.onLoadError, this);
21904 ds.un("remove", this.updateInfo, this);
21905 ds.un("add", this.updateInfo, this);
21906 this.ds = undefined;
21910 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21911 * @param {Roo.data.Store} store The data store to bind
21913 bind : function(ds){
21914 ds.on("beforeload", this.beforeLoad, this);
21915 ds.on("load", this.onLoad, this);
21916 ds.on("loadexception", this.onLoadError, this);
21917 ds.on("remove", this.updateInfo, this);
21918 ds.on("add", this.updateInfo, this);
21929 * @class Roo.bootstrap.MessageBar
21930 * @extends Roo.bootstrap.Component
21931 * Bootstrap MessageBar class
21932 * @cfg {String} html contents of the MessageBar
21933 * @cfg {String} weight (info | success | warning | danger) default info
21934 * @cfg {String} beforeClass insert the bar before the given class
21935 * @cfg {Boolean} closable (true | false) default false
21936 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21939 * Create a new Element
21940 * @param {Object} config The config object
21943 Roo.bootstrap.MessageBar = function(config){
21944 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21947 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21953 beforeClass: 'bootstrap-sticky-wrap',
21955 getAutoCreate : function(){
21959 cls: 'alert alert-dismissable alert-' + this.weight,
21964 html: this.html || ''
21970 cfg.cls += ' alert-messages-fixed';
21984 onRender : function(ct, position)
21986 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21989 var cfg = Roo.apply({}, this.getAutoCreate());
21993 cfg.cls += ' ' + this.cls;
21996 cfg.style = this.style;
21998 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
22000 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22003 this.el.select('>button.close').on('click', this.hide, this);
22009 if (!this.rendered) {
22015 this.fireEvent('show', this);
22021 if (!this.rendered) {
22027 this.fireEvent('hide', this);
22030 update : function()
22032 // var e = this.el.dom.firstChild;
22034 // if(this.closable){
22035 // e = e.nextSibling;
22038 // e.data = this.html || '';
22040 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22056 * @class Roo.bootstrap.Graph
22057 * @extends Roo.bootstrap.Component
22058 * Bootstrap Graph class
22062 @cfg {String} graphtype bar | vbar | pie
22063 @cfg {number} g_x coodinator | centre x (pie)
22064 @cfg {number} g_y coodinator | centre y (pie)
22065 @cfg {number} g_r radius (pie)
22066 @cfg {number} g_height height of the chart (respected by all elements in the set)
22067 @cfg {number} g_width width of the chart (respected by all elements in the set)
22068 @cfg {Object} title The title of the chart
22071 -opts (object) options for the chart
22073 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
22074 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
22076 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.
22077 o stacked (boolean) whether or not to tread values as in a stacked bar chart
22079 o stretch (boolean)
22081 -opts (object) options for the pie
22084 o startAngle (number)
22085 o endAngle (number)
22089 * Create a new Input
22090 * @param {Object} config The config object
22093 Roo.bootstrap.Graph = function(config){
22094 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
22100 * The img click event for the img.
22101 * @param {Roo.EventObject} e
22107 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
22118 //g_colors: this.colors,
22125 getAutoCreate : function(){
22136 onRender : function(ct,position){
22137 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
22138 this.raphael = Raphael(this.el.dom);
22140 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22141 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22142 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22143 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
22145 r.text(160, 10, "Single Series Chart").attr(txtattr);
22146 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
22147 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
22148 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
22150 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
22151 r.barchart(330, 10, 300, 220, data1);
22152 r.barchart(10, 250, 300, 220, data2, {stacked: true});
22153 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
22156 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22157 // r.barchart(30, 30, 560, 250, xdata, {
22158 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
22159 // axis : "0 0 1 1",
22160 // axisxlabels : xdata
22161 // //yvalues : cols,
22164 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22166 // this.load(null,xdata,{
22167 // axis : "0 0 1 1",
22168 // axisxlabels : xdata
22173 load : function(graphtype,xdata,opts){
22174 this.raphael.clear();
22176 graphtype = this.graphtype;
22181 var r = this.raphael,
22182 fin = function () {
22183 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
22185 fout = function () {
22186 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
22188 pfin = function() {
22189 this.sector.stop();
22190 this.sector.scale(1.1, 1.1, this.cx, this.cy);
22193 this.label[0].stop();
22194 this.label[0].attr({ r: 7.5 });
22195 this.label[1].attr({ "font-weight": 800 });
22198 pfout = function() {
22199 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
22202 this.label[0].animate({ r: 5 }, 500, "bounce");
22203 this.label[1].attr({ "font-weight": 400 });
22209 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
22212 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
22215 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
22216 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
22218 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
22225 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
22230 setTitle: function(o)
22235 initEvents: function() {
22238 this.el.on('click', this.onClick, this);
22242 onClick : function(e)
22244 Roo.log('img onclick');
22245 this.fireEvent('click', this, e);
22257 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22260 * @class Roo.bootstrap.dash.NumberBox
22261 * @extends Roo.bootstrap.Component
22262 * Bootstrap NumberBox class
22263 * @cfg {String} headline Box headline
22264 * @cfg {String} content Box content
22265 * @cfg {String} icon Box icon
22266 * @cfg {String} footer Footer text
22267 * @cfg {String} fhref Footer href
22270 * Create a new NumberBox
22271 * @param {Object} config The config object
22275 Roo.bootstrap.dash.NumberBox = function(config){
22276 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
22280 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
22289 getAutoCreate : function(){
22293 cls : 'small-box ',
22301 cls : 'roo-headline',
22302 html : this.headline
22306 cls : 'roo-content',
22307 html : this.content
22321 cls : 'ion ' + this.icon
22330 cls : 'small-box-footer',
22331 href : this.fhref || '#',
22335 cfg.cn.push(footer);
22342 onRender : function(ct,position){
22343 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
22350 setHeadline: function (value)
22352 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
22355 setFooter: function (value, href)
22357 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
22360 this.el.select('a.small-box-footer',true).first().attr('href', href);
22365 setContent: function (value)
22367 this.el.select('.roo-content',true).first().dom.innerHTML = value;
22370 initEvents: function()
22384 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22387 * @class Roo.bootstrap.dash.TabBox
22388 * @extends Roo.bootstrap.Component
22389 * Bootstrap TabBox class
22390 * @cfg {String} title Title of the TabBox
22391 * @cfg {String} icon Icon of the TabBox
22392 * @cfg {Boolean} showtabs (true|false) show the tabs default true
22393 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
22396 * Create a new TabBox
22397 * @param {Object} config The config object
22401 Roo.bootstrap.dash.TabBox = function(config){
22402 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
22407 * When a pane is added
22408 * @param {Roo.bootstrap.dash.TabPane} pane
22412 * @event activatepane
22413 * When a pane is activated
22414 * @param {Roo.bootstrap.dash.TabPane} pane
22416 "activatepane" : true
22424 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
22429 tabScrollable : false,
22431 getChildContainer : function()
22433 return this.el.select('.tab-content', true).first();
22436 getAutoCreate : function(){
22440 cls: 'pull-left header',
22448 cls: 'fa ' + this.icon
22454 cls: 'nav nav-tabs pull-right',
22460 if(this.tabScrollable){
22467 cls: 'nav nav-tabs pull-right',
22478 cls: 'nav-tabs-custom',
22483 cls: 'tab-content no-padding',
22491 initEvents : function()
22493 //Roo.log('add add pane handler');
22494 this.on('addpane', this.onAddPane, this);
22497 * Updates the box title
22498 * @param {String} html to set the title to.
22500 setTitle : function(value)
22502 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
22504 onAddPane : function(pane)
22506 this.panes.push(pane);
22507 //Roo.log('addpane');
22509 // tabs are rendere left to right..
22510 if(!this.showtabs){
22514 var ctr = this.el.select('.nav-tabs', true).first();
22517 var existing = ctr.select('.nav-tab',true);
22518 var qty = existing.getCount();;
22521 var tab = ctr.createChild({
22523 cls : 'nav-tab' + (qty ? '' : ' active'),
22531 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
22534 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
22536 pane.el.addClass('active');
22541 onTabClick : function(ev,un,ob,pane)
22543 //Roo.log('tab - prev default');
22544 ev.preventDefault();
22547 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
22548 pane.tab.addClass('active');
22549 //Roo.log(pane.title);
22550 this.getChildContainer().select('.tab-pane',true).removeClass('active');
22551 // technically we should have a deactivate event.. but maybe add later.
22552 // and it should not de-activate the selected tab...
22553 this.fireEvent('activatepane', pane);
22554 pane.el.addClass('active');
22555 pane.fireEvent('activate');
22560 getActivePane : function()
22563 Roo.each(this.panes, function(p) {
22564 if(p.el.hasClass('active')){
22585 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22587 * @class Roo.bootstrap.TabPane
22588 * @extends Roo.bootstrap.Component
22589 * Bootstrap TabPane class
22590 * @cfg {Boolean} active (false | true) Default false
22591 * @cfg {String} title title of panel
22595 * Create a new TabPane
22596 * @param {Object} config The config object
22599 Roo.bootstrap.dash.TabPane = function(config){
22600 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
22606 * When a pane is activated
22607 * @param {Roo.bootstrap.dash.TabPane} pane
22614 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22619 // the tabBox that this is attached to.
22622 getAutoCreate : function()
22630 cfg.cls += ' active';
22635 initEvents : function()
22637 //Roo.log('trigger add pane handler');
22638 this.parent().fireEvent('addpane', this)
22642 * Updates the tab title
22643 * @param {String} html to set the title to.
22645 setTitle: function(str)
22651 this.tab.select('a', true).first().dom.innerHTML = str;
22668 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22671 * @class Roo.bootstrap.menu.Menu
22672 * @extends Roo.bootstrap.Component
22673 * Bootstrap Menu class - container for Menu
22674 * @cfg {String} html Text of the menu
22675 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22676 * @cfg {String} icon Font awesome icon
22677 * @cfg {String} pos Menu align to (top | bottom) default bottom
22681 * Create a new Menu
22682 * @param {Object} config The config object
22686 Roo.bootstrap.menu.Menu = function(config){
22687 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22691 * @event beforeshow
22692 * Fires before this menu is displayed
22693 * @param {Roo.bootstrap.menu.Menu} this
22697 * @event beforehide
22698 * Fires before this menu is hidden
22699 * @param {Roo.bootstrap.menu.Menu} this
22704 * Fires after this menu is displayed
22705 * @param {Roo.bootstrap.menu.Menu} this
22710 * Fires after this menu is hidden
22711 * @param {Roo.bootstrap.menu.Menu} this
22716 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22717 * @param {Roo.bootstrap.menu.Menu} this
22718 * @param {Roo.EventObject} e
22725 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22729 weight : 'default',
22734 getChildContainer : function() {
22735 if(this.isSubMenu){
22739 return this.el.select('ul.dropdown-menu', true).first();
22742 getAutoCreate : function()
22747 cls : 'roo-menu-text',
22755 cls : 'fa ' + this.icon
22766 cls : 'dropdown-button btn btn-' + this.weight,
22771 cls : 'dropdown-toggle btn btn-' + this.weight,
22781 cls : 'dropdown-menu'
22787 if(this.pos == 'top'){
22788 cfg.cls += ' dropup';
22791 if(this.isSubMenu){
22794 cls : 'dropdown-menu'
22801 onRender : function(ct, position)
22803 this.isSubMenu = ct.hasClass('dropdown-submenu');
22805 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22808 initEvents : function()
22810 if(this.isSubMenu){
22814 this.hidden = true;
22816 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22817 this.triggerEl.on('click', this.onTriggerPress, this);
22819 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22820 this.buttonEl.on('click', this.onClick, this);
22826 if(this.isSubMenu){
22830 return this.el.select('ul.dropdown-menu', true).first();
22833 onClick : function(e)
22835 this.fireEvent("click", this, e);
22838 onTriggerPress : function(e)
22840 if (this.isVisible()) {
22847 isVisible : function(){
22848 return !this.hidden;
22853 this.fireEvent("beforeshow", this);
22855 this.hidden = false;
22856 this.el.addClass('open');
22858 Roo.get(document).on("mouseup", this.onMouseUp, this);
22860 this.fireEvent("show", this);
22867 this.fireEvent("beforehide", this);
22869 this.hidden = true;
22870 this.el.removeClass('open');
22872 Roo.get(document).un("mouseup", this.onMouseUp);
22874 this.fireEvent("hide", this);
22877 onMouseUp : function()
22891 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22894 * @class Roo.bootstrap.menu.Item
22895 * @extends Roo.bootstrap.Component
22896 * Bootstrap MenuItem class
22897 * @cfg {Boolean} submenu (true | false) default false
22898 * @cfg {String} html text of the item
22899 * @cfg {String} href the link
22900 * @cfg {Boolean} disable (true | false) default false
22901 * @cfg {Boolean} preventDefault (true | false) default true
22902 * @cfg {String} icon Font awesome icon
22903 * @cfg {String} pos Submenu align to (left | right) default right
22907 * Create a new Item
22908 * @param {Object} config The config object
22912 Roo.bootstrap.menu.Item = function(config){
22913 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22917 * Fires when the mouse is hovering over this menu
22918 * @param {Roo.bootstrap.menu.Item} this
22919 * @param {Roo.EventObject} e
22924 * Fires when the mouse exits this menu
22925 * @param {Roo.bootstrap.menu.Item} this
22926 * @param {Roo.EventObject} e
22932 * The raw click event for the entire grid.
22933 * @param {Roo.EventObject} e
22939 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22944 preventDefault: true,
22949 getAutoCreate : function()
22954 cls : 'roo-menu-item-text',
22962 cls : 'fa ' + this.icon
22971 href : this.href || '#',
22978 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22982 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22984 if(this.pos == 'left'){
22985 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22992 initEvents : function()
22994 this.el.on('mouseover', this.onMouseOver, this);
22995 this.el.on('mouseout', this.onMouseOut, this);
22997 this.el.select('a', true).first().on('click', this.onClick, this);
23001 onClick : function(e)
23003 if(this.preventDefault){
23004 e.preventDefault();
23007 this.fireEvent("click", this, e);
23010 onMouseOver : function(e)
23012 if(this.submenu && this.pos == 'left'){
23013 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23016 this.fireEvent("mouseover", this, e);
23019 onMouseOut : function(e)
23021 this.fireEvent("mouseout", this, e);
23033 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23036 * @class Roo.bootstrap.menu.Separator
23037 * @extends Roo.bootstrap.Component
23038 * Bootstrap Separator class
23041 * Create a new Separator
23042 * @param {Object} config The config object
23046 Roo.bootstrap.menu.Separator = function(config){
23047 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23050 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23052 getAutoCreate : function(){
23073 * @class Roo.bootstrap.Tooltip
23074 * Bootstrap Tooltip class
23075 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
23076 * to determine which dom element triggers the tooltip.
23078 * It needs to add support for additional attributes like tooltip-position
23081 * Create a new Toolti
23082 * @param {Object} config The config object
23085 Roo.bootstrap.Tooltip = function(config){
23086 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
23089 Roo.apply(Roo.bootstrap.Tooltip, {
23091 * @function init initialize tooltip monitoring.
23095 currentTip : false,
23096 currentRegion : false,
23102 Roo.get(document).on('mouseover', this.enter ,this);
23103 Roo.get(document).on('mouseout', this.leave, this);
23106 this.currentTip = new Roo.bootstrap.Tooltip();
23109 enter : function(ev)
23111 var dom = ev.getTarget();
23113 //Roo.log(['enter',dom]);
23114 var el = Roo.fly(dom);
23115 if (this.currentEl) {
23117 //Roo.log(this.currentEl);
23118 //Roo.log(this.currentEl.contains(dom));
23119 if (this.currentEl == el) {
23122 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
23130 if (this.currentTip.el) {
23131 this.currentTip.el.hide(); // force hiding...
23136 // you can not look for children, as if el is the body.. then everythign is the child..
23137 if (!el.attr('tooltip')) { //
23138 if (!el.select("[tooltip]").elements.length) {
23141 // is the mouse over this child...?
23142 bindEl = el.select("[tooltip]").first();
23143 var xy = ev.getXY();
23144 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
23145 //Roo.log("not in region.");
23148 //Roo.log("child element over..");
23151 this.currentEl = bindEl;
23152 this.currentTip.bind(bindEl);
23153 this.currentRegion = Roo.lib.Region.getRegion(dom);
23154 this.currentTip.enter();
23157 leave : function(ev)
23159 var dom = ev.getTarget();
23160 //Roo.log(['leave',dom]);
23161 if (!this.currentEl) {
23166 if (dom != this.currentEl.dom) {
23169 var xy = ev.getXY();
23170 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
23173 // only activate leave if mouse cursor is outside... bounding box..
23178 if (this.currentTip) {
23179 this.currentTip.leave();
23181 //Roo.log('clear currentEl');
23182 this.currentEl = false;
23187 'left' : ['r-l', [-2,0], 'right'],
23188 'right' : ['l-r', [2,0], 'left'],
23189 'bottom' : ['t-b', [0,2], 'top'],
23190 'top' : [ 'b-t', [0,-2], 'bottom']
23196 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
23201 delay : null, // can be { show : 300 , hide: 500}
23205 hoverState : null, //???
23207 placement : 'bottom',
23209 getAutoCreate : function(){
23216 cls : 'tooltip-arrow'
23219 cls : 'tooltip-inner'
23226 bind : function(el)
23232 enter : function () {
23234 if (this.timeout != null) {
23235 clearTimeout(this.timeout);
23238 this.hoverState = 'in';
23239 //Roo.log("enter - show");
23240 if (!this.delay || !this.delay.show) {
23245 this.timeout = setTimeout(function () {
23246 if (_t.hoverState == 'in') {
23249 }, this.delay.show);
23253 clearTimeout(this.timeout);
23255 this.hoverState = 'out';
23256 if (!this.delay || !this.delay.hide) {
23262 this.timeout = setTimeout(function () {
23263 //Roo.log("leave - timeout");
23265 if (_t.hoverState == 'out') {
23267 Roo.bootstrap.Tooltip.currentEl = false;
23275 this.render(document.body);
23278 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
23280 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
23282 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
23284 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
23286 var placement = typeof this.placement == 'function' ?
23287 this.placement.call(this, this.el, on_el) :
23290 var autoToken = /\s?auto?\s?/i;
23291 var autoPlace = autoToken.test(placement);
23293 placement = placement.replace(autoToken, '') || 'top';
23297 //this.el.setXY([0,0]);
23299 //this.el.dom.style.display='block';
23300 this.el.addClass(placement);
23302 //this.el.appendTo(on_el);
23304 var p = this.getPosition();
23305 var box = this.el.getBox();
23310 var align = Roo.bootstrap.Tooltip.alignment[placement];
23311 this.el.alignTo(this.bindEl, align[0],align[1]);
23312 //var arrow = this.el.select('.arrow',true).first();
23313 //arrow.set(align[2],
23315 this.el.addClass('in fade');
23316 this.hoverState = null;
23318 if (this.el.hasClass('fade')) {
23329 //this.el.setXY([0,0]);
23330 this.el.removeClass('in');
23346 * @class Roo.bootstrap.LocationPicker
23347 * @extends Roo.bootstrap.Component
23348 * Bootstrap LocationPicker class
23349 * @cfg {Number} latitude Position when init default 0
23350 * @cfg {Number} longitude Position when init default 0
23351 * @cfg {Number} zoom default 15
23352 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
23353 * @cfg {Boolean} mapTypeControl default false
23354 * @cfg {Boolean} disableDoubleClickZoom default false
23355 * @cfg {Boolean} scrollwheel default true
23356 * @cfg {Boolean} streetViewControl default false
23357 * @cfg {Number} radius default 0
23358 * @cfg {String} locationName
23359 * @cfg {Boolean} draggable default true
23360 * @cfg {Boolean} enableAutocomplete default false
23361 * @cfg {Boolean} enableReverseGeocode default true
23362 * @cfg {String} markerTitle
23365 * Create a new LocationPicker
23366 * @param {Object} config The config object
23370 Roo.bootstrap.LocationPicker = function(config){
23372 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
23377 * Fires when the picker initialized.
23378 * @param {Roo.bootstrap.LocationPicker} this
23379 * @param {Google Location} location
23383 * @event positionchanged
23384 * Fires when the picker position changed.
23385 * @param {Roo.bootstrap.LocationPicker} this
23386 * @param {Google Location} location
23388 positionchanged : true,
23391 * Fires when the map resize.
23392 * @param {Roo.bootstrap.LocationPicker} this
23397 * Fires when the map show.
23398 * @param {Roo.bootstrap.LocationPicker} this
23403 * Fires when the map hide.
23404 * @param {Roo.bootstrap.LocationPicker} this
23409 * Fires when click the map.
23410 * @param {Roo.bootstrap.LocationPicker} this
23411 * @param {Map event} e
23415 * @event mapRightClick
23416 * Fires when right click the map.
23417 * @param {Roo.bootstrap.LocationPicker} this
23418 * @param {Map event} e
23420 mapRightClick : true,
23422 * @event markerClick
23423 * Fires when click the marker.
23424 * @param {Roo.bootstrap.LocationPicker} this
23425 * @param {Map event} e
23427 markerClick : true,
23429 * @event markerRightClick
23430 * Fires when right click the marker.
23431 * @param {Roo.bootstrap.LocationPicker} this
23432 * @param {Map event} e
23434 markerRightClick : true,
23436 * @event OverlayViewDraw
23437 * Fires when OverlayView Draw
23438 * @param {Roo.bootstrap.LocationPicker} this
23440 OverlayViewDraw : true,
23442 * @event OverlayViewOnAdd
23443 * Fires when OverlayView Draw
23444 * @param {Roo.bootstrap.LocationPicker} this
23446 OverlayViewOnAdd : true,
23448 * @event OverlayViewOnRemove
23449 * Fires when OverlayView Draw
23450 * @param {Roo.bootstrap.LocationPicker} this
23452 OverlayViewOnRemove : true,
23454 * @event OverlayViewShow
23455 * Fires when OverlayView Draw
23456 * @param {Roo.bootstrap.LocationPicker} this
23457 * @param {Pixel} cpx
23459 OverlayViewShow : true,
23461 * @event OverlayViewHide
23462 * Fires when OverlayView Draw
23463 * @param {Roo.bootstrap.LocationPicker} this
23465 OverlayViewHide : true
23470 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
23472 gMapContext: false,
23478 mapTypeControl: false,
23479 disableDoubleClickZoom: false,
23481 streetViewControl: false,
23485 enableAutocomplete: false,
23486 enableReverseGeocode: true,
23489 getAutoCreate: function()
23494 cls: 'roo-location-picker'
23500 initEvents: function(ct, position)
23502 if(!this.el.getWidth() || this.isApplied()){
23506 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23511 initial: function()
23513 if(!this.mapTypeId){
23514 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
23517 this.gMapContext = this.GMapContext();
23519 this.initOverlayView();
23521 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
23525 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
23526 _this.setPosition(_this.gMapContext.marker.position);
23529 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
23530 _this.fireEvent('mapClick', this, event);
23534 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
23535 _this.fireEvent('mapRightClick', this, event);
23539 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
23540 _this.fireEvent('markerClick', this, event);
23544 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
23545 _this.fireEvent('markerRightClick', this, event);
23549 this.setPosition(this.gMapContext.location);
23551 this.fireEvent('initial', this, this.gMapContext.location);
23554 initOverlayView: function()
23558 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
23562 _this.fireEvent('OverlayViewDraw', _this);
23567 _this.fireEvent('OverlayViewOnAdd', _this);
23570 onRemove: function()
23572 _this.fireEvent('OverlayViewOnRemove', _this);
23575 show: function(cpx)
23577 _this.fireEvent('OverlayViewShow', _this, cpx);
23582 _this.fireEvent('OverlayViewHide', _this);
23588 fromLatLngToContainerPixel: function(event)
23590 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
23593 isApplied: function()
23595 return this.getGmapContext() == false ? false : true;
23598 getGmapContext: function()
23600 return this.gMapContext
23603 GMapContext: function()
23605 var position = new google.maps.LatLng(this.latitude, this.longitude);
23607 var _map = new google.maps.Map(this.el.dom, {
23610 mapTypeId: this.mapTypeId,
23611 mapTypeControl: this.mapTypeControl,
23612 disableDoubleClickZoom: this.disableDoubleClickZoom,
23613 scrollwheel: this.scrollwheel,
23614 streetViewControl: this.streetViewControl,
23615 locationName: this.locationName,
23616 draggable: this.draggable,
23617 enableAutocomplete: this.enableAutocomplete,
23618 enableReverseGeocode: this.enableReverseGeocode
23621 var _marker = new google.maps.Marker({
23622 position: position,
23624 title: this.markerTitle,
23625 draggable: this.draggable
23632 location: position,
23633 radius: this.radius,
23634 locationName: this.locationName,
23635 addressComponents: {
23636 formatted_address: null,
23637 addressLine1: null,
23638 addressLine2: null,
23640 streetNumber: null,
23644 stateOrProvince: null
23647 domContainer: this.el.dom,
23648 geodecoder: new google.maps.Geocoder()
23652 drawCircle: function(center, radius, options)
23654 if (this.gMapContext.circle != null) {
23655 this.gMapContext.circle.setMap(null);
23659 options = Roo.apply({}, options, {
23660 strokeColor: "#0000FF",
23661 strokeOpacity: .35,
23663 fillColor: "#0000FF",
23667 options.map = this.gMapContext.map;
23668 options.radius = radius;
23669 options.center = center;
23670 this.gMapContext.circle = new google.maps.Circle(options);
23671 return this.gMapContext.circle;
23677 setPosition: function(location)
23679 this.gMapContext.location = location;
23680 this.gMapContext.marker.setPosition(location);
23681 this.gMapContext.map.panTo(location);
23682 this.drawCircle(location, this.gMapContext.radius, {});
23686 if (this.gMapContext.settings.enableReverseGeocode) {
23687 this.gMapContext.geodecoder.geocode({
23688 latLng: this.gMapContext.location
23689 }, function(results, status) {
23691 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23692 _this.gMapContext.locationName = results[0].formatted_address;
23693 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23695 _this.fireEvent('positionchanged', this, location);
23702 this.fireEvent('positionchanged', this, location);
23707 google.maps.event.trigger(this.gMapContext.map, "resize");
23709 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23711 this.fireEvent('resize', this);
23714 setPositionByLatLng: function(latitude, longitude)
23716 this.setPosition(new google.maps.LatLng(latitude, longitude));
23719 getCurrentPosition: function()
23722 latitude: this.gMapContext.location.lat(),
23723 longitude: this.gMapContext.location.lng()
23727 getAddressName: function()
23729 return this.gMapContext.locationName;
23732 getAddressComponents: function()
23734 return this.gMapContext.addressComponents;
23737 address_component_from_google_geocode: function(address_components)
23741 for (var i = 0; i < address_components.length; i++) {
23742 var component = address_components[i];
23743 if (component.types.indexOf("postal_code") >= 0) {
23744 result.postalCode = component.short_name;
23745 } else if (component.types.indexOf("street_number") >= 0) {
23746 result.streetNumber = component.short_name;
23747 } else if (component.types.indexOf("route") >= 0) {
23748 result.streetName = component.short_name;
23749 } else if (component.types.indexOf("neighborhood") >= 0) {
23750 result.city = component.short_name;
23751 } else if (component.types.indexOf("locality") >= 0) {
23752 result.city = component.short_name;
23753 } else if (component.types.indexOf("sublocality") >= 0) {
23754 result.district = component.short_name;
23755 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23756 result.stateOrProvince = component.short_name;
23757 } else if (component.types.indexOf("country") >= 0) {
23758 result.country = component.short_name;
23762 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23763 result.addressLine2 = "";
23767 setZoomLevel: function(zoom)
23769 this.gMapContext.map.setZoom(zoom);
23782 this.fireEvent('show', this);
23793 this.fireEvent('hide', this);
23798 Roo.apply(Roo.bootstrap.LocationPicker, {
23800 OverlayView : function(map, options)
23802 options = options || {};
23816 * @class Roo.bootstrap.Alert
23817 * @extends Roo.bootstrap.Component
23818 * Bootstrap Alert class
23819 * @cfg {String} title The title of alert
23820 * @cfg {String} html The content of alert
23821 * @cfg {String} weight ( success | info | warning | danger )
23822 * @cfg {String} faicon font-awesomeicon
23825 * Create a new alert
23826 * @param {Object} config The config object
23830 Roo.bootstrap.Alert = function(config){
23831 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23835 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23842 getAutoCreate : function()
23851 cls : 'roo-alert-icon'
23856 cls : 'roo-alert-title',
23861 cls : 'roo-alert-text',
23868 cfg.cn[0].cls += ' fa ' + this.faicon;
23872 cfg.cls += ' alert-' + this.weight;
23878 initEvents: function()
23880 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23883 setTitle : function(str)
23885 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23888 setText : function(str)
23890 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23893 setWeight : function(weight)
23896 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23899 this.weight = weight;
23901 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23904 setIcon : function(icon)
23907 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23912 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
23933 * @class Roo.bootstrap.UploadCropbox
23934 * @extends Roo.bootstrap.Component
23935 * Bootstrap UploadCropbox class
23936 * @cfg {String} emptyText show when image has been loaded
23937 * @cfg {Number} minWidth default 300
23938 * @cfg {Number} minHeight default 300
23941 * Create a new UploadCropbox
23942 * @param {Object} config The config object
23945 Roo.bootstrap.UploadCropbox = function(config){
23946 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
23950 * @event beforeSelectFile
23951 * Fire before select file
23952 * @param {Roo.bootstrap.UploadCropbox} this
23954 "beforeSelectFile" : true,
23957 * Fire after initEvent
23958 * @param {Roo.bootstrap.UploadCropbox} this
23963 * Fire after initEvent
23964 * @param {Roo.bootstrap.UploadCropbox} this
23965 * @param {String} imageData
23972 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
23974 emptyText : 'Click to upload image',
23981 cropImageData : false,
23982 cropType : 'image/png',
23986 getAutoCreate : function()
23990 cls : 'roo-upload-cropbox',
23994 cls : 'roo-upload-cropbox-image-section',
23998 cls : 'roo-upload-cropbox-canvas',
24002 cls : 'roo-upload-cropbox-image'
24008 cls : 'roo-upload-cropbox-thumb'
24014 cls : 'roo-upload-cropbox-footer-section',
24017 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
24025 cls : 'btn btn-default roo-upload-cropbox-rotate-left',
24026 html : '<i class="fa fa-undo"></i>'
24036 cls : 'btn btn-default roo-upload-cropbox-picture',
24037 html : '<i class="fa fa-picture-o"></i>'
24047 cls : 'btn btn-default roo-upload-cropbox-rotate-right',
24048 html : '<i class="fa fa-repeat"></i>'
24061 initEvents : function()
24063 this.imageSection = this.el.select('.roo-upload-cropbox-image-section', true).first();
24064 this.imageSection.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24066 this.imageCanvas = this.el.select('.roo-upload-cropbox-canvas', true).first();
24067 this.imageCanvas.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24069 this.image = this.el.select('.roo-upload-cropbox-image', true).first();
24070 this.image.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24072 this.thumb = this.el.select('.roo-upload-cropbox-thumb', true).first();
24073 this.thumb.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24075 this.footerSection = this.el.select('.roo-upload-cropbox-footer-section', true).first();
24076 this.footerSection.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24077 this.footerSection.hide();
24079 this.rotateLeft = this.el.select('.roo-upload-cropbox-rotate-left', true).first();
24080 this.rotateLeft.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24082 this.pictureBtn = this.el.select('.roo-upload-cropbox-picture', true).first();
24083 this.pictureBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24085 this.rotateRight = this.el.select('.roo-upload-cropbox-rotate-right', true).first();
24086 this.rotateRight.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24088 this.calcThumbBoxSize();
24092 this.fireEvent('initial', this);
24097 this.image.on('load', this.onLoadCanvasImage, this);
24099 if(!this.imageSectionHasOnClickEvent){
24100 this.imageSection.on('click', this.beforeSelectFile, this);
24101 this.imageSectionHasOnClickEvent = true;
24104 this.imageSection.on('mousedown', this.onMouseDown, this);
24106 this.imageSection.on('mousemove', this.onMouseMove, this);
24108 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
24110 this.imageSection.on(mousewheel, this.onMouseWheel, this);
24112 Roo.get(document).on('mouseup', this.onMouseUp, this);
24114 this.pictureBtn.on('click', this.beforeSelectFile, this);
24116 this.rotateLeft.on('click', this.onRotateLeft, this);
24118 this.rotateRight.on('click', this.onRotateRight, this);
24122 unbind : function()
24124 this.image.un('load', this.onLoadCanvasImage, this);
24126 if(this.imageSectionHasOnClickEvent){
24127 this.imageSection.un('click', this.beforeSelectFile, this);
24128 this.imageSectionHasOnClickEvent = false;
24131 this.imageSection.un('mousedown', this.onMouseDown, this);
24133 this.imageSection.un('mousemove', this.onMouseMove, this);
24135 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
24137 this.imageSection.un(mousewheel, this.onMouseWheel, this);
24139 Roo.get(document).un('mouseup', this.onMouseUp, this);
24141 this.pictureBtn.un('click', this.beforeSelectFile, this);
24143 this.rotateLeft.un('click', this.onRotateLeft, this);
24145 this.rotateRight.un('click', this.onRotateRight, this);
24151 this.baseScale = 1;
24153 this.dragable = false;
24156 this.cropImageData = false;
24158 this.imageCanvas.dom.removeAttribute('style');
24159 this.image.dom.removeAttribute('style');
24160 this.image.attr('src', '');
24162 if(!this.imageSectionHasOnClickEvent){
24163 this.imageSection.on('click', this.beforeSelectFile, this);
24164 this.imageSectionHasOnClickEvent = true;
24169 beforeSelectFile : function(e)
24171 e.preventDefault();
24172 this.fireEvent('beforeSelectFile', this);
24175 loadCanvasImage : function(src)
24179 this.image.attr('src', src);
24182 onLoadCanvasImage : function(src)
24184 if(this.imageSectionHasOnClickEvent){
24185 this.imageSection.un('click', this.beforeSelectFile, this);
24186 this.imageSectionHasOnClickEvent = false;
24189 this.image.OriginWidth = this.image.getWidth();
24190 this.image.OriginHeight = this.image.getHeight();
24192 this.fitThumbBox();
24194 this.image.setWidth(this.image.OriginWidth * this.getScaleLevel(false));
24195 this.image.setHeight(this.image.OriginHeight * this.getScaleLevel(false));
24197 this.footerSection.show();
24199 this.setCanvasPosition();
24202 setCanvasPosition : function()
24204 var pw = (this.imageSection.getWidth(true) - this.image.getWidth()) / 2;
24205 var ph = (this.imageSection.getHeight(true) - this.image.getHeight()) / 2;
24207 this.imageCanvas.setLeft(pw);
24208 this.imageCanvas.setTop(ph);
24211 onMouseDown : function(e)
24215 this.dragable = true;
24216 this.mouseX = e.getPageX();
24217 this.mouseY = e.getPageY();
24221 onMouseMove : function(e)
24225 if (!this.dragable){
24229 var transform = new WebKitCSSMatrix(window.getComputedStyle(this.thumb.dom).webkitTransform);
24231 var minX = this.thumb.getLeft(true) + transform.m41;
24232 var minY = this.thumb.getTop(true) + transform.m42;
24234 var maxX = minX + this.thumb.getWidth() - this.image.getWidth();
24235 var maxY = minY + this.thumb.getHeight() - this.image.getHeight();
24237 if(this.rotate == 90 || this.rotate == 270){
24238 minX = this.thumb.getLeft(true) + transform.m41 - (this.image.getWidth() - this.image.getHeight()) / 2;
24239 minY = this.thumb.getTop(true) + transform.m42 + (this.image.getWidth() - this.image.getHeight()) / 2;
24241 maxX = minX + this.thumb.getWidth() - this.image.getHeight();
24242 maxY = minY + this.thumb.getHeight() - this.image.getWidth();
24245 var x = e.getPageX() - this.mouseX;
24246 var y = e.getPageY() - this.mouseY;
24248 var bgX = x + this.imageCanvas.getLeft(true);
24249 var bgY = y + this.imageCanvas.getTop(true);
24251 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
24252 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
24254 this.imageCanvas.setLeft(bgX);
24255 this.imageCanvas.setTop(bgY);
24257 this.mouseX = e.getPageX();
24258 this.mouseY = e.getPageY();
24261 onMouseUp : function(e)
24265 this.dragable = false;
24268 onMouseWheel : function(e)
24272 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
24274 var width = this.image.OriginWidth * this.getScaleLevel(false);
24275 var height = this.image.OriginHeight * this.getScaleLevel(false);
24278 e.getWheelDelta() == -1 &&
24281 (this.rotate == 0 || this.rotate == 180) && (width < this.thumb.getWidth() || height < this.thumb.getHeight())
24285 (this.rotate == 90 || this.rotate == 270) && (height < this.thumb.getWidth() || width < this.thumb.getHeight())
24289 this.scale = (e.getWheelDelta() == 1) ? (this.scale - 1) : (this.scale + 1);
24293 this.image.setWidth(width);
24294 this.image.setHeight(height);
24296 this.setCanvasPosition();
24300 onRotateLeft : function(e)
24306 (this.rotate == 0 || this.rotate == 180)
24308 (this.image.getHeight() < this.thumb.getWidth() || this.image.getWidth() < this.thumb.getHeight())
24312 (this.rotate == 90 || this.rotate == 270)
24314 (this.image.getWidth() < this.thumb.getWidth() || this.image.getHeight() < this.thumb.getHeight())
24321 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
24323 this.imageCanvas.setStyle({
24324 '-ms-transform' : 'rotate(' + this.rotate + 'deg)',
24325 '-webkit-transform' : 'rotate(' + this.rotate + 'deg)',
24326 'transform' : 'rotate(' + this.rotate + 'deg)'
24329 this.setCanvasPosition();
24333 onRotateRight : function(e)
24339 (this.rotate == 0 || this.rotate == 180)
24341 (this.image.getHeight() < this.thumb.getWidth() || this.image.getWidth() < this.thumb.getHeight())
24345 (this.rotate == 90 || this.rotate == 270)
24347 (this.image.getWidth() < this.thumb.getWidth() || this.image.getHeight() < this.thumb.getHeight())
24354 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
24356 this.imageCanvas.setStyle({
24357 '-ms-transform' : 'rotate(' + this.rotate + 'deg)',
24358 '-webkit-transform' : 'rotate(' + this.rotate + 'deg)',
24359 'transform' : 'rotate(' + this.rotate + 'deg)'
24362 this.setCanvasPosition();
24369 var canvas = document.createElement("canvas");
24371 var context = canvas.getContext("2d");
24373 canvas.width = this.minWidth;
24374 canvas.height = this.minHeight;
24376 var centerX = this.minWidth / 2;
24377 var centerY = this.minHeight / 2;
24379 var cropWidth = this.thumb.getWidth() * this.getScaleLevel(true);
24380 var cropHeight = this.thumb.getHeight() * this.getScaleLevel(true);
24382 var transform = new WebKitCSSMatrix(window.getComputedStyle(this.thumb.dom).webkitTransform);
24383 var thumbX = this.thumb.getLeft(true) + transform.m41;
24384 var thumbY = this.thumb.getTop(true) + transform.m42;
24386 var x = (thumbX - this.imageCanvas.getLeft(true)) * this.getScaleLevel(true);
24387 var y = (thumbY - this.imageCanvas.getTop(true)) * this.getScaleLevel(true);
24389 if(this.rotate == 90){
24391 x = thumbY + (this.image.getWidth() - this.image.getHeight()) / 2 - this.imageCanvas.getTop(true);
24392 y = this.image.getHeight() - this.thumb.getWidth() - (thumbX - (this.image.getWidth() - this.image.getHeight()) / 2 - this.imageCanvas.getLeft(true));
24394 x = x * this.getScaleLevel(true);
24395 y = y * this.getScaleLevel(true);
24400 cropWidth = this.thumb.getHeight() * this.getScaleLevel(true);
24401 cropHeight = this.thumb.getWidth() * this.getScaleLevel(true);
24403 canvas.width = this.minWidth > this.minHeight ? this.minWidth : this.minHeight;
24404 canvas.height = this.minWidth > this.minHeight ? this.minWidth : this.minHeight;
24406 centerX = this.minWidth > this.minHeight ? (this.minWidth / 2) : (this.minHeight / 2);
24407 centerY = this.minWidth > this.minHeight ? (this.minWidth / 2) : (this.minHeight / 2);
24409 context.translate(centerX, centerY);
24410 context.rotate(this.rotate * Math.PI / 180);
24412 context.drawImage(this.image.dom, x, y, cropWidth, cropHeight, centerX * -1, centerY * -1, this.minHeight, this.minWidth);
24414 var canvas2 = document.createElement("canvas");
24415 var context2 = canvas2.getContext("2d");
24417 canvas2.width = this.minWidth;
24418 canvas2.height = this.minHeight;
24420 context2.drawImage(canvas, Math.abs(this.minWidth - this.minHeight), 0, this.minWidth, this.minHeight, 0, 0, this.minWidth, this.minHeight);
24422 this.cropImageData = canvas2.toDataURL(this.cropType);
24424 this.fireEvent('crop', this, this.cropImageData);
24430 if(this.rotate == 270){
24432 x = thumbY + (this.image.getWidth() - this.image.getHeight()) / 2 - this.imageCanvas.getTop(true);
24433 y = thumbX - (this.image.getWidth() - this.image.getHeight()) / 2 - this.imageCanvas.getLeft(true);
24435 x = (this.image.getWidth() - this.thumb.getHeight() - x) * this.getScaleLevel(true);
24436 y = y * this.getScaleLevel(true);
24441 cropWidth = this.thumb.getHeight() * this.getScaleLevel(true);
24442 cropHeight = this.thumb.getWidth() * this.getScaleLevel(true);
24444 canvas.width = this.minWidth > this.minHeight ? this.minWidth : this.minHeight;
24445 canvas.height = this.minWidth > this.minHeight ? this.minWidth : this.minHeight;
24447 centerX = this.minWidth > this.minHeight ? (this.minWidth / 2) : (this.minHeight / 2);
24448 centerY = this.minWidth > this.minHeight ? (this.minWidth / 2) : (this.minHeight / 2);
24450 context.translate(centerX, centerY);
24451 context.rotate(this.rotate * Math.PI / 180);
24453 context.drawImage(this.image.dom, x, y, cropWidth, cropHeight, centerX * -1, centerY * -1, this.minHeight, this.minWidth);
24455 var canvas2 = document.createElement("canvas");
24456 var context2 = canvas2.getContext("2d");
24458 canvas2.width = this.minWidth;
24459 canvas2.height = this.minHeight;
24461 context2.drawImage(canvas, 0, 0, this.minWidth, this.minHeight, 0, 0, this.minWidth, this.minHeight);
24463 this.cropImageData = canvas2.toDataURL(this.cropType);
24465 this.fireEvent('crop', this, this.cropImageData);
24471 if(this.rotate == 180){
24472 x = this.image.OriginWidth - this.thumb.getWidth() * this.getScaleLevel(true) - x;
24473 y = this.image.OriginHeight - this.thumb.getHeight() * this.getScaleLevel(true) - y;
24479 context.translate(centerX, centerY);
24481 context.rotate(this.rotate * Math.PI / 180);
24483 context.drawImage(this.image.dom, x, y, cropWidth, cropHeight, centerX * -1, centerY * -1, canvas.width, canvas.height);
24485 this.cropImageData = canvas.toDataURL(this.cropType);
24487 this.fireEvent('crop', this, this.cropImageData);
24490 calcThumbBoxSize : function()
24495 width = this.minWidth * height / this.minHeight;
24497 if(this.minWidth > this.minHeight){
24499 height = this.minHeight * width / this.minWidth;
24502 this.thumb.setStyle({
24503 width : width + 'px',
24504 height : height + 'px'
24511 fitThumbBox : function()
24513 var width = this.thumb.getWidth();
24514 var height = this.image.OriginHeight * width / this.image.OriginWidth;
24516 this.baseScale = width / this.image.OriginWidth;
24518 if(this.image.OriginWidth > this.image.OriginHeight){
24519 height = this.thumb.getHeight();
24520 width = this.image.OriginWidth * height / this.image.OriginHeight;
24522 this.baseScale = height / this.image.OriginHeight;
24528 getScaleLevel : function(reverse)
24531 return Math.pow(1.1, this.scale * -1) / this.baseScale;
24534 return this.baseScale * Math.pow(1.1, this.scale);