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)
15220 this.el.select('.popover-title',true).first().dom.innerHTML = str;
15222 setContent: function(str)
15225 this.el.select('.popover-content',true).first().dom.innerHTML = str;
15227 // as it get's added to the bottom of the page.
15228 onRender : function(ct, position)
15230 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
15232 var cfg = Roo.apply({}, this.getAutoCreate());
15236 cfg.cls += ' ' + this.cls;
15239 cfg.style = this.style;
15241 Roo.log("adding to ")
15242 this.el = Roo.get(document.body).createChild(cfg, position);
15248 initEvents : function()
15250 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
15251 this.el.enableDisplayMode('block');
15253 if (this.over === false) {
15256 if (this.triggers === false) {
15259 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15260 var triggers = this.trigger ? this.trigger.split(' ') : [];
15261 Roo.each(triggers, function(trigger) {
15263 if (trigger == 'click') {
15264 on_el.on('click', this.toggle, this);
15265 } else if (trigger != 'manual') {
15266 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
15267 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
15269 on_el.on(eventIn ,this.enter, this);
15270 on_el.on(eventOut, this.leave, this);
15281 toggle : function () {
15282 this.hoverState == 'in' ? this.leave() : this.enter();
15285 enter : function () {
15288 clearTimeout(this.timeout);
15290 this.hoverState = 'in';
15292 if (!this.delay || !this.delay.show) {
15297 this.timeout = setTimeout(function () {
15298 if (_t.hoverState == 'in') {
15301 }, this.delay.show)
15303 leave : function() {
15304 clearTimeout(this.timeout);
15306 this.hoverState = 'out';
15308 if (!this.delay || !this.delay.hide) {
15313 this.timeout = setTimeout(function () {
15314 if (_t.hoverState == 'out') {
15317 }, this.delay.hide)
15320 show : function (on_el)
15323 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15326 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
15327 if (this.html !== false) {
15328 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
15330 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
15331 if (!this.title.length) {
15332 this.el.select('.popover-title',true).hide();
15335 var placement = typeof this.placement == 'function' ?
15336 this.placement.call(this, this.el, on_el) :
15339 var autoToken = /\s?auto?\s?/i;
15340 var autoPlace = autoToken.test(placement);
15342 placement = placement.replace(autoToken, '') || 'top';
15346 //this.el.setXY([0,0]);
15348 this.el.dom.style.display='block';
15349 this.el.addClass(placement);
15351 //this.el.appendTo(on_el);
15353 var p = this.getPosition();
15354 var box = this.el.getBox();
15359 var align = Roo.bootstrap.Popover.alignment[placement];
15360 this.el.alignTo(on_el, align[0],align[1]);
15361 //var arrow = this.el.select('.arrow',true).first();
15362 //arrow.set(align[2],
15364 this.el.addClass('in');
15367 if (this.el.hasClass('fade')) {
15374 this.el.setXY([0,0]);
15375 this.el.removeClass('in');
15377 this.hoverState = null;
15383 Roo.bootstrap.Popover.alignment = {
15384 'left' : ['r-l', [-10,0], 'right'],
15385 'right' : ['l-r', [10,0], 'left'],
15386 'bottom' : ['t-b', [0,10], 'top'],
15387 'top' : [ 'b-t', [0,-10], 'bottom']
15398 * @class Roo.bootstrap.Progress
15399 * @extends Roo.bootstrap.Component
15400 * Bootstrap Progress class
15401 * @cfg {Boolean} striped striped of the progress bar
15402 * @cfg {Boolean} active animated of the progress bar
15406 * Create a new Progress
15407 * @param {Object} config The config object
15410 Roo.bootstrap.Progress = function(config){
15411 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
15414 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
15419 getAutoCreate : function(){
15427 cfg.cls += ' progress-striped';
15431 cfg.cls += ' active';
15450 * @class Roo.bootstrap.ProgressBar
15451 * @extends Roo.bootstrap.Component
15452 * Bootstrap ProgressBar class
15453 * @cfg {Number} aria_valuenow aria-value now
15454 * @cfg {Number} aria_valuemin aria-value min
15455 * @cfg {Number} aria_valuemax aria-value max
15456 * @cfg {String} label label for the progress bar
15457 * @cfg {String} panel (success | info | warning | danger )
15458 * @cfg {String} role role of the progress bar
15459 * @cfg {String} sr_only text
15463 * Create a new ProgressBar
15464 * @param {Object} config The config object
15467 Roo.bootstrap.ProgressBar = function(config){
15468 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
15471 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
15475 aria_valuemax : 100,
15481 getAutoCreate : function()
15486 cls: 'progress-bar',
15487 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
15499 cfg.role = this.role;
15502 if(this.aria_valuenow){
15503 cfg['aria-valuenow'] = this.aria_valuenow;
15506 if(this.aria_valuemin){
15507 cfg['aria-valuemin'] = this.aria_valuemin;
15510 if(this.aria_valuemax){
15511 cfg['aria-valuemax'] = this.aria_valuemax;
15514 if(this.label && !this.sr_only){
15515 cfg.html = this.label;
15519 cfg.cls += ' progress-bar-' + this.panel;
15525 update : function(aria_valuenow)
15527 this.aria_valuenow = aria_valuenow;
15529 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
15544 * @class Roo.bootstrap.TabGroup
15545 * @extends Roo.bootstrap.Column
15546 * Bootstrap Column class
15547 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
15548 * @cfg {Boolean} carousel true to make the group behave like a carousel
15549 * @cfg {Number} bullets show the panel pointer.. default 0
15550 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
15551 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
15552 * @cfg {Number} timer auto slide timer .. default 0 millisecond
15555 * Create a new TabGroup
15556 * @param {Object} config The config object
15559 Roo.bootstrap.TabGroup = function(config){
15560 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
15562 this.navId = Roo.id();
15565 Roo.bootstrap.TabGroup.register(this);
15569 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
15572 transition : false,
15577 slideOnTouch : false,
15579 getAutoCreate : function()
15581 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
15583 cfg.cls += ' tab-content';
15585 Roo.log('get auto create...............');
15587 if (this.carousel) {
15588 cfg.cls += ' carousel slide';
15591 cls : 'carousel-inner'
15594 if(this.bullets > 0 && !Roo.isTouch){
15597 cls : 'carousel-bullets',
15601 if(this.bullets_cls){
15602 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
15605 for (var i = 0; i < this.bullets; i++){
15607 cls : 'bullet bullet-' + i
15615 cfg.cn[0].cn = bullets;
15622 initEvents: function()
15624 Roo.log('-------- init events on tab group ---------');
15626 if(this.bullets > 0 && !Roo.isTouch){
15632 if(Roo.isTouch && this.slideOnTouch){
15633 this.el.on("touchstart", this.onTouchStart, this);
15636 if(this.autoslide){
15639 this.slideFn = window.setInterval(function() {
15640 _this.showPanelNext();
15646 onTouchStart : function(e, el, o)
15648 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
15652 this.showPanelNext();
15655 getChildContainer : function()
15657 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
15661 * register a Navigation item
15662 * @param {Roo.bootstrap.NavItem} the navitem to add
15664 register : function(item)
15666 this.tabs.push( item);
15667 item.navId = this.navId; // not really needed..
15671 getActivePanel : function()
15674 Roo.each(this.tabs, function(t) {
15684 getPanelByName : function(n)
15687 Roo.each(this.tabs, function(t) {
15688 if (t.tabId == n) {
15696 indexOfPanel : function(p)
15699 Roo.each(this.tabs, function(t,i) {
15700 if (t.tabId == p.tabId) {
15709 * show a specific panel
15710 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
15711 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
15713 showPanel : function (pan)
15715 if(this.transition){
15716 Roo.log("waiting for the transitionend");
15720 if (typeof(pan) == 'number') {
15721 pan = this.tabs[pan];
15723 if (typeof(pan) == 'string') {
15724 pan = this.getPanelByName(pan);
15726 if (pan.tabId == this.getActivePanel().tabId) {
15729 var cur = this.getActivePanel();
15731 if (false === cur.fireEvent('beforedeactivate')) {
15735 if(this.bullets > 0 && !Roo.isTouch){
15736 this.setActiveBullet(this.indexOfPanel(pan));
15739 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
15741 this.transition = true;
15742 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
15743 var lr = dir == 'next' ? 'left' : 'right';
15744 pan.el.addClass(dir); // or prev
15745 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
15746 cur.el.addClass(lr); // or right
15747 pan.el.addClass(lr);
15750 cur.el.on('transitionend', function() {
15751 Roo.log("trans end?");
15753 pan.el.removeClass([lr,dir]);
15754 pan.setActive(true);
15756 cur.el.removeClass([lr]);
15757 cur.setActive(false);
15759 _this.transition = false;
15761 }, this, { single: true } );
15766 cur.setActive(false);
15767 pan.setActive(true);
15772 showPanelNext : function()
15774 var i = this.indexOfPanel(this.getActivePanel());
15776 if (i >= this.tabs.length - 1 && !this.autoslide) {
15780 if (i >= this.tabs.length - 1 && this.autoslide) {
15784 this.showPanel(this.tabs[i+1]);
15787 showPanelPrev : function()
15789 var i = this.indexOfPanel(this.getActivePanel());
15791 if (i < 1 && !this.autoslide) {
15795 if (i < 1 && this.autoslide) {
15796 i = this.tabs.length;
15799 this.showPanel(this.tabs[i-1]);
15802 initBullet : function()
15810 for (var i = 0; i < this.bullets; i++){
15811 var bullet = this.el.select('.bullet-' + i, true).first();
15817 bullet.on('click', (function(e, el, o, ii, t){
15819 e.preventDefault();
15821 _this.showPanel(ii);
15823 if(_this.autoslide && _this.slideFn){
15824 clearInterval(_this.slideFn);
15825 _this.slideFn = window.setInterval(function() {
15826 _this.showPanelNext();
15830 }).createDelegate(this, [i, bullet], true));
15834 setActiveBullet : function(i)
15840 Roo.each(this.el.select('.bullet', true).elements, function(el){
15841 el.removeClass('selected');
15844 var bullet = this.el.select('.bullet-' + i, true).first();
15850 bullet.addClass('selected');
15861 Roo.apply(Roo.bootstrap.TabGroup, {
15865 * register a Navigation Group
15866 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15868 register : function(navgrp)
15870 this.groups[navgrp.navId] = navgrp;
15874 * fetch a Navigation Group based on the navigation ID
15875 * if one does not exist , it will get created.
15876 * @param {string} the navgroup to add
15877 * @returns {Roo.bootstrap.NavGroup} the navgroup
15879 get: function(navId) {
15880 if (typeof(this.groups[navId]) == 'undefined') {
15881 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15883 return this.groups[navId] ;
15898 * @class Roo.bootstrap.TabPanel
15899 * @extends Roo.bootstrap.Component
15900 * Bootstrap TabPanel class
15901 * @cfg {Boolean} active panel active
15902 * @cfg {String} html panel content
15903 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15904 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15908 * Create a new TabPanel
15909 * @param {Object} config The config object
15912 Roo.bootstrap.TabPanel = function(config){
15913 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15917 * Fires when the active status changes
15918 * @param {Roo.bootstrap.TabPanel} this
15919 * @param {Boolean} state the new state
15924 * @event beforedeactivate
15925 * Fires before a tab is de-activated - can be used to do validation on a form.
15926 * @param {Roo.bootstrap.TabPanel} this
15927 * @return {Boolean} false if there is an error
15930 'beforedeactivate': true
15933 this.tabId = this.tabId || Roo.id();
15937 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15944 getAutoCreate : function(){
15947 // item is needed for carousel - not sure if it has any effect otherwise
15948 cls: 'tab-pane item',
15949 html: this.html || ''
15953 cfg.cls += ' active';
15957 cfg.tabId = this.tabId;
15964 initEvents: function()
15966 Roo.log('-------- init events on tab panel ---------');
15968 var p = this.parent();
15969 this.navId = this.navId || p.navId;
15971 if (typeof(this.navId) != 'undefined') {
15972 // not really needed.. but just in case.. parent should be a NavGroup.
15973 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15974 Roo.log(['register', tg, this]);
15977 var i = tg.tabs.length - 1;
15979 if(this.active && tg.bullets > 0 && i < tg.bullets){
15980 tg.setActiveBullet(i);
15987 onRender : function(ct, position)
15989 // Roo.log("Call onRender: " + this.xtype);
15991 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15999 setActive: function(state)
16001 Roo.log("panel - set active " + this.tabId + "=" + state);
16003 this.active = state;
16005 this.el.removeClass('active');
16007 } else if (!this.el.hasClass('active')) {
16008 this.el.addClass('active');
16011 this.fireEvent('changed', this, state);
16028 * @class Roo.bootstrap.DateField
16029 * @extends Roo.bootstrap.Input
16030 * Bootstrap DateField class
16031 * @cfg {Number} weekStart default 0
16032 * @cfg {String} viewMode default empty, (months|years)
16033 * @cfg {String} minViewMode default empty, (months|years)
16034 * @cfg {Number} startDate default -Infinity
16035 * @cfg {Number} endDate default Infinity
16036 * @cfg {Boolean} todayHighlight default false
16037 * @cfg {Boolean} todayBtn default false
16038 * @cfg {Boolean} calendarWeeks default false
16039 * @cfg {Object} daysOfWeekDisabled default empty
16040 * @cfg {Boolean} singleMode default false (true | false)
16042 * @cfg {Boolean} keyboardNavigation default true
16043 * @cfg {String} language default en
16046 * Create a new DateField
16047 * @param {Object} config The config object
16050 Roo.bootstrap.DateField = function(config){
16051 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16055 * Fires when this field show.
16056 * @param {Roo.bootstrap.DateField} this
16057 * @param {Mixed} date The date value
16062 * Fires when this field hide.
16063 * @param {Roo.bootstrap.DateField} this
16064 * @param {Mixed} date The date value
16069 * Fires when select a date.
16070 * @param {Roo.bootstrap.DateField} this
16071 * @param {Mixed} date The date value
16077 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16080 * @cfg {String} format
16081 * The default date format string which can be overriden for localization support. The format must be
16082 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16086 * @cfg {String} altFormats
16087 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16088 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16090 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16098 todayHighlight : false,
16104 keyboardNavigation: true,
16106 calendarWeeks: false,
16108 startDate: -Infinity,
16112 daysOfWeekDisabled: [],
16116 singleMode : false,
16118 UTCDate: function()
16120 return new Date(Date.UTC.apply(Date, arguments));
16123 UTCToday: function()
16125 var today = new Date();
16126 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16129 getDate: function() {
16130 var d = this.getUTCDate();
16131 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16134 getUTCDate: function() {
16138 setDate: function(d) {
16139 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
16142 setUTCDate: function(d) {
16144 this.setValue(this.formatDate(this.date));
16147 onRender: function(ct, position)
16150 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
16152 this.language = this.language || 'en';
16153 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
16154 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
16156 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
16157 this.format = this.format || 'm/d/y';
16158 this.isInline = false;
16159 this.isInput = true;
16160 this.component = this.el.select('.add-on', true).first() || false;
16161 this.component = (this.component && this.component.length === 0) ? false : this.component;
16162 this.hasInput = this.component && this.inputEL().length;
16164 if (typeof(this.minViewMode === 'string')) {
16165 switch (this.minViewMode) {
16167 this.minViewMode = 1;
16170 this.minViewMode = 2;
16173 this.minViewMode = 0;
16178 if (typeof(this.viewMode === 'string')) {
16179 switch (this.viewMode) {
16192 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
16194 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
16196 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16198 this.picker().on('mousedown', this.onMousedown, this);
16199 this.picker().on('click', this.onClick, this);
16201 this.picker().addClass('datepicker-dropdown');
16203 this.startViewMode = this.viewMode;
16205 if(this.singleMode){
16206 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
16207 v.setVisibilityMode(Roo.Element.DISPLAY)
16211 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16212 v.setStyle('width', '189px');
16216 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
16217 if(!this.calendarWeeks){
16222 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16223 v.attr('colspan', function(i, val){
16224 return parseInt(val) + 1;
16229 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
16231 this.setStartDate(this.startDate);
16232 this.setEndDate(this.endDate);
16234 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
16241 if(this.isInline) {
16246 picker : function()
16248 return this.pickerEl;
16249 // return this.el.select('.datepicker', true).first();
16252 fillDow: function()
16254 var dowCnt = this.weekStart;
16263 if(this.calendarWeeks){
16271 while (dowCnt < this.weekStart + 7) {
16275 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
16279 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
16282 fillMonths: function()
16285 var months = this.picker().select('>.datepicker-months td', true).first();
16287 months.dom.innerHTML = '';
16293 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
16296 months.createChild(month);
16303 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;
16305 if (this.date < this.startDate) {
16306 this.viewDate = new Date(this.startDate);
16307 } else if (this.date > this.endDate) {
16308 this.viewDate = new Date(this.endDate);
16310 this.viewDate = new Date(this.date);
16318 var d = new Date(this.viewDate),
16319 year = d.getUTCFullYear(),
16320 month = d.getUTCMonth(),
16321 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
16322 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
16323 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
16324 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
16325 currentDate = this.date && this.date.valueOf(),
16326 today = this.UTCToday();
16328 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
16330 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16332 // this.picker.select('>tfoot th.today').
16333 // .text(dates[this.language].today)
16334 // .toggle(this.todayBtn !== false);
16336 this.updateNavArrows();
16339 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
16341 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
16343 prevMonth.setUTCDate(day);
16345 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
16347 var nextMonth = new Date(prevMonth);
16349 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
16351 nextMonth = nextMonth.valueOf();
16353 var fillMonths = false;
16355 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
16357 while(prevMonth.valueOf() < nextMonth) {
16360 if (prevMonth.getUTCDay() === this.weekStart) {
16362 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
16370 if(this.calendarWeeks){
16371 // ISO 8601: First week contains first thursday.
16372 // ISO also states week starts on Monday, but we can be more abstract here.
16374 // Start of current week: based on weekstart/current date
16375 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
16376 // Thursday of this week
16377 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
16378 // First Thursday of year, year from thursday
16379 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
16380 // Calendar week: ms between thursdays, div ms per day, div 7 days
16381 calWeek = (th - yth) / 864e5 / 7 + 1;
16383 fillMonths.cn.push({
16391 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
16393 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
16396 if (this.todayHighlight &&
16397 prevMonth.getUTCFullYear() == today.getFullYear() &&
16398 prevMonth.getUTCMonth() == today.getMonth() &&
16399 prevMonth.getUTCDate() == today.getDate()) {
16400 clsName += ' today';
16403 if (currentDate && prevMonth.valueOf() === currentDate) {
16404 clsName += ' active';
16407 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
16408 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
16409 clsName += ' disabled';
16412 fillMonths.cn.push({
16414 cls: 'day ' + clsName,
16415 html: prevMonth.getDate()
16418 prevMonth.setDate(prevMonth.getDate()+1);
16421 var currentYear = this.date && this.date.getUTCFullYear();
16422 var currentMonth = this.date && this.date.getUTCMonth();
16424 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
16426 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
16427 v.removeClass('active');
16429 if(currentYear === year && k === currentMonth){
16430 v.addClass('active');
16433 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
16434 v.addClass('disabled');
16440 year = parseInt(year/10, 10) * 10;
16442 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
16444 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
16447 for (var i = -1; i < 11; i++) {
16448 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
16450 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
16458 showMode: function(dir)
16461 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
16464 Roo.each(this.picker().select('>div',true).elements, function(v){
16465 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16468 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
16473 if(this.isInline) return;
16475 this.picker().removeClass(['bottom', 'top']);
16477 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16479 * place to the top of element!
16483 this.picker().addClass('top');
16484 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16489 this.picker().addClass('bottom');
16491 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16494 parseDate : function(value)
16496 if(!value || value instanceof Date){
16499 var v = Date.parseDate(value, this.format);
16500 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
16501 v = Date.parseDate(value, 'Y-m-d');
16503 if(!v && this.altFormats){
16504 if(!this.altFormatsArray){
16505 this.altFormatsArray = this.altFormats.split("|");
16507 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
16508 v = Date.parseDate(value, this.altFormatsArray[i]);
16514 formatDate : function(date, fmt)
16516 return (!date || !(date instanceof Date)) ?
16517 date : date.dateFormat(fmt || this.format);
16520 onFocus : function()
16522 Roo.bootstrap.DateField.superclass.onFocus.call(this);
16526 onBlur : function()
16528 Roo.bootstrap.DateField.superclass.onBlur.call(this);
16530 var d = this.inputEl().getValue();
16539 this.picker().show();
16543 this.fireEvent('show', this, this.date);
16548 if(this.isInline) return;
16549 this.picker().hide();
16550 this.viewMode = this.startViewMode;
16553 this.fireEvent('hide', this, this.date);
16557 onMousedown: function(e)
16559 e.stopPropagation();
16560 e.preventDefault();
16565 Roo.bootstrap.DateField.superclass.keyup.call(this);
16569 setValue: function(v)
16572 // v can be a string or a date..
16575 var d = new Date(this.parseDate(v) ).clearTime();
16577 if(isNaN(d.getTime())){
16578 this.date = this.viewDate = '';
16579 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
16583 v = this.formatDate(d);
16585 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
16587 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
16591 this.fireEvent('select', this, this.date);
16595 getValue: function()
16597 return this.formatDate(this.date);
16600 fireKey: function(e)
16602 if (!this.picker().isVisible()){
16603 if (e.keyCode == 27) // allow escape to hide and re-show picker
16608 var dateChanged = false,
16610 newDate, newViewDate;
16615 e.preventDefault();
16619 if (!this.keyboardNavigation) break;
16620 dir = e.keyCode == 37 ? -1 : 1;
16623 newDate = this.moveYear(this.date, dir);
16624 newViewDate = this.moveYear(this.viewDate, dir);
16625 } else if (e.shiftKey){
16626 newDate = this.moveMonth(this.date, dir);
16627 newViewDate = this.moveMonth(this.viewDate, dir);
16629 newDate = new Date(this.date);
16630 newDate.setUTCDate(this.date.getUTCDate() + dir);
16631 newViewDate = new Date(this.viewDate);
16632 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
16634 if (this.dateWithinRange(newDate)){
16635 this.date = newDate;
16636 this.viewDate = newViewDate;
16637 this.setValue(this.formatDate(this.date));
16639 e.preventDefault();
16640 dateChanged = true;
16645 if (!this.keyboardNavigation) break;
16646 dir = e.keyCode == 38 ? -1 : 1;
16648 newDate = this.moveYear(this.date, dir);
16649 newViewDate = this.moveYear(this.viewDate, dir);
16650 } else if (e.shiftKey){
16651 newDate = this.moveMonth(this.date, dir);
16652 newViewDate = this.moveMonth(this.viewDate, dir);
16654 newDate = new Date(this.date);
16655 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
16656 newViewDate = new Date(this.viewDate);
16657 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
16659 if (this.dateWithinRange(newDate)){
16660 this.date = newDate;
16661 this.viewDate = newViewDate;
16662 this.setValue(this.formatDate(this.date));
16664 e.preventDefault();
16665 dateChanged = true;
16669 this.setValue(this.formatDate(this.date));
16671 e.preventDefault();
16674 this.setValue(this.formatDate(this.date));
16688 onClick: function(e)
16690 e.stopPropagation();
16691 e.preventDefault();
16693 var target = e.getTarget();
16695 if(target.nodeName.toLowerCase() === 'i'){
16696 target = Roo.get(target).dom.parentNode;
16699 var nodeName = target.nodeName;
16700 var className = target.className;
16701 var html = target.innerHTML;
16702 //Roo.log(nodeName);
16704 switch(nodeName.toLowerCase()) {
16706 switch(className) {
16712 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
16713 switch(this.viewMode){
16715 this.viewDate = this.moveMonth(this.viewDate, dir);
16719 this.viewDate = this.moveYear(this.viewDate, dir);
16725 var date = new Date();
16726 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
16728 this.setValue(this.formatDate(this.date));
16735 if (className.indexOf('disabled') < 0) {
16736 this.viewDate.setUTCDate(1);
16737 if (className.indexOf('month') > -1) {
16738 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
16740 var year = parseInt(html, 10) || 0;
16741 this.viewDate.setUTCFullYear(year);
16745 if(this.singleMode){
16746 this.setValue(this.formatDate(this.viewDate));
16757 //Roo.log(className);
16758 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
16759 var day = parseInt(html, 10) || 1;
16760 var year = this.viewDate.getUTCFullYear(),
16761 month = this.viewDate.getUTCMonth();
16763 if (className.indexOf('old') > -1) {
16770 } else if (className.indexOf('new') > -1) {
16778 //Roo.log([year,month,day]);
16779 this.date = this.UTCDate(year, month, day,0,0,0,0);
16780 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16782 //Roo.log(this.formatDate(this.date));
16783 this.setValue(this.formatDate(this.date));
16790 setStartDate: function(startDate)
16792 this.startDate = startDate || -Infinity;
16793 if (this.startDate !== -Infinity) {
16794 this.startDate = this.parseDate(this.startDate);
16797 this.updateNavArrows();
16800 setEndDate: function(endDate)
16802 this.endDate = endDate || Infinity;
16803 if (this.endDate !== Infinity) {
16804 this.endDate = this.parseDate(this.endDate);
16807 this.updateNavArrows();
16810 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16812 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16813 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16814 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16816 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16817 return parseInt(d, 10);
16820 this.updateNavArrows();
16823 updateNavArrows: function()
16825 if(this.singleMode){
16829 var d = new Date(this.viewDate),
16830 year = d.getUTCFullYear(),
16831 month = d.getUTCMonth();
16833 Roo.each(this.picker().select('.prev', true).elements, function(v){
16835 switch (this.viewMode) {
16838 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16844 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16851 Roo.each(this.picker().select('.next', true).elements, function(v){
16853 switch (this.viewMode) {
16856 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16862 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16870 moveMonth: function(date, dir)
16872 if (!dir) return date;
16873 var new_date = new Date(date.valueOf()),
16874 day = new_date.getUTCDate(),
16875 month = new_date.getUTCMonth(),
16876 mag = Math.abs(dir),
16878 dir = dir > 0 ? 1 : -1;
16881 // If going back one month, make sure month is not current month
16882 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16884 return new_date.getUTCMonth() == month;
16886 // If going forward one month, make sure month is as expected
16887 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16889 return new_date.getUTCMonth() != new_month;
16891 new_month = month + dir;
16892 new_date.setUTCMonth(new_month);
16893 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16894 if (new_month < 0 || new_month > 11)
16895 new_month = (new_month + 12) % 12;
16897 // For magnitudes >1, move one month at a time...
16898 for (var i=0; i<mag; i++)
16899 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16900 new_date = this.moveMonth(new_date, dir);
16901 // ...then reset the day, keeping it in the new month
16902 new_month = new_date.getUTCMonth();
16903 new_date.setUTCDate(day);
16905 return new_month != new_date.getUTCMonth();
16908 // Common date-resetting loop -- if date is beyond end of month, make it
16911 new_date.setUTCDate(--day);
16912 new_date.setUTCMonth(new_month);
16917 moveYear: function(date, dir)
16919 return this.moveMonth(date, dir*12);
16922 dateWithinRange: function(date)
16924 return date >= this.startDate && date <= this.endDate;
16930 this.picker().remove();
16935 Roo.apply(Roo.bootstrap.DateField, {
16946 html: '<i class="fa fa-arrow-left"/>'
16956 html: '<i class="fa fa-arrow-right"/>'
16998 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16999 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
17000 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
17001 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17002 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17015 navFnc: 'FullYear',
17020 navFnc: 'FullYear',
17025 Roo.apply(Roo.bootstrap.DateField, {
17029 cls: 'datepicker dropdown-menu roo-dynamic',
17033 cls: 'datepicker-days',
17037 cls: 'table-condensed',
17039 Roo.bootstrap.DateField.head,
17043 Roo.bootstrap.DateField.footer
17050 cls: 'datepicker-months',
17054 cls: 'table-condensed',
17056 Roo.bootstrap.DateField.head,
17057 Roo.bootstrap.DateField.content,
17058 Roo.bootstrap.DateField.footer
17065 cls: 'datepicker-years',
17069 cls: 'table-condensed',
17071 Roo.bootstrap.DateField.head,
17072 Roo.bootstrap.DateField.content,
17073 Roo.bootstrap.DateField.footer
17092 * @class Roo.bootstrap.TimeField
17093 * @extends Roo.bootstrap.Input
17094 * Bootstrap DateField class
17098 * Create a new TimeField
17099 * @param {Object} config The config object
17102 Roo.bootstrap.TimeField = function(config){
17103 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17107 * Fires when this field show.
17108 * @param {Roo.bootstrap.DateField} thisthis
17109 * @param {Mixed} date The date value
17114 * Fires when this field hide.
17115 * @param {Roo.bootstrap.DateField} this
17116 * @param {Mixed} date The date value
17121 * Fires when select a date.
17122 * @param {Roo.bootstrap.DateField} this
17123 * @param {Mixed} date The date value
17129 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
17132 * @cfg {String} format
17133 * The default time format string which can be overriden for localization support. The format must be
17134 * valid according to {@link Date#parseDate} (defaults to 'H:i').
17138 onRender: function(ct, position)
17141 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
17143 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
17145 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17147 this.pop = this.picker().select('>.datepicker-time',true).first();
17148 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17150 this.picker().on('mousedown', this.onMousedown, this);
17151 this.picker().on('click', this.onClick, this);
17153 this.picker().addClass('datepicker-dropdown');
17158 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
17159 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
17160 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
17161 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
17162 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
17163 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
17167 fireKey: function(e){
17168 if (!this.picker().isVisible()){
17169 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17175 e.preventDefault();
17183 this.onTogglePeriod();
17186 this.onIncrementMinutes();
17189 this.onDecrementMinutes();
17198 onClick: function(e) {
17199 e.stopPropagation();
17200 e.preventDefault();
17203 picker : function()
17205 return this.el.select('.datepicker', true).first();
17208 fillTime: function()
17210 var time = this.pop.select('tbody', true).first();
17212 time.dom.innerHTML = '';
17227 cls: 'hours-up glyphicon glyphicon-chevron-up'
17247 cls: 'minutes-up glyphicon glyphicon-chevron-up'
17268 cls: 'timepicker-hour',
17283 cls: 'timepicker-minute',
17298 cls: 'btn btn-primary period',
17320 cls: 'hours-down glyphicon glyphicon-chevron-down'
17340 cls: 'minutes-down glyphicon glyphicon-chevron-down'
17358 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
17365 var hours = this.time.getHours();
17366 var minutes = this.time.getMinutes();
17379 hours = hours - 12;
17383 hours = '0' + hours;
17387 minutes = '0' + minutes;
17390 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
17391 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
17392 this.pop.select('button', true).first().dom.innerHTML = period;
17398 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
17400 var cls = ['bottom'];
17402 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
17409 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
17414 this.picker().addClass(cls.join('-'));
17418 Roo.each(cls, function(c){
17420 _this.picker().setTop(_this.inputEl().getHeight());
17424 _this.picker().setTop(0 - _this.picker().getHeight());
17429 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
17433 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
17440 onFocus : function()
17442 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
17446 onBlur : function()
17448 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
17454 this.picker().show();
17459 this.fireEvent('show', this, this.date);
17464 this.picker().hide();
17467 this.fireEvent('hide', this, this.date);
17470 setTime : function()
17473 this.setValue(this.time.format(this.format));
17475 this.fireEvent('select', this, this.date);
17480 onMousedown: function(e){
17481 e.stopPropagation();
17482 e.preventDefault();
17485 onIncrementHours: function()
17487 Roo.log('onIncrementHours');
17488 this.time = this.time.add(Date.HOUR, 1);
17493 onDecrementHours: function()
17495 Roo.log('onDecrementHours');
17496 this.time = this.time.add(Date.HOUR, -1);
17500 onIncrementMinutes: function()
17502 Roo.log('onIncrementMinutes');
17503 this.time = this.time.add(Date.MINUTE, 1);
17507 onDecrementMinutes: function()
17509 Roo.log('onDecrementMinutes');
17510 this.time = this.time.add(Date.MINUTE, -1);
17514 onTogglePeriod: function()
17516 Roo.log('onTogglePeriod');
17517 this.time = this.time.add(Date.HOUR, 12);
17524 Roo.apply(Roo.bootstrap.TimeField, {
17554 cls: 'btn btn-info ok',
17566 Roo.apply(Roo.bootstrap.TimeField, {
17570 cls: 'datepicker dropdown-menu',
17574 cls: 'datepicker-time',
17578 cls: 'table-condensed',
17580 Roo.bootstrap.TimeField.content,
17581 Roo.bootstrap.TimeField.footer
17600 * @class Roo.bootstrap.MonthField
17601 * @extends Roo.bootstrap.Input
17602 * Bootstrap MonthField class
17604 * @cfg {String} language default en
17607 * Create a new MonthField
17608 * @param {Object} config The config object
17611 Roo.bootstrap.MonthField = function(config){
17612 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
17617 * Fires when this field show.
17618 * @param {Roo.bootstrap.MonthField} this
17619 * @param {Mixed} date The date value
17624 * Fires when this field hide.
17625 * @param {Roo.bootstrap.MonthField} this
17626 * @param {Mixed} date The date value
17631 * Fires when select a date.
17632 * @param {Roo.bootstrap.MonthField} this
17633 * @param {String} oldvalue The old value
17634 * @param {String} newvalue The new value
17640 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
17642 onRender: function(ct, position)
17645 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
17647 this.language = this.language || 'en';
17648 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
17649 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
17651 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
17652 this.isInline = false;
17653 this.isInput = true;
17654 this.component = this.el.select('.add-on', true).first() || false;
17655 this.component = (this.component && this.component.length === 0) ? false : this.component;
17656 this.hasInput = this.component && this.inputEL().length;
17658 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
17660 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17662 this.picker().on('mousedown', this.onMousedown, this);
17663 this.picker().on('click', this.onClick, this);
17665 this.picker().addClass('datepicker-dropdown');
17667 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17668 v.setStyle('width', '189px');
17675 if(this.isInline) {
17681 setValue: function(v, suppressEvent)
17683 var o = this.getValue();
17685 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
17689 if(suppressEvent !== true){
17690 this.fireEvent('select', this, o, v);
17695 getValue: function()
17700 onClick: function(e)
17702 e.stopPropagation();
17703 e.preventDefault();
17705 var target = e.getTarget();
17707 if(target.nodeName.toLowerCase() === 'i'){
17708 target = Roo.get(target).dom.parentNode;
17711 var nodeName = target.nodeName;
17712 var className = target.className;
17713 var html = target.innerHTML;
17715 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
17719 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
17721 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17727 picker : function()
17729 return this.pickerEl;
17732 fillMonths: function()
17735 var months = this.picker().select('>.datepicker-months td', true).first();
17737 months.dom.innerHTML = '';
17743 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
17746 months.createChild(month);
17755 if(typeof(this.vIndex) == 'undefined' && this.value.length){
17756 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
17759 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
17760 e.removeClass('active');
17762 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
17763 e.addClass('active');
17770 if(this.isInline) return;
17772 this.picker().removeClass(['bottom', 'top']);
17774 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17776 * place to the top of element!
17780 this.picker().addClass('top');
17781 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17786 this.picker().addClass('bottom');
17788 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17791 onFocus : function()
17793 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17797 onBlur : function()
17799 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17801 var d = this.inputEl().getValue();
17810 this.picker().show();
17811 this.picker().select('>.datepicker-months', true).first().show();
17815 this.fireEvent('show', this, this.date);
17820 if(this.isInline) return;
17821 this.picker().hide();
17822 this.fireEvent('hide', this, this.date);
17826 onMousedown: function(e)
17828 e.stopPropagation();
17829 e.preventDefault();
17834 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17838 fireKey: function(e)
17840 if (!this.picker().isVisible()){
17841 if (e.keyCode == 27) // allow escape to hide and re-show picker
17851 e.preventDefault();
17855 dir = e.keyCode == 37 ? -1 : 1;
17857 this.vIndex = this.vIndex + dir;
17859 if(this.vIndex < 0){
17863 if(this.vIndex > 11){
17867 if(isNaN(this.vIndex)){
17871 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17877 dir = e.keyCode == 38 ? -1 : 1;
17879 this.vIndex = this.vIndex + dir * 4;
17881 if(this.vIndex < 0){
17885 if(this.vIndex > 11){
17889 if(isNaN(this.vIndex)){
17893 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17898 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17899 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17903 e.preventDefault();
17906 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17907 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17923 this.picker().remove();
17928 Roo.apply(Roo.bootstrap.MonthField, {
17947 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17948 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17953 Roo.apply(Roo.bootstrap.MonthField, {
17957 cls: 'datepicker dropdown-menu roo-dynamic',
17961 cls: 'datepicker-months',
17965 cls: 'table-condensed',
17967 Roo.bootstrap.DateField.content
17987 * @class Roo.bootstrap.CheckBox
17988 * @extends Roo.bootstrap.Input
17989 * Bootstrap CheckBox class
17991 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17992 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17993 * @cfg {String} boxLabel The text that appears beside the checkbox
17994 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17995 * @cfg {Boolean} checked initnal the element
17996 * @cfg {Boolean} inline inline the element (default false)
17997 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
18000 * Create a new CheckBox
18001 * @param {Object} config The config object
18004 Roo.bootstrap.CheckBox = function(config){
18005 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
18010 * Fires when the element is checked or unchecked.
18011 * @param {Roo.bootstrap.CheckBox} this This input
18012 * @param {Boolean} checked The new checked value
18019 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18021 inputType: 'checkbox',
18029 getAutoCreate : function()
18031 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18037 cfg.cls = 'form-group ' + this.inputType; //input-group
18040 cfg.cls += ' ' + this.inputType + '-inline';
18046 type : this.inputType,
18047 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18048 cls : 'roo-' + this.inputType, //'form-box',
18049 placeholder : this.placeholder || ''
18053 if (this.weight) { // Validity check?
18054 cfg.cls += " " + this.inputType + "-" + this.weight;
18057 if (this.disabled) {
18058 input.disabled=true;
18062 input.checked = this.checked;
18066 input.name = this.name;
18070 input.cls += ' input-' + this.size;
18075 ['xs','sm','md','lg'].map(function(size){
18076 if (settings[size]) {
18077 cfg.cls += ' col-' + size + '-' + settings[size];
18081 var inputblock = input;
18083 if (this.before || this.after) {
18086 cls : 'input-group',
18091 inputblock.cn.push({
18093 cls : 'input-group-addon',
18098 inputblock.cn.push(input);
18101 inputblock.cn.push({
18103 cls : 'input-group-addon',
18110 if (align ==='left' && this.fieldLabel.length) {
18111 Roo.log("left and has label");
18117 cls : 'control-label col-md-' + this.labelWidth,
18118 html : this.fieldLabel
18122 cls : "col-md-" + (12 - this.labelWidth),
18129 } else if ( this.fieldLabel.length) {
18134 tag: this.boxLabel ? 'span' : 'label',
18136 cls: 'control-label box-input-label',
18137 //cls : 'input-group-addon',
18138 html : this.fieldLabel
18148 Roo.log(" no label && no align");
18149 cfg.cn = [ inputblock ] ;
18154 var boxLabelCfg = {
18156 //'for': id, // box label is handled by onclick - so no for...
18158 html: this.boxLabel
18162 boxLabelCfg.tooltip = this.tooltip;
18165 cfg.cn.push(boxLabelCfg);
18175 * return the real input element.
18177 inputEl: function ()
18179 return this.el.select('input.roo-' + this.inputType,true).first();
18182 labelEl: function()
18184 return this.el.select('label.control-label',true).first();
18186 /* depricated... */
18190 return this.labelEl();
18193 initEvents : function()
18195 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18197 this.inputEl().on('click', this.onClick, this);
18199 if (this.boxLabel) {
18200 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
18203 this.startValue = this.getValue();
18206 Roo.bootstrap.CheckBox.register(this);
18210 onClick : function()
18212 this.setChecked(!this.checked);
18215 setChecked : function(state,suppressEvent)
18217 this.startValue = this.getValue();
18219 if(this.inputType == 'radio'){
18221 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18222 e.dom.checked = false;
18225 this.inputEl().dom.checked = true;
18227 this.inputEl().dom.value = this.inputValue;
18229 if(suppressEvent !== true){
18230 this.fireEvent('check', this, true);
18238 this.checked = state;
18240 this.inputEl().dom.checked = state;
18242 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18244 if(suppressEvent !== true){
18245 this.fireEvent('check', this, state);
18251 getValue : function()
18253 if(this.inputType == 'radio'){
18254 return this.getGroupValue();
18257 return this.inputEl().getValue();
18261 getGroupValue : function()
18263 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
18267 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
18270 setValue : function(v,suppressEvent)
18272 if(this.inputType == 'radio'){
18273 this.setGroupValue(v, suppressEvent);
18277 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
18282 setGroupValue : function(v, suppressEvent)
18284 this.startValue = this.getValue();
18286 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18287 e.dom.checked = false;
18289 if(e.dom.value == v){
18290 e.dom.checked = true;
18294 if(suppressEvent !== true){
18295 this.fireEvent('check', this, true);
18303 validate : function()
18307 (this.inputType == 'radio' && this.validateRadio()) ||
18308 (this.inputType == 'checkbox' && this.validateCheckbox())
18314 this.markInvalid();
18318 validateRadio : function()
18322 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18323 if(!e.dom.checked){
18335 validateCheckbox : function()
18338 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
18341 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18349 for(var i in group){
18354 r = (group[i].getValue() == group[i].inputValue) ? true : false;
18361 * Mark this field as valid
18363 markValid : function()
18365 if(this.allowBlank){
18371 this.fireEvent('valid', this);
18373 if(this.inputType == 'radio'){
18374 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18375 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
18376 e.findParent('.form-group', false, true).addClass(_this.validClass);
18383 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18384 this.el.findParent('.form-group', false, true).addClass(this.validClass);
18388 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18394 for(var i in group){
18395 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18396 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
18401 * Mark this field as invalid
18402 * @param {String} msg The validation message
18404 markInvalid : function(msg)
18406 if(this.allowBlank){
18412 this.fireEvent('invalid', this, msg);
18414 if(this.inputType == 'radio'){
18415 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18416 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
18417 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
18424 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18425 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
18429 var group = Roo.bootstrap.CheckBox.get(this.groupId);
18435 for(var i in group){
18436 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
18437 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
18444 Roo.apply(Roo.bootstrap.CheckBox, {
18449 * register a CheckBox Group
18450 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
18452 register : function(checkbox)
18454 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
18455 this.groups[checkbox.groupId] = {};
18458 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
18462 this.groups[checkbox.groupId][checkbox.name] = checkbox;
18466 * fetch a CheckBox Group based on the group ID
18467 * @param {string} the group ID
18468 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
18470 get: function(groupId) {
18471 if (typeof(this.groups[groupId]) == 'undefined') {
18475 return this.groups[groupId] ;
18487 *<div class="radio">
18489 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
18490 Option one is this and that—be sure to include why it's great
18497 *<label class="radio-inline">fieldLabel</label>
18498 *<label class="radio-inline">
18499 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
18507 * @class Roo.bootstrap.Radio
18508 * @extends Roo.bootstrap.CheckBox
18509 * Bootstrap Radio class
18512 * Create a new Radio
18513 * @param {Object} config The config object
18516 Roo.bootstrap.Radio = function(config){
18517 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
18521 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
18523 inputType: 'radio',
18527 getAutoCreate : function()
18529 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18530 align = align || 'left'; // default...
18537 tag : this.inline ? 'span' : 'div',
18542 var inline = this.inline ? ' radio-inline' : '';
18546 // does not need for, as we wrap the input with it..
18548 cls : 'control-label box-label' + inline,
18551 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
18555 //cls : 'control-label' + inline,
18556 html : this.fieldLabel,
18557 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
18566 type : this.inputType,
18567 //value : (!this.checked) ? this.valueOff : this.inputValue,
18568 value : this.inputValue,
18570 placeholder : this.placeholder || '' // ?? needed????
18573 if (this.weight) { // Validity check?
18574 input.cls += " radio-" + this.weight;
18576 if (this.disabled) {
18577 input.disabled=true;
18581 input.checked = this.checked;
18585 input.name = this.name;
18589 input.cls += ' input-' + this.size;
18592 //?? can span's inline have a width??
18595 ['xs','sm','md','lg'].map(function(size){
18596 if (settings[size]) {
18597 cfg.cls += ' col-' + size + '-' + settings[size];
18601 var inputblock = input;
18603 if (this.before || this.after) {
18606 cls : 'input-group',
18611 inputblock.cn.push({
18613 cls : 'input-group-addon',
18617 inputblock.cn.push(input);
18619 inputblock.cn.push({
18621 cls : 'input-group-addon',
18629 if (this.fieldLabel && this.fieldLabel.length) {
18630 cfg.cn.push(fieldLabel);
18633 // normal bootstrap puts the input inside the label.
18634 // however with our styled version - it has to go after the input.
18636 //lbl.cn.push(inputblock);
18640 cls: 'radio' + inline,
18647 cfg.cn.push( lblwrap);
18652 html: this.boxLabel
18661 initEvents : function()
18663 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18665 this.inputEl().on('click', this.onClick, this);
18666 if (this.boxLabel) {
18667 Roo.log('find label')
18668 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
18673 inputEl: function ()
18675 return this.el.select('input.roo-radio',true).first();
18677 onClick : function()
18680 this.setChecked(true);
18683 setChecked : function(state,suppressEvent)
18686 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18687 v.dom.checked = false;
18690 Roo.log(this.inputEl().dom);
18691 this.checked = state;
18692 this.inputEl().dom.checked = state;
18694 if(suppressEvent !== true){
18695 this.fireEvent('check', this, state);
18698 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
18702 getGroupValue : function()
18705 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
18706 if(v.dom.checked == true){
18707 value = v.dom.value;
18715 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
18716 * @return {Mixed} value The field value
18718 getValue : function(){
18719 return this.getGroupValue();
18725 //<script type="text/javascript">
18728 * Based Ext JS Library 1.1.1
18729 * Copyright(c) 2006-2007, Ext JS, LLC.
18735 * @class Roo.HtmlEditorCore
18736 * @extends Roo.Component
18737 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
18739 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18742 Roo.HtmlEditorCore = function(config){
18745 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
18750 * @event initialize
18751 * Fires when the editor is fully initialized (including the iframe)
18752 * @param {Roo.HtmlEditorCore} this
18757 * Fires when the editor is first receives the focus. Any insertion must wait
18758 * until after this event.
18759 * @param {Roo.HtmlEditorCore} this
18763 * @event beforesync
18764 * Fires before the textarea is updated with content from the editor iframe. Return false
18765 * to cancel the sync.
18766 * @param {Roo.HtmlEditorCore} this
18767 * @param {String} html
18771 * @event beforepush
18772 * Fires before the iframe editor is updated with content from the textarea. Return false
18773 * to cancel the push.
18774 * @param {Roo.HtmlEditorCore} this
18775 * @param {String} html
18780 * Fires when the textarea is updated with content from the editor iframe.
18781 * @param {Roo.HtmlEditorCore} this
18782 * @param {String} html
18787 * Fires when the iframe editor is updated with content from the textarea.
18788 * @param {Roo.HtmlEditorCore} this
18789 * @param {String} html
18794 * @event editorevent
18795 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18796 * @param {Roo.HtmlEditorCore} this
18802 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18804 // defaults : white / black...
18805 this.applyBlacklists();
18812 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18816 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18822 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18827 * @cfg {Number} height (in pixels)
18831 * @cfg {Number} width (in pixels)
18836 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18839 stylesheets: false,
18844 // private properties
18845 validationEvent : false,
18847 initialized : false,
18849 sourceEditMode : false,
18850 onFocus : Roo.emptyFn,
18852 hideMode:'offsets',
18856 // blacklist + whitelisted elements..
18863 * Protected method that will not generally be called directly. It
18864 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18865 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18867 getDocMarkup : function(){
18871 // inherit styels from page...??
18872 if (this.stylesheets === false) {
18874 Roo.get(document.head).select('style').each(function(node) {
18875 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18878 Roo.get(document.head).select('link').each(function(node) {
18879 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18882 } else if (!this.stylesheets.length) {
18884 st = '<style type="text/css">' +
18885 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18891 st += '<style type="text/css">' +
18892 'IMG { cursor: pointer } ' +
18896 return '<html><head>' + st +
18897 //<style type="text/css">' +
18898 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18900 ' </head><body class="roo-htmleditor-body"></body></html>';
18904 onRender : function(ct, position)
18907 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18908 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18911 this.el.dom.style.border = '0 none';
18912 this.el.dom.setAttribute('tabIndex', -1);
18913 this.el.addClass('x-hidden hide');
18917 if(Roo.isIE){ // fix IE 1px bogus margin
18918 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18922 this.frameId = Roo.id();
18926 var iframe = this.owner.wrap.createChild({
18928 cls: 'form-control', // bootstrap..
18930 name: this.frameId,
18931 frameBorder : 'no',
18932 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18937 this.iframe = iframe.dom;
18939 this.assignDocWin();
18941 this.doc.designMode = 'on';
18944 this.doc.write(this.getDocMarkup());
18948 var task = { // must defer to wait for browser to be ready
18950 //console.log("run task?" + this.doc.readyState);
18951 this.assignDocWin();
18952 if(this.doc.body || this.doc.readyState == 'complete'){
18954 this.doc.designMode="on";
18958 Roo.TaskMgr.stop(task);
18959 this.initEditor.defer(10, this);
18966 Roo.TaskMgr.start(task);
18971 onResize : function(w, h)
18973 Roo.log('resize: ' +w + ',' + h );
18974 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18978 if(typeof w == 'number'){
18980 this.iframe.style.width = w + 'px';
18982 if(typeof h == 'number'){
18984 this.iframe.style.height = h + 'px';
18986 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18993 * Toggles the editor between standard and source edit mode.
18994 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18996 toggleSourceEdit : function(sourceEditMode){
18998 this.sourceEditMode = sourceEditMode === true;
19000 if(this.sourceEditMode){
19002 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
19005 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
19006 //this.iframe.className = '';
19009 //this.setSize(this.owner.wrap.getSize());
19010 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19017 * Protected method that will not generally be called directly. If you need/want
19018 * custom HTML cleanup, this is the method you should override.
19019 * @param {String} html The HTML to be cleaned
19020 * return {String} The cleaned HTML
19022 cleanHtml : function(html){
19023 html = String(html);
19024 if(html.length > 5){
19025 if(Roo.isSafari){ // strip safari nonsense
19026 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19029 if(html == ' '){
19036 * HTML Editor -> Textarea
19037 * Protected method that will not generally be called directly. Syncs the contents
19038 * of the editor iframe with the textarea.
19040 syncValue : function(){
19041 if(this.initialized){
19042 var bd = (this.doc.body || this.doc.documentElement);
19043 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19044 var html = bd.innerHTML;
19046 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19047 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19049 html = '<div style="'+m[0]+'">' + html + '</div>';
19052 html = this.cleanHtml(html);
19053 // fix up the special chars.. normaly like back quotes in word...
19054 // however we do not want to do this with chinese..
19055 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19056 var cc = b.charCodeAt();
19058 (cc >= 0x4E00 && cc < 0xA000 ) ||
19059 (cc >= 0x3400 && cc < 0x4E00 ) ||
19060 (cc >= 0xf900 && cc < 0xfb00 )
19066 if(this.owner.fireEvent('beforesync', this, html) !== false){
19067 this.el.dom.value = html;
19068 this.owner.fireEvent('sync', this, html);
19074 * Protected method that will not generally be called directly. Pushes the value of the textarea
19075 * into the iframe editor.
19077 pushValue : function(){
19078 if(this.initialized){
19079 var v = this.el.dom.value.trim();
19081 // if(v.length < 1){
19085 if(this.owner.fireEvent('beforepush', this, v) !== false){
19086 var d = (this.doc.body || this.doc.documentElement);
19088 this.cleanUpPaste();
19089 this.el.dom.value = d.innerHTML;
19090 this.owner.fireEvent('push', this, v);
19096 deferFocus : function(){
19097 this.focus.defer(10, this);
19101 focus : function(){
19102 if(this.win && !this.sourceEditMode){
19109 assignDocWin: function()
19111 var iframe = this.iframe;
19114 this.doc = iframe.contentWindow.document;
19115 this.win = iframe.contentWindow;
19117 // if (!Roo.get(this.frameId)) {
19120 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19121 // this.win = Roo.get(this.frameId).dom.contentWindow;
19123 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
19127 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19128 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
19133 initEditor : function(){
19134 //console.log("INIT EDITOR");
19135 this.assignDocWin();
19139 this.doc.designMode="on";
19141 this.doc.write(this.getDocMarkup());
19144 var dbody = (this.doc.body || this.doc.documentElement);
19145 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
19146 // this copies styles from the containing element into thsi one..
19147 // not sure why we need all of this..
19148 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
19150 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
19151 //ss['background-attachment'] = 'fixed'; // w3c
19152 dbody.bgProperties = 'fixed'; // ie
19153 //Roo.DomHelper.applyStyles(dbody, ss);
19154 Roo.EventManager.on(this.doc, {
19155 //'mousedown': this.onEditorEvent,
19156 'mouseup': this.onEditorEvent,
19157 'dblclick': this.onEditorEvent,
19158 'click': this.onEditorEvent,
19159 'keyup': this.onEditorEvent,
19164 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
19166 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
19167 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
19169 this.initialized = true;
19171 this.owner.fireEvent('initialize', this);
19176 onDestroy : function(){
19182 //for (var i =0; i < this.toolbars.length;i++) {
19183 // // fixme - ask toolbars for heights?
19184 // this.toolbars[i].onDestroy();
19187 //this.wrap.dom.innerHTML = '';
19188 //this.wrap.remove();
19193 onFirstFocus : function(){
19195 this.assignDocWin();
19198 this.activated = true;
19201 if(Roo.isGecko){ // prevent silly gecko errors
19203 var s = this.win.getSelection();
19204 if(!s.focusNode || s.focusNode.nodeType != 3){
19205 var r = s.getRangeAt(0);
19206 r.selectNodeContents((this.doc.body || this.doc.documentElement));
19211 this.execCmd('useCSS', true);
19212 this.execCmd('styleWithCSS', false);
19215 this.owner.fireEvent('activate', this);
19219 adjustFont: function(btn){
19220 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
19221 //if(Roo.isSafari){ // safari
19224 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
19225 if(Roo.isSafari){ // safari
19226 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
19227 v = (v < 10) ? 10 : v;
19228 v = (v > 48) ? 48 : v;
19229 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
19234 v = Math.max(1, v+adjust);
19236 this.execCmd('FontSize', v );
19239 onEditorEvent : function(e)
19241 this.owner.fireEvent('editorevent', this, e);
19242 // this.updateToolbar();
19243 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
19246 insertTag : function(tg)
19248 // could be a bit smarter... -> wrap the current selected tRoo..
19249 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
19251 range = this.createRange(this.getSelection());
19252 var wrappingNode = this.doc.createElement(tg.toLowerCase());
19253 wrappingNode.appendChild(range.extractContents());
19254 range.insertNode(wrappingNode);
19261 this.execCmd("formatblock", tg);
19265 insertText : function(txt)
19269 var range = this.createRange();
19270 range.deleteContents();
19271 //alert(Sender.getAttribute('label'));
19273 range.insertNode(this.doc.createTextNode(txt));
19279 * Executes a Midas editor command on the editor document and performs necessary focus and
19280 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
19281 * @param {String} cmd The Midas command
19282 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
19284 relayCmd : function(cmd, value){
19286 this.execCmd(cmd, value);
19287 this.owner.fireEvent('editorevent', this);
19288 //this.updateToolbar();
19289 this.owner.deferFocus();
19293 * Executes a Midas editor command directly on the editor document.
19294 * For visual commands, you should use {@link #relayCmd} instead.
19295 * <b>This should only be called after the editor is initialized.</b>
19296 * @param {String} cmd The Midas command
19297 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
19299 execCmd : function(cmd, value){
19300 this.doc.execCommand(cmd, false, value === undefined ? null : value);
19307 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
19309 * @param {String} text | dom node..
19311 insertAtCursor : function(text)
19316 if(!this.activated){
19322 var r = this.doc.selection.createRange();
19333 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
19337 // from jquery ui (MIT licenced)
19339 var win = this.win;
19341 if (win.getSelection && win.getSelection().getRangeAt) {
19342 range = win.getSelection().getRangeAt(0);
19343 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
19344 range.insertNode(node);
19345 } else if (win.document.selection && win.document.selection.createRange) {
19346 // no firefox support
19347 var txt = typeof(text) == 'string' ? text : text.outerHTML;
19348 win.document.selection.createRange().pasteHTML(txt);
19350 // no firefox support
19351 var txt = typeof(text) == 'string' ? text : text.outerHTML;
19352 this.execCmd('InsertHTML', txt);
19361 mozKeyPress : function(e){
19363 var c = e.getCharCode(), cmd;
19366 c = String.fromCharCode(c).toLowerCase();
19380 this.cleanUpPaste.defer(100, this);
19388 e.preventDefault();
19396 fixKeys : function(){ // load time branching for fastest keydown performance
19398 return function(e){
19399 var k = e.getKey(), r;
19402 r = this.doc.selection.createRange();
19405 r.pasteHTML('    ');
19412 r = this.doc.selection.createRange();
19414 var target = r.parentElement();
19415 if(!target || target.tagName.toLowerCase() != 'li'){
19417 r.pasteHTML('<br />');
19423 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19424 this.cleanUpPaste.defer(100, this);
19430 }else if(Roo.isOpera){
19431 return function(e){
19432 var k = e.getKey();
19436 this.execCmd('InsertHTML','    ');
19439 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19440 this.cleanUpPaste.defer(100, this);
19445 }else if(Roo.isSafari){
19446 return function(e){
19447 var k = e.getKey();
19451 this.execCmd('InsertText','\t');
19455 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
19456 this.cleanUpPaste.defer(100, this);
19464 getAllAncestors: function()
19466 var p = this.getSelectedNode();
19469 a.push(p); // push blank onto stack..
19470 p = this.getParentElement();
19474 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
19478 a.push(this.doc.body);
19482 lastSelNode : false,
19485 getSelection : function()
19487 this.assignDocWin();
19488 return Roo.isIE ? this.doc.selection : this.win.getSelection();
19491 getSelectedNode: function()
19493 // this may only work on Gecko!!!
19495 // should we cache this!!!!
19500 var range = this.createRange(this.getSelection()).cloneRange();
19503 var parent = range.parentElement();
19505 var testRange = range.duplicate();
19506 testRange.moveToElementText(parent);
19507 if (testRange.inRange(range)) {
19510 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
19513 parent = parent.parentElement;
19518 // is ancestor a text element.
19519 var ac = range.commonAncestorContainer;
19520 if (ac.nodeType == 3) {
19521 ac = ac.parentNode;
19524 var ar = ac.childNodes;
19527 var other_nodes = [];
19528 var has_other_nodes = false;
19529 for (var i=0;i<ar.length;i++) {
19530 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
19533 // fullly contained node.
19535 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
19540 // probably selected..
19541 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
19542 other_nodes.push(ar[i]);
19546 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
19551 has_other_nodes = true;
19553 if (!nodes.length && other_nodes.length) {
19554 nodes= other_nodes;
19556 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
19562 createRange: function(sel)
19564 // this has strange effects when using with
19565 // top toolbar - not sure if it's a great idea.
19566 //this.editor.contentWindow.focus();
19567 if (typeof sel != "undefined") {
19569 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
19571 return this.doc.createRange();
19574 return this.doc.createRange();
19577 getParentElement: function()
19580 this.assignDocWin();
19581 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
19583 var range = this.createRange(sel);
19586 var p = range.commonAncestorContainer;
19587 while (p.nodeType == 3) { // text node
19598 * Range intersection.. the hard stuff...
19602 * [ -- selected range --- ]
19606 * if end is before start or hits it. fail.
19607 * if start is after end or hits it fail.
19609 * if either hits (but other is outside. - then it's not
19615 // @see http://www.thismuchiknow.co.uk/?p=64.
19616 rangeIntersectsNode : function(range, node)
19618 var nodeRange = node.ownerDocument.createRange();
19620 nodeRange.selectNode(node);
19622 nodeRange.selectNodeContents(node);
19625 var rangeStartRange = range.cloneRange();
19626 rangeStartRange.collapse(true);
19628 var rangeEndRange = range.cloneRange();
19629 rangeEndRange.collapse(false);
19631 var nodeStartRange = nodeRange.cloneRange();
19632 nodeStartRange.collapse(true);
19634 var nodeEndRange = nodeRange.cloneRange();
19635 nodeEndRange.collapse(false);
19637 return rangeStartRange.compareBoundaryPoints(
19638 Range.START_TO_START, nodeEndRange) == -1 &&
19639 rangeEndRange.compareBoundaryPoints(
19640 Range.START_TO_START, nodeStartRange) == 1;
19644 rangeCompareNode : function(range, node)
19646 var nodeRange = node.ownerDocument.createRange();
19648 nodeRange.selectNode(node);
19650 nodeRange.selectNodeContents(node);
19654 range.collapse(true);
19656 nodeRange.collapse(true);
19658 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
19659 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
19661 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
19663 var nodeIsBefore = ss == 1;
19664 var nodeIsAfter = ee == -1;
19666 if (nodeIsBefore && nodeIsAfter)
19668 if (!nodeIsBefore && nodeIsAfter)
19669 return 1; //right trailed.
19671 if (nodeIsBefore && !nodeIsAfter)
19672 return 2; // left trailed.
19677 // private? - in a new class?
19678 cleanUpPaste : function()
19680 // cleans up the whole document..
19681 Roo.log('cleanuppaste');
19683 this.cleanUpChildren(this.doc.body);
19684 var clean = this.cleanWordChars(this.doc.body.innerHTML);
19685 if (clean != this.doc.body.innerHTML) {
19686 this.doc.body.innerHTML = clean;
19691 cleanWordChars : function(input) {// change the chars to hex code
19692 var he = Roo.HtmlEditorCore;
19694 var output = input;
19695 Roo.each(he.swapCodes, function(sw) {
19696 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
19698 output = output.replace(swapper, sw[1]);
19705 cleanUpChildren : function (n)
19707 if (!n.childNodes.length) {
19710 for (var i = n.childNodes.length-1; i > -1 ; i--) {
19711 this.cleanUpChild(n.childNodes[i]);
19718 cleanUpChild : function (node)
19721 //console.log(node);
19722 if (node.nodeName == "#text") {
19723 // clean up silly Windows -- stuff?
19726 if (node.nodeName == "#comment") {
19727 node.parentNode.removeChild(node);
19728 // clean up silly Windows -- stuff?
19731 var lcname = node.tagName.toLowerCase();
19732 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
19733 // whitelist of tags..
19735 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
19737 node.parentNode.removeChild(node);
19742 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
19744 // remove <a name=....> as rendering on yahoo mailer is borked with this.
19745 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
19747 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
19748 // remove_keep_children = true;
19751 if (remove_keep_children) {
19752 this.cleanUpChildren(node);
19753 // inserts everything just before this node...
19754 while (node.childNodes.length) {
19755 var cn = node.childNodes[0];
19756 node.removeChild(cn);
19757 node.parentNode.insertBefore(cn, node);
19759 node.parentNode.removeChild(node);
19763 if (!node.attributes || !node.attributes.length) {
19764 this.cleanUpChildren(node);
19768 function cleanAttr(n,v)
19771 if (v.match(/^\./) || v.match(/^\//)) {
19774 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19777 if (v.match(/^#/)) {
19780 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19781 node.removeAttribute(n);
19785 var cwhite = this.cwhite;
19786 var cblack = this.cblack;
19788 function cleanStyle(n,v)
19790 if (v.match(/expression/)) { //XSS?? should we even bother..
19791 node.removeAttribute(n);
19795 var parts = v.split(/;/);
19798 Roo.each(parts, function(p) {
19799 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19803 var l = p.split(':').shift().replace(/\s+/g,'');
19804 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19806 if ( cwhite.length && cblack.indexOf(l) > -1) {
19807 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19808 //node.removeAttribute(n);
19812 // only allow 'c whitelisted system attributes'
19813 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19814 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19815 //node.removeAttribute(n);
19825 if (clean.length) {
19826 node.setAttribute(n, clean.join(';'));
19828 node.removeAttribute(n);
19834 for (var i = node.attributes.length-1; i > -1 ; i--) {
19835 var a = node.attributes[i];
19838 if (a.name.toLowerCase().substr(0,2)=='on') {
19839 node.removeAttribute(a.name);
19842 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19843 node.removeAttribute(a.name);
19846 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19847 cleanAttr(a.name,a.value); // fixme..
19850 if (a.name == 'style') {
19851 cleanStyle(a.name,a.value);
19854 /// clean up MS crap..
19855 // tecnically this should be a list of valid class'es..
19858 if (a.name == 'class') {
19859 if (a.value.match(/^Mso/)) {
19860 node.className = '';
19863 if (a.value.match(/body/)) {
19864 node.className = '';
19875 this.cleanUpChildren(node);
19881 * Clean up MS wordisms...
19883 cleanWord : function(node)
19888 this.cleanWord(this.doc.body);
19891 if (node.nodeName == "#text") {
19892 // clean up silly Windows -- stuff?
19895 if (node.nodeName == "#comment") {
19896 node.parentNode.removeChild(node);
19897 // clean up silly Windows -- stuff?
19901 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19902 node.parentNode.removeChild(node);
19906 // remove - but keep children..
19907 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19908 while (node.childNodes.length) {
19909 var cn = node.childNodes[0];
19910 node.removeChild(cn);
19911 node.parentNode.insertBefore(cn, node);
19913 node.parentNode.removeChild(node);
19914 this.iterateChildren(node, this.cleanWord);
19918 if (node.className.length) {
19920 var cn = node.className.split(/\W+/);
19922 Roo.each(cn, function(cls) {
19923 if (cls.match(/Mso[a-zA-Z]+/)) {
19928 node.className = cna.length ? cna.join(' ') : '';
19930 node.removeAttribute("class");
19934 if (node.hasAttribute("lang")) {
19935 node.removeAttribute("lang");
19938 if (node.hasAttribute("style")) {
19940 var styles = node.getAttribute("style").split(";");
19942 Roo.each(styles, function(s) {
19943 if (!s.match(/:/)) {
19946 var kv = s.split(":");
19947 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19950 // what ever is left... we allow.
19953 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19954 if (!nstyle.length) {
19955 node.removeAttribute('style');
19958 this.iterateChildren(node, this.cleanWord);
19964 * iterateChildren of a Node, calling fn each time, using this as the scole..
19965 * @param {DomNode} node node to iterate children of.
19966 * @param {Function} fn method of this class to call on each item.
19968 iterateChildren : function(node, fn)
19970 if (!node.childNodes.length) {
19973 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19974 fn.call(this, node.childNodes[i])
19980 * cleanTableWidths.
19982 * Quite often pasting from word etc.. results in tables with column and widths.
19983 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
19986 cleanTableWidths : function(node)
19991 this.cleanTableWidths(this.doc.body);
19996 if (node.nodeName == "#text" || node.nodeName == "#comment") {
19999 Roo.log(node.tagName);
20000 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
20001 this.iterateChildren(node, this.cleanTableWidths);
20004 if (node.hasAttribute('width')) {
20005 node.removeAttribute('width');
20009 if (node.hasAttribute("style")) {
20012 var styles = node.getAttribute("style").split(";");
20014 Roo.each(styles, function(s) {
20015 if (!s.match(/:/)) {
20018 var kv = s.split(":");
20019 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20022 // what ever is left... we allow.
20025 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20026 if (!nstyle.length) {
20027 node.removeAttribute('style');
20031 this.iterateChildren(node, this.cleanTableWidths);
20039 domToHTML : function(currentElement, depth, nopadtext) {
20041 depth = depth || 0;
20042 nopadtext = nopadtext || false;
20044 if (!currentElement) {
20045 return this.domToHTML(this.doc.body);
20048 //Roo.log(currentElement);
20050 var allText = false;
20051 var nodeName = currentElement.nodeName;
20052 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20054 if (nodeName == '#text') {
20056 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20061 if (nodeName != 'BODY') {
20064 // Prints the node tagName, such as <A>, <IMG>, etc
20067 for(i = 0; i < currentElement.attributes.length;i++) {
20069 var aname = currentElement.attributes.item(i).name;
20070 if (!currentElement.attributes.item(i).value.length) {
20073 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20076 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20085 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20088 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20093 // Traverse the tree
20095 var currentElementChild = currentElement.childNodes.item(i);
20096 var allText = true;
20097 var innerHTML = '';
20099 while (currentElementChild) {
20100 // Formatting code (indent the tree so it looks nice on the screen)
20101 var nopad = nopadtext;
20102 if (lastnode == 'SPAN') {
20106 if (currentElementChild.nodeName == '#text') {
20107 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
20108 toadd = nopadtext ? toadd : toadd.trim();
20109 if (!nopad && toadd.length > 80) {
20110 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
20112 innerHTML += toadd;
20115 currentElementChild = currentElement.childNodes.item(i);
20121 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
20123 // Recursively traverse the tree structure of the child node
20124 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
20125 lastnode = currentElementChild.nodeName;
20127 currentElementChild=currentElement.childNodes.item(i);
20133 // The remaining code is mostly for formatting the tree
20134 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
20139 ret+= "</"+tagName+">";
20145 applyBlacklists : function()
20147 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
20148 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
20152 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
20153 if (b.indexOf(tag) > -1) {
20156 this.white.push(tag);
20160 Roo.each(w, function(tag) {
20161 if (b.indexOf(tag) > -1) {
20164 if (this.white.indexOf(tag) > -1) {
20167 this.white.push(tag);
20172 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
20173 if (w.indexOf(tag) > -1) {
20176 this.black.push(tag);
20180 Roo.each(b, function(tag) {
20181 if (w.indexOf(tag) > -1) {
20184 if (this.black.indexOf(tag) > -1) {
20187 this.black.push(tag);
20192 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
20193 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
20197 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
20198 if (b.indexOf(tag) > -1) {
20201 this.cwhite.push(tag);
20205 Roo.each(w, function(tag) {
20206 if (b.indexOf(tag) > -1) {
20209 if (this.cwhite.indexOf(tag) > -1) {
20212 this.cwhite.push(tag);
20217 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
20218 if (w.indexOf(tag) > -1) {
20221 this.cblack.push(tag);
20225 Roo.each(b, function(tag) {
20226 if (w.indexOf(tag) > -1) {
20229 if (this.cblack.indexOf(tag) > -1) {
20232 this.cblack.push(tag);
20237 setStylesheets : function(stylesheets)
20239 if(typeof(stylesheets) == 'string'){
20240 Roo.get(this.iframe.contentDocument.head).createChild({
20242 rel : 'stylesheet',
20251 Roo.each(stylesheets, function(s) {
20256 Roo.get(_this.iframe.contentDocument.head).createChild({
20258 rel : 'stylesheet',
20267 removeStylesheets : function()
20271 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
20276 // hide stuff that is not compatible
20290 * @event specialkey
20294 * @cfg {String} fieldClass @hide
20297 * @cfg {String} focusClass @hide
20300 * @cfg {String} autoCreate @hide
20303 * @cfg {String} inputType @hide
20306 * @cfg {String} invalidClass @hide
20309 * @cfg {String} invalidText @hide
20312 * @cfg {String} msgFx @hide
20315 * @cfg {String} validateOnBlur @hide
20319 Roo.HtmlEditorCore.white = [
20320 'area', 'br', 'img', 'input', 'hr', 'wbr',
20322 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
20323 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
20324 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
20325 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
20326 'table', 'ul', 'xmp',
20328 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
20331 'dir', 'menu', 'ol', 'ul', 'dl',
20337 Roo.HtmlEditorCore.black = [
20338 // 'embed', 'object', // enable - backend responsiblity to clean thiese
20340 'base', 'basefont', 'bgsound', 'blink', 'body',
20341 'frame', 'frameset', 'head', 'html', 'ilayer',
20342 'iframe', 'layer', 'link', 'meta', 'object',
20343 'script', 'style' ,'title', 'xml' // clean later..
20345 Roo.HtmlEditorCore.clean = [
20346 'script', 'style', 'title', 'xml'
20348 Roo.HtmlEditorCore.remove = [
20353 Roo.HtmlEditorCore.ablack = [
20357 Roo.HtmlEditorCore.aclean = [
20358 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
20362 Roo.HtmlEditorCore.pwhite= [
20363 'http', 'https', 'mailto'
20366 // white listed style attributes.
20367 Roo.HtmlEditorCore.cwhite= [
20368 // 'text-align', /// default is to allow most things..
20374 // black listed style attributes.
20375 Roo.HtmlEditorCore.cblack= [
20376 // 'font-size' -- this can be set by the project
20380 Roo.HtmlEditorCore.swapCodes =[
20399 * @class Roo.bootstrap.HtmlEditor
20400 * @extends Roo.bootstrap.TextArea
20401 * Bootstrap HtmlEditor class
20404 * Create a new HtmlEditor
20405 * @param {Object} config The config object
20408 Roo.bootstrap.HtmlEditor = function(config){
20409 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
20410 if (!this.toolbars) {
20411 this.toolbars = [];
20413 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
20416 * @event initialize
20417 * Fires when the editor is fully initialized (including the iframe)
20418 * @param {HtmlEditor} this
20423 * Fires when the editor is first receives the focus. Any insertion must wait
20424 * until after this event.
20425 * @param {HtmlEditor} this
20429 * @event beforesync
20430 * Fires before the textarea is updated with content from the editor iframe. Return false
20431 * to cancel the sync.
20432 * @param {HtmlEditor} this
20433 * @param {String} html
20437 * @event beforepush
20438 * Fires before the iframe editor is updated with content from the textarea. Return false
20439 * to cancel the push.
20440 * @param {HtmlEditor} this
20441 * @param {String} html
20446 * Fires when the textarea is updated with content from the editor iframe.
20447 * @param {HtmlEditor} this
20448 * @param {String} html
20453 * Fires when the iframe editor is updated with content from the textarea.
20454 * @param {HtmlEditor} this
20455 * @param {String} html
20459 * @event editmodechange
20460 * Fires when the editor switches edit modes
20461 * @param {HtmlEditor} this
20462 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
20464 editmodechange: true,
20466 * @event editorevent
20467 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20468 * @param {HtmlEditor} this
20472 * @event firstfocus
20473 * Fires when on first focus - needed by toolbars..
20474 * @param {HtmlEditor} this
20479 * Auto save the htmlEditor value as a file into Events
20480 * @param {HtmlEditor} this
20484 * @event savedpreview
20485 * preview the saved version of htmlEditor
20486 * @param {HtmlEditor} this
20493 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
20497 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
20502 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20507 * @cfg {Number} height (in pixels)
20511 * @cfg {Number} width (in pixels)
20516 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20519 stylesheets: false,
20524 // private properties
20525 validationEvent : false,
20527 initialized : false,
20530 onFocus : Roo.emptyFn,
20532 hideMode:'offsets',
20535 tbContainer : false,
20537 toolbarContainer :function() {
20538 return this.wrap.select('.x-html-editor-tb',true).first();
20542 * Protected method that will not generally be called directly. It
20543 * is called when the editor creates its toolbar. Override this method if you need to
20544 * add custom toolbar buttons.
20545 * @param {HtmlEditor} editor
20547 createToolbar : function(){
20549 Roo.log("create toolbars");
20551 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
20552 this.toolbars[0].render(this.toolbarContainer());
20556 // if (!editor.toolbars || !editor.toolbars.length) {
20557 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
20560 // for (var i =0 ; i < editor.toolbars.length;i++) {
20561 // editor.toolbars[i] = Roo.factory(
20562 // typeof(editor.toolbars[i]) == 'string' ?
20563 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
20564 // Roo.bootstrap.HtmlEditor);
20565 // editor.toolbars[i].init(editor);
20571 onRender : function(ct, position)
20573 // Roo.log("Call onRender: " + this.xtype);
20575 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
20577 this.wrap = this.inputEl().wrap({
20578 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
20581 this.editorcore.onRender(ct, position);
20583 if (this.resizable) {
20584 this.resizeEl = new Roo.Resizable(this.wrap, {
20588 minHeight : this.height,
20589 height: this.height,
20590 handles : this.resizable,
20593 resize : function(r, w, h) {
20594 _t.onResize(w,h); // -something
20600 this.createToolbar(this);
20603 if(!this.width && this.resizable){
20604 this.setSize(this.wrap.getSize());
20606 if (this.resizeEl) {
20607 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
20608 // should trigger onReize..
20614 onResize : function(w, h)
20616 Roo.log('resize: ' +w + ',' + h );
20617 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
20621 if(this.inputEl() ){
20622 if(typeof w == 'number'){
20623 var aw = w - this.wrap.getFrameWidth('lr');
20624 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
20627 if(typeof h == 'number'){
20628 var tbh = -11; // fixme it needs to tool bar size!
20629 for (var i =0; i < this.toolbars.length;i++) {
20630 // fixme - ask toolbars for heights?
20631 tbh += this.toolbars[i].el.getHeight();
20632 //if (this.toolbars[i].footer) {
20633 // tbh += this.toolbars[i].footer.el.getHeight();
20641 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
20642 ah -= 5; // knock a few pixes off for look..
20643 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
20647 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
20648 this.editorcore.onResize(ew,eh);
20653 * Toggles the editor between standard and source edit mode.
20654 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20656 toggleSourceEdit : function(sourceEditMode)
20658 this.editorcore.toggleSourceEdit(sourceEditMode);
20660 if(this.editorcore.sourceEditMode){
20661 Roo.log('editor - showing textarea');
20664 // Roo.log(this.syncValue());
20666 this.inputEl().removeClass(['hide', 'x-hidden']);
20667 this.inputEl().dom.removeAttribute('tabIndex');
20668 this.inputEl().focus();
20670 Roo.log('editor - hiding textarea');
20672 // Roo.log(this.pushValue());
20675 this.inputEl().addClass(['hide', 'x-hidden']);
20676 this.inputEl().dom.setAttribute('tabIndex', -1);
20677 //this.deferFocus();
20680 if(this.resizable){
20681 this.setSize(this.wrap.getSize());
20684 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
20687 // private (for BoxComponent)
20688 adjustSize : Roo.BoxComponent.prototype.adjustSize,
20690 // private (for BoxComponent)
20691 getResizeEl : function(){
20695 // private (for BoxComponent)
20696 getPositionEl : function(){
20701 initEvents : function(){
20702 this.originalValue = this.getValue();
20706 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20709 // markInvalid : Roo.emptyFn,
20711 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
20714 // clearInvalid : Roo.emptyFn,
20716 setValue : function(v){
20717 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
20718 this.editorcore.pushValue();
20723 deferFocus : function(){
20724 this.focus.defer(10, this);
20728 focus : function(){
20729 this.editorcore.focus();
20735 onDestroy : function(){
20741 for (var i =0; i < this.toolbars.length;i++) {
20742 // fixme - ask toolbars for heights?
20743 this.toolbars[i].onDestroy();
20746 this.wrap.dom.innerHTML = '';
20747 this.wrap.remove();
20752 onFirstFocus : function(){
20753 //Roo.log("onFirstFocus");
20754 this.editorcore.onFirstFocus();
20755 for (var i =0; i < this.toolbars.length;i++) {
20756 this.toolbars[i].onFirstFocus();
20762 syncValue : function()
20764 this.editorcore.syncValue();
20767 pushValue : function()
20769 this.editorcore.pushValue();
20773 // hide stuff that is not compatible
20787 * @event specialkey
20791 * @cfg {String} fieldClass @hide
20794 * @cfg {String} focusClass @hide
20797 * @cfg {String} autoCreate @hide
20800 * @cfg {String} inputType @hide
20803 * @cfg {String} invalidClass @hide
20806 * @cfg {String} invalidText @hide
20809 * @cfg {String} msgFx @hide
20812 * @cfg {String} validateOnBlur @hide
20821 Roo.namespace('Roo.bootstrap.htmleditor');
20823 * @class Roo.bootstrap.HtmlEditorToolbar1
20828 new Roo.bootstrap.HtmlEditor({
20831 new Roo.bootstrap.HtmlEditorToolbar1({
20832 disable : { fonts: 1 , format: 1, ..., ... , ...],
20838 * @cfg {Object} disable List of elements to disable..
20839 * @cfg {Array} btns List of additional buttons.
20843 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20846 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20849 Roo.apply(this, config);
20851 // default disabled, based on 'good practice'..
20852 this.disable = this.disable || {};
20853 Roo.applyIf(this.disable, {
20856 specialElements : true
20858 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20860 this.editor = config.editor;
20861 this.editorcore = config.editor.editorcore;
20863 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20865 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20866 // dont call parent... till later.
20868 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20873 editorcore : false,
20878 "h1","h2","h3","h4","h5","h6",
20880 "abbr", "acronym", "address", "cite", "samp", "var",
20884 onRender : function(ct, position)
20886 // Roo.log("Call onRender: " + this.xtype);
20888 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20890 this.el.dom.style.marginBottom = '0';
20892 var editorcore = this.editorcore;
20893 var editor= this.editor;
20896 var btn = function(id,cmd , toggle, handler){
20898 var event = toggle ? 'toggle' : 'click';
20903 xns: Roo.bootstrap,
20906 enableToggle:toggle !== false,
20908 pressed : toggle ? false : null,
20911 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20912 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20921 xns: Roo.bootstrap,
20922 glyphicon : 'font',
20926 xns: Roo.bootstrap,
20930 Roo.each(this.formats, function(f) {
20931 style.menu.items.push({
20933 xns: Roo.bootstrap,
20934 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20939 editorcore.insertTag(this.tagname);
20946 children.push(style);
20949 btn('bold',false,true);
20950 btn('italic',false,true);
20951 btn('align-left', 'justifyleft',true);
20952 btn('align-center', 'justifycenter',true);
20953 btn('align-right' , 'justifyright',true);
20954 btn('link', false, false, function(btn) {
20955 //Roo.log("create link?");
20956 var url = prompt(this.createLinkText, this.defaultLinkValue);
20957 if(url && url != 'http:/'+'/'){
20958 this.editorcore.relayCmd('createlink', url);
20961 btn('list','insertunorderedlist',true);
20962 btn('pencil', false,true, function(btn){
20965 this.toggleSourceEdit(btn.pressed);
20971 xns: Roo.bootstrap,
20976 xns: Roo.bootstrap,
20981 cog.menu.items.push({
20983 xns: Roo.bootstrap,
20984 html : Clean styles,
20989 editorcore.insertTag(this.tagname);
20998 this.xtype = 'NavSimplebar';
21000 for(var i=0;i< children.length;i++) {
21002 this.buttons.add(this.addxtypeChild(children[i]));
21006 editor.on('editorevent', this.updateToolbar, this);
21008 onBtnClick : function(id)
21010 this.editorcore.relayCmd(id);
21011 this.editorcore.focus();
21015 * Protected method that will not generally be called directly. It triggers
21016 * a toolbar update by reading the markup state of the current selection in the editor.
21018 updateToolbar: function(){
21020 if(!this.editorcore.activated){
21021 this.editor.onFirstFocus(); // is this neeed?
21025 var btns = this.buttons;
21026 var doc = this.editorcore.doc;
21027 btns.get('bold').setActive(doc.queryCommandState('bold'));
21028 btns.get('italic').setActive(doc.queryCommandState('italic'));
21029 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21031 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21032 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21033 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21035 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21036 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21039 var ans = this.editorcore.getAllAncestors();
21040 if (this.formatCombo) {
21043 var store = this.formatCombo.store;
21044 this.formatCombo.setValue("");
21045 for (var i =0; i < ans.length;i++) {
21046 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21048 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21056 // hides menus... - so this cant be on a menu...
21057 Roo.bootstrap.MenuMgr.hideAll();
21059 Roo.bootstrap.MenuMgr.hideAll();
21060 //this.editorsyncValue();
21062 onFirstFocus: function() {
21063 this.buttons.each(function(item){
21067 toggleSourceEdit : function(sourceEditMode){
21070 if(sourceEditMode){
21071 Roo.log("disabling buttons");
21072 this.buttons.each( function(item){
21073 if(item.cmd != 'pencil'){
21079 Roo.log("enabling buttons");
21080 if(this.editorcore.initialized){
21081 this.buttons.each( function(item){
21087 Roo.log("calling toggole on editor");
21088 // tell the editor that it's been pressed..
21089 this.editor.toggleSourceEdit(sourceEditMode);
21099 * @class Roo.bootstrap.Table.AbstractSelectionModel
21100 * @extends Roo.util.Observable
21101 * Abstract base class for grid SelectionModels. It provides the interface that should be
21102 * implemented by descendant classes. This class should not be directly instantiated.
21105 Roo.bootstrap.Table.AbstractSelectionModel = function(){
21106 this.locked = false;
21107 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
21111 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
21112 /** @ignore Called by the grid automatically. Do not call directly. */
21113 init : function(grid){
21119 * Locks the selections.
21122 this.locked = true;
21126 * Unlocks the selections.
21128 unlock : function(){
21129 this.locked = false;
21133 * Returns true if the selections are locked.
21134 * @return {Boolean}
21136 isLocked : function(){
21137 return this.locked;
21141 * @extends Roo.bootstrap.Table.AbstractSelectionModel
21142 * @class Roo.bootstrap.Table.RowSelectionModel
21143 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
21144 * It supports multiple selections and keyboard selection/navigation.
21146 * @param {Object} config
21149 Roo.bootstrap.Table.RowSelectionModel = function(config){
21150 Roo.apply(this, config);
21151 this.selections = new Roo.util.MixedCollection(false, function(o){
21156 this.lastActive = false;
21160 * @event selectionchange
21161 * Fires when the selection changes
21162 * @param {SelectionModel} this
21164 "selectionchange" : true,
21166 * @event afterselectionchange
21167 * Fires after the selection changes (eg. by key press or clicking)
21168 * @param {SelectionModel} this
21170 "afterselectionchange" : true,
21172 * @event beforerowselect
21173 * Fires when a row is selected being selected, return false to cancel.
21174 * @param {SelectionModel} this
21175 * @param {Number} rowIndex The selected index
21176 * @param {Boolean} keepExisting False if other selections will be cleared
21178 "beforerowselect" : true,
21181 * Fires when a row is selected.
21182 * @param {SelectionModel} this
21183 * @param {Number} rowIndex The selected index
21184 * @param {Roo.data.Record} r The record
21186 "rowselect" : true,
21188 * @event rowdeselect
21189 * Fires when a row is deselected.
21190 * @param {SelectionModel} this
21191 * @param {Number} rowIndex The selected index
21193 "rowdeselect" : true
21195 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
21196 this.locked = false;
21199 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
21201 * @cfg {Boolean} singleSelect
21202 * True to allow selection of only one row at a time (defaults to false)
21204 singleSelect : false,
21207 initEvents : function(){
21209 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
21210 this.grid.on("mousedown", this.handleMouseDown, this);
21211 }else{ // allow click to work like normal
21212 this.grid.on("rowclick", this.handleDragableRowClick, this);
21215 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
21216 "up" : function(e){
21218 this.selectPrevious(e.shiftKey);
21219 }else if(this.last !== false && this.lastActive !== false){
21220 var last = this.last;
21221 this.selectRange(this.last, this.lastActive-1);
21222 this.grid.getView().focusRow(this.lastActive);
21223 if(last !== false){
21227 this.selectFirstRow();
21229 this.fireEvent("afterselectionchange", this);
21231 "down" : function(e){
21233 this.selectNext(e.shiftKey);
21234 }else if(this.last !== false && this.lastActive !== false){
21235 var last = this.last;
21236 this.selectRange(this.last, this.lastActive+1);
21237 this.grid.getView().focusRow(this.lastActive);
21238 if(last !== false){
21242 this.selectFirstRow();
21244 this.fireEvent("afterselectionchange", this);
21249 var view = this.grid.view;
21250 view.on("refresh", this.onRefresh, this);
21251 view.on("rowupdated", this.onRowUpdated, this);
21252 view.on("rowremoved", this.onRemove, this);
21256 onRefresh : function(){
21257 var ds = this.grid.dataSource, i, v = this.grid.view;
21258 var s = this.selections;
21259 s.each(function(r){
21260 if((i = ds.indexOfId(r.id)) != -1){
21269 onRemove : function(v, index, r){
21270 this.selections.remove(r);
21274 onRowUpdated : function(v, index, r){
21275 if(this.isSelected(r)){
21276 v.onRowSelect(index);
21282 * @param {Array} records The records to select
21283 * @param {Boolean} keepExisting (optional) True to keep existing selections
21285 selectRecords : function(records, keepExisting){
21287 this.clearSelections();
21289 var ds = this.grid.dataSource;
21290 for(var i = 0, len = records.length; i < len; i++){
21291 this.selectRow(ds.indexOf(records[i]), true);
21296 * Gets the number of selected rows.
21299 getCount : function(){
21300 return this.selections.length;
21304 * Selects the first row in the grid.
21306 selectFirstRow : function(){
21311 * Select the last row.
21312 * @param {Boolean} keepExisting (optional) True to keep existing selections
21314 selectLastRow : function(keepExisting){
21315 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
21319 * Selects the row immediately following the last selected row.
21320 * @param {Boolean} keepExisting (optional) True to keep existing selections
21322 selectNext : function(keepExisting){
21323 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
21324 this.selectRow(this.last+1, keepExisting);
21325 this.grid.getView().focusRow(this.last);
21330 * Selects the row that precedes the last selected row.
21331 * @param {Boolean} keepExisting (optional) True to keep existing selections
21333 selectPrevious : function(keepExisting){
21335 this.selectRow(this.last-1, keepExisting);
21336 this.grid.getView().focusRow(this.last);
21341 * Returns the selected records
21342 * @return {Array} Array of selected records
21344 getSelections : function(){
21345 return [].concat(this.selections.items);
21349 * Returns the first selected record.
21352 getSelected : function(){
21353 return this.selections.itemAt(0);
21358 * Clears all selections.
21360 clearSelections : function(fast){
21361 if(this.locked) return;
21363 var ds = this.grid.dataSource;
21364 var s = this.selections;
21365 s.each(function(r){
21366 this.deselectRow(ds.indexOfId(r.id));
21370 this.selections.clear();
21377 * Selects all rows.
21379 selectAll : function(){
21380 if(this.locked) return;
21381 this.selections.clear();
21382 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
21383 this.selectRow(i, true);
21388 * Returns True if there is a selection.
21389 * @return {Boolean}
21391 hasSelection : function(){
21392 return this.selections.length > 0;
21396 * Returns True if the specified row is selected.
21397 * @param {Number/Record} record The record or index of the record to check
21398 * @return {Boolean}
21400 isSelected : function(index){
21401 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
21402 return (r && this.selections.key(r.id) ? true : false);
21406 * Returns True if the specified record id is selected.
21407 * @param {String} id The id of record to check
21408 * @return {Boolean}
21410 isIdSelected : function(id){
21411 return (this.selections.key(id) ? true : false);
21415 handleMouseDown : function(e, t){
21416 var view = this.grid.getView(), rowIndex;
21417 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
21420 if(e.shiftKey && this.last !== false){
21421 var last = this.last;
21422 this.selectRange(last, rowIndex, e.ctrlKey);
21423 this.last = last; // reset the last
21424 view.focusRow(rowIndex);
21426 var isSelected = this.isSelected(rowIndex);
21427 if(e.button !== 0 && isSelected){
21428 view.focusRow(rowIndex);
21429 }else if(e.ctrlKey && isSelected){
21430 this.deselectRow(rowIndex);
21431 }else if(!isSelected){
21432 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
21433 view.focusRow(rowIndex);
21436 this.fireEvent("afterselectionchange", this);
21439 handleDragableRowClick : function(grid, rowIndex, e)
21441 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
21442 this.selectRow(rowIndex, false);
21443 grid.view.focusRow(rowIndex);
21444 this.fireEvent("afterselectionchange", this);
21449 * Selects multiple rows.
21450 * @param {Array} rows Array of the indexes of the row to select
21451 * @param {Boolean} keepExisting (optional) True to keep existing selections
21453 selectRows : function(rows, keepExisting){
21455 this.clearSelections();
21457 for(var i = 0, len = rows.length; i < len; i++){
21458 this.selectRow(rows[i], true);
21463 * Selects a range of rows. All rows in between startRow and endRow are also selected.
21464 * @param {Number} startRow The index of the first row in the range
21465 * @param {Number} endRow The index of the last row in the range
21466 * @param {Boolean} keepExisting (optional) True to retain existing selections
21468 selectRange : function(startRow, endRow, keepExisting){
21469 if(this.locked) return;
21471 this.clearSelections();
21473 if(startRow <= endRow){
21474 for(var i = startRow; i <= endRow; i++){
21475 this.selectRow(i, true);
21478 for(var i = startRow; i >= endRow; i--){
21479 this.selectRow(i, true);
21485 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
21486 * @param {Number} startRow The index of the first row in the range
21487 * @param {Number} endRow The index of the last row in the range
21489 deselectRange : function(startRow, endRow, preventViewNotify){
21490 if(this.locked) return;
21491 for(var i = startRow; i <= endRow; i++){
21492 this.deselectRow(i, preventViewNotify);
21498 * @param {Number} row The index of the row to select
21499 * @param {Boolean} keepExisting (optional) True to keep existing selections
21501 selectRow : function(index, keepExisting, preventViewNotify){
21502 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
21503 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
21504 if(!keepExisting || this.singleSelect){
21505 this.clearSelections();
21507 var r = this.grid.dataSource.getAt(index);
21508 this.selections.add(r);
21509 this.last = this.lastActive = index;
21510 if(!preventViewNotify){
21511 this.grid.getView().onRowSelect(index);
21513 this.fireEvent("rowselect", this, index, r);
21514 this.fireEvent("selectionchange", this);
21520 * @param {Number} row The index of the row to deselect
21522 deselectRow : function(index, preventViewNotify){
21523 if(this.locked) return;
21524 if(this.last == index){
21527 if(this.lastActive == index){
21528 this.lastActive = false;
21530 var r = this.grid.dataSource.getAt(index);
21531 this.selections.remove(r);
21532 if(!preventViewNotify){
21533 this.grid.getView().onRowDeselect(index);
21535 this.fireEvent("rowdeselect", this, index);
21536 this.fireEvent("selectionchange", this);
21540 restoreLast : function(){
21542 this.last = this._last;
21547 acceptsNav : function(row, col, cm){
21548 return !cm.isHidden(col) && cm.isCellEditable(col, row);
21552 onEditorKey : function(field, e){
21553 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
21558 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
21560 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
21562 }else if(k == e.ENTER && !e.ctrlKey){
21566 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
21568 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
21570 }else if(k == e.ESC){
21574 g.startEditing(newCell[0], newCell[1]);
21579 * Ext JS Library 1.1.1
21580 * Copyright(c) 2006-2007, Ext JS, LLC.
21582 * Originally Released Under LGPL - original licence link has changed is not relivant.
21585 * <script type="text/javascript">
21589 * @class Roo.bootstrap.PagingToolbar
21591 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
21593 * Create a new PagingToolbar
21594 * @param {Object} config The config object
21596 Roo.bootstrap.PagingToolbar = function(config)
21598 // old args format still supported... - xtype is prefered..
21599 // created from xtype...
21600 var ds = config.dataSource;
21601 this.toolbarItems = [];
21602 if (config.items) {
21603 this.toolbarItems = config.items;
21604 // config.items = [];
21607 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
21614 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
21618 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
21620 * @cfg {Roo.data.Store} dataSource
21621 * The underlying data store providing the paged data
21624 * @cfg {String/HTMLElement/Element} container
21625 * container The id or element that will contain the toolbar
21628 * @cfg {Boolean} displayInfo
21629 * True to display the displayMsg (defaults to false)
21632 * @cfg {Number} pageSize
21633 * The number of records to display per page (defaults to 20)
21637 * @cfg {String} displayMsg
21638 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
21640 displayMsg : 'Displaying {0} - {1} of {2}',
21642 * @cfg {String} emptyMsg
21643 * The message to display when no records are found (defaults to "No data to display")
21645 emptyMsg : 'No data to display',
21647 * Customizable piece of the default paging text (defaults to "Page")
21650 beforePageText : "Page",
21652 * Customizable piece of the default paging text (defaults to "of %0")
21655 afterPageText : "of {0}",
21657 * Customizable piece of the default paging text (defaults to "First Page")
21660 firstText : "First Page",
21662 * Customizable piece of the default paging text (defaults to "Previous Page")
21665 prevText : "Previous Page",
21667 * Customizable piece of the default paging text (defaults to "Next Page")
21670 nextText : "Next Page",
21672 * Customizable piece of the default paging text (defaults to "Last Page")
21675 lastText : "Last Page",
21677 * Customizable piece of the default paging text (defaults to "Refresh")
21680 refreshText : "Refresh",
21684 onRender : function(ct, position)
21686 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
21687 this.navgroup.parentId = this.id;
21688 this.navgroup.onRender(this.el, null);
21689 // add the buttons to the navgroup
21691 if(this.displayInfo){
21692 Roo.log(this.el.select('ul.navbar-nav',true).first());
21693 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
21694 this.displayEl = this.el.select('.x-paging-info', true).first();
21695 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
21696 // this.displayEl = navel.el.select('span',true).first();
21702 Roo.each(_this.buttons, function(e){
21703 Roo.factory(e).onRender(_this.el, null);
21707 Roo.each(_this.toolbarItems, function(e) {
21708 _this.navgroup.addItem(e);
21712 this.first = this.navgroup.addItem({
21713 tooltip: this.firstText,
21715 icon : 'fa fa-backward',
21717 preventDefault: true,
21718 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
21721 this.prev = this.navgroup.addItem({
21722 tooltip: this.prevText,
21724 icon : 'fa fa-step-backward',
21726 preventDefault: true,
21727 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
21729 //this.addSeparator();
21732 var field = this.navgroup.addItem( {
21734 cls : 'x-paging-position',
21736 html : this.beforePageText +
21737 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
21738 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
21741 this.field = field.el.select('input', true).first();
21742 this.field.on("keydown", this.onPagingKeydown, this);
21743 this.field.on("focus", function(){this.dom.select();});
21746 this.afterTextEl = field.el.select('.x-paging-after',true).first();
21747 //this.field.setHeight(18);
21748 //this.addSeparator();
21749 this.next = this.navgroup.addItem({
21750 tooltip: this.nextText,
21752 html : ' <i class="fa fa-step-forward">',
21754 preventDefault: true,
21755 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
21757 this.last = this.navgroup.addItem({
21758 tooltip: this.lastText,
21759 icon : 'fa fa-forward',
21762 preventDefault: true,
21763 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
21765 //this.addSeparator();
21766 this.loading = this.navgroup.addItem({
21767 tooltip: this.refreshText,
21768 icon: 'fa fa-refresh',
21769 preventDefault: true,
21770 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
21776 updateInfo : function(){
21777 if(this.displayEl){
21778 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
21779 var msg = count == 0 ?
21783 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
21785 this.displayEl.update(msg);
21790 onLoad : function(ds, r, o){
21791 this.cursor = o.params ? o.params.start : 0;
21792 var d = this.getPageData(),
21796 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
21797 this.field.dom.value = ap;
21798 this.first.setDisabled(ap == 1);
21799 this.prev.setDisabled(ap == 1);
21800 this.next.setDisabled(ap == ps);
21801 this.last.setDisabled(ap == ps);
21802 this.loading.enable();
21807 getPageData : function(){
21808 var total = this.ds.getTotalCount();
21811 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
21812 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
21817 onLoadError : function(){
21818 this.loading.enable();
21822 onPagingKeydown : function(e){
21823 var k = e.getKey();
21824 var d = this.getPageData();
21826 var v = this.field.dom.value, pageNum;
21827 if(!v || isNaN(pageNum = parseInt(v, 10))){
21828 this.field.dom.value = d.activePage;
21831 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21832 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21835 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))
21837 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21838 this.field.dom.value = pageNum;
21839 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21842 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21844 var v = this.field.dom.value, pageNum;
21845 var increment = (e.shiftKey) ? 10 : 1;
21846 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21848 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21849 this.field.dom.value = d.activePage;
21852 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21854 this.field.dom.value = parseInt(v, 10) + increment;
21855 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21856 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21863 beforeLoad : function(){
21865 this.loading.disable();
21870 onClick : function(which){
21879 ds.load({params:{start: 0, limit: this.pageSize}});
21882 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21885 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21888 var total = ds.getTotalCount();
21889 var extra = total % this.pageSize;
21890 var lastStart = extra ? (total - extra) : total-this.pageSize;
21891 ds.load({params:{start: lastStart, limit: this.pageSize}});
21894 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21900 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21901 * @param {Roo.data.Store} store The data store to unbind
21903 unbind : function(ds){
21904 ds.un("beforeload", this.beforeLoad, this);
21905 ds.un("load", this.onLoad, this);
21906 ds.un("loadexception", this.onLoadError, this);
21907 ds.un("remove", this.updateInfo, this);
21908 ds.un("add", this.updateInfo, this);
21909 this.ds = undefined;
21913 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21914 * @param {Roo.data.Store} store The data store to bind
21916 bind : function(ds){
21917 ds.on("beforeload", this.beforeLoad, this);
21918 ds.on("load", this.onLoad, this);
21919 ds.on("loadexception", this.onLoadError, this);
21920 ds.on("remove", this.updateInfo, this);
21921 ds.on("add", this.updateInfo, this);
21932 * @class Roo.bootstrap.MessageBar
21933 * @extends Roo.bootstrap.Component
21934 * Bootstrap MessageBar class
21935 * @cfg {String} html contents of the MessageBar
21936 * @cfg {String} weight (info | success | warning | danger) default info
21937 * @cfg {String} beforeClass insert the bar before the given class
21938 * @cfg {Boolean} closable (true | false) default false
21939 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21942 * Create a new Element
21943 * @param {Object} config The config object
21946 Roo.bootstrap.MessageBar = function(config){
21947 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21950 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21956 beforeClass: 'bootstrap-sticky-wrap',
21958 getAutoCreate : function(){
21962 cls: 'alert alert-dismissable alert-' + this.weight,
21967 html: this.html || ''
21973 cfg.cls += ' alert-messages-fixed';
21987 onRender : function(ct, position)
21989 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21992 var cfg = Roo.apply({}, this.getAutoCreate());
21996 cfg.cls += ' ' + this.cls;
21999 cfg.style = this.style;
22001 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
22003 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22006 this.el.select('>button.close').on('click', this.hide, this);
22012 if (!this.rendered) {
22018 this.fireEvent('show', this);
22024 if (!this.rendered) {
22030 this.fireEvent('hide', this);
22033 update : function()
22035 // var e = this.el.dom.firstChild;
22037 // if(this.closable){
22038 // e = e.nextSibling;
22041 // e.data = this.html || '';
22043 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22059 * @class Roo.bootstrap.Graph
22060 * @extends Roo.bootstrap.Component
22061 * Bootstrap Graph class
22065 @cfg {String} graphtype bar | vbar | pie
22066 @cfg {number} g_x coodinator | centre x (pie)
22067 @cfg {number} g_y coodinator | centre y (pie)
22068 @cfg {number} g_r radius (pie)
22069 @cfg {number} g_height height of the chart (respected by all elements in the set)
22070 @cfg {number} g_width width of the chart (respected by all elements in the set)
22071 @cfg {Object} title The title of the chart
22074 -opts (object) options for the chart
22076 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
22077 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
22079 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.
22080 o stacked (boolean) whether or not to tread values as in a stacked bar chart
22082 o stretch (boolean)
22084 -opts (object) options for the pie
22087 o startAngle (number)
22088 o endAngle (number)
22092 * Create a new Input
22093 * @param {Object} config The config object
22096 Roo.bootstrap.Graph = function(config){
22097 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
22103 * The img click event for the img.
22104 * @param {Roo.EventObject} e
22110 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
22121 //g_colors: this.colors,
22128 getAutoCreate : function(){
22139 onRender : function(ct,position){
22140 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
22141 this.raphael = Raphael(this.el.dom);
22143 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22144 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22145 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22146 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
22148 r.text(160, 10, "Single Series Chart").attr(txtattr);
22149 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
22150 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
22151 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
22153 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
22154 r.barchart(330, 10, 300, 220, data1);
22155 r.barchart(10, 250, 300, 220, data2, {stacked: true});
22156 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
22159 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22160 // r.barchart(30, 30, 560, 250, xdata, {
22161 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
22162 // axis : "0 0 1 1",
22163 // axisxlabels : xdata
22164 // //yvalues : cols,
22167 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22169 // this.load(null,xdata,{
22170 // axis : "0 0 1 1",
22171 // axisxlabels : xdata
22176 load : function(graphtype,xdata,opts){
22177 this.raphael.clear();
22179 graphtype = this.graphtype;
22184 var r = this.raphael,
22185 fin = function () {
22186 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
22188 fout = function () {
22189 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
22191 pfin = function() {
22192 this.sector.stop();
22193 this.sector.scale(1.1, 1.1, this.cx, this.cy);
22196 this.label[0].stop();
22197 this.label[0].attr({ r: 7.5 });
22198 this.label[1].attr({ "font-weight": 800 });
22201 pfout = function() {
22202 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
22205 this.label[0].animate({ r: 5 }, 500, "bounce");
22206 this.label[1].attr({ "font-weight": 400 });
22212 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
22215 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
22218 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
22219 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
22221 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
22228 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
22233 setTitle: function(o)
22238 initEvents: function() {
22241 this.el.on('click', this.onClick, this);
22245 onClick : function(e)
22247 Roo.log('img onclick');
22248 this.fireEvent('click', this, e);
22260 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22263 * @class Roo.bootstrap.dash.NumberBox
22264 * @extends Roo.bootstrap.Component
22265 * Bootstrap NumberBox class
22266 * @cfg {String} headline Box headline
22267 * @cfg {String} content Box content
22268 * @cfg {String} icon Box icon
22269 * @cfg {String} footer Footer text
22270 * @cfg {String} fhref Footer href
22273 * Create a new NumberBox
22274 * @param {Object} config The config object
22278 Roo.bootstrap.dash.NumberBox = function(config){
22279 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
22283 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
22292 getAutoCreate : function(){
22296 cls : 'small-box ',
22304 cls : 'roo-headline',
22305 html : this.headline
22309 cls : 'roo-content',
22310 html : this.content
22324 cls : 'ion ' + this.icon
22333 cls : 'small-box-footer',
22334 href : this.fhref || '#',
22338 cfg.cn.push(footer);
22345 onRender : function(ct,position){
22346 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
22353 setHeadline: function (value)
22355 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
22358 setFooter: function (value, href)
22360 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
22363 this.el.select('a.small-box-footer',true).first().attr('href', href);
22368 setContent: function (value)
22370 this.el.select('.roo-content',true).first().dom.innerHTML = value;
22373 initEvents: function()
22387 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22390 * @class Roo.bootstrap.dash.TabBox
22391 * @extends Roo.bootstrap.Component
22392 * Bootstrap TabBox class
22393 * @cfg {String} title Title of the TabBox
22394 * @cfg {String} icon Icon of the TabBox
22395 * @cfg {Boolean} showtabs (true|false) show the tabs default true
22396 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
22399 * Create a new TabBox
22400 * @param {Object} config The config object
22404 Roo.bootstrap.dash.TabBox = function(config){
22405 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
22410 * When a pane is added
22411 * @param {Roo.bootstrap.dash.TabPane} pane
22415 * @event activatepane
22416 * When a pane is activated
22417 * @param {Roo.bootstrap.dash.TabPane} pane
22419 "activatepane" : true
22427 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
22432 tabScrollable : false,
22434 getChildContainer : function()
22436 return this.el.select('.tab-content', true).first();
22439 getAutoCreate : function(){
22443 cls: 'pull-left header',
22451 cls: 'fa ' + this.icon
22457 cls: 'nav nav-tabs pull-right',
22463 if(this.tabScrollable){
22470 cls: 'nav nav-tabs pull-right',
22481 cls: 'nav-tabs-custom',
22486 cls: 'tab-content no-padding',
22494 initEvents : function()
22496 //Roo.log('add add pane handler');
22497 this.on('addpane', this.onAddPane, this);
22500 * Updates the box title
22501 * @param {String} html to set the title to.
22503 setTitle : function(value)
22505 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
22507 onAddPane : function(pane)
22509 this.panes.push(pane);
22510 //Roo.log('addpane');
22512 // tabs are rendere left to right..
22513 if(!this.showtabs){
22517 var ctr = this.el.select('.nav-tabs', true).first();
22520 var existing = ctr.select('.nav-tab',true);
22521 var qty = existing.getCount();;
22524 var tab = ctr.createChild({
22526 cls : 'nav-tab' + (qty ? '' : ' active'),
22534 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
22537 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
22539 pane.el.addClass('active');
22544 onTabClick : function(ev,un,ob,pane)
22546 //Roo.log('tab - prev default');
22547 ev.preventDefault();
22550 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
22551 pane.tab.addClass('active');
22552 //Roo.log(pane.title);
22553 this.getChildContainer().select('.tab-pane',true).removeClass('active');
22554 // technically we should have a deactivate event.. but maybe add later.
22555 // and it should not de-activate the selected tab...
22556 this.fireEvent('activatepane', pane);
22557 pane.el.addClass('active');
22558 pane.fireEvent('activate');
22563 getActivePane : function()
22566 Roo.each(this.panes, function(p) {
22567 if(p.el.hasClass('active')){
22588 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
22590 * @class Roo.bootstrap.TabPane
22591 * @extends Roo.bootstrap.Component
22592 * Bootstrap TabPane class
22593 * @cfg {Boolean} active (false | true) Default false
22594 * @cfg {String} title title of panel
22598 * Create a new TabPane
22599 * @param {Object} config The config object
22602 Roo.bootstrap.dash.TabPane = function(config){
22603 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
22609 * When a pane is activated
22610 * @param {Roo.bootstrap.dash.TabPane} pane
22617 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
22622 // the tabBox that this is attached to.
22625 getAutoCreate : function()
22633 cfg.cls += ' active';
22638 initEvents : function()
22640 //Roo.log('trigger add pane handler');
22641 this.parent().fireEvent('addpane', this)
22645 * Updates the tab title
22646 * @param {String} html to set the title to.
22648 setTitle: function(str)
22654 this.tab.select('a', true).first().dom.innerHTML = str;
22671 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22674 * @class Roo.bootstrap.menu.Menu
22675 * @extends Roo.bootstrap.Component
22676 * Bootstrap Menu class - container for Menu
22677 * @cfg {String} html Text of the menu
22678 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
22679 * @cfg {String} icon Font awesome icon
22680 * @cfg {String} pos Menu align to (top | bottom) default bottom
22684 * Create a new Menu
22685 * @param {Object} config The config object
22689 Roo.bootstrap.menu.Menu = function(config){
22690 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
22694 * @event beforeshow
22695 * Fires before this menu is displayed
22696 * @param {Roo.bootstrap.menu.Menu} this
22700 * @event beforehide
22701 * Fires before this menu is hidden
22702 * @param {Roo.bootstrap.menu.Menu} this
22707 * Fires after this menu is displayed
22708 * @param {Roo.bootstrap.menu.Menu} this
22713 * Fires after this menu is hidden
22714 * @param {Roo.bootstrap.menu.Menu} this
22719 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
22720 * @param {Roo.bootstrap.menu.Menu} this
22721 * @param {Roo.EventObject} e
22728 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
22732 weight : 'default',
22737 getChildContainer : function() {
22738 if(this.isSubMenu){
22742 return this.el.select('ul.dropdown-menu', true).first();
22745 getAutoCreate : function()
22750 cls : 'roo-menu-text',
22758 cls : 'fa ' + this.icon
22769 cls : 'dropdown-button btn btn-' + this.weight,
22774 cls : 'dropdown-toggle btn btn-' + this.weight,
22784 cls : 'dropdown-menu'
22790 if(this.pos == 'top'){
22791 cfg.cls += ' dropup';
22794 if(this.isSubMenu){
22797 cls : 'dropdown-menu'
22804 onRender : function(ct, position)
22806 this.isSubMenu = ct.hasClass('dropdown-submenu');
22808 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
22811 initEvents : function()
22813 if(this.isSubMenu){
22817 this.hidden = true;
22819 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
22820 this.triggerEl.on('click', this.onTriggerPress, this);
22822 this.buttonEl = this.el.select('button.dropdown-button', true).first();
22823 this.buttonEl.on('click', this.onClick, this);
22829 if(this.isSubMenu){
22833 return this.el.select('ul.dropdown-menu', true).first();
22836 onClick : function(e)
22838 this.fireEvent("click", this, e);
22841 onTriggerPress : function(e)
22843 if (this.isVisible()) {
22850 isVisible : function(){
22851 return !this.hidden;
22856 this.fireEvent("beforeshow", this);
22858 this.hidden = false;
22859 this.el.addClass('open');
22861 Roo.get(document).on("mouseup", this.onMouseUp, this);
22863 this.fireEvent("show", this);
22870 this.fireEvent("beforehide", this);
22872 this.hidden = true;
22873 this.el.removeClass('open');
22875 Roo.get(document).un("mouseup", this.onMouseUp);
22877 this.fireEvent("hide", this);
22880 onMouseUp : function()
22894 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22897 * @class Roo.bootstrap.menu.Item
22898 * @extends Roo.bootstrap.Component
22899 * Bootstrap MenuItem class
22900 * @cfg {Boolean} submenu (true | false) default false
22901 * @cfg {String} html text of the item
22902 * @cfg {String} href the link
22903 * @cfg {Boolean} disable (true | false) default false
22904 * @cfg {Boolean} preventDefault (true | false) default true
22905 * @cfg {String} icon Font awesome icon
22906 * @cfg {String} pos Submenu align to (left | right) default right
22910 * Create a new Item
22911 * @param {Object} config The config object
22915 Roo.bootstrap.menu.Item = function(config){
22916 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22920 * Fires when the mouse is hovering over this menu
22921 * @param {Roo.bootstrap.menu.Item} this
22922 * @param {Roo.EventObject} e
22927 * Fires when the mouse exits this menu
22928 * @param {Roo.bootstrap.menu.Item} this
22929 * @param {Roo.EventObject} e
22935 * The raw click event for the entire grid.
22936 * @param {Roo.EventObject} e
22942 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22947 preventDefault: true,
22952 getAutoCreate : function()
22957 cls : 'roo-menu-item-text',
22965 cls : 'fa ' + this.icon
22974 href : this.href || '#',
22981 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22985 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22987 if(this.pos == 'left'){
22988 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22995 initEvents : function()
22997 this.el.on('mouseover', this.onMouseOver, this);
22998 this.el.on('mouseout', this.onMouseOut, this);
23000 this.el.select('a', true).first().on('click', this.onClick, this);
23004 onClick : function(e)
23006 if(this.preventDefault){
23007 e.preventDefault();
23010 this.fireEvent("click", this, e);
23013 onMouseOver : function(e)
23015 if(this.submenu && this.pos == 'left'){
23016 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23019 this.fireEvent("mouseover", this, e);
23022 onMouseOut : function(e)
23024 this.fireEvent("mouseout", this, e);
23036 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23039 * @class Roo.bootstrap.menu.Separator
23040 * @extends Roo.bootstrap.Component
23041 * Bootstrap Separator class
23044 * Create a new Separator
23045 * @param {Object} config The config object
23049 Roo.bootstrap.menu.Separator = function(config){
23050 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23053 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23055 getAutoCreate : function(){
23076 * @class Roo.bootstrap.Tooltip
23077 * Bootstrap Tooltip class
23078 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
23079 * to determine which dom element triggers the tooltip.
23081 * It needs to add support for additional attributes like tooltip-position
23084 * Create a new Toolti
23085 * @param {Object} config The config object
23088 Roo.bootstrap.Tooltip = function(config){
23089 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
23092 Roo.apply(Roo.bootstrap.Tooltip, {
23094 * @function init initialize tooltip monitoring.
23098 currentTip : false,
23099 currentRegion : false,
23105 Roo.get(document).on('mouseover', this.enter ,this);
23106 Roo.get(document).on('mouseout', this.leave, this);
23109 this.currentTip = new Roo.bootstrap.Tooltip();
23112 enter : function(ev)
23114 var dom = ev.getTarget();
23116 //Roo.log(['enter',dom]);
23117 var el = Roo.fly(dom);
23118 if (this.currentEl) {
23120 //Roo.log(this.currentEl);
23121 //Roo.log(this.currentEl.contains(dom));
23122 if (this.currentEl == el) {
23125 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
23133 if (this.currentTip.el) {
23134 this.currentTip.el.hide(); // force hiding...
23139 // you can not look for children, as if el is the body.. then everythign is the child..
23140 if (!el.attr('tooltip')) { //
23141 if (!el.select("[tooltip]").elements.length) {
23144 // is the mouse over this child...?
23145 bindEl = el.select("[tooltip]").first();
23146 var xy = ev.getXY();
23147 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
23148 //Roo.log("not in region.");
23151 //Roo.log("child element over..");
23154 this.currentEl = bindEl;
23155 this.currentTip.bind(bindEl);
23156 this.currentRegion = Roo.lib.Region.getRegion(dom);
23157 this.currentTip.enter();
23160 leave : function(ev)
23162 var dom = ev.getTarget();
23163 //Roo.log(['leave',dom]);
23164 if (!this.currentEl) {
23169 if (dom != this.currentEl.dom) {
23172 var xy = ev.getXY();
23173 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
23176 // only activate leave if mouse cursor is outside... bounding box..
23181 if (this.currentTip) {
23182 this.currentTip.leave();
23184 //Roo.log('clear currentEl');
23185 this.currentEl = false;
23190 'left' : ['r-l', [-2,0], 'right'],
23191 'right' : ['l-r', [2,0], 'left'],
23192 'bottom' : ['t-b', [0,2], 'top'],
23193 'top' : [ 'b-t', [0,-2], 'bottom']
23199 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
23204 delay : null, // can be { show : 300 , hide: 500}
23208 hoverState : null, //???
23210 placement : 'bottom',
23212 getAutoCreate : function(){
23219 cls : 'tooltip-arrow'
23222 cls : 'tooltip-inner'
23229 bind : function(el)
23235 enter : function () {
23237 if (this.timeout != null) {
23238 clearTimeout(this.timeout);
23241 this.hoverState = 'in';
23242 //Roo.log("enter - show");
23243 if (!this.delay || !this.delay.show) {
23248 this.timeout = setTimeout(function () {
23249 if (_t.hoverState == 'in') {
23252 }, this.delay.show);
23256 clearTimeout(this.timeout);
23258 this.hoverState = 'out';
23259 if (!this.delay || !this.delay.hide) {
23265 this.timeout = setTimeout(function () {
23266 //Roo.log("leave - timeout");
23268 if (_t.hoverState == 'out') {
23270 Roo.bootstrap.Tooltip.currentEl = false;
23278 this.render(document.body);
23281 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
23283 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
23285 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
23287 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
23289 var placement = typeof this.placement == 'function' ?
23290 this.placement.call(this, this.el, on_el) :
23293 var autoToken = /\s?auto?\s?/i;
23294 var autoPlace = autoToken.test(placement);
23296 placement = placement.replace(autoToken, '') || 'top';
23300 //this.el.setXY([0,0]);
23302 //this.el.dom.style.display='block';
23303 this.el.addClass(placement);
23305 //this.el.appendTo(on_el);
23307 var p = this.getPosition();
23308 var box = this.el.getBox();
23313 var align = Roo.bootstrap.Tooltip.alignment[placement];
23314 this.el.alignTo(this.bindEl, align[0],align[1]);
23315 //var arrow = this.el.select('.arrow',true).first();
23316 //arrow.set(align[2],
23318 this.el.addClass('in fade');
23319 this.hoverState = null;
23321 if (this.el.hasClass('fade')) {
23332 //this.el.setXY([0,0]);
23333 this.el.removeClass('in');
23349 * @class Roo.bootstrap.LocationPicker
23350 * @extends Roo.bootstrap.Component
23351 * Bootstrap LocationPicker class
23352 * @cfg {Number} latitude Position when init default 0
23353 * @cfg {Number} longitude Position when init default 0
23354 * @cfg {Number} zoom default 15
23355 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
23356 * @cfg {Boolean} mapTypeControl default false
23357 * @cfg {Boolean} disableDoubleClickZoom default false
23358 * @cfg {Boolean} scrollwheel default true
23359 * @cfg {Boolean} streetViewControl default false
23360 * @cfg {Number} radius default 0
23361 * @cfg {String} locationName
23362 * @cfg {Boolean} draggable default true
23363 * @cfg {Boolean} enableAutocomplete default false
23364 * @cfg {Boolean} enableReverseGeocode default true
23365 * @cfg {String} markerTitle
23368 * Create a new LocationPicker
23369 * @param {Object} config The config object
23373 Roo.bootstrap.LocationPicker = function(config){
23375 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
23380 * Fires when the picker initialized.
23381 * @param {Roo.bootstrap.LocationPicker} this
23382 * @param {Google Location} location
23386 * @event positionchanged
23387 * Fires when the picker position changed.
23388 * @param {Roo.bootstrap.LocationPicker} this
23389 * @param {Google Location} location
23391 positionchanged : true,
23394 * Fires when the map resize.
23395 * @param {Roo.bootstrap.LocationPicker} this
23400 * Fires when the map show.
23401 * @param {Roo.bootstrap.LocationPicker} this
23406 * Fires when the map hide.
23407 * @param {Roo.bootstrap.LocationPicker} this
23412 * Fires when click the map.
23413 * @param {Roo.bootstrap.LocationPicker} this
23414 * @param {Map event} e
23418 * @event mapRightClick
23419 * Fires when right click the map.
23420 * @param {Roo.bootstrap.LocationPicker} this
23421 * @param {Map event} e
23423 mapRightClick : true,
23425 * @event markerClick
23426 * Fires when click the marker.
23427 * @param {Roo.bootstrap.LocationPicker} this
23428 * @param {Map event} e
23430 markerClick : true,
23432 * @event markerRightClick
23433 * Fires when right click the marker.
23434 * @param {Roo.bootstrap.LocationPicker} this
23435 * @param {Map event} e
23437 markerRightClick : true,
23439 * @event OverlayViewDraw
23440 * Fires when OverlayView Draw
23441 * @param {Roo.bootstrap.LocationPicker} this
23443 OverlayViewDraw : true,
23445 * @event OverlayViewOnAdd
23446 * Fires when OverlayView Draw
23447 * @param {Roo.bootstrap.LocationPicker} this
23449 OverlayViewOnAdd : true,
23451 * @event OverlayViewOnRemove
23452 * Fires when OverlayView Draw
23453 * @param {Roo.bootstrap.LocationPicker} this
23455 OverlayViewOnRemove : true,
23457 * @event OverlayViewShow
23458 * Fires when OverlayView Draw
23459 * @param {Roo.bootstrap.LocationPicker} this
23460 * @param {Pixel} cpx
23462 OverlayViewShow : true,
23464 * @event OverlayViewHide
23465 * Fires when OverlayView Draw
23466 * @param {Roo.bootstrap.LocationPicker} this
23468 OverlayViewHide : true
23473 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
23475 gMapContext: false,
23481 mapTypeControl: false,
23482 disableDoubleClickZoom: false,
23484 streetViewControl: false,
23488 enableAutocomplete: false,
23489 enableReverseGeocode: true,
23492 getAutoCreate: function()
23497 cls: 'roo-location-picker'
23503 initEvents: function(ct, position)
23505 if(!this.el.getWidth() || this.isApplied()){
23509 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23514 initial: function()
23516 if(!this.mapTypeId){
23517 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
23520 this.gMapContext = this.GMapContext();
23522 this.initOverlayView();
23524 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
23528 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
23529 _this.setPosition(_this.gMapContext.marker.position);
23532 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
23533 _this.fireEvent('mapClick', this, event);
23537 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
23538 _this.fireEvent('mapRightClick', this, event);
23542 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
23543 _this.fireEvent('markerClick', this, event);
23547 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
23548 _this.fireEvent('markerRightClick', this, event);
23552 this.setPosition(this.gMapContext.location);
23554 this.fireEvent('initial', this, this.gMapContext.location);
23557 initOverlayView: function()
23561 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
23565 _this.fireEvent('OverlayViewDraw', _this);
23570 _this.fireEvent('OverlayViewOnAdd', _this);
23573 onRemove: function()
23575 _this.fireEvent('OverlayViewOnRemove', _this);
23578 show: function(cpx)
23580 _this.fireEvent('OverlayViewShow', _this, cpx);
23585 _this.fireEvent('OverlayViewHide', _this);
23591 fromLatLngToContainerPixel: function(event)
23593 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
23596 isApplied: function()
23598 return this.getGmapContext() == false ? false : true;
23601 getGmapContext: function()
23603 return this.gMapContext
23606 GMapContext: function()
23608 var position = new google.maps.LatLng(this.latitude, this.longitude);
23610 var _map = new google.maps.Map(this.el.dom, {
23613 mapTypeId: this.mapTypeId,
23614 mapTypeControl: this.mapTypeControl,
23615 disableDoubleClickZoom: this.disableDoubleClickZoom,
23616 scrollwheel: this.scrollwheel,
23617 streetViewControl: this.streetViewControl,
23618 locationName: this.locationName,
23619 draggable: this.draggable,
23620 enableAutocomplete: this.enableAutocomplete,
23621 enableReverseGeocode: this.enableReverseGeocode
23624 var _marker = new google.maps.Marker({
23625 position: position,
23627 title: this.markerTitle,
23628 draggable: this.draggable
23635 location: position,
23636 radius: this.radius,
23637 locationName: this.locationName,
23638 addressComponents: {
23639 formatted_address: null,
23640 addressLine1: null,
23641 addressLine2: null,
23643 streetNumber: null,
23647 stateOrProvince: null
23650 domContainer: this.el.dom,
23651 geodecoder: new google.maps.Geocoder()
23655 drawCircle: function(center, radius, options)
23657 if (this.gMapContext.circle != null) {
23658 this.gMapContext.circle.setMap(null);
23662 options = Roo.apply({}, options, {
23663 strokeColor: "#0000FF",
23664 strokeOpacity: .35,
23666 fillColor: "#0000FF",
23670 options.map = this.gMapContext.map;
23671 options.radius = radius;
23672 options.center = center;
23673 this.gMapContext.circle = new google.maps.Circle(options);
23674 return this.gMapContext.circle;
23680 setPosition: function(location)
23682 this.gMapContext.location = location;
23683 this.gMapContext.marker.setPosition(location);
23684 this.gMapContext.map.panTo(location);
23685 this.drawCircle(location, this.gMapContext.radius, {});
23689 if (this.gMapContext.settings.enableReverseGeocode) {
23690 this.gMapContext.geodecoder.geocode({
23691 latLng: this.gMapContext.location
23692 }, function(results, status) {
23694 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
23695 _this.gMapContext.locationName = results[0].formatted_address;
23696 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
23698 _this.fireEvent('positionchanged', this, location);
23705 this.fireEvent('positionchanged', this, location);
23710 google.maps.event.trigger(this.gMapContext.map, "resize");
23712 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
23714 this.fireEvent('resize', this);
23717 setPositionByLatLng: function(latitude, longitude)
23719 this.setPosition(new google.maps.LatLng(latitude, longitude));
23722 getCurrentPosition: function()
23725 latitude: this.gMapContext.location.lat(),
23726 longitude: this.gMapContext.location.lng()
23730 getAddressName: function()
23732 return this.gMapContext.locationName;
23735 getAddressComponents: function()
23737 return this.gMapContext.addressComponents;
23740 address_component_from_google_geocode: function(address_components)
23744 for (var i = 0; i < address_components.length; i++) {
23745 var component = address_components[i];
23746 if (component.types.indexOf("postal_code") >= 0) {
23747 result.postalCode = component.short_name;
23748 } else if (component.types.indexOf("street_number") >= 0) {
23749 result.streetNumber = component.short_name;
23750 } else if (component.types.indexOf("route") >= 0) {
23751 result.streetName = component.short_name;
23752 } else if (component.types.indexOf("neighborhood") >= 0) {
23753 result.city = component.short_name;
23754 } else if (component.types.indexOf("locality") >= 0) {
23755 result.city = component.short_name;
23756 } else if (component.types.indexOf("sublocality") >= 0) {
23757 result.district = component.short_name;
23758 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
23759 result.stateOrProvince = component.short_name;
23760 } else if (component.types.indexOf("country") >= 0) {
23761 result.country = component.short_name;
23765 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
23766 result.addressLine2 = "";
23770 setZoomLevel: function(zoom)
23772 this.gMapContext.map.setZoom(zoom);
23785 this.fireEvent('show', this);
23796 this.fireEvent('hide', this);
23801 Roo.apply(Roo.bootstrap.LocationPicker, {
23803 OverlayView : function(map, options)
23805 options = options || {};
23819 * @class Roo.bootstrap.Alert
23820 * @extends Roo.bootstrap.Component
23821 * Bootstrap Alert class
23822 * @cfg {String} title The title of alert
23823 * @cfg {String} html The content of alert
23824 * @cfg {String} weight ( success | info | warning | danger )
23825 * @cfg {String} faicon font-awesomeicon
23828 * Create a new alert
23829 * @param {Object} config The config object
23833 Roo.bootstrap.Alert = function(config){
23834 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23838 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23845 getAutoCreate : function()
23854 cls : 'roo-alert-icon'
23859 cls : 'roo-alert-title',
23864 cls : 'roo-alert-text',
23871 cfg.cn[0].cls += ' fa ' + this.faicon;
23875 cfg.cls += ' alert-' + this.weight;
23881 initEvents: function()
23883 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23886 setTitle : function(str)
23888 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23891 setText : function(str)
23893 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23896 setWeight : function(weight)
23899 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23902 this.weight = weight;
23904 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23907 setIcon : function(icon)
23910 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23915 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
23936 * @class Roo.bootstrap.UploadCropbox
23937 * @extends Roo.bootstrap.Component
23938 * Bootstrap UploadCropbox class
23939 * @cfg {String} emptyText show when image has been loaded
23940 * @cfg {Number} minWidth default 300
23941 * @cfg {Number} minHeight default 300
23944 * Create a new UploadCropbox
23945 * @param {Object} config The config object
23948 Roo.bootstrap.UploadCropbox = function(config){
23949 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
23953 * @event beforeSelectFile
23954 * Fire before select file
23955 * @param {Roo.bootstrap.UploadCropbox} this
23957 "beforeSelectFile" : true,
23960 * Fire after initEvent
23961 * @param {Roo.bootstrap.UploadCropbox} this
23966 * Fire after initEvent
23967 * @param {Roo.bootstrap.UploadCropbox} this
23968 * @param {String} imageData
23975 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
23977 emptyText : 'Click to upload image',
23984 cropImageData : false,
23985 cropType : 'image/png',
23989 getAutoCreate : function()
23993 cls : 'roo-upload-cropbox',
23997 cls : 'roo-upload-cropbox-image-section',
24001 cls : 'roo-upload-cropbox-canvas',
24005 cls : 'roo-upload-cropbox-image'
24011 cls : 'roo-upload-cropbox-thumb'
24017 cls : 'roo-upload-cropbox-footer-section',
24020 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
24028 cls : 'btn btn-default roo-upload-cropbox-rotate-left',
24029 html : '<i class="fa fa-undo"></i>'
24039 cls : 'btn btn-default roo-upload-cropbox-picture',
24040 html : '<i class="fa fa-picture-o"></i>'
24050 cls : 'btn btn-default roo-upload-cropbox-rotate-right',
24051 html : '<i class="fa fa-repeat"></i>'
24064 initEvents : function()
24066 this.imageSection = this.el.select('.roo-upload-cropbox-image-section', true).first();
24067 this.imageSection.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24069 this.imageCanvas = this.el.select('.roo-upload-cropbox-canvas', true).first();
24070 this.imageCanvas.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24072 this.image = this.el.select('.roo-upload-cropbox-image', true).first();
24073 this.image.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24075 this.thumb = this.el.select('.roo-upload-cropbox-thumb', true).first();
24076 this.thumb.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24078 this.footerSection = this.el.select('.roo-upload-cropbox-footer-section', true).first();
24079 this.footerSection.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24080 this.footerSection.hide();
24082 this.rotateLeft = this.el.select('.roo-upload-cropbox-rotate-left', true).first();
24083 this.rotateLeft.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24085 this.pictureBtn = this.el.select('.roo-upload-cropbox-picture', true).first();
24086 this.pictureBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24088 this.rotateRight = this.el.select('.roo-upload-cropbox-rotate-right', true).first();
24089 this.rotateRight.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
24091 this.calcThumbBoxSize();
24095 this.fireEvent('initial', this);
24100 this.image.on('load', this.onLoadCanvasImage, this);
24102 if(!this.imageSectionHasOnClickEvent){
24103 this.imageSection.on('click', this.beforeSelectFile, this);
24104 this.imageSectionHasOnClickEvent = true;
24107 this.imageSection.on('mousedown', this.onMouseDown, this);
24109 this.imageSection.on('mousemove', this.onMouseMove, this);
24111 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
24113 this.imageSection.on(mousewheel, this.onMouseWheel, this);
24115 Roo.get(document).on('mouseup', this.onMouseUp, this);
24117 this.pictureBtn.on('click', this.beforeSelectFile, this);
24119 this.rotateLeft.on('click', this.onRotateLeft, this);
24121 this.rotateRight.on('click', this.onRotateRight, this);
24125 unbind : function()
24127 this.image.un('load', this.onLoadCanvasImage, this);
24129 if(this.imageSectionHasOnClickEvent){
24130 this.imageSection.un('click', this.beforeSelectFile, this);
24131 this.imageSectionHasOnClickEvent = false;
24134 this.imageSection.un('mousedown', this.onMouseDown, this);
24136 this.imageSection.un('mousemove', this.onMouseMove, this);
24138 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
24140 this.imageSection.un(mousewheel, this.onMouseWheel, this);
24142 Roo.get(document).un('mouseup', this.onMouseUp, this);
24144 this.pictureBtn.un('click', this.beforeSelectFile, this);
24146 this.rotateLeft.un('click', this.onRotateLeft, this);
24148 this.rotateRight.un('click', this.onRotateRight, this);
24154 this.baseScale = 1;
24156 this.dragable = false;
24159 this.cropImageData = false;
24161 this.imageCanvas.dom.removeAttribute('style');
24162 this.image.dom.removeAttribute('style');
24163 this.image.attr('src', '');
24165 if(!this.imageSectionHasOnClickEvent){
24166 this.imageSection.on('click', this.beforeSelectFile, this);
24167 this.imageSectionHasOnClickEvent = true;
24172 beforeSelectFile : function(e)
24174 e.preventDefault();
24175 this.fireEvent('beforeSelectFile', this);
24178 loadCanvasImage : function(src)
24182 this.image.attr('src', src);
24185 onLoadCanvasImage : function(src)
24187 if(this.imageSectionHasOnClickEvent){
24188 this.imageSection.un('click', this.beforeSelectFile, this);
24189 this.imageSectionHasOnClickEvent = false;
24192 this.image.OriginWidth = this.image.getWidth();
24193 this.image.OriginHeight = this.image.getHeight();
24195 this.fitThumbBox();
24197 this.image.setWidth(this.image.OriginWidth * this.getScaleLevel(false));
24198 this.image.setHeight(this.image.OriginHeight * this.getScaleLevel(false));
24200 this.footerSection.show();
24202 this.setCanvasPosition();
24205 setCanvasPosition : function()
24207 var pw = (this.imageSection.getWidth(true) - this.image.getWidth()) / 2;
24208 var ph = (this.imageSection.getHeight(true) - this.image.getHeight()) / 2;
24210 this.imageCanvas.setLeft(pw);
24211 this.imageCanvas.setTop(ph);
24214 onMouseDown : function(e)
24218 this.dragable = true;
24219 this.mouseX = e.getPageX();
24220 this.mouseY = e.getPageY();
24224 onMouseMove : function(e)
24228 if (!this.dragable){
24232 var transform = new WebKitCSSMatrix(window.getComputedStyle(this.thumb.dom).webkitTransform);
24234 var minX = this.thumb.getLeft(true) + transform.m41;
24235 var minY = this.thumb.getTop(true) + transform.m42;
24237 var maxX = minX + this.thumb.getWidth() - this.image.getWidth();
24238 var maxY = minY + this.thumb.getHeight() - this.image.getHeight();
24240 if(this.rotate == 90 || this.rotate == 270){
24241 minX = this.thumb.getLeft(true) + transform.m41 - (this.image.getWidth() - this.image.getHeight()) / 2;
24242 minY = this.thumb.getTop(true) + transform.m42 + (this.image.getWidth() - this.image.getHeight()) / 2;
24244 maxX = minX + this.thumb.getWidth() - this.image.getHeight();
24245 maxY = minY + this.thumb.getHeight() - this.image.getWidth();
24248 var x = e.getPageX() - this.mouseX;
24249 var y = e.getPageY() - this.mouseY;
24251 var bgX = x + this.imageCanvas.getLeft(true);
24252 var bgY = y + this.imageCanvas.getTop(true);
24254 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
24255 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
24257 this.imageCanvas.setLeft(bgX);
24258 this.imageCanvas.setTop(bgY);
24260 this.mouseX = e.getPageX();
24261 this.mouseY = e.getPageY();
24264 onMouseUp : function(e)
24268 this.dragable = false;
24271 onMouseWheel : function(e)
24275 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
24277 var width = this.image.OriginWidth * this.getScaleLevel(false);
24278 var height = this.image.OriginHeight * this.getScaleLevel(false);
24281 e.getWheelDelta() == -1 &&
24284 (this.rotate == 0 || this.rotate == 180) && (width < this.thumb.getWidth() || height < this.thumb.getHeight())
24288 (this.rotate == 90 || this.rotate == 270) && (height < this.thumb.getWidth() || width < this.thumb.getHeight())
24292 this.scale = (e.getWheelDelta() == 1) ? (this.scale - 1) : (this.scale + 1);
24296 this.image.setWidth(width);
24297 this.image.setHeight(height);
24299 this.setCanvasPosition();
24303 onRotateLeft : function(e)
24309 (this.rotate == 0 || this.rotate == 180)
24311 (this.image.getHeight() < this.thumb.getWidth() || this.image.getWidth() < this.thumb.getHeight())
24315 (this.rotate == 90 || this.rotate == 270)
24317 (this.image.getWidth() < this.thumb.getWidth() || this.image.getHeight() < this.thumb.getHeight())
24324 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
24326 this.imageCanvas.setStyle({
24327 '-ms-transform' : 'rotate(' + this.rotate + 'deg)',
24328 '-webkit-transform' : 'rotate(' + this.rotate + 'deg)',
24329 'transform' : 'rotate(' + this.rotate + 'deg)'
24332 this.setCanvasPosition();
24336 onRotateRight : function(e)
24342 (this.rotate == 0 || this.rotate == 180)
24344 (this.image.getHeight() < this.thumb.getWidth() || this.image.getWidth() < this.thumb.getHeight())
24348 (this.rotate == 90 || this.rotate == 270)
24350 (this.image.getWidth() < this.thumb.getWidth() || this.image.getHeight() < this.thumb.getHeight())
24357 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
24359 this.imageCanvas.setStyle({
24360 '-ms-transform' : 'rotate(' + this.rotate + 'deg)',
24361 '-webkit-transform' : 'rotate(' + this.rotate + 'deg)',
24362 'transform' : 'rotate(' + this.rotate + 'deg)'
24365 this.setCanvasPosition();
24372 var canvas = document.createElement("canvas");
24374 var context = canvas.getContext("2d");
24376 canvas.width = this.minWidth;
24377 canvas.height = this.minHeight;
24379 var centerX = this.minWidth / 2;
24380 var centerY = this.minHeight / 2;
24382 var cropWidth = this.thumb.getWidth() * this.getScaleLevel(true);
24383 var cropHeight = this.thumb.getHeight() * this.getScaleLevel(true);
24385 var transform = new WebKitCSSMatrix(window.getComputedStyle(this.thumb.dom).webkitTransform);
24386 var thumbX = this.thumb.getLeft(true) + transform.m41;
24387 var thumbY = this.thumb.getTop(true) + transform.m42;
24389 var x = (thumbX - this.imageCanvas.getLeft(true)) * this.getScaleLevel(true);
24390 var y = (thumbY - this.imageCanvas.getTop(true)) * this.getScaleLevel(true);
24392 if(this.rotate == 90){
24394 x = thumbY + (this.image.getWidth() - this.image.getHeight()) / 2 - this.imageCanvas.getTop(true);
24395 y = this.image.getHeight() - this.thumb.getWidth() - (thumbX - (this.image.getWidth() - this.image.getHeight()) / 2 - this.imageCanvas.getLeft(true));
24397 x = x * this.getScaleLevel(true);
24398 y = y * this.getScaleLevel(true);
24403 cropWidth = this.thumb.getHeight() * this.getScaleLevel(true);
24404 cropHeight = this.thumb.getWidth() * this.getScaleLevel(true);
24406 canvas.width = this.minWidth > this.minHeight ? this.minWidth : this.minHeight;
24407 canvas.height = this.minWidth > this.minHeight ? this.minWidth : this.minHeight;
24409 centerX = this.minWidth > this.minHeight ? (this.minWidth / 2) : (this.minHeight / 2);
24410 centerY = this.minWidth > this.minHeight ? (this.minWidth / 2) : (this.minHeight / 2);
24412 context.translate(centerX, centerY);
24413 context.rotate(this.rotate * Math.PI / 180);
24415 context.drawImage(this.image.dom, x, y, cropWidth, cropHeight, centerX * -1, centerY * -1, this.minHeight, this.minWidth);
24417 var canvas2 = document.createElement("canvas");
24418 var context2 = canvas2.getContext("2d");
24420 canvas2.width = this.minWidth;
24421 canvas2.height = this.minHeight;
24423 context2.drawImage(canvas, Math.abs(this.minWidth - this.minHeight), 0, this.minWidth, this.minHeight, 0, 0, this.minWidth, this.minHeight);
24425 this.cropImageData = canvas2.toDataURL(this.cropType);
24427 this.fireEvent('crop', this, this.cropImageData);
24433 if(this.rotate == 270){
24435 x = thumbY + (this.image.getWidth() - this.image.getHeight()) / 2 - this.imageCanvas.getTop(true);
24436 y = thumbX - (this.image.getWidth() - this.image.getHeight()) / 2 - this.imageCanvas.getLeft(true);
24438 x = (this.image.getWidth() - this.thumb.getHeight() - x) * this.getScaleLevel(true);
24439 y = y * this.getScaleLevel(true);
24444 cropWidth = this.thumb.getHeight() * this.getScaleLevel(true);
24445 cropHeight = this.thumb.getWidth() * this.getScaleLevel(true);
24447 canvas.width = this.minWidth > this.minHeight ? this.minWidth : this.minHeight;
24448 canvas.height = this.minWidth > this.minHeight ? this.minWidth : this.minHeight;
24450 centerX = this.minWidth > this.minHeight ? (this.minWidth / 2) : (this.minHeight / 2);
24451 centerY = this.minWidth > this.minHeight ? (this.minWidth / 2) : (this.minHeight / 2);
24453 context.translate(centerX, centerY);
24454 context.rotate(this.rotate * Math.PI / 180);
24456 context.drawImage(this.image.dom, x, y, cropWidth, cropHeight, centerX * -1, centerY * -1, this.minHeight, this.minWidth);
24458 var canvas2 = document.createElement("canvas");
24459 var context2 = canvas2.getContext("2d");
24461 canvas2.width = this.minWidth;
24462 canvas2.height = this.minHeight;
24464 context2.drawImage(canvas, 0, 0, this.minWidth, this.minHeight, 0, 0, this.minWidth, this.minHeight);
24466 this.cropImageData = canvas2.toDataURL(this.cropType);
24468 this.fireEvent('crop', this, this.cropImageData);
24474 if(this.rotate == 180){
24475 x = this.image.OriginWidth - this.thumb.getWidth() * this.getScaleLevel(true) - x;
24476 y = this.image.OriginHeight - this.thumb.getHeight() * this.getScaleLevel(true) - y;
24482 context.translate(centerX, centerY);
24484 context.rotate(this.rotate * Math.PI / 180);
24486 context.drawImage(this.image.dom, x, y, cropWidth, cropHeight, centerX * -1, centerY * -1, canvas.width, canvas.height);
24488 this.cropImageData = canvas.toDataURL(this.cropType);
24490 this.fireEvent('crop', this, this.cropImageData);
24493 calcThumbBoxSize : function()
24498 width = this.minWidth * height / this.minHeight;
24500 if(this.minWidth > this.minHeight){
24502 height = this.minHeight * width / this.minWidth;
24505 this.thumb.setStyle({
24506 width : width + 'px',
24507 height : height + 'px'
24514 fitThumbBox : function()
24516 var width = this.thumb.getWidth();
24517 var height = this.image.OriginHeight * width / this.image.OriginWidth;
24519 this.baseScale = width / this.image.OriginWidth;
24521 if(this.image.OriginWidth > this.image.OriginHeight){
24522 height = this.thumb.getHeight();
24523 width = this.image.OriginWidth * height / this.image.OriginHeight;
24525 this.baseScale = height / this.image.OriginHeight;
24531 getScaleLevel : function(reverse)
24534 return Math.pow(1.1, this.scale * -1) / this.baseScale;
24537 return this.baseScale * Math.pow(1.1, this.scale);